cxhint.pas

来自「胜天进销存源码,国产优秀的进销存」· PAS 代码 · 共 1,789 行 · 第 1/4 页

PAS
1,789
字号
end;

procedure TcxCustomHintWindow.SetAnimate(AValue: TcxHintAnimate);
begin
  AnimationStyle := AValue;
end;

procedure TcxCustomHintWindow.LoadPropertiesFromController(
  const AHintController: TcxCustomHintStyleController);
begin
  Caption := AHintController.HintWindow.Caption;
  LoadPropertiesFromHintStyle(AHintController.HintStyle);
end;

procedure TcxCustomHintWindow.LoadPropertiesFromHintInterface(const AHintIntf: IcxHint);
var
  FDefaultFont: TFont;
begin
  FCaption := AHintIntf.GetHintCaption;
  Animate := AHintIntf.GetAnimate;
  AnimationDelay := AHintIntf.GetAnimationDelay;
  FCallOutPosition := AHintIntf.GetCallOutPosition;
  FBorderColor := AHintIntf.GetBorderColor;
  FHintColor := AHintIntf.GetColor;
  FIconSize := AHintIntf.GetIconSize;
  FIconType := AHintIntf.GetIconType;
  FRounded := AHintIntf.GetRounded;
  FStandardHint := AHintIntf.GetStandard;
  if FRounded = False then
    FRoundRadius := 0
  else
    FRoundRadius := AHintIntf.GetRoundRadius;
  if Assigned(AHintIntf.GetHintIcon) then
    FIcon.Assign(AHintIntf.GetHintIcon)
  else
    FreeAndNil(FIcon);
  FDefaultFont := TFont.Create;
  try
  if Assigned(AHintIntf.GetHintFont) then
    Font.Assign(AHintIntf.GetHintFont)
  else
    Font.Assign(FDefaultFont);
  if Assigned(AHintIntf.GetHintCaptionFont) then
    FCaptionFont.Assign(AHintIntf.GetHintCaptionFont)
  else
    FCaptionFont.Assign(FDefaultFont);
  finally
    FreeAndNil(FDefaultFont);
  end;
end;

procedure TcxCustomHintWindow.LoadPropertiesFromHintStyle(
  const AHintStyle: TcxCustomHintStyle);
begin
  Animate := AHintStyle.Animate;
  AnimationDelay := AHintStyle.AnimationDelay;
  FCallOutPosition := AHintStyle.CallOutPosition;
  FBorderColor := AHintStyle.BorderColor;
  FHintColor := AHintStyle.Color;
  FIcon.Assign(AHintStyle.Icon);
  FIconSize := AHintStyle.IconSize;
  FIconType := AHintStyle.IconType;
  FRounded := AHintStyle.Rounded;
  FStandardHint := AHintStyle.Standard;
  if FRounded = False then
    FRoundRadius := 0
  else
    FRoundRadius := AHintStyle.RoundRadius;
  Font.Assign(AHintStyle.Font);
  FCaptionFont.Assign(AHintStyle.CaptionFont);
end;

procedure TcxCustomHintWindow.CalculateValues;

  function GetIconWidth: Integer;
  var
    FBitmap: TBitmap;
  begin
    FBitmap := TBitmap.Create;
    try
      FBitmap.Width := FIcon.Width;
      FBitmap.Height := FIcon.Height;
      DrawIconEx(FBitmap.Canvas.Handle, 0, 0, FIcon.Handle,
        FIcon.Width, FIcon.Height, 0, 0, DI_NORMAL);
      Result := FIcon.Width;
    finally
      FBitmap.Free;
    end;
  end;

begin
  FIndentDelta := 6;
  if FRounded = False then
  begin
    FLeftRightMargint := FIndentDelta;
    FTopBottomMargin := FIndentDelta;
  end
  else
  begin
    FLeftRightMargint := (FRoundRadius div 2) + 2;
    FTopBottomMargin := (FRoundRadius div 2) + 2;
  end;
  if not FIcon.Empty then
  begin
    if FIconType <> cxhiCustom then
      FIconWidth := FIcon.Width
    else
      FIconWidth := GetIconWidth;
    FIconHeight := FIcon.Height;
    case FIconSize of
      cxisLarge:
      begin
        FIconHeight := 32;
        FIconWidth := 32;
      end;
      cxisSmall:
      begin
        FIconHeight := 16;
        FIconWidth := 16;
      end;
    end;
  end
  else
  begin
    FIconHeight := 0;
    FIconWidth := 0;
  end;
  FIconLeftMargin := FLeftRightMargint;
  FIconTopMargin := FLeftRightMargint;
