fccombobutton.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:37k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit fccombobutton;
  2. {$include fcifdef.pas}
  3. interface
  4. uses Windows, Messages, Classes, Controls, Forms, Graphics, StdCtrls,
  5.   ExtCtrls, CommCtrl, buttons,
  6.   fccommon;
  7. type
  8. //  TButtonLayout = (blGlyphLeft, blGlyphRight, blGlyphTop, blGlyphBottom);
  9. //  TButtonState = (bsUp, bsDisabled, bsDown, bsExclusive);
  10. //  TButtonStyle = (bsAutoDetect, bsWin31, bsNew);
  11. //  TNumGlyphs = 1..4;
  12.   TfcComboButton = class;
  13.   TfcComboButtonActionLink = class(TControlActionLink)
  14.   protected
  15.     FClient: TSpeedButton;
  16.     procedure AssignClient(AClient: TObject); override;
  17.     function IsCheckedLinked: Boolean; override;
  18.     {$ifdef fcDelphi6Up}
  19.     function IsGroupIndexLinked: Boolean; override;
  20.     procedure SetGroupIndex(Value: Integer); override;
  21.     {$endif}
  22.     procedure SetChecked(Value: Boolean); override;
  23.   end;
  24.   TfcComboButton = class(TGraphicControl)
  25.   private
  26.     FGroupIndex: Integer;
  27.     FDown: Boolean;
  28.     FDragging: Boolean;
  29.     FAllowAllUp: Boolean;
  30.     FLayout: TButtonLayout;
  31.     FSpacing: Integer;
  32.     FTransparent: Boolean;
  33.     FMargin: Integer;
  34.     FFlat: Boolean;
  35.     FMouseInControl: Boolean;
  36.     FEllipsis: boolean;
  37.     procedure GlyphChanged(Sender: TObject);
  38.     procedure UpdateExclusive;
  39.     function GetGlyph: TBitmap;
  40.     procedure SetGlyph(Value: TBitmap);
  41.     function GetNumGlyphs: TNumGlyphs;
  42.     procedure SetNumGlyphs(Value: TNumGlyphs);
  43.     procedure SetDown(Value: Boolean);
  44.     procedure SetFlat(Value: Boolean);
  45.     procedure SetAllowAllUp(Value: Boolean);
  46.     procedure SetGroupIndex(Value: Integer);
  47.     procedure SetLayout(Value: TButtonLayout);
  48.     procedure SetSpacing(Value: Integer);
  49.     procedure SetTransparent(Value: Boolean);
  50.     procedure SetMargin(Value: Integer);
  51.     procedure UpdateTracking;
  52.     procedure WMLButtonDblClk(var Message: TWMLButtonDown); message WM_LBUTTONDBLCLK;
  53.     procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
  54.     procedure CMButtonPressed(var Message: TMessage); message CM_BUTTONPRESSED;
  55.     procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  56.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  57.     procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  58.     procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
  59.     procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
  60.     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  61.   protected
  62.     FGlyph: Pointer;
  63.     FState: TButtonState;
  64.     procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
  65.     function GetActionLinkClass: TControlActionLinkClass; override;
  66.     function GetPalette: HPALETTE; override;
  67.     procedure Loaded; override;
  68.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  69.       X, Y: Integer); override;
  70.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  71.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  72.       X, Y: Integer); override;
  73.     procedure Paint; override;
  74.     property MouseInControl: Boolean read FMouseInControl;
  75.     property Ellipsis: boolean read FEllipsis write FEllipsis;
  76.   public
  77.     constructor Create(AOwner: TComponent); override;
  78.     destructor Destroy; override;
  79.     procedure Click; override;
  80.   published
  81.     property Action;
  82.     property AllowAllUp: Boolean read FAllowAllUp write SetAllowAllUp default False;
  83.     property Anchors;
  84.     property BiDiMode;
  85.     property Constraints;
  86.     property GroupIndex: Integer read FGroupIndex write SetGroupIndex default 0;
  87.     property Down: Boolean read FDown write SetDown default False;
  88.     property Caption;
  89.     property Enabled;
  90.     property Flat: Boolean read FFlat write SetFlat default False;
  91.     property Font;
  92.     property Glyph: TBitmap read GetGlyph write SetGlyph;
  93.     property Layout: TButtonLayout read FLayout write SetLayout default blGlyphLeft;
  94.     property Margin: Integer read FMargin write SetMargin default -1;
  95.     property NumGlyphs: TNumGlyphs read GetNumGlyphs write SetNumGlyphs default 1;
  96.     property ParentFont;
  97.     property ParentShowHint;
  98.     property ParentBiDiMode;
  99.     property PopupMenu;
  100.     property ShowHint;
  101.     property Spacing: Integer read FSpacing write SetSpacing default 4;
  102.     property Transparent: Boolean read FTransparent write SetTransparent default True;
  103.     property Visible;
  104.     property OnClick;
  105.     property OnDblClick;
  106.     property OnMouseDown;
  107.     property OnMouseMove;
  108.     property OnMouseUp;
  109.   end;
  110.   TGlyphList = class(TImageList)
  111.   private
  112.     Used: TBits;
  113.     FCount: Integer;
  114.     function AllocateIndex: Integer;
  115.   public
  116.     constructor CreateSize(AWidth, AHeight: Integer);
  117.     destructor Destroy; override;
  118.     function AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
  119.     procedure Delete(Index: Integer);
  120.     property Count: Integer read FCount;
  121.   end;
  122.   TfcComboButtonGlyph = class
  123.   private
  124.     FOriginal: TBitmap;
  125.     FGlyphList: TGlyphList;
  126.     FIndexs: array[TButtonState] of Integer;
  127.     FTransparentColor: TColor;
  128.     FNumGlyphs: TNumGlyphs;
  129.     FOnChange: TNotifyEvent;
  130.     FComboButton: TControl;
  131.     procedure GlyphChanged(Sender: TObject);
  132.     procedure SetGlyph(Value: TBitmap);
  133.     procedure SetNumGlyphs(Value: TNumGlyphs);
  134.     procedure Invalidate;
  135.     function CreateButtonGlyph(State: TButtonState): Integer;
  136.     procedure DrawButtonGlyph(Canvas: TCanvas; const GlyphPos: TPoint;
  137.       State: TButtonState; Transparent: Boolean);
  138.     procedure DrawButtonText(Canvas: TCanvas; const Caption: string;
  139.       TextBounds: TRect; State: TButtonState; BiDiFlags: Longint);
  140.     procedure CalcButtonLayout(Canvas: TCanvas; const Client: TRect;
  141.       const Offset: TPoint; const Caption: string; Layout: TButtonLayout;
  142.       Margin, Spacing: Integer; var GlyphPos: TPoint; var TextBounds: TRect;
  143.       BiDiFlags: Longint);
  144.   public
  145.     property ComboButton: TControl read FComboButton;
  146.     constructor Create(AComboButton: TControl);
  147.     destructor Destroy; override;
  148.     { return the text rectangle }
  149.     function Draw(Canvas: TCanvas; const Client: TRect; const Offset: TPoint;
  150.       const Caption: string; Layout: TButtonLayout; Margin, Spacing: Integer;
  151.       State: TButtonState; Transparent: Boolean; BiDiFlags: Longint): TRect;
  152.     property Glyph: TBitmap read FOriginal write SetGlyph;
  153.     property NumGlyphs: TNumGlyphs read FNumGlyphs write SetNumGlyphs;
  154.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  155.   end;
  156. implementation
  157. uses Consts, SysUtils, ActnList,
  158.      {$ifdef fcDelphi7Up}
  159.      Themes,
  160.      {$endif}
  161.      {$ifdef ThemeManager}
  162.      thememgr, themesrv, uxtheme,
  163.      {$endif}
  164. ImgList;
  165. //{$R Buttons.res}
  166. {function GetBitBtnGlyph(Kind: TBitBtnKind): TBitmap;
  167. begin
  168.   if BitBtnGlyphs[Kind] = nil then
  169.   begin
  170.     BitBtnGlyphs[Kind] := TBitmap.Create;
  171.     BitBtnGlyphs[Kind].LoadFromResourceName(HInstance, BitBtnResNames[Kind]);
  172.   end;
  173.   Result := BitBtnGlyphs[Kind];
  174. end;
  175. }
  176. type
  177.   TGlyphCache = class
  178.   private
  179.     GlyphLists: TList;
  180.   public
  181.     constructor Create;
  182.     destructor Destroy; override;
  183.     function GetList(AWidth, AHeight: Integer): TGlyphList;
  184.     procedure ReturnList(List: TGlyphList);
  185.     function Empty: Boolean;
  186.   end;
  187.     
  188. { TGlyphList }
  189.     
  190. constructor TGlyphList.CreateSize(AWidth, AHeight: Integer);
  191. begin
  192.   inherited CreateSize(AWidth, AHeight);
  193.   Used := TBits.Create;
  194. end;
  195.     
  196. destructor TGlyphList.Destroy;
  197. begin
  198.   Used.Free;
  199.   inherited Destroy;
  200. end;
  201.     
  202. function TGlyphList.AllocateIndex: Integer;
  203. begin
  204.   Result := Used.OpenBit;
  205.   if Result >= Used.Size then
  206.   begin
  207.     Result := inherited Add(nil, nil);
  208.     Used.Size := Result + 1;
  209.   end;
  210.   Used[Result] := True;
  211. end;
  212. function TGlyphList.AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
  213. begin
  214.   Result := AllocateIndex;
  215.   ReplaceMasked(Result, Image, MaskColor);
  216.   Inc(FCount);
  217. end;
  218.     
  219. procedure TGlyphList.Delete(Index: Integer);
  220. begin
  221.   if Used[Index] then
  222.   begin
  223.     Dec(FCount);
  224.     Used[Index] := False;
  225.   end;
  226. end;
  227.     
  228. { TGlyphCache }
  229.     
  230. constructor TGlyphCache.Create;
  231. begin
  232.   inherited Create;
  233.   GlyphLists := TList.Create;
  234. end;
  235.     
  236. destructor TGlyphCache.Destroy;
  237. begin
  238.   GlyphLists.Free;
  239.   inherited Destroy;
  240. end;
  241. function TGlyphCache.GetList(AWidth, AHeight: Integer): TGlyphList;
  242. var
  243.   I: Integer;
  244. begin
  245.   for I := GlyphLists.Count - 1 downto 0 do
  246.   begin
  247.     Result := GlyphLists[I];
  248.     with Result do
  249.       if (AWidth = Width) and (AHeight = Height) then Exit;
  250.   end;
  251.   Result := TGlyphList.CreateSize(AWidth, AHeight);
  252.   GlyphLists.Add(Result);
  253. end;
  254.     
  255. procedure TGlyphCache.ReturnList(List: TGlyphList);
  256. begin
  257.   if List = nil then Exit;
  258.   if List.Count = 0 then
  259.   begin
  260.     GlyphLists.Remove(List);
  261.     List.Free;
  262.   end;
  263. end;
  264.     
  265. function TGlyphCache.Empty: Boolean;
  266. begin
  267.   Result := GlyphLists.Count = 0;
  268. end;
  269.     
  270. var
  271.   GlyphCache: TGlyphCache = nil;
  272.   ButtonCount: Integer = 0;
  273. { TfcComboButtonGlyph }
  274. constructor TfcComboButtonGlyph.Create;
  275. var
  276.   I: TButtonState;
  277. begin
  278.   inherited Create;
  279.   FOriginal := TBitmap.Create;
  280.   FOriginal.OnChange := GlyphChanged;
  281.   FTransparentColor := clOlive;
  282.   FNumGlyphs := 1;
  283.   for I := Low(I) to High(I) do
  284.     FIndexs[I] := -1;
  285.   if GlyphCache = nil then GlyphCache := TGlyphCache.Create;
  286.   FComboButton:= AComboButton;
  287. end;
  288. destructor TfcComboButtonGlyph.Destroy;
  289. begin
  290.   FOriginal.Free;
  291.   Invalidate;
  292.   if Assigned(GlyphCache) and GlyphCache.Empty then
  293.   begin
  294.     GlyphCache.Free;
  295.     GlyphCache := nil;
  296.   end;
  297.   inherited Destroy;
  298. end;
  299.     
  300. procedure TfcComboButtonGlyph.Invalidate;
  301. var
  302.   I: TButtonState;
  303. begin
  304.   for I := Low(I) to High(I) do
  305.   begin
  306.     if FIndexs[I] <> -1 then FGlyphList.Delete(FIndexs[I]);
  307.     FIndexs[I] := -1;
  308.   end;
  309.   GlyphCache.ReturnList(FGlyphList);
  310.   FGlyphList := nil;
  311. end;
  312.     
  313. procedure TfcComboButtonGlyph.GlyphChanged(Sender: TObject);
  314. begin
  315.   if Sender = FOriginal then
  316.   begin
  317.     FTransparentColor := FOriginal.TransparentColor;
  318.     Invalidate;
  319.     if Assigned(FOnChange) then FOnChange(Self);
  320.   end;
  321. end;
  322.     
  323. procedure TfcComboButtonGlyph.SetGlyph(Value: TBitmap);
  324. var
  325.   Glyphs: Integer;
  326. begin
  327.   Invalidate;
  328.   FOriginal.Assign(Value);
  329.   if (Value <> nil) and (Value.Height > 0) then
  330.   begin
  331.     FTransparentColor := Value.TransparentColor;
  332.     if Value.Width mod Value.Height = 0 then
  333.     begin
  334.       Glyphs := Value.Width div Value.Height;
  335.       if Glyphs > 4 then Glyphs := 1;
  336.       SetNumGlyphs(Glyphs);
  337.     end;
  338.   end;
  339. end;
  340.     
  341. procedure TfcComboButtonGlyph.SetNumGlyphs(Value: TNumGlyphs);
  342. begin
  343.   if (Value <> FNumGlyphs) and (Value > 0) then
  344.   begin
  345.     Invalidate;
  346.     FNumGlyphs := Value;
  347.     GlyphChanged(Glyph);
  348.   end;
  349. end;
  350.     
  351. function TfcComboButtonGlyph.CreateButtonGlyph(State: TButtonState): Integer;
  352. const
  353.   ROP_DSPDxax = $00E20746;
  354. var
  355.   TmpImage, DDB, MonoBmp: TBitmap;
  356.   IWidth, IHeight: Integer;
  357.   IRect, ORect: TRect;
  358.   I: TButtonState;
  359.   DestDC: HDC;
  360. begin
  361.   if (State = bsDown) and (NumGlyphs < 3) then State := bsUp;
  362.   Result := FIndexs[State];
  363.   if Result <> -1 then Exit;
  364.   if (FOriginal.Width or FOriginal.Height) = 0 then Exit;
  365.   IWidth := FOriginal.Width div FNumGlyphs;
  366.   IHeight := FOriginal.Height;
  367.   if FGlyphList = nil then
  368.   begin
  369.     if GlyphCache = nil then GlyphCache := TGlyphCache.Create;
  370.     FGlyphList := GlyphCache.GetList(IWidth, IHeight);
  371.   end;
  372.   TmpImage := TBitmap.Create;
  373.   try
  374.     TmpImage.Width := IWidth;
  375.     TmpImage.Height := IHeight;
  376.     IRect := Rect(0, 0, IWidth, IHeight);
  377.     TmpImage.Canvas.Brush.Color := clBtnFace;
  378.     TmpImage.Palette := CopyPalette(FOriginal.Palette);
  379.     I := State;
  380.     if Ord(I) >= NumGlyphs then I := bsUp;
  381.     ORect := Rect(Ord(I) * IWidth, 0, (Ord(I) + 1) * IWidth, IHeight);
  382.     case State of
  383.       bsUp, bsDown,
  384.       bsExclusive:
  385.         begin
  386.           TmpImage.Canvas.CopyRect(IRect, FOriginal.Canvas, ORect);
  387.           if FOriginal.TransparentMode = tmFixed then
  388.             FIndexs[State] := FGlyphList.AddMasked(TmpImage, FTransparentColor)
  389.           else
  390.             FIndexs[State] := FGlyphList.AddMasked(TmpImage, clDefault);
  391.         end;
  392.       bsDisabled:
  393.         begin
  394.           MonoBmp := nil;
  395.           DDB := nil;
  396.           try
  397.             MonoBmp := TBitmap.Create;
  398.             DDB := TBitmap.Create;
  399.             DDB.Assign(FOriginal);
  400.             DDB.HandleType := bmDDB;
  401.             if NumGlyphs > 1 then
  402.             with TmpImage.Canvas do
  403.             begin    { Change white & gray to clBtnHighlight and clBtnShadow }
  404.               CopyRect(IRect, DDB.Canvas, ORect);
  405.               MonoBmp.Monochrome := True;
  406.               MonoBmp.Width := IWidth;
  407.               MonoBmp.Height := IHeight;
  408.     
  409.               { Convert white to clBtnHighlight }
  410.               DDB.Canvas.Brush.Color := clWhite;
  411.               MonoBmp.Canvas.CopyRect(IRect, DDB.Canvas, ORect);
  412.               Brush.Color := clBtnHighlight;
  413.               DestDC := Handle;
  414.               SetTextColor(DestDC, clBlack);
  415.               SetBkColor(DestDC, clWhite);
  416.               BitBlt(DestDC, 0, 0, IWidth, IHeight,
  417.                      MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  418.               { Convert gray to clBtnShadow }
  419.               DDB.Canvas.Brush.Color := clGray;
  420.               MonoBmp.Canvas.CopyRect(IRect, DDB.Canvas, ORect);
  421.               Brush.Color := clBtnShadow;
  422.               DestDC := Handle;
  423.               SetTextColor(DestDC, clBlack);
  424.               SetBkColor(DestDC, clWhite);
  425.               BitBlt(DestDC, 0, 0, IWidth, IHeight,
  426.                      MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  427.     
  428.               { Convert transparent color to clBtnFace }
  429.               DDB.Canvas.Brush.Color := ColorToRGB(FTransparentColor);
  430.               MonoBmp.Canvas.CopyRect(IRect, DDB.Canvas, ORect);
  431.               Brush.Color := clBtnFace;
  432.               DestDC := Handle;
  433.               SetTextColor(DestDC, clBlack);
  434.               SetBkColor(DestDC, clWhite);
  435.               BitBlt(DestDC, 0, 0, IWidth, IHeight,
  436.                      MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  437.             end
  438.             else
  439.             begin
  440.               { Create a disabled version }
  441.               with MonoBmp do
  442.               begin
  443.                 Assign(FOriginal);
  444.                 HandleType := bmDDB;
  445.                 Canvas.Brush.Color := clBlack;
  446.                 Width := IWidth;
  447.                 if Monochrome then
  448.                 begin
  449.                   Canvas.Font.Color := clWhite;
  450.                   Monochrome := False;
  451.                   Canvas.Brush.Color := clWhite;
  452.                 end;
  453.                 Monochrome := True;
  454.               end;
  455.               with TmpImage.Canvas do
  456.               begin
  457.                 Brush.Color := clBtnFace;
  458.                 FillRect(IRect);
  459.                 Brush.Color := clBtnHighlight;
  460.                 SetTextColor(Handle, clBlack);
  461.                 SetBkColor(Handle, clWhite);
  462.                 BitBlt(Handle, 1, 1, IWidth, IHeight,
  463.                   MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  464.                 Brush.Color := clBtnShadow;
  465.                 SetTextColor(Handle, clBlack);
  466.                 SetBkColor(Handle, clWhite);
  467.                 BitBlt(Handle, 0, 0, IWidth, IHeight,
  468.                   MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  469.               end;
  470.             end;
  471.           finally
  472.             DDB.Free;
  473.             MonoBmp.Free;
  474.           end;
  475.           FIndexs[State] := FGlyphList.AddMasked(TmpImage, clDefault);
  476.         end;
  477.     end;
  478.   finally
  479.     TmpImage.Free;
  480.   end;
  481.   Result := FIndexs[State];
  482.   FOriginal.Dormant;
  483. end;
  484. procedure TfcComboButtonGlyph.DrawButtonGlyph(Canvas: TCanvas; const GlyphPos: TPoint;
  485.   State: TButtonState; Transparent: Boolean);
  486. var
  487.   Index: Integer;
  488.   {$ifdef fcUseThemeManager}
  489.   Details: TThemedElementDetails;
  490.   R: TRect;
  491.   Button: TThemedButton;
  492.   {$endif}
  493. begin
  494.   if FOriginal = nil then Exit;
  495.   if (FOriginal.Width = 0) or (FOriginal.Height = 0) then Exit;
  496.   Index := CreateButtonGlyph(State);
  497.   with GlyphPos do
  498.   begin
  499.     if fcUseThemes(ComboButton) then
  500.     begin
  501.      {$ifdef fcUseThemeManager}
  502.       R.TopLeft := GlyphPos;
  503.       R.Right := R.Left + FOriginal.Width div FNumGlyphs;
  504.       R.Bottom := R.Top + FOriginal.Height;
  505.       case State of
  506.         bsDisabled:
  507.           Button := tbPushButtonDisabled;
  508.         bsDown,
  509.         bsExclusive:
  510.           Button := tbPushButtonPressed;
  511.       else
  512.         // bsUp
  513.         Button := tbPushButtonNormal;
  514.       end;
  515.       Details := ThemeServices.GetElementDetails(Button);
  516.       ThemeServices.DrawIcon(Canvas.Handle, Details, R, FGlyphList.Handle, Index);
  517.      {$endif}
  518.     end
  519.     else
  520.       if Transparent or (State = bsExclusive) then
  521.       begin
  522.         ImageList_DrawEx(FGlyphList.Handle, Index, Canvas.Handle, X, Y, 0, 0,
  523.           clNone, clNone, ILD_Transparent)
  524.       end
  525.       else
  526.         ImageList_DrawEx(FGlyphList.Handle, Index, Canvas.Handle, X, Y, 0, 0,
  527.           ColorToRGB(clBtnFace), clNone, ILD_Normal);
  528.   end;
  529. end;
  530. procedure TfcComboButtonGlyph.DrawButtonText(Canvas: TCanvas; const Caption: string;
  531.   TextBounds: TRect; State: TButtonState; BiDiFlags: LongInt);
  532. begin
  533.   with Canvas do
  534.   begin
  535.     Brush.Style := bsClear;
  536.     if State = bsDisabled then
  537.     begin
  538.       OffsetRect(TextBounds, 1, 1);
  539.       Font.Color := clBtnHighlight;
  540.       DrawText(Handle, PChar(Caption), Length(Caption), TextBounds,
  541.         DT_CENTER or DT_VCENTER or BiDiFlags);
  542.       OffsetRect(TextBounds, -1, -1);
  543.       Font.Color := clBtnShadow;
  544.       DrawText(Handle, PChar(Caption), Length(Caption), TextBounds,
  545.         DT_CENTER or DT_VCENTER or BiDiFlags);
  546.     end else
  547.       DrawText(Handle, PChar(Caption), Length(Caption), TextBounds,
  548.         DT_CENTER or DT_VCENTER or BiDiFlags);
  549.   end;
  550. end;
  551.     
  552. procedure TfcComboButtonGlyph.CalcButtonLayout(Canvas: TCanvas; const Client: TRect;
  553.   const Offset: TPoint; const Caption: string; Layout: TButtonLayout; Margin,
  554.   Spacing: Integer; var GlyphPos: TPoint; var TextBounds: TRect;
  555.   BiDiFlags: LongInt);
  556. var
  557.   TextPos: TPoint;
  558.   ClientSize, GlyphSize, TextSize: TPoint;
  559.   TotalSize: TPoint;
  560. begin
  561.   if (BiDiFlags and DT_RIGHT) = DT_RIGHT then
  562.     if Layout = blGlyphLeft then Layout := blGlyphRight
  563.     else 
  564.       if Layout = blGlyphRight then Layout := blGlyphLeft;
  565.   { calculate the item sizes }
  566.   ClientSize := Point(Client.Right - Client.Left, Client.Bottom -
  567.     Client.Top);
  568.     
  569.   if FOriginal <> nil then
  570.     GlyphSize := Point(FOriginal.Width div FNumGlyphs, FOriginal.Height) else
  571.     GlyphSize := Point(0, 0);
  572.     
  573.   if Length(Caption) > 0 then
  574.   begin
  575.     TextBounds := Rect(0, 0, Client.Right - Client.Left, 0);
  576.     DrawText(Canvas.Handle, PChar(Caption), Length(Caption), TextBounds,
  577.       DT_CALCRECT or BiDiFlags);
  578.     TextSize := Point(TextBounds.Right - TextBounds.Left, TextBounds.Bottom -
  579.       TextBounds.Top);
  580.   end
  581.   else
  582.   begin
  583.     TextBounds := Rect(0, 0, 0, 0);
  584.     TextSize := Point(0,0);
  585.   end;
  586.     
  587.   { If the layout has the glyph on the right or the left, then both the
  588.     text and the glyph are centered vertically.  If the glyph is on the top
  589.     or the bottom, then both the text and the glyph are centered horizontally.}
  590.   if Layout in [blGlyphLeft, blGlyphRight] then
  591.   begin
  592.     GlyphPos.Y := (ClientSize.Y - GlyphSize.Y + 1) div 2;
  593.     TextPos.Y := (ClientSize.Y - TextSize.Y + 1) div 2;
  594.   end
  595.   else
  596.   begin
  597.     GlyphPos.X := (ClientSize.X - GlyphSize.X + 1) div 2;
  598.     TextPos.X := (ClientSize.X - TextSize.X + 1) div 2;
  599.   end;
  600.     
  601.   { if there is no text or no bitmap, then Spacing is irrelevant }
  602.   if (TextSize.X = 0) or (GlyphSize.X = 0) then
  603.     Spacing := 0;
  604.     
  605.   { adjust Margin and Spacing }
  606.   if Margin = -1 then
  607.   begin
  608.     if Spacing = -1 then
  609.     begin
  610.       TotalSize := Point(GlyphSize.X + TextSize.X, GlyphSize.Y + TextSize.Y);
  611.       if Layout in [blGlyphLeft, blGlyphRight] then
  612.         Margin := (ClientSize.X - TotalSize.X) div 3
  613.       else
  614.         Margin := (ClientSize.Y - TotalSize.Y) div 3;
  615.       Spacing := Margin;
  616.     end
  617.     else
  618.     begin
  619.       TotalSize := Point(GlyphSize.X + Spacing + TextSize.X, GlyphSize.Y +
  620.         Spacing + TextSize.Y);
  621.       if Layout in [blGlyphLeft, blGlyphRight] then
  622.         Margin := (ClientSize.X - TotalSize.X + 1) div 2
  623.       else
  624.         Margin := (ClientSize.Y - TotalSize.Y + 1) div 2;
  625.     end;
  626.   end
  627.   else
  628.   begin
  629.     if Spacing = -1 then
  630.     begin
  631.       TotalSize := Point(ClientSize.X - (Margin + GlyphSize.X), ClientSize.Y -
  632.         (Margin + GlyphSize.Y));
  633.       if Layout in [blGlyphLeft, blGlyphRight] then
  634.         Spacing := (TotalSize.X - TextSize.X) div 2
  635.       else
  636.         Spacing := (TotalSize.Y - TextSize.Y) div 2;
  637.     end;
  638.   end;
  639.     
  640.   case Layout of
  641.     blGlyphLeft:
  642.       begin
  643.         GlyphPos.X := Margin;
  644.         TextPos.X := GlyphPos.X + GlyphSize.X + Spacing;
  645.       end;
  646.     blGlyphRight:
  647.       begin
  648.         GlyphPos.X := ClientSize.X - Margin - GlyphSize.X;
  649.         TextPos.X := GlyphPos.X - Spacing - TextSize.X;
  650.       end;
  651.     blGlyphTop:
  652.       begin
  653.         GlyphPos.Y := Margin;
  654.         TextPos.Y := GlyphPos.Y + GlyphSize.Y + Spacing;
  655.       end;
  656.     blGlyphBottom:
  657.       begin
  658.         GlyphPos.Y := ClientSize.Y - Margin - GlyphSize.Y;
  659.         TextPos.Y := GlyphPos.Y - Spacing - TextSize.Y;
  660.       end;
  661.   end;
  662.     
  663.   { fixup the result variables }
  664.   with GlyphPos do
  665.   begin
  666.     Inc(X, Client.Left + Offset.X);
  667.     Inc(Y, Client.Top + Offset.Y);
  668.   end;
  669.   { Themed text is not shifted, but gets a different color. }
  670.   { Themed text is not shifted, but gets a different color. }
  671.   if fcUseThemes(ComboButton) then
  672.     OffsetRect(TextBounds, TextPos.X + Client.Left, TextPos.Y + Client.Top)
  673.   else
  674.     OffsetRect(TextBounds, TextPos.X + Client.Left + Offset.X, TextPos.Y + Client.Top + Offset.Y);
  675. end;
  676.     
  677. function TfcComboButtonGlyph.Draw(Canvas: TCanvas; const Client: TRect;
  678.   const Offset: TPoint; const Caption: string; Layout: TButtonLayout;
  679.   Margin, Spacing: Integer; State: TButtonState; Transparent: Boolean;
  680.   BiDiFlags: LongInt): TRect;
  681. var
  682.   GlyphPos: TPoint;
  683. begin
  684.   CalcButtonLayout(Canvas, Client, Offset, Caption, Layout, Margin, Spacing,
  685.     GlyphPos, Result, BiDiFlags);
  686.   DrawButtonGlyph(Canvas, GlyphPos, State, Transparent);
  687.   DrawButtonText(Canvas, Caption, Result, State, BiDiFlags);
  688. end;
  689. procedure TfcComboButtonActionLink.AssignClient(AClient: TObject);
  690. begin
  691.   inherited AssignClient(AClient);
  692.   FClient := AClient as TSpeedButton;
  693. end;
  694. function TfcComboButtonActionLink.IsCheckedLinked: Boolean;
  695. begin
  696.   Result := inherited IsCheckedLinked and (FClient.GroupIndex <> 0) and
  697.     FClient.AllowAllUp and (FClient.Down = (Action as TCustomAction).Checked);
  698. end;
  699. {$ifdef fcDelphi6Up}
  700. function TfcComboButtonActionLink.IsGroupIndexLinked: Boolean;
  701. begin
  702.   Result := (FClient is TSpeedButton) and
  703.     (TSpeedButton(FClient).GroupIndex = (Action as TCustomAction).GroupIndex);
  704. end;
  705. {$endif}
  706. procedure TfcComboButtonActionLink.SetChecked(Value: Boolean);
  707. begin
  708.   if IsCheckedLinked then TSpeedButton(FClient).Down := Value;
  709. end;
  710. {$ifdef fcDelphi6Up}
  711. procedure TfcComboButtonActionLink.SetGroupIndex(Value: Integer);
  712. begin
  713.   if IsGroupIndexLinked then TSpeedButton(FClient).GroupIndex := Value;
  714. end;
  715. {$endif}
  716. { TfcComboButton }
  717. constructor TfcComboButton.Create(AOwner: TComponent);
  718. begin
  719.   FGlyph := TfcComboButtonGlyph.Create(self);
  720.   TfcComboButtonGlyph(FGlyph).OnChange := GlyphChanged;
  721.   inherited Create(AOwner);
  722.   SetBounds(0, 0, 23, 22);
  723.   ControlStyle := [csCaptureMouse, csDoubleClicks];
  724.   ParentFont := True;
  725.   Color := clBtnFace;
  726.   FSpacing := 4;
  727.   FMargin := -1;
  728.   FLayout := blGlyphLeft;
  729.   FTransparent := True;
  730.   Inc(ButtonCount);
  731. end;
  732.     
  733. destructor TfcComboButton.Destroy;
  734. begin
  735.   Dec(ButtonCount);
  736.   inherited Destroy;
  737.   TfcComboButtonGlyph(FGlyph).Free;
  738. end;
  739. {$ifdef ThemeManager}
  740. procedure PerformEraseBackground(Control: TControl; DC: HDC);
  741. var
  742.   LastOrigin: TPoint;
  743. begin
  744.   GetWindowOrgEx(DC, LastOrigin);
  745.   SetWindowOrgEx(DC, LastOrigin.X + Control.Left, LastOrigin.Y + Control.Top, nil);
  746.   Control.Parent.Perform(WM_ERASEBKGND, Integer(DC), Integer(DC));
  747.   SetWindowOrgEx(DC, LastOrigin.X, LastOrigin.Y, nil);
  748. end;
  749. {$endif}
  750. // Should likely support button style as well as combobutton
  751. procedure TfcComboButton.Paint;
  752. const
  753.   DownStyles: array[Boolean] of Integer = (BDR_RAISEDINNER, BDR_SUNKENOUTER);
  754.   FillStyles: array[Boolean] of Integer = (BF_MIDDLE, 0);
  755. var
  756.   PaintRect: TRect;
  757.   DrawFlags: Integer;
  758.   Offset: TPoint;
  759.   {$ifdef fcUseThemeManager}
  760.   ComboBox: TThemedCombobox;
  761.   Details: TThemedElementDetails;
  762.   W, X, Y: Integer;
  763.   R: TRect;
  764.   Pressed: boolean;
  765.   {$endif}
  766. begin
  767.   if not Enabled then
  768.   begin
  769.     FState := bsDisabled;
  770.     FDragging := False;
  771.   end
  772.   else if FState = bsDisabled then
  773.     if FDown and (GroupIndex <> 0) then
  774.       FState := bsExclusive
  775.     else
  776.       FState := bsUp;
  777.   Canvas.Font := Self.Font;
  778.   if fcUseThemes(self) then
  779.   begin
  780.     {$ifdef fcUseThemeManager}
  781.     PerformEraseBackground(Self, Canvas.Handle);
  782.     if Ellipsis then begin
  783.        Pressed:= FState in [bsDown, bsExclusive];
  784.        if Pressed then
  785.           Details := ThemeServices.GetElementDetails(tbPushButtonPressed)
  786.        else
  787.           if MouseInControl then
  788.              Details := ThemeServices.GetElementDetails(tbPushButtonHot)
  789.           else
  790.              Details := ThemeServices.GetElementDetails(tbPushButtonNormal);
  791.        PaintRect := ClientRect;
  792.        ThemeServices.DrawElement(Canvas.Handle, Details, PaintRect);
  793.        R:= PaintRect;
  794.        X := R.Left + ((R.Right - R.Left) shr 1) - 1;
  795.        Y := R.Top + ((R.Bottom - R.Top) shr 1) - 1;
  796.        W := ClientWidth shr 3;
  797.        if W = 0 then W := 1;
  798.        PatBlt(Canvas.Handle, X, Y, W, W, BLACKNESS);
  799.        PatBlt(Canvas.handle, X - (W * 2), Y, W, W, BLACKNESS);
  800.        PatBlt(Canvas.Handle, X + (W * 2), Y, W, W, BLACKNESS);
  801.     end
  802.     else begin
  803.        if not Enabled then // Not ellpisis
  804.          ComboBox:= tcDropDownButtonDisabled
  805.        else
  806.          if FState in [bsDown, bsExclusive] then
  807.            ComboBox:= tcDropDownButtonPressed
  808.          else
  809.            if MouseInControl then
  810.              ComboBox:= tcDropDownButtonHot
  811.            else
  812.               ComboBox:= tcDropDownButtonNormal;
  813.        PaintRect := ClientRect;
  814.        if (parent.parent<>nil) and (parent.parent.parent<>nil) and
  815.           not fcIsClass(parent.parent.parent.classtype, 'TCustomGrid') then
  816.        begin
  817.          PaintRect.Top:= PaintRect.Top-1;
  818.          PaintRect.Bottom:= PaintRect.Bottom+1;
  819.          PaintRect.Right:= PaintRect.Right+1;
  820.          PaintRect.Left:= PaintRect.Left+1;
  821.        end
  822.        else begin  // parent of combo is grid
  823.          PaintRect.Bottom:= PaintRect.Bottom+1;
  824.        end;
  825.        Details := ThemeServices.GetElementDetails(ComboBox);
  826.        ThemeServices.DrawElement(Canvas.Handle, Details, PaintRect);
  827.        PaintRect := ThemeServices.ContentRect(Canvas.Handle, Details, PaintRect);
  828.        if ComboBox = tcDropDownButtonPressed then
  829.        begin
  830.          Offset := Point(0, 0);
  831.        end
  832.        else
  833.          Offset := Point(0, 0);
  834.        TfcComboButtonGlyph(FGlyph).Draw(Canvas, PaintRect, Offset, Caption, FLayout, FMargin, FSpacing, FState, Transparent,
  835.          DrawTextBiDiModeFlags(0));
  836.      end
  837.     {$endif}
  838.   end
  839.   else
  840.   begin
  841.     PaintRect := Rect(0, 0, Width, Height);
  842.     if not FFlat then
  843.     begin
  844.       DrawFlags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT;
  845.       if FState in [bsDown, bsExclusive] then
  846.         DrawFlags := DrawFlags or DFCS_PUSHED;
  847.       DrawFrameControl(Canvas.Handle, PaintRect, DFC_BUTTON, DrawFlags);
  848.     end
  849.     else
  850.     begin
  851.       if (FState in [bsDown, bsExclusive]) or
  852.         (FMouseInControl and (FState <> bsDisabled)) or
  853.         (csDesigning in ComponentState) then
  854.         DrawEdge(Canvas.Handle, PaintRect, DownStyles[FState in [bsDown, bsExclusive]],
  855.           FillStyles[Transparent] or BF_RECT)
  856.       else if not Transparent then
  857.       begin
  858.         Canvas.Brush.Color := Color;
  859.         Canvas.FillRect(PaintRect);
  860.       end;
  861.       InflateRect(PaintRect, -1, -1);
  862.     end;
  863.     if FState in [bsDown, bsExclusive] then
  864.     begin
  865.       if (FState = bsExclusive) and (not FFlat or not FMouseInControl) then
  866.       begin
  867.         Canvas.Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight);
  868.         Canvas.FillRect(PaintRect);
  869.       end;
  870.       Offset.X := 1;
  871.       Offset.Y := 1;
  872.     end
  873.     else
  874.     begin
  875.       Offset.X := 0;
  876.       Offset.Y := 0;
  877.     end;
  878.     TfcComboButtonGlyph(FGlyph).Draw(Canvas, PaintRect, Offset, Caption, FLayout, FMargin,
  879.       FSpacing, FState, Transparent, DrawTextBiDiModeFlags(0));
  880.   end;
  881. end;
  882. procedure TfcComboButton.UpdateTracking;
  883. var
  884.   P: TPoint;
  885. begin
  886.   if FFlat then
  887.   begin
  888.     if Enabled then
  889.     begin
  890.       GetCursorPos(P);
  891.       FMouseInControl := not (FindDragTarget(P, True) = Self);
  892.       if FMouseInControl then
  893.         Perform(CM_MOUSELEAVE, 0, 0)
  894.       else
  895.         Perform(CM_MOUSEENTER, 0, 0);
  896.     end;
  897.   end;
  898. end;
  899.     
  900. procedure TfcComboButton.Loaded;
  901. var
  902.   State: TButtonState;
  903. begin
  904.   inherited Loaded;
  905.   if Enabled then
  906.     State := bsUp
  907.   else
  908.     State := bsDisabled;
  909.   TfcComboButtonGlyph(FGlyph).CreateButtonGlyph(State);
  910. end;
  911. procedure TfcComboButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  912.   X, Y: Integer);
  913. begin
  914.   inherited MouseDown(Button, Shift, X, Y);
  915.   if (Button = mbLeft) and Enabled then
  916.   begin
  917.     if not FDown then
  918.     begin
  919.       FState := bsDown;
  920.       Invalidate;
  921.     end;
  922.     FDragging := True;
  923.   end;
  924. end;
  925. procedure TfcComboButton.MouseMove(Shift: TShiftState; X, Y: Integer);
  926. var
  927.   NewState: TButtonState;
  928. begin
  929.   inherited MouseMove(Shift, X, Y);
  930.   if FDragging then
  931.   begin
  932.     if not FDown then NewState := bsUp
  933.     else NewState := bsExclusive;
  934.     if (X >= 0) and (X < ClientWidth) and (Y >= 0) and (Y <= ClientHeight) then
  935.       if FDown then NewState := bsExclusive else NewState := bsDown;
  936.     if NewState <> FState then
  937.     begin
  938.       FState := NewState;
  939.       Invalidate;
  940.     end;
  941.   end
  942.   else if not FMouseInControl then
  943.     UpdateTracking;
  944. end;
  945.     
  946. procedure TfcComboButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
  947.   X, Y: Integer);
  948. var
  949.   DoClick: Boolean;
  950. begin
  951.   inherited MouseUp(Button, Shift, X, Y);
  952.   if FDragging then
  953.   begin
  954.     FDragging := False;
  955.     DoClick := (X >= 0) and (X < ClientWidth) and (Y >= 0) and (Y <= ClientHeight);
  956.     if FGroupIndex = 0 then
  957.     begin
  958.       { Redraw face in-case mouse is captured }
  959.       FState := bsUp;
  960.       FMouseInControl := False;
  961.       if DoClick and not (FState in [bsExclusive, bsDown]) then
  962.         Invalidate;
  963.     end
  964.     else
  965.       if DoClick then
  966.       begin
  967.         SetDown(not FDown);
  968.         if FDown then Repaint;
  969.       end
  970.       else
  971.       begin
  972.         if FDown then FState := bsExclusive;
  973.         Repaint;
  974.       end;
  975.     if DoClick then Click;
  976.     UpdateTracking;
  977.   end;
  978. end;
  979.     
  980. procedure TfcComboButton.Click;
  981. begin
  982.   inherited Click;
  983. end;
  984. function TfcComboButton.GetPalette: HPALETTE;
  985. begin
  986.   Result := Glyph.Palette;
  987. end;
  988. function TfcComboButton.GetActionLinkClass: TControlActionLinkClass;
  989. begin
  990.   Result := TfcComboButtonActionLink;
  991. end;
  992. function TfcComboButton.GetGlyph: TBitmap;
  993. begin
  994.   Result := TfcComboButtonGlyph(FGlyph).Glyph;
  995. end;
  996. procedure TfcComboButton.SetGlyph(Value: TBitmap);
  997. begin
  998.   TfcComboButtonGlyph(FGlyph).Glyph := Value;
  999.   Invalidate;
  1000. end;
  1001.     
  1002. function TfcComboButton.GetNumGlyphs: TNumGlyphs;
  1003. begin
  1004.   Result := TfcComboButtonGlyph(FGlyph).NumGlyphs;
  1005. end;
  1006.     
  1007. procedure TfcComboButton.SetNumGlyphs(Value: TNumGlyphs);
  1008. begin
  1009.   if Value < 0 then Value := 1
  1010.   else if Value > 4 then Value := 4;
  1011.   if Value <> TfcComboButtonGlyph(FGlyph).NumGlyphs then
  1012.   begin
  1013.     TfcComboButtonGlyph(FGlyph).NumGlyphs := Value;
  1014.     Invalidate;
  1015.   end;
  1016. end;
  1017.     
  1018. procedure TfcComboButton.GlyphChanged(Sender: TObject);
  1019. begin
  1020.   Invalidate;
  1021. end;
  1022.     
  1023. procedure TfcComboButton.UpdateExclusive;
  1024. var
  1025.   Msg: TMessage;
  1026. begin
  1027.   if (FGroupIndex <> 0) and (Parent <> nil) then
  1028.   begin
  1029.     Msg.Msg := CM_BUTTONPRESSED;
  1030.     Msg.WParam := FGroupIndex;
  1031.     Msg.LParam := Longint(Self);
  1032.     Msg.Result := 0;
  1033.     Parent.Broadcast(Msg);
  1034.   end;
  1035. end;
  1036. procedure TfcComboButton.SetDown(Value: Boolean);
  1037. begin
  1038.   if FGroupIndex = 0 then Value := False;
  1039.   if Value <> FDown then
  1040.   begin
  1041.     if FDown and (not FAllowAllUp) then Exit;
  1042.     FDown := Value;
  1043.     if Value then
  1044.     begin
  1045.       if FState = bsUp then Invalidate;
  1046.       FState := bsExclusive
  1047.     end
  1048.     else
  1049.     begin
  1050.       FState := bsUp;
  1051.       Repaint;
  1052.     end;
  1053.     if Value then UpdateExclusive;
  1054.   end;
  1055. end;
  1056.     
  1057. procedure TfcComboButton.SetFlat(Value: Boolean);
  1058. begin
  1059.   if Value <> FFlat then
  1060.   begin
  1061.     FFlat := Value;
  1062.     Invalidate;
  1063.   end;
  1064. end;
  1065.     
  1066. procedure TfcComboButton.SetGroupIndex(Value: Integer);
  1067. begin
  1068.   if FGroupIndex <> Value then
  1069.   begin
  1070.     FGroupIndex := Value;
  1071.     UpdateExclusive;
  1072.   end;
  1073. end;
  1074.     
  1075. procedure TfcComboButton.SetLayout(Value: TButtonLayout);
  1076. begin
  1077.   if FLayout <> Value then
  1078.   begin
  1079.     FLayout := Value;
  1080.     Invalidate;
  1081.   end;
  1082. end;
  1083.     
  1084. procedure TfcComboButton.SetMargin(Value: Integer);
  1085. begin
  1086.   if (Value <> FMargin) and (Value >= -1) then
  1087.   begin
  1088.     FMargin := Value;
  1089.     Invalidate;
  1090.   end;
  1091. end;
  1092.     
  1093. procedure TfcComboButton.SetSpacing(Value: Integer);
  1094. begin
  1095.   if Value <> FSpacing then
  1096.   begin
  1097.     FSpacing := Value;
  1098.     Invalidate;
  1099.   end;
  1100. end;
  1101. procedure TfcComboButton.SetTransparent(Value: Boolean);
  1102. begin
  1103.   if Value <> FTransparent then
  1104.   begin
  1105.     FTransparent := Value;
  1106.     if Value then
  1107.       ControlStyle := ControlStyle - [csOpaque] else
  1108.       ControlStyle := ControlStyle + [csOpaque];
  1109.     Invalidate;
  1110.   end;
  1111. end;
  1112. procedure TfcComboButton.SetAllowAllUp(Value: Boolean);
  1113. begin
  1114.   if FAllowAllUp <> Value then
  1115.   begin
  1116.     FAllowAllUp := Value;
  1117.     UpdateExclusive;
  1118.   end;
  1119. end;
  1120.     
  1121. procedure TfcComboButton.WMLButtonDblClk(var Message: TWMLButtonDown);
  1122. begin
  1123.   inherited;
  1124.   if FDown then DblClick;
  1125. end;
  1126. procedure TfcComboButton.CMEnabledChanged(var Message: TMessage);
  1127. const
  1128.   NewState: array[Boolean] of TButtonState = (bsDisabled, bsUp);
  1129. begin
  1130.   TfcComboButtonGlyph(FGlyph).CreateButtonGlyph(NewState[Enabled]);
  1131.   UpdateTracking;
  1132.   Repaint;
  1133. end;
  1134.     
  1135. procedure TfcComboButton.CMButtonPressed(var Message: TMessage);
  1136. var
  1137.   Sender: TfcComboButton;
  1138. begin
  1139.   if Message.WParam = FGroupIndex then
  1140.   begin
  1141.     Sender := TfcComboButton(Message.LParam);
  1142.     if Sender <> Self then
  1143.     begin
  1144.       if Sender.Down and FDown then
  1145.       begin
  1146.         FDown := False;
  1147.         FState := bsUp;
  1148.         if (Action is TCustomAction) then
  1149.           TCustomAction(Action).Checked := False;
  1150.         Invalidate;
  1151.       end;
  1152.       FAllowAllUp := Sender.AllowAllUp;
  1153.     end;
  1154.   end;
  1155. end;
  1156. procedure TfcComboButton.CMDialogChar(var Message: TCMDialogChar);
  1157. begin
  1158.   with Message do
  1159.     if IsAccel(CharCode, Caption) and Enabled and Visible and
  1160.       (Parent <> nil) and Parent.Showing then
  1161.     begin
  1162.       Click;
  1163.       Result := 1;
  1164.     end else
  1165.       inherited;
  1166. end;
  1167.     
  1168. procedure TfcComboButton.CMFontChanged(var Message: TMessage);
  1169. begin
  1170.   Invalidate;
  1171. end;
  1172.     
  1173. procedure TfcComboButton.CMTextChanged(var Message: TMessage);
  1174. begin
  1175.   Invalidate;
  1176. end;
  1177.     
  1178. procedure TfcComboButton.CMSysColorChange(var Message: TMessage);
  1179. begin
  1180.   with TfcComboButtonGlyph(FGlyph) do
  1181.   begin
  1182.     Invalidate;
  1183.     CreateButtonGlyph(FState);
  1184.   end;
  1185. end;
  1186.     
  1187. procedure TfcComboButton.CMMouseEnter(var Message: TMessage);
  1188. var
  1189.   NeedRepaint: Boolean;
  1190. begin
  1191.   inherited;
  1192.   { Don't draw a border if DragMode <> dmAutomatic since this button is meant to 
  1193.     be used as a dock client. }
  1194.   NeedRepaint := FFlat and not FMouseInControl and Enabled and (DragMode <> dmAutomatic) and (GetCapture = 0);
  1195.   { Windows XP introduced hot states also for non-flat buttons. }
  1196.   if (NeedRepaint or fcUseThemes(self)) and not (csDesigning in ComponentState) then
  1197.   begin
  1198.     FMouseInControl := True;
  1199.     if Enabled then
  1200.       Repaint;
  1201.   end;
  1202. end;
  1203. procedure TfcComboButton.CMMouseLeave(var Message: TMessage);
  1204. var
  1205.   NeedRepaint: Boolean;
  1206. begin
  1207.   inherited;
  1208.   NeedRepaint := FFlat and FMouseInControl and Enabled and not FDragging;
  1209.   { Windows XP introduced hot states also for non-flat buttons. }
  1210.   if NeedRepaint or fcUseThemes(self) then
  1211.   begin
  1212.     FMouseInControl := False;
  1213.     if Enabled then
  1214.       Repaint;
  1215.   end;
  1216. end;
  1217. procedure TfcComboButton.ActionChange(Sender: TObject; CheckDefaults: Boolean);
  1218.   procedure CopyImage(ImageList: TCustomImageList; Index: Integer);
  1219.   begin
  1220.     with Glyph do
  1221.     begin
  1222.       Width := ImageList.Width;
  1223.       Height := ImageList.Height;
  1224.       Canvas.Brush.Color := clFuchsia;//! for lack of a better color
  1225.       Canvas.FillRect(Rect(0,0, Width, Height));
  1226.       ImageList.Draw(Canvas, 0, 0, Index);
  1227.     end;
  1228.   end;
  1229. begin
  1230.   inherited ActionChange(Sender, CheckDefaults);
  1231.   if Sender is TCustomAction then
  1232.     with TCustomAction(Sender) do
  1233.     begin
  1234.       if CheckDefaults or (Self.GroupIndex = 0) then
  1235.         Self.GroupIndex := GroupIndex;
  1236.       { Copy image from action's imagelist }
  1237.       if (Glyph.Empty) and (ActionList <> nil) and (ActionList.Images <> nil) and
  1238.         (ImageIndex >= 0) and (ImageIndex < ActionList.Images.Count) then
  1239.         CopyImage(ActionList.Images, ImageIndex);
  1240.     end;
  1241. end;
  1242. initialization
  1243. //  FillChar(BitBtnGlyphs, SizeOf(BitBtnGlyphs), 0);
  1244. finalization
  1245. //  DestroyLocals;
  1246. end.