Rxhints.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:15k
- {*******************************************************}
- { }
- { Delphi VCL Extensions (RX) }
- { }
- { Copyright (c) 1997 Master-Bank }
- { }
- {*******************************************************}
- unit RxHints;
- {$I RX.INC}
- interface
- uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF} Messages,
- Graphics, Classes, Controls, Forms, Dialogs;
- type
- THintStyle = (hsRectangle, hsRoundRect, hsEllipse);
- THintPos = (hpTopRight, hpTopLeft, hpBottomRight, hpBottomLeft);
- THintShadowSize = 0..15;
- TRxHintWindow = class(THintWindow)
- private
- FSrcImage: TBitmap;
- FImage: TBitmap;
- FPos: THintPos;
- FRect: TRect;
- FTextRect: TRect;
- FTileSize: TPoint;
- FRoundFactor: Integer;
- procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND;
- {$IFDEF RX_D3}
- procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
- {$ENDIF}
- function CreateRegion(Shade: Boolean): HRgn;
- procedure FillRegion(Rgn: HRgn; Shade: Boolean);
- protected
- procedure CreateParams(var Params: TCreateParams); override;
- procedure Paint; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure ActivateHint(Rect: TRect; const AHint: string); override;
- {$IFDEF RX_D3}
- procedure ActivateHintData(Rect: TRect; const AHint: string;
- AData: Pointer); override;
- {$ENDIF}
- function CalcHintRect(MaxWidth: Integer; const AHint: string;
- AData: Pointer): TRect; {$IFDEF RX_D3} override; {$ENDIF}
- end;
- procedure SetHintStyle(Style: THintStyle; ShadowSize: THintShadowSize;
- Tail: Boolean; Alignment: TAlignment);
- procedure SetStandardHints;
- procedure RegisterHintWindow(AClass: THintWindowClass);
- function GetHintControl: TControl;
- implementation
- uses SysUtils, VclUtils, AppUtils, MaxMin;
- const
- HintStyle: THintStyle = hsRectangle;
- HintShadowSize: THintShadowSize = 0;
- HintTail: Boolean = False;
- HintAlignment: TAlignment = taLeftJustify;
- { Utility routines }
- procedure RegisterHintWindow(AClass: THintWindowClass);
- begin
- HintWindowClass := AClass;
- with Application do
- if ShowHint then begin
- ShowHint := False;
- ShowHint := True;
- end;
- end;
- procedure SetStandardHints;
- begin
- RegisterHintWindow(THintWindow);
- end;
- procedure SetHintStyle(Style: THintStyle; ShadowSize: THintShadowSize;
- Tail: Boolean; Alignment: TAlignment);
- begin
- HintStyle := Style;
- HintShadowSize := ShadowSize;
- HintTail := Tail;
- HintAlignment := Alignment;
- RegisterHintWindow(TRxHintWindow);
- end;
- function GetHintControl: TControl;
- var
- CursorPos: TPoint;
- begin
- GetCursorPos(CursorPos);
- Result := FindDragTarget(CursorPos, True);
- while (Result <> nil) and not Result.ShowHint do
- Result := Result.Parent;
- if (Result <> nil) and (csDesigning in Result.ComponentState) then
- Result := nil;
- end;
- procedure StandardHintFont(AFont: TFont);
- {$IFDEF WIN32}
- var
- NonClientMetrics: TNonClientMetrics;
- {$ENDIF}
- begin
- {$IFDEF WIN32}
- NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
- if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
- AFont.Handle := CreateFontIndirect(NonClientMetrics.lfStatusFont)
- else begin
- AFont.Name := 'MS Sans Serif';
- AFont.Size := 8;
- end;
- AFont.Color := clInfoText;
- {$ELSE}
- AFont.Name := 'MS Sans Serif';
- AFont.Size := 8;
- AFont.Color := clWindowText;
- {$ENDIF}
- end;
- {$IFDEF WIN32}
- {$IFNDEF RX_D3}
- function GetCursorHeightMargin: Integer;
- { Return number of scanlines between the scanline containing cursor hotspot
- and the last scanline included in the cursor mask. }
- var
- IconInfo: TIconInfo;
- BitmapInfoSize: Integer;
- BitmapBitsSize: Integer;
- Bitmap: PBitmapInfoHeader;
- Bits: Pointer;
- BytesPerScanline, ImageSize: Integer;
- function FindScanline(Source: Pointer; MaxLen: Cardinal;
- Value: Cardinal): Cardinal; assembler;
- asm
- PUSH ECX
- MOV ECX,EDX
- MOV EDX,EDI
- MOV EDI,EAX
- POP EAX
- REPE SCASB
- MOV EAX,ECX
- MOV EDI,EDX
- end;
- begin
- { Default value is entire icon height }
- Result := GetSystemMetrics(SM_CYCURSOR);
- if GetIconInfo(GetCursor, IconInfo) then
- try
- GetDIBSizes(IconInfo.hbmMask, BitmapInfoSize, BitmapBitsSize);
- Bitmap := AllocMem(BitmapInfoSize + BitmapBitsSize);
- try
- Bits := Pointer(Longint(Bitmap) + BitmapInfoSize);
- if GetDIB(IconInfo.hbmMask, 0, Bitmap^, Bits^) and
- (Bitmap^.biBitCount = 1) then
- begin
- { Point Bits to the end of this bottom-up bitmap }
- with Bitmap^ do
- begin
- BytesPerScanline := ((biWidth * biBitCount + 31) and not 31) div 8;
- ImageSize := biWidth * BytesPerScanline;
- Bits := Pointer(Integer(Bits) + BitmapBitsSize - ImageSize);
- { Use the width to determine the height since another mask bitmap
- may immediately follow }
- Result := FindScanline(Bits, ImageSize, $FF);
- { In case the and mask is blank, look for an empty scanline in the
- xor mask. }
- if (Result = 0) and (biHeight >= 2 * biWidth) then
- Result := FindScanline(Pointer(Integer(Bits) - ImageSize),
- ImageSize, $00);
- Result := Result div BytesPerScanline;
- end;
- Dec(Result, IconInfo.yHotSpot);
- end;
- finally
- FreeMem(Bitmap, BitmapInfoSize + BitmapBitsSize);
- end;
- finally
- if IconInfo.hbmColor <> 0 then DeleteObject(IconInfo.hbmColor);
- if IconInfo.hbmMask <> 0 then DeleteObject(IconInfo.hbmMask);
- end;
- end;
- {$ENDIF}
- {$ENDIF}
- { TRxHintWindow }
- constructor TRxHintWindow.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- StandardHintFont(Canvas.Font);
- FImage := TBitmap.Create;
- FSrcImage := TBitmap.Create;
- end;
- destructor TRxHintWindow.Destroy;
- begin
- FSrcImage.Free;
- FImage.Free;
- inherited Destroy;
- end;
- procedure TRxHintWindow.CreateParams(var Params: TCreateParams);
- begin
- inherited CreateParams(Params);
- Params.Style := Params.Style and not WS_BORDER;
- end;
- {$IFDEF RX_D3}
- procedure TRxHintWindow.WMNCPaint(var Message: TMessage);
- begin
- end;
- {$ENDIF}
- procedure TRxHintWindow.WMEraseBkgnd(var Message: TMessage);
- begin
- Message.Result := 1;
- end;
- function TRxHintWindow.CreateRegion(Shade: Boolean): HRgn;
- var
- R: TRect;
- W, TileOffs: Integer;
- Tail, Dest: HRgn;
- P: TPoint;
- function CreatePolyRgn(const Points: array of TPoint): HRgn;
- type
- PPoints = ^TPoints;
- TPoints = array[0..0] of TPoint;
- begin
- Result := CreatePolygonRgn(PPoints(@Points)^, High(Points) + 1, WINDING);
- end;
- begin
- R := FRect;
- Result := 0;
- if Shade then OffsetRect(R, HintShadowSize, HintShadowSize);
- case HintStyle of
- hsRoundRect: Result := CreateRoundRectRgn(R.Left, R.Top, R.Right, R.Bottom,
- FRoundFactor, FRoundFactor);
- hsEllipse: Result := CreateEllipticRgnIndirect(R);
- hsRectangle: Result := CreateRectRgnIndirect(R);
- end;
- if HintTail then begin
- R := FTextRect;
- GetCursorPos(P);
- TileOffs := 0;
- if FPos in [hpTopLeft, hpBottomLeft] then TileOffs := Width;
- if Shade then begin
- OffsetRect(R, HintShadowSize, HintShadowSize);
- Inc(TileOffs, HintShadowSize);
- end;
- W := Min(Max(8, Min(WidthOf(R), HeightOf(R)) div 4), WidthOf(R) div 2);
- case FPos of
- hpTopRight:
- Tail := CreatePolyRgn([Point(TileOffs, Height - HintShadowSize),
- Point(R.Left + W div 4, R.Bottom), Point(R.Left + 2 * W, R.Bottom)]);
- hpTopLeft:
- Tail := CreatePolyRgn([Point(TileOffs, Height - HintShadowSize),
- Point(R.Right - W div 4, R.Bottom), Point(R.Right - 2 * W, R.Bottom)]);
- hpBottomRight:
- Tail := CreatePolyRgn([Point(TileOffs, 0),
- Point(R.Left + W div 4, R.Top), Point(R.Left + 2 * W, R.Top)]);
- else {hpBottomLeft}
- Tail := CreatePolyRgn([Point(TileOffs, 0),
- Point(R.Right - W div 4, R.Top), Point(R.Right - 2 * W, R.Top)]);
- end;
- try
- Dest := Result;
- Result := CreateRectRgnIndirect(R);
- try
- CombineRgn(Result, Dest, Tail, RGN_OR);
- finally
- if Dest <> 0 then DeleteObject(Dest);
- end;
- finally
- DeleteObject(Tail);
- end;
- end;
- end;
- procedure TRxHintWindow.FillRegion(Rgn: HRgn; Shade: Boolean);
- begin
- if Shade then begin
- FImage.Canvas.Brush.Bitmap :=
- {$IFDEF RX_D4}
- AllocPatternBitmap(clBtnFace, clWindowText);
- {$ELSE}
- CreateTwoColorsBrushPattern(clBtnFace, clWindowText);
- {$ENDIF}
- FImage.Canvas.Pen.Style := psClear;
- end
- else begin
- FImage.Canvas.Pen.Style := psSolid;
- FImage.Canvas.Brush.Color := Color;
- end;
- try
- PaintRgn(FImage.Canvas.Handle, Rgn);
- if not Shade then begin
- FImage.Canvas.Brush.Color := Font.Color;
- {$IFDEF WIN32}
- if (HintStyle = hsRectangle) and not HintTail then begin
- DrawEdge(FImage.Canvas.Handle, FRect, BDR_RAISEDOUTER, BF_RECT);
- end
- else
- {$ENDIF}
- FrameRgn(FImage.Canvas.Handle, Rgn, FImage.Canvas.Brush.Handle, 1, 1);
- end;
- finally
- if Shade then begin
- {$IFDEF RX_D4}
- FImage.Canvas.Brush.Bitmap := nil;
- {$ELSE}
- FImage.Canvas.Brush.Bitmap.Free;
- {$ENDIF}
- FImage.Canvas.Pen.Style := psSolid;
- end;
- FImage.Canvas.Brush.Color := Color;
- end;
- end;
- procedure TRxHintWindow.Paint;
- var
- R: TRect;
- FShadeRgn, FRgn: HRgn;
- procedure PaintText(R: TRect);
- const
- Flag: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER);
- {$IFNDEF WIN32}
- var
- ACaption: array[0..255] of Char;
- {$ENDIF}
- begin
- {$IFDEF WIN32}
- DrawText(FImage.Canvas.Handle, PChar(Caption),
- {$ELSE}
- DrawText(FImage.Canvas.Handle, StrPCopy(ACaption, Caption),
- {$ENDIF}
- -1, R, DT_NOPREFIX or DT_WORDBREAK or Flag[HintAlignment]
- {$IFDEF RX_D4} or DrawTextBiDiModeFlagsReadingOnly {$ENDIF});
- end;
- begin
- R := ClientRect;
- FImage.Handle := CreateCompatibleBitmap(Canvas.Handle,
- WidthOf(ClientRect), HeightOf(ClientRect));
- FImage.Canvas.Font := Self.Canvas.Font;
- if (HintStyle <> hsRectangle) or (HintShadowSize > 0) or HintTail then
- FImage.Canvas.Draw(0, 0, FSrcImage);
- FRgn := CreateRegion(False);
- FShadeRgn := CreateRegion(True);
- try
- FillRegion(FShadeRgn, True);
- FillRegion(FRgn, False);
- finally
- DeleteObject(FShadeRgn);
- DeleteObject(FRgn);
- end;
- R := FTextRect;
- if HintAlignment = taLeftJustify then Inc(R.Left, 2);
- PaintText(R);
- Canvas.Draw(0, 0, FImage);
- end;
- procedure TRxHintWindow.ActivateHint(Rect: TRect; const AHint: string);
- var
- R: TRect;
- ScreenDC: HDC;
- P: TPoint;
- begin
- Caption := AHint;
- GetCursorPos(P);
- FPos := hpBottomRight;
- R := CalcHintRect(Screen.Width, AHint, nil);
- {$IFDEF RX_D3}
- OffsetRect(R, Rect.Left - R.Left, Rect.Top - R.Top);
- {$ELSE}
- {$IFDEF WIN32}
- OffsetRect(R, P.X, P.Y + GetCursorHeightMargin);
- {$ELSE}
- OffsetRect(R, P.X, Rect.Top - R.Top);
- {$ENDIF WIN32}
- {$ENDIF}
- Rect := R;
- BoundsRect := Rect;
- if HintTail then begin
- Rect.Top := P.Y - Height - 3;
- if Rect.Top < 0 then Rect.Top := BoundsRect.Top
- else Rect.Bottom := Rect.Top + HeightOf(BoundsRect);
- Rect.Left := P.X + 1;
- if Rect.Left < 0 then Rect.Left := BoundsRect.Left
- else Rect.Right := Rect.Left + WidthOf(BoundsRect);
- end;
- if Rect.Top + Height > Screen.Height then begin
- Rect.Top := Screen.Height - Height;
- if Rect.Top <= P.Y then Rect.Top := P.Y - Height - 3;
- end;
- if Rect.Left + Width > Screen.Width then begin
- Rect.Left := Screen.Width - Width;
- if Rect.Left <= P.X then Rect.Left := P.X - Width -3;
- end;
- if Rect.Left < 0 then begin
- Rect.Left := 0;
- if Rect.Left + Width >= P.X then Rect.Left := P.X - Width - 1;
- end;
- if Rect.Top < 0 then begin
- Rect.Top := 0;
- if Rect.Top + Height >= P.Y then Rect.Top := P.Y - Height - 1;
- end;
- if (HintStyle <> hsRectangle) or (HintShadowSize > 0) or HintTail then
- begin
- FPos := hpBottomRight;
- if (Rect.Top + Height < P.Y) then FPos := hpTopRight;
- if (Rect.Left + Width < P.X) then begin
- if FPos = hpBottomRight then FPos := hpBottomLeft
- else FPos := hpTopLeft;
- end;
- if HintTail then begin
- if (FPos in [hpBottomRight, hpBottomLeft]) then begin
- OffsetRect(FRect, 0, FTileSize.Y);
- OffsetRect(FTextRect, 0, FTileSize.Y);
- end;
- if (FPos in [hpBottomRight, hpTopRight]) then begin
- OffsetRect(FRect, FTileSize.X, 0);
- OffsetRect(FTextRect, FTileSize.X, 0);
- end;
- end;
- if HandleAllocated then begin
- SetWindowPos(Handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW or
- SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOMOVE);
- if Screen.ActiveForm <> nil then UpdateWindow(Screen.ActiveForm.Handle);
- end;
- ScreenDC := GetDC(0);
- try
- with FSrcImage do begin
- Width := WidthOf(BoundsRect);
- Height := HeightOf(BoundsRect);
- BitBlt(Canvas.Handle, 0, 0, Width, Height, ScreenDC, Rect.Left,
- Rect.Top, SRCCOPY);
- end;
- finally
- ReleaseDC(0, ScreenDC);
- end;
- end;
- SetWindowPos(Handle, HWND_TOPMOST, Rect.Left, Rect.Top, 0,
- 0, SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOSIZE);
- end;
- function TRxHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string;
- AData: Pointer): TRect;
- const
- Flag: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER);
- var
- A: Integer;
- X, Y, Factor: Double;
- {$IFNDEF WIN32}
- ACaption: array[0..255] of Char;
- {$ENDIF}
- begin
- Result := Rect(0, 0, MaxWidth, 0);
- DrawText(Canvas.Handle,
- {$IFDEF WIN32}
- PChar(AHint),
- {$ELSE}
- StrPCopy(ACaption, AHint),
- {$ENDIF}
- -1, Result, DT_CALCRECT or DT_WORDBREAK or DT_NOPREFIX or Flag[HintAlignment]
- {$IFDEF RX_D4} or DrawTextBiDiModeFlagsReadingOnly {$ENDIF});
- Inc(Result.Right, 8);
- Inc(Result.Bottom, 4);
- FRect := Result;
- FTextRect := Result;
- InflateRect(FTextRect, -1, -1);
- case HintAlignment of
- taCenter: OffsetRect(FTextRect, -1, 0);
- taRightJustify: OffsetRect(FTextRect, -4, 0);
- end;
- FRoundFactor := Max(6, Min(WidthOf(Result), HeightOf(Result)) div 4);
- if HintStyle = hsRoundRect then
- InflateRect(FRect, FRoundFactor div 4, FRoundFactor div 4)
- else if HintStyle = hsEllipse then begin
- X := WidthOf(FRect) / 2;
- Y := HeightOf(FRect) / 2;
- if (X <> 0) and (Y <> 0) then begin
- Factor := Round(Y / 3);
- A := Round(Sqrt((Sqr(X) * Sqr(Y + Factor)) / (Sqr(Y + Factor) - Sqr(Y))));
- InflateRect(FRect, A - Round(X), Round(Factor));
- end;
- end;
- Result := FRect;
- OffsetRect(FRect, -Result.Left, -Result.Top);
- OffsetRect(FTextRect, -Result.Left, -Result.Top);
- Inc(Result.Right, HintShadowSize);
- Inc(Result.Bottom, HintShadowSize);
- if HintTail then begin
- FTileSize.Y := Max(14, Min(WidthOf(FTextRect), HeightOf(FTextRect)) div 2);
- FTileSize.X := FTileSize.Y - 8;
- Inc(Result.Right, FTileSize.X);
- Inc(Result.Bottom, FTileSize.Y);
- end;
- end;
- {$IFDEF RX_D3}
- procedure TRxHintWindow.ActivateHintData(Rect: TRect; const AHint: string;
- AData: Pointer);
- begin
- ActivateHint(Rect, AHint);
- end;
- {$ENDIF}
- end.