end;

procedure TcxCustomHintWindow.CalculateRects(const ACaption, AText: string;
  const AMaxWidth: Integer);

  function IsCaptionEpty: Boolean;
  begin
    Result := ACaption = '';
  end;

  function GetIconHorzOffset: Integer;
  begin
    if FIconWidth > 0 then
      Result := FIndentDelta
    else
      Result := 0;
  end;

  function GetMaxCaptionWidth(AIsCaption: Boolean = True): Integer;
  var
    ADec: Integer;
  begin
    Result := AMaxWidth;
    if Result <= 0 then
    begin
      Result := MaxInt;
      Exit;
    end;
    ADec := GetIconHorzOffset + 2 * FLeftRightMargint + FIndentDelta;
    if AIsCaption then
      Inc(ADec, FIconWidth);
    Dec(Result, ADec);
  end;

  procedure GetCaptionBounds(var ARect: TRect; ACaption: string);
  begin
    DrawText(Canvas.Handle, PChar(ACaption),
      Length(ACaption), ARect, DT_CALCRECT or DT_WORDBREAK or DT_NOPREFIX);
  end;

  procedure OffsetRectWithIndents(var ARect: TRect; AIsCaption: Boolean = True);
  var
   AIconHorzOffset: Integer;
  begin
    AIconHorzOffset := GetIconHorzOffset;
    if AIsCaption then
      Inc(AIconHorzOffset, FIconWidth);
    InflateRectEx(ARect, FLeftRightMargint + AIconHorzOffset, FTopBottomMargin,
      FLeftRightMargint + AIconHorzOffset + FIndentDelta, FTopBottomMargin);
  end;

  procedure VertOffsetTextRect(var ATextRect: TRect; const ACaptionBounds: TRect);
  var
    AVertOffset: Integer;
  begin
    if RectHeight(ACaptionBounds) > FIconHeight then
      AVertOffset := RectHeight(ACaptionBounds) + FIndentDelta
    else
      AVertOffset := FIconHeight + FIndentDelta;
    Inc(ATextRect.Top, AVertOffset);
    Inc(ATextRect.Bottom, AVertOffset);
  end;

  function CalcCallOutPosition(AHintWndRect: TRect): TRect;
  begin
    Result := cxEmptyRect;
    FCalculatedCallOutPos := CalculateAutoCallOutPosition(AHintWndRect);
    with Result do
      case FCalculatedCallOutPos of
        cxbpRightBottom, cxbpRightTop: Right := FCallOutSize;
        cxbpBottomLeft, cxbpBottomRight: Bottom := FCallOutSize;
        cxbpLeftTop, cxbpLeftBottom:
          begin
            Left := FCallOutSize;
            Right := FCallOutSize;
            FIconLeftMargin := FIconLeftMargin + FCallOutSize;
          end;
        cxbpTopLeft, cxbpTopRight:
          begin
            Top := FCallOutSize;
            Bottom := FCallOutSize;
            FIconTopMargin := FIconTopMargin + FCallOutSize;
          end;
      end;
  end;

  procedure OffsetRectWithCallOutPosition(var ARect: TRect;
    const ACalloutPosition: TRect);
  begin
    with ACalloutPosition do
      InflateRectEx(ARect, Left, Top, Right, Bottom);
  end;

  procedure CorrectRectHeightWithIcon(var ARect: TRect);
  begin
    if RectHeight(ARect) < FIconHeight then
      ARect.Bottom := ARect.Top + FIconHeight;
  end;

  procedure CalculateTextsBouds(var ACaptionBounds, ATextBounds: TRect);
  begin
    if ACaption = '' then
    begin
      ATextBounds := Rect(0, 0, GetMaxCaptionWidth, 1);
      ACaptionBounds := Rect(0, 0, 0, 0);
    end
    else
    begin
      ACaptionBounds := Rect(0, 0, GetMaxCaptionWidth, 1);
      Canvas.Font.Assign(FCaptionFont);
      GetCaptionBounds(ACaptionBounds, ACaption);
      ATextBounds := Rect(0, 0, GetMaxCaptionWidth(False), 1);
    end;
    Canvas.Font.Assign(Font);
    if AText = '' then
      ATextBounds := cxEmptyRect
    else
      GetCaptionBounds(ATextBounds, AText);
  end;

  procedure OffsetRectsWithIndents(var ACaptionRect, ATextRect,
    AHintWndRect: TRect);
  var
    ACallOutPosition: TRect;
  begin
    if ACaption <> '' then
    begin
      OffsetRectWithIndents(ACaptionRect);
      OffsetRectWithIndents(ATextRect, False);
      VertOffsetTextRect(ATextRect, ACaptionRect);
      if ACaptionRect.Right > ATextRect.Right then
        ATextRect.Right := ACaptionRect.Right
      else
        ACaptionRect.Right := ATextRect.Right;
    end
    else
    begin
      OffsetRectWithIndents(ATextRect);
      CorrectRectHeightWithIcon(ATextRect);
    end;
    with ATextRect do
      AHintWndRect :=
        Rect(0, 0, Right + FLeftRightMargint, Bottom + FTopBottomMargin);
    ACallOutPosition := CalcCallOutPosition(AHintWndRect);
    if FCaption <> '' then
      OffsetRectWithCallOutPosition(ACaptionRect, ACallOutPosition);
    OffsetRectWithCallOutPosition(ATextRect, ACallOutPosition);
    OffsetRectWithCallOutPosition(AHintWndRect, ACallOutPosition);
  end;

begin
  CalculateValues;
  CalculateTextsBouds(FCaptionRect, FTextRect);
  OffsetRectsWithIndents(FCaptionRect, FTextRect, FHintWndRect);
end;

function TcxCustomHintWindow.CalculateAutoCallOutPosition(const ARect: TRect): TcxCallOutPosition;
var
  FCursorPos: TPoint;
begin
  if FCallOutPosition = cxbpAuto then
  begin
    Windows.GetCursorPos(FCursorPos);
    if FCursorPos.Y < (Screen.Height div 2) then
    begin
      if FCursorPos.X - RectWidth(ARect) < 0 then
        Result := cxbpTopLeft
      else
        Result := cxbpTopRight;
    end
    else
    begin
      if FCursorPos.X - RectWidth(ARect) < 0 then
        Result := cxbpBottomLeft
      else
        Result := cxbpBottomRight;
    end;
  end
  else
    Result := FCallOutPosition;
end;

procedure TcxCustomHintWindow.CalculateIcon;
type
  TcxRealHintIconType = (IDIAPPLICATION, IDIINFORMATION, IDIWARNING,
    IDIERROR, IDIQUESTION, IDIWINLOGO);
const
  FRealIconTypes: array[TcxRealHintIconType] of MakeIntResource = (
    IDI_APPLICATION, IDI_INFORMATION, IDI_WARNING, IDI_ERROR, IDI_QUESTION,
    IDI_WINLOGO);
begin
  if FIconType = cxhiNone then
  begin
    if Assigned(FIcon) and not FIcon.Empty then
    begin
      FreeAndNil(FIcon);
      FIcon := TIcon.Create;
    end;
    Exit;
  end;
  if FIconType = cxhiCustom then
    Exit;
  if FIconType = cxhiCurrentApplication then
    FIcon.Assign(Application.Icon)
  else
    FIcon.Handle := LoadIcon(0,
      FRealIconTypes[TcxRealHintIconType(Ord(FIconType) - 1)]);
end;

procedure TcxCustomHintWindow.EnableRegion;
begin
  CreateBalloonForm;
end;

procedure TcxCustomHintWindow.CreateBalloonForm;
var
  R: TRect;
  CallOutRgn: HRGN;
  CallOutTops: array[0..2] of TPoint;
begin
  if (FCalculatedCallOutPos = cxbpNone) and (Rounded = False) then
  begin
    DisableRegion;
    Exit;
  end;
  R := ClientRect;

  case FCalculatedCallOutPos of
    cxbpLeftBottom:
      begin
        InflateRectEx(R, FCallOutSize, 0, 0, 0);
        CallOutTops[0] := Point(R.Left, R.Bottom - FCallOutSize);
        CallOutTops[1] := Point(R.Left, R.Bottom - FCallOutSize * 2);
        CallOutTops[2] := Point(R.Left - FCallOutSize, R.Bottom - FCallOutSize);
      end;
    cxbpLeftTop:
      begin
        InflateRectEx(R, FCallOutSize, 0, 0, 0);
        CallOutTops[0] := Point(R.Left, R.Top + FCallOutSize);
        CallOutTops[1] := Point(R.Left, R.Top + FCallOutSize * 2);
        CallOutTops[2] := Point(R.Left - FCallOutSize, R.Top + FCallOutSize);
      end;
    cxbpTopRight:
      begin
        InflateRectEx(R, 0, FCallOutSize, 0, 0);
        CallOutTops[0] := Point(R.Right - FCallOutSize, R.Top);
        CallOutTops[1] := Point(R.Right - FCallOutSize * 2, R.Top);
        CallOutTops[2] := Point(R.Right - FCallOutSize, R.Top - FCallOutSize);
      end;
    cxbpTopLeft:
      begin
        InflateRectEx(R, 0, FCallOutSize, 0, 0);
        CallOutTops[0] := Point(R.Left + FCallOutSize, R.Top);
        CallOutTops[1] := Point(R.Left + FCallOutSize * 2, R.Top);
        CallOutTops[2] := Point(R.Left + FCallOutSize, R.Top - FCallOutSize);
      end;
    cxbpRightBottom:
      begin
        InflateRectEx(R, 0, 0, -FCallOutSize, 0);
        CallOutTops[0] := Point(R.Right - 1, R.Bottom - FCallOutSize);
        CallOutTops[1] := Point(R.Right - 1, R.Bottom - FCallOutSize * 2);
        CallOutTops[2] := Point(R.Right + FCallOutSize, R.Bottom - FCallOutSize);
      end;
    cxbpRightTop:
      begin
        InflateRectEx(R, 0, 0, -FCallOutSize, 0);
        CallOutTops[0] := Point(R.Right - 1, R.Top + FCallOutSize);
        CallOutTops[1] := Point(R.Right - 1, R.Top + FCallOutSize * 2);
        CallOutTops[2] := Point(R.Right + FCallOutSize, R.Top + FCallOutSize);
      end;
    cxbpBottomRight:
      begin
        InflateRectEx(R, 0, 0, 0, -FCallOutSize);
        CallOutTops[0] := Point(R.Right - FCallOutSize, R.Bottom - 1);
        CallOutTops[1] := Point(R.Right - FCallOutSize * 2, R.Bottom - 1);
        CallOutTops[2] := Point(R.Right - FCallOutSize, R.Bottom + FCallOutSize);
      end;
    cxbpBottomLeft:
      begin
        InflateRectEx(R, 0, 0, 0, -FCallOutSize);
        CallOutTops[0] := Point(R.Left + FCallOutSize, R.Bottom - 1);
        CallOutTops[1] := Point(R.Left + FCallOutSize * 2, R.Bottom - 1);
        CallOutTops[2] := Point(R.Left + FCallOutSize, R.Bottom + FCallOutSize);
      end;
  end;

  Rgn := CreateRoundRectRgn(R.Left, R.Top, R.Right, R.Bottom, FRoundRadius, FRoundRadius);
  CallOutRgn := 0;
  if FCalculatedCallOutPos <> cxbpNone then
  begin
    CallOutRgn := CreatePolygonRgn(CallOutTops, 3, WINDING);
    CombineRgn(Rgn, Rgn, CallOutRgn, RGN_OR );
  end;
  OffsetRgn(Rgn, 1, 1);
  SetWindowRgn(Handle, Rgn, True);
  if CallOutRgn <> 0 then
    DeleteObject(CallOutRgn);
end;

initialization
{$IFNDEF DELPHI6}
  UserHandle := GetModuleHandle('USER32');
  if UserHandle <> 0 then
    @AnimateWindowProc := GetProcAddress(UserHandle, 'AnimateWindow');
{$ENDIF}
  FControllerList := TList.Create;
  FHintedControlController := TcxHintedControlController.Create(nil);

finalization
  FreeAndNil(FHintedControlController);
  if FControllerList.Count <> 0 then
    raise EcxEditError.Create('HintStyleControllerList.Count <> 0');
  FreeAndNil(FControllerList);

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?