home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 October / Chip_2001-10_cd1.bin / zkuste / delphi / kompon / d12456 / OFFBTN97.ZIP / OffBtn97 / OffBtn.pas next >
Pascal/Delphi Source File  |  2001-08-12  |  54KB  |  1,698 lines

  1. unit OffBtn;
  2.  
  3. {  Office 97/2000 Assistant style button written by Jonathan Hosking,
  4.    August 2001.
  5.  
  6.    Get future component updates from the following address
  7.    Website: http://www.the-hoskings.freeserve.co.uk/
  8.  
  9.    Send any bugs, suggestions, etc to the following Email
  10.    Email: jonathan@the-hoskings.freeserve.co.uk
  11.  
  12.    Thanks to Kambiz for adding bi-directional support, the auto
  13.    height adjustment routines and fixing some bugs
  14.    Email: khojasteh@mail.com
  15.  
  16.    Thanks to Michel for fixing a bug in the keyboard routines and
  17.    helping with the auto transparency feature
  18.    Email: michelb@docudatasoft.com  }
  19.  
  20. {$IFNDEF VER80} { Not using Delphi 1.0 }
  21.   {$IFNDEF VER90} { Not using Delphi 2.0 }
  22.     {$IFNDEF VER93} { Not using C++Builder 1.0 }
  23.       {$DEFINE OFFBTND3} { Using at least Delphi 3.0 or C++Builder 3.0 }
  24.       {$IFNDEF VER100} { Not using Delphi 3.0 }
  25.         {$IFNDEF VER110} { Not using C++Builder 3.0 }
  26.           {$DEFINE OFFBTND4} { Using at least Delphi 4.0 or C++Builder 4.0 }
  27.         {$ENDIF}
  28.       {$ENDIF}
  29.     {$ENDIF}
  30.   {$ENDIF}
  31. {$ENDIF}
  32.  
  33. interface
  34.  
  35. uses
  36.   {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  37.   SysUtils, Messages, Classes, Graphics, Controls, Forms,
  38.   Dialogs, Menus;
  39.  
  40. type
  41.   TOffBtnAbout = (abNone,abAbout);
  42.   TOffBtnState = (bsInactive, bsActive, bsDown, bsDownAndOut);
  43.   TOffBtnType = (bsButton, bsRadioButton, bsUpButton, bsDownButton, bsHintButton);
  44.   TGlyphPosition = (bsTop, bsBottom, bsLeft, bsRight);
  45.   TOffice97Button = class(TCustomControl)
  46.   private
  47.     { Private declarations }
  48.     fAutoHeight: Boolean;
  49.     fAutoTransparency: Boolean;
  50.     fBtnKey: Boolean;
  51.     fCancel: Boolean;
  52.     fClicksDisabled: Boolean;
  53.     fDefault: Boolean;
  54.     fFocused: Boolean;
  55.     fNoDots: Boolean;
  56.     fOffice2000Look: Boolean;
  57.     fShowGlyph: Boolean;
  58.     fUseCustomGlyphs: Boolean;
  59.     fWordWrap: Boolean;
  60.     fCaption: TCaption;
  61.     fActive: TBitmap;
  62.     fTransparent: Boolean;
  63.     fControl: TBitmap;
  64.     fCustomActive: TBitmap;
  65.     fCustomDisabled: TBitmap;
  66.     fCustomDownActive: TBitmap;
  67.     fCustomInactive: TBitmap;
  68.     fDisabled: TBitmap;
  69.     fDownActive: TBitmap;
  70.     fInactive: TBitmap;
  71.     fAbout: TOffBtnAbout;
  72.     fType: TOffBtnType;
  73.     fHoverFont: TFont;
  74.     fMouseExit: TNotifyEvent;
  75.     fMouseEnter: TNotifyEvent;
  76.     fActiveColor: TColor;
  77.     fActiveOutlineColor: TColor;
  78.     fActiveOutlineColor2: TColor;
  79.     fInactiveColor: TColor;
  80.     fTransparentColor: TColor;
  81.     fGlyphPosition: TGlyphPosition;
  82.     fModalResult: TModalResult;
  83.     capWrap: TStringList;
  84.     capLines,tX: Integer;
  85.     procedure DrawTransparentBitmap(Dest:TCanvas;const X,Y:Smallint;srcBmp:TBitmap;const transpColor:TColor);
  86.     function CreateDisabledBitmap(FOriginal: TBitmap; OutlineColor: TColor): TBitmap;
  87.     procedure DrawOfficeFocusRect(txtRect: TRect; capWrap: TStringList);
  88.     procedure GetWrapText(txt: String; tX: Integer);
  89.     procedure DrawFrame;
  90.     procedure DrawOffice2000Frame;
  91.     procedure SetAutoHeight(Val: Boolean);
  92.     procedure SetAutoTransparency(Val: Boolean);
  93.     procedure SetCaption(Val: TCaption);
  94.     procedure SetDefault(Value: Boolean);
  95.     function CurrentGlyph: TBitmap;
  96.     procedure SetActiveColor(Val: TColor);
  97.     procedure SetActiveOutlineColor(Val: TColor);
  98.     procedure SetActiveOutlineColor2(Val: TColor);
  99.     procedure SetControlType(Val: TOffBtnType);
  100.     procedure SetCustomActiveGlyph(Val: TBitmap);
  101.     procedure SetCustomDisabledGlyph(Val: TBitmap);
  102.     procedure SetCustomDownActiveGlyph(Val: TBitmap);
  103.     procedure SetCustomInactiveGlyph(Val: TBitmap);
  104.     procedure SetGlyphPosition(Val: TGlyphPosition);
  105.     procedure SetInactiveColor(Val: TColor);
  106.     procedure SetOffice2000Look(Val: Boolean);
  107.     procedure SetShowGlyph(Val: Boolean);
  108.     procedure SetTransparent(Val: Boolean);
  109.     procedure SetTransparentColor(Val: TColor);
  110.     procedure SetUseCustomGlyphs(Val: Boolean);
  111.     procedure SetWordWrap(Val: Boolean);
  112.     procedure SetHoverFont(Val: TFont);
  113.     procedure HoverFontChanged(Sender: TObject);
  114.     procedure ShowAbout(Val: TOffBtnAbout);
  115.     procedure Layout(var txtRect, bitRect: TRect);
  116.     procedure CalculateTxt(var txtRect: TRect;Glyph: TBitmap);
  117.     procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message wm_EraseBkgnd;
  118.     procedure WMLButtonDown(var Message: TWMLButtonDown); message wm_LButtonDown;
  119.     procedure WMMouseMove(var Message: TWMMouseMove); message wm_MouseMove;
  120.     procedure WMLButtonUp(var Message: TWMLButtonUp); message wm_LButtonUp;
  121.     procedure WMRButtonDown(var Message: TWMRButtonDown); message wm_RButtonDown;
  122.     procedure CNCommand(var Message: TWMCommand); message cn_Command;
  123.     procedure CNKeyDown(var Message: TWMKeyDown); message cn_KeyDown;
  124.     procedure CMDialogChar(var Message: TCMDialogChar); message cm_DialogChar;
  125.     procedure CMDialogKey(var Message: TCMDialogKey); message cm_DialogKey;
  126.     procedure CMEnabledChanged(var Message: TMessage); message cm_EnabledChanged;
  127.     procedure CMFocusChanged(var Message: TMessage); message cm_FocusChanged;
  128.     procedure WMKillFocus(var Message: TWMKillFocus); message wm_KillFocus;
  129.     procedure WMSetFocus(var Message: TWMSetFocus); message wm_SetFocus;
  130.   protected
  131.     { Protected declarations }
  132.     fState: TOffBtnState;
  133.     procedure Paint; override;
  134.     procedure WndProc(var Message: TMessage); override;
  135.     procedure CreateWnd; override;
  136.     {$IFDEF OFFBTND4}
  137.     procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
  138.     {$ENDIF}
  139.   public
  140.     { Public declarations }
  141.     constructor Create(AOwner: TComponent); override;
  142.     destructor Destroy; override;
  143.     procedure Click; override;
  144.     procedure AdjustHeight;
  145.   published
  146.     { Published declarations }
  147.     property Office2000Look: Boolean read fOffice2000Look write SetOffice2000Look default True;
  148.     property About: TOffBtnAbout read fAbout write ShowAbout default abNone;
  149.     {$IFDEF OFFBTND4}
  150.     property Action;
  151.     {$ENDIF}
  152.     property ActiveColor: TColor read fActiveColor write SetActiveColor default $00808080;
  153.     property ActiveGlyph: TBitmap read fCustomActive write SetCustomActiveGlyph;
  154.     property ActiveOutlineColor: TColor read fActiveOutlineColor write SetActiveOutlineColor default clWhite;
  155.     property ActiveOutlineColor2: TColor read fActiveOutlineColor2 write SetActiveOutlineColor2 default $00D6E7E7;
  156.     property Align;
  157.     {$IFDEF OFFBTND4}
  158.     property Anchors;
  159.     {$ENDIF}
  160.     property AutoHeight: Boolean read fAutoHeight write SetAutoHeight default False;
  161.     property AutoTransparency: Boolean read fAutoTransparency write SetAutoTransparency default True;
  162.     {$IFDEF OFFBTND4}
  163.     property BiDiMode;
  164.     {$ENDIF}
  165.     property Cancel: Boolean read fCancel write fCancel default False;
  166.     property Caption: TCaption read fCaption write SetCaption;
  167.     property Color;
  168.     property ControlType: TOffBtnType read fType write SetControlType default bsButton;
  169.     property Default: Boolean read fDefault write SetDefault default False;
  170.     property DisabledGlyph: TBitmap read fCustomDisabled write SetCustomDisabledGlyph;
  171.     property DownActiveGlyph: TBitmap read fCustomDownActive write SetCustomDownActiveGlyph;
  172.     property DragCursor;
  173.     property DragMode;
  174.     property Enabled;
  175.     property Font;
  176.     property HoverFont: TFont read fHoverFont write SetHoverFont;
  177.     property InactiveColor: TColor read fInactiveColor write SetInactiveColor default clSilver;
  178.     property InactiveGlyph: TBitmap read fCustomInactive write SetCustomInactiveGlyph;
  179.     property ModalResult: TModalResult read fModalResult write fModalResult default 0;
  180.     {$IFDEF OFFBTND4}
  181.     property ParentBiDiMode;
  182.     {$ENDIF}
  183.     property ParentFont;
  184.     property ParentShowHint;
  185.     property PopupMenu;
  186.     property Position: TGlyphPosition read fGlyphPosition write SetGlyphPosition default bsLeft;
  187.     property ShowGlyph: Boolean read fShowGlyph write SetShowGlyph default False;
  188.     property ShowHint;
  189.     property TabOrder;
  190.     property TabStop default True;
  191.     property Transparent: Boolean read fTransparent write SetTransparent default False;
  192.     property TransparentColor: TColor read fTransparentColor write SetTransparentColor default clBlack;
  193.     property UseCustomGlyphs: Boolean read fUseCustomGlyphs write SetUseCustomGlyphs default False;
  194.     property Visible;
  195.     property WordWrap: Boolean read fWordWrap write SetWordWrap default True;
  196.     property OnClick;
  197.     property OnDblClick;
  198.     property OnDragDrop;
  199.     property OnDragOver;
  200.     property OnEndDrag;
  201.     property OnEnter;
  202.     property OnExit;
  203.     property OnKeyDown;
  204.     property OnKeyPress;
  205.     property OnKeyUp;
  206.     property OnMouseDown;
  207.     property OnMouseExit: TNotifyEvent read fMouseExit write fMouseExit;
  208.     property OnMouseEnter: TNotifyEvent read fMouseEnter write fMouseEnter;
  209.     property OnMouseMove;
  210.     property OnMouseUp;
  211.   end;
  212.  
  213. procedure Register;
  214.  
  215. implementation
  216.  
  217. { TOffice97Button }
  218.  
  219. {$IFDEF OFFBTND4}
  220. uses ActnList;
  221. {$ENDIF}
  222.  
  223. {$R OFFBTN.RES}
  224.  
  225. const
  226.   CopyRightStr: PChar = 'TOffice97Button Component v2.12 (12/08/2001)'+#13+#13+
  227.     'By Jonathan Hosking'+#13+#13+'Compiled in '+
  228.     {$IFDEF VER80}  'Delphi 1.0' {$ENDIF}
  229.     {$IFDEF VER90}  'Delphi 2.0' {$ENDIF}
  230.     {$IFDEF VER100} 'Delphi 3.0' {$ENDIF}
  231.     {$IFDEF VER120} 'Delphi 4.0' {$ENDIF}
  232.     {$IFDEF VER130} 'Delphi 5.0' {$ENDIF}
  233.     {$IFDEF VER140} 'Delphi 6.0' {$ENDIF}
  234.     {$IFDEF VER93}  'C++Builder 1.0' {$ENDIF}
  235.     {$IFDEF VER110} 'C++Builder 3.0' {$ENDIF}
  236.     {$IFDEF VER125} 'C++Builder 4.0' {$ENDIF};
  237. var
  238.   CopyRightPtr: Pointer;
  239.  
  240. type
  241.   TParentControl = class(TWinControl);
  242.  
  243. { This procedure is exactly copied from RxLibrary VCLUtils. }
  244. procedure CopyParentImage(Control: TControl; Dest: TCanvas);
  245. var
  246.   I, Count, X, Y, SaveIndex: Integer;
  247.   DC: HDC;
  248.   R, SelfR, CtlR: TRect;
  249. begin
  250.   if (Control = nil) or (Control.Parent = nil) then Exit;
  251.   Count := Control.Parent.ControlCount;
  252.   DC := Dest.Handle;
  253.   {$IFDEF WIN32}
  254.   with Control.Parent do ControlState := ControlState + [csPaintCopy];
  255.   try
  256.   {$ENDIF}
  257.     with Control do begin
  258.       SelfR := Bounds(Left, Top, Width, Height);
  259.       X := -Left; Y := -Top;
  260.     end;
  261.     { Copy parent control image }
  262.     SaveIndex := SaveDC(DC);
  263.     try
  264.       SetViewportOrgEx(DC, X, Y, nil);
  265.       IntersectClipRect(DC, 0, 0, Control.Parent.ClientWidth,
  266.         Control.Parent.ClientHeight);
  267.       with TParentControl(Control.Parent) do begin
  268.         Perform(WM_ERASEBKGND, DC, 0);
  269.         PaintWindow(DC);
  270.       end;
  271.     finally
  272.       RestoreDC(DC, SaveIndex);
  273.     end;
  274.     { Copy images of graphic controls }
  275.     for I := 0 to Count - 1 do begin
  276.       if Control.Parent.Controls[I] = Control then Break
  277.       else if (Control.Parent.Controls[I] <> nil) and
  278.         (Control.Parent.Controls[I] is TGraphicControl) then
  279.       begin
  280.         with TGraphicControl(Control.Parent.Controls[I]) do begin
  281.           CtlR := Bounds(Left, Top, Width, Height);
  282.           if Bool(IntersectRect(R, SelfR, CtlR)) and Visible then
  283.           begin
  284.             {$IFDEF WIN32}
  285.             ControlState := ControlState + [csPaintCopy];
  286.             {$ENDIF}
  287.             SaveIndex := SaveDC(DC);
  288.             try
  289.               SetViewportOrgEx(DC, Left + X, Top + Y, nil);
  290.               IntersectClipRect(DC, 0, 0, Width, Height);
  291.               Perform(WM_PAINT, DC, 0);
  292.             finally
  293.               RestoreDC(DC, SaveIndex);
  294.               {$IFDEF WIN32}
  295.               ControlState := ControlState - [csPaintCopy];
  296.               {$ENDIF}
  297.             end;
  298.           end;
  299.         end;
  300.       end;
  301.     end;
  302.   {$IFDEF WIN32}
  303.   finally
  304.     with Control.Parent do ControlState := ControlState - [csPaintCopy];
  305.   end;
  306.   {$ENDIF}
  307. end;
  308.  
  309. { This procedure draws a transparent bitmap }
  310. procedure TOffice97Button.DrawTransparentBitmap(Dest:TCanvas;const X,Y:Smallint;srcBmp:TBitmap;const transpColor:TColor);
  311. var
  312.   ANDBitmap,ORBitmap: TBitmap;
  313.   oldCopyMode: TCopyMode;
  314.   src: TRect;
  315. begin
  316.   ANDBitmap := TBitmap.Create;
  317.   ORBitmap := TBitmap.Create;
  318.   try
  319.     Src := Bounds(0,0,srcBmp.Width,srcBmp.Height);
  320.     with ORBitmap do
  321.     begin
  322.       Width := srcBmp.Width;
  323.       Height := srcBmp.Height;
  324.       Canvas.Brush.Color := clBlack;
  325.       Canvas.CopyMode := cmSrcCopy;
  326.       Canvas.BrushCopy(Src,srcBmp,Src,transpColor);
  327.     end;
  328.     with ANDBitmap do
  329.     begin
  330.       Width := srcBmp.Width;
  331.       Height := srcBmp.Height;
  332.       Canvas.Brush.Color := clWhite;
  333.       Canvas.CopyMode := cmSrcInvert;
  334.       Canvas.BrushCopy(Src,srcBmp,Src,transpColor);
  335.     end;
  336.     with Dest do
  337.     begin
  338.       oldCopyMode := CopyMode;
  339.       CopyMode := cmSrcAnd;
  340.       Draw(x,y,ANDBitmap);
  341.       CopyMode := cmSrcPaint;
  342.       Draw(x,y,ORBitmap);
  343.       CopyMode := oldCopyMode;
  344.     end;
  345.   finally
  346.     ORBitmap.Free;
  347.     ANDBitmap.Free;
  348.   end;
  349. end;
  350.  
  351. { This procedure creates a "Disabled" style bitmap }
  352. function TOffice97Button.CreateDisabledBitmap(FOriginal: TBitmap; OutlineColor: TColor): TBitmap;
  353. const
  354.   ROP_DSPDxax = $00E20746;
  355. var
  356.   MonoBmp: TBitmap;
  357.   IRect: TRect;
  358.   IH,IW: Integer;
  359. begin
  360.   IRect := Rect(0, 0, FOriginal.Width, FOriginal.Height);
  361.   IW := IRect.Right - IRect.Left;
  362.   IH := IRect.Bottom - IRect.Top;
  363.   Result := TBitmap.Create;
  364.   try
  365.     Result.Width := FOriginal.Width;
  366.     Result.Height := FOriginal.Height;
  367.     MonoBmp := TBitmap.Create;
  368.     try
  369.       with MonoBmp do
  370.       begin
  371.         Width := FOriginal.Width;
  372.         Height := FOriginal.Height;
  373.         Canvas.CopyRect(IRect, FOriginal.Canvas, IRect);
  374.         {$IFDEF VER100}
  375.         HandleType := bmDDB;
  376.         {$ENDIF}
  377.         Canvas.Brush.Color := OutlineColor;
  378.         if Monochrome then
  379.         begin
  380.           Canvas.Font.Color := clWhite;
  381.           Monochrome := False;
  382.           Canvas.Brush.Color := clWhite;
  383.         end;
  384.         Monochrome := True;
  385.       end;
  386.       with Result.Canvas do
  387.       begin
  388.         Brush.Color := clBtnFace;
  389.         FillRect(IRect);
  390.         Brush.Color := clBtnHighlight;
  391.         SetTextColor(Handle, clBlack);
  392.         SetBkColor(Handle, clWhite);
  393.         BitBlt(Handle, 1, 1, IW, IH, MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  394.         Brush.Color := clBtnShadow;
  395.         SetTextColor(Handle, clBlack);
  396.         SetBkColor(Handle, clWhite);
  397.         BitBlt(Handle, 0, 0, IW, IH, MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax);
  398.       end;
  399.     finally
  400.       MonoBmp.Free;
  401.     end;
  402.   except
  403.     Result.Free;
  404.     raise;
  405.   end;
  406. end;
  407.  
  408. { This procedure draws an "Office" style focus
  409.  
  410.   Thanks to Kambiz for adding bi-directional support to this procedure }
  411. procedure TOffice97Button.DrawOfficeFocusRect(txtRect: TRect; capWrap: TStringList);
  412. var
  413.   tmp,tmp2,x1,x2,y1,y2: Integer;
  414. begin
  415.   x1 := txtRect.Left - 1;
  416.   x2 := txtRect.Right + 2;
  417.   y1 := txtRect.Top - 1;
  418.   y2 := txtRect.Bottom + 1;
  419.   with fControl.Canvas do
  420.   begin
  421.     Pen.Color := Self.Font.Color;
  422.     Pen.Style := psDot;
  423.     Brush.Style := bsClear;
  424.     if (capLines = 1) or (not fWordWrap) then
  425.     begin
  426.       { Since there's only 1 line of text, or no wordwrapping, we use the
  427.         standard focus }
  428.       Rectangle(x1,y1,x2,y2);
  429.       Exit;
  430.     end;
  431.     { Draw our "Office" style focus }
  432.     tmp := x1+2+TextWidth(capWrap.Strings[capLines-1]);
  433.     if tmp > x1+(x2-x1) then tmp := x1+(x2-x1);
  434.     tmp2 := y1+((capLines-1)*TextHeight('0'));
  435.     {$IFDEF OFFBTND4}
  436.     if UseRightToLeftAlignment then
  437.     begin
  438.       tmp := x2-x1-tmp+4;
  439.       PolyLine([Point(x1,tmp2),Point(x1,y1),Point(x2,y1),Point(x2,y2),
  440.         Point(tmp,y2),Point(tmp,tmp2), Point(x1,tmp2)]);
  441.     end
  442.     else
  443.     {$ENDIF}
  444.       PolyLine([Point(x1,y2),Point(x1,y1),Point(x2,y1),Point(x2,tmp2),
  445.         Point(tmp,tmp2),Point(tmp,y2), Point(x1,y2)]);
  446.   end;
  447. end;
  448.  
  449. { This procedure divides text into a wordwrapped arrary }
  450. procedure TOffice97Button.GetWrapText(txt: String; tX: Integer);
  451. var
  452.   Count,LastSpace,OCount: Integer;
  453.   tmpTxt: String;
  454.   txtStop: Boolean;
  455. begin
  456.   capLines := 0;
  457.   capWrap.Clear;
  458.   if fControl.Canvas.TextWidth(txt) <= tX then
  459.   begin
  460.     { If just a single line is required, we can skip the loop }
  461.     capLines := 1;
  462.     capWrap.Add(txt);
  463.     Exit;
  464.   end;
  465.   { Chop the line of text into several lines }
  466.   OCount := -1;
  467.   Count := 0;
  468.   repeat
  469.     if Count = OCount then
  470.     begin
  471.       capLines := 0;
  472.       capWrap.Clear;
  473.       Exit;
  474.     end;
  475.     OCount := Count;
  476.     LastSpace := 0;
  477.     tmpTxt := '';
  478.     txtStop := False;
  479.     repeat
  480.       inc(Count);
  481.       if fControl.Canvas.TextWidth(tmpTxt+txt[Count]) > tX then
  482.       begin
  483.         txtStop := True;
  484.         dec(Count);
  485.       end
  486.       else
  487.       begin
  488.         tmpTxt := tmpTxt + txt[Count];
  489.         if txt[Count] = #32 then LastSpace := length(tmpTxt)-1;
  490.       end;
  491.     until (txtStop) or (Count = length(txt));
  492.     if (Count < length(txt)) and (LastSpace <> 0) then
  493.     begin
  494.       tmpTxt := copy(tmpTxt,1,LastSpace);
  495.       Count := OCount + LastSpace + 1;
  496.     end;
  497.     inc(capLines);
  498.     capWrap.Add(tmpTxt);
  499.   until Count = length(txt);
  500. end;
  501.  
  502. { This is the main window procedure }
  503. procedure TOffice97Button.WndProc(var Message: TMessage);
  504. begin
  505.   case Message.Msg of
  506.     WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
  507.       if not (csDesigning in ComponentState) and (not Focused) then
  508.       begin
  509.         { We don't allow clicks here, otherwise the control looks like it has
  510.           been clicked twice }
  511.         fClicksDisabled := True;
  512.         {$IFDEF WIN32}
  513.         Windows.SetFocus(Handle);
  514.         {$ELSE}
  515.         WinProcs.SetFocus(Handle);
  516.         {$ENDIF}
  517.         fClicksDisabled := False;
  518.         if not Focused then Exit;
  519.       end;
  520.     CN_COMMAND:
  521.       if fClicksDisabled then Exit;
  522.   end;
  523.   inherited WndProc(Message);
  524. end;
  525.  
  526. constructor TOffice97Button.Create(AOwner: TComponent);
  527. begin
  528.   { Setup the control }
  529.   Inherited Create(AOwner);
  530.   CopyRightPtr := @CopyRightStr;
  531.   fAbout := abNone;
  532.   fActiveColor := $00808080;
  533.   fActiveOutlineColor := clWhite;
  534.   fActiveOutlineColor2 := $00D6E7E7;
  535.   fInactiveColor := clSilver;
  536.   fState := bsInactive;
  537.   fType := bsButton;
  538.   fTransparent := False;
  539.   fTransparentColor := clBlack;
  540.   fGlyphPosition := bsLeft;
  541.   Color := $00CCFFFF;
  542.   fActive := TBitmap.Create;
  543.   fActive.Handle := LoadBitmap(HInstance,'OFFICE_1');
  544.   fDisabled := TBitmap.Create;
  545.   fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_2');
  546.   fDownActive := TBitmap.Create;
  547.   fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_3');
  548.   fInactive := TBitmap.Create;
  549.   fInactive.Handle := LoadBitmap(HInstance,'OFFICE_4');
  550.   fCustomActive := TBitmap.Create;
  551.   fCustomDisabled := TBitmap.Create;
  552.   fCustomDownActive := TBitmap.Create;
  553.   fCustomInactive := TBitmap.Create;
  554.   capWrap := TStringList.Create;
  555.   fHoverFont := TFont.Create;
  556.   fHoverFont.OnChange := HoverFontChanged;
  557.   Width := 70;
  558.   Height := 23;
  559.   TabStop := True;
  560.   fOffice2000Look := True;
  561.   fShowGlyph := False;
  562.   fBtnKey := False;
  563.   fNoDots := False;
  564.   fUseCustomGlyphs := False;
  565.   fWordWrap := True;
  566.   fAutoHeight := False;
  567.   fAutoTransparency := True;
  568. end;
  569.  
  570. destructor TOffice97Button.Destroy;
  571. begin
  572.   { Kill the control }
  573.   fHoverFont.Free;
  574.   capWrap.Free;
  575.   fCustomInactive.Free;
  576.   fCustomDownActive.Free;
  577.   fCustomDisabled.Free;
  578.   fCustomActive.Free;
  579.   fInactive.Free;
  580.   fDownActive.Free;
  581.   fDisabled.Free;
  582.   fActive.Free;
  583.   Inherited Destroy;
  584. end;
  585.  
  586. procedure TOffice97Button.Click;
  587. var
  588.   {$IFDEF OFFBTND3}
  589.   Form: TCustomForm;
  590.   {$ELSE}
  591.   Form: TForm;
  592.   {$ENDIF}
  593.   oState: TOffBtnState;
  594.   Count: Integer;
  595. begin
  596.   oState := fState;
  597.   if fBtnKey then
  598.   begin
  599.     { If a button was pressed, show the Down state }
  600.     fState := bsDown;
  601.     if fState <> oState then
  602.     begin
  603.       Invalidate;
  604.       Application.ProcessMessages;
  605.     end;
  606.   end;
  607.   { Handle ModalResult }
  608.   Form := GetParentForm(Self);
  609.   { When the control is clicked, all other TOffice97Buttons should be in the
  610.     inactive state }
  611.   for count := 0 to Form.ComponentCount - 1 do
  612.     if (Form.Components[Count] is TOffice97Button) and
  613.       (Form.Components[Count] <> Self) then
  614.     begin
  615.       TOffice97Button(Form.Components[Count]).fState := bsInactive;
  616.       TOffice97Button(Form.Components[Count]).Invalidate;
  617.     end;
  618.   if Form <> nil then Form.ModalResult := fModalResult;
  619.   if (fBtnKey) or (fState <> oState) then
  620.   begin
  621.     { If a button was pressed, restore the original state }
  622.     fState := oState;
  623.     Invalidate;
  624.     Application.ProcessMessages;
  625.   end;
  626.   { Reset key pressed variable }
  627.   fBtnKey := False;
  628.   inherited Click;
  629. end;
  630.  
  631. procedure TOffice97Button.CreateWnd;
  632. begin
  633.   inherited CreateWnd;
  634.   fFocused := fDefault;
  635.   fNoDots := not fDefault;
  636. end;
  637.  
  638. {$IFDEF OFFBTND4}
  639. procedure TOffice97Button.ActionChange(Sender: TObject; CheckDefaults: Boolean);
  640. begin
  641.   inherited ActionChange(Sender, CheckDefaults);
  642.   if Sender is TCustomAction then
  643.     with TCustomAction(Sender) do
  644.       Self.Caption := Caption;
  645. end;
  646. {$ENDIF}
  647.  
  648. procedure TOffice97Button.CNCommand(var Message: TWMCommand);
  649. begin
  650.   if Message.NotifyCode = BN_CLICKED then Click;
  651. end;
  652.  
  653. { Thanks to Michel for this procedure }
  654. procedure TOffice97Button.CNKeyDown(var Message: TWMKeyDown);
  655. begin
  656.   inherited;
  657.   if (Message.CharCode = VK_RETURN) and fFocused then
  658.   begin
  659.     { Set key pressed variable }
  660.     fBtnKey := True;
  661.     Click;
  662.     { If we are using a modal form, release the mouse capture }
  663.     if fModalResult <> mrNone then
  664.       MouseCapture := False;
  665.     Message.Result := 1;
  666.   end;
  667. end;
  668.  
  669. { Thanks to Kambiz and Michel for fixing a bug in this procedure }
  670. procedure TOffice97Button.CMDialogChar(var Message: TCMDialogChar);
  671. begin
  672.   with Message do
  673.     if IsAccel(CharCode, fCaption) and CanFocus then
  674.     begin
  675.       { Set key pressed variable }
  676.       fBtnKey := True;
  677.       Click;
  678.       { If we are using a modal form, release the mouse capture }
  679.       if fModalResult <> mrNone then MouseCapture := False;
  680.       Result := 1;
  681.     end else
  682.       inherited;
  683. end;
  684.  
  685. procedure TOffice97Button.CMDialogKey(var Message: TCMDialogKey);
  686. begin
  687.   with Message do
  688.     if (((CharCode = VK_RETURN) and fFocused) or ((CharCode = VK_ESCAPE) and fCancel))
  689.       and (KeyDataToShiftState(KeyData) = []) and CanFocus then
  690.     begin
  691.       { Set key pressed variable }
  692.       fBtnKey := True;
  693.       Click;
  694.       { If we are using a modal form, release the mouse capture }
  695.       if fModalResult <> mrNone then MouseCapture := False;
  696.       Result := 1;
  697.     end
  698.     else
  699.     begin
  700.       if (CharCode = VK_F4) and (KeyDataToShiftState(KeyData) = [ssAlt]) then
  701.       begin
  702.         fState := bsInActive;
  703.         MouseCapture := False;
  704.       end;
  705.       inherited;
  706.     end;
  707. end;
  708.  
  709. procedure TOffice97Button.CMEnabledChanged(var Message: TMessage);
  710. begin
  711.   Inherited;
  712.   Invalidate;
  713. end;
  714.  
  715. procedure TOffice97Button.CMFocusChanged(var Message: TMessage);
  716. begin
  717.   Inherited;
  718.   Invalidate;
  719. end;
  720.  
  721. { This procedure picks up the focus loss }
  722.  
  723. procedure TOffice97Button.WMKillFocus(var Message: TWMKillFocus);
  724. begin
  725.   fState := bsInactive;
  726.   fFocused := False;
  727.   fNoDots := True;
  728.   Invalidate;
  729. end;
  730.  
  731. { This procedure picks up the focus gain }
  732.  
  733. procedure TOffice97Button.WMSetFocus(var Message: TWMSetFocus);
  734. begin
  735.   fState := bsInactive;
  736.   fFocused := True;
  737.   fNoDots := False;
  738.   Invalidate;
  739. end;
  740.  
  741. { Start of component configuration routines
  742.  
  743.   Thanks to Kambiz for adding auto height adjustment to them }
  744.  
  745. procedure TOffice97Button.SetCaption(Val: TCaption);
  746. begin
  747.   if fCaption <> Val then
  748.   begin
  749.     fCaption := Val;
  750.     if fAutoHeight then AdjustHeight;
  751.     Invalidate;
  752.   end;
  753. end;
  754.  
  755. { Thanks to Kambiz for this procedure }
  756. procedure TOffice97Button.SetAutoHeight(Val: Boolean);
  757. begin
  758.   if fAutoHeight <> Val then
  759.   begin
  760.     fAutoHeight := Val;
  761.     if fAutoHeight then AdjustHeight;
  762.     Invalidate;
  763.   end;
  764. end;
  765.  
  766. procedure TOffice97Button.SetAutoTransparency(Val: Boolean);
  767. begin
  768.   if fAutoTransparency <> Val then
  769.   begin
  770.     fAutoTransparency := Val;
  771.     Invalidate;
  772.   end;
  773. end;
  774.  
  775. procedure TOffice97Button.SetDefault(Value: Boolean);
  776. begin
  777.   fDefault := Value;
  778.   with GetParentForm(Self) do
  779.     Perform(cm_FocusChanged, 0, Longint(ActiveControl));
  780. end;
  781.  
  782. procedure TOffice97Button.SetActiveColor(Val: TColor);
  783. begin
  784.   if fActiveColor <> Val then
  785.   begin
  786.     fActiveColor := Val;
  787.     Invalidate;
  788.   end;
  789. end;
  790.  
  791. procedure TOffice97Button.SetActiveOutlineColor(Val: TColor);
  792. begin
  793.   if fActiveOutlineColor <> Val then
  794.   begin
  795.     fActiveOutlineColor := Val;
  796.     Invalidate;
  797.   end;
  798. end;
  799.  
  800. procedure TOffice97Button.SetActiveOutlineColor2(Val: TColor);
  801. begin
  802.   if fActiveOutlineColor2 <> Val then
  803.   begin
  804.     fActiveOutlineColor2 := Val;
  805.     Invalidate;
  806.   end;
  807. end;
  808.  
  809. procedure TOffice97Button.SetControlType(Val: TOffBtnType);
  810. begin
  811.   { Load the default glyphs for the new Control type }
  812.   if fType <> Val then
  813.   begin
  814.     fType := Val;
  815.     case fType of
  816.       bsButton:
  817.         begin
  818.           fActive.Handle := LoadBitmap(HInstance,'OFFICE_1');
  819.           fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_2');
  820.           fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_3');
  821.           fInactive.Handle := LoadBitmap(HInstance,'OFFICE_4');
  822.         end;
  823.       bsRadioButton:
  824.         begin
  825.           if fOffice2000Look then
  826.           begin
  827.             fActive.Handle := LoadBitmap(HInstance,'OFFICE_17');
  828.             fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_18');
  829.             fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_19');
  830.             fInactive.Handle := LoadBitmap(HInstance,'OFFICE_20');
  831.           end
  832.           else
  833.           begin
  834.             fActive.Handle := LoadBitmap(HInstance,'OFFICE_5');
  835.             fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_6');
  836.             fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_7');
  837.             fInactive.Handle := LoadBitmap(HInstance,'OFFICE_8');
  838.           end;
  839.         end;
  840.       bsUpButton:
  841.         begin
  842.           fActive.Handle := LoadBitmap(HInstance,'OFFICE_9');
  843.           fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_10');
  844.           fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_11');
  845.           fInactive.Handle := LoadBitmap(HInstance,'OFFICE_12');
  846.         end;
  847.       bsDownButton:
  848.         begin
  849.           fActive.Handle := LoadBitmap(HInstance,'OFFICE_13');
  850.           fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_14');
  851.           fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_15');
  852.           fInactive.Handle := LoadBitmap(HInstance,'OFFICE_16');
  853.         end;
  854.       bsHintButton:
  855.         begin
  856.           fActive.Handle := LoadBitmap(HInstance,'OFFICE_21');
  857.           fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_22');
  858.           fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_23');
  859.           fInactive.Handle := LoadBitmap(HInstance,'OFFICE_24');
  860.         end;
  861.     end;
  862.     if (fType <> bsButton) and (fGlyphPosition in [bsLeft,bsRight]) then
  863.       fGlyphPosition := bsTop;
  864.     if fAutoHeight then AdjustHeight;
  865.     ShowGlyph := not (Office2000Look and (fType = bsButton));
  866.     Invalidate;
  867.   end;
  868. end;
  869.  
  870. procedure TOffice97Button.SetCustomActiveGlyph(Val: TBitmap);
  871. begin
  872.   fCustomActive.Assign(Val);
  873.   if fAutoHeight then AdjustHeight;
  874.   Invalidate;
  875. end;
  876.  
  877. procedure TOffice97Button.SetCustomDisabledGlyph(Val: TBitmap);
  878. begin
  879.   fCustomDisabled.Assign(Val);
  880.   if fAutoHeight then AdjustHeight;
  881.   Invalidate;
  882. end;
  883.  
  884. procedure TOffice97Button.SetCustomDownActiveGlyph(Val: TBitmap);
  885. begin
  886.   fCustomDownActive.Assign(Val);
  887.   if fAutoHeight then AdjustHeight;
  888.   Invalidate;
  889. end;
  890.  
  891. procedure TOffice97Button.SetCustomInactiveGlyph(Val: TBitmap);
  892. begin
  893.   fCustomInactive.Assign(Val);
  894.   if fAutoHeight then AdjustHeight;
  895.   Invalidate;
  896. end;
  897.  
  898. procedure TOffice97Button.SetGlyphPosition(Val: TGlyphPosition);
  899. begin
  900.   if fGlyphPosition <> Val then
  901.   begin
  902.     fGlyphPosition := Val;
  903.     if (fType <> bsButton) and (fGlyphPosition in [bsLeft,bsRight]) then
  904.       fGlyphPosition := bsTop;
  905.     if fAutoHeight then AdjustHeight;
  906.     Invalidate;
  907.   end;
  908. end;
  909.  
  910. procedure TOffice97Button.SetInactiveColor(Val: TColor);
  911. begin
  912.   if fInactiveColor <> Val then
  913.   begin
  914.     fInactiveColor := Val;
  915.     Invalidate;
  916.   end;
  917. end;
  918.  
  919. procedure TOffice97Button.SetOffice2000Look(Val: Boolean);
  920. begin
  921.   if fOffice2000Look <> Val then
  922.   begin
  923.     fOffice2000Look := Val;
  924.     if fOffice2000Look = True then
  925.     begin
  926.       { Setup control for Office 2000 look }
  927.       fActiveColor := $00808080;
  928.       fActiveOutlineColor := clWhite;
  929.       fActiveOutlineColor2 := $00D6E7E7;
  930.       fInactiveColor := clSilver;
  931.       Color := $00CCFFFF;
  932.       { Normal buttons don't have glyphs }
  933.       if fType = bsButton then fShowGlyph := False;
  934.       { Update radiobutton glyphs }
  935.       if fType = bsRadioButton then
  936.       begin
  937.         fActive.Handle := LoadBitmap(HInstance,'OFFICE_17');
  938.         fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_18');
  939.         fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_19');
  940.         fInactive.Handle := LoadBitmap(HInstance,'OFFICE_20');
  941.       end;
  942.     end
  943.     else
  944.     begin
  945.       { Setup the control for Office 97 look }
  946.       fActiveColor := clGray;
  947.       fActiveOutlineColor := clWhite;
  948.       fInactiveColor := clSilver;
  949.       fState := bsInactive;
  950.       Color := $00E1FFFF;
  951.       fShowGlyph := True;
  952.       { Update radiobutton glyphs }
  953.       if fType = bsRadioButton then
  954.       begin
  955.         fActive.Handle := LoadBitmap(HInstance,'OFFICE_5');
  956.         fDisabled.Handle := LoadBitmap(HInstance,'OFFICE_6');
  957.         fDownActive.Handle := LoadBitmap(HInstance,'OFFICE_7');
  958.         fInactive.Handle := LoadBitmap(HInstance,'OFFICE_8');
  959.       end
  960.     end;
  961.     Invalidate;
  962.   end;
  963. end;
  964.  
  965. procedure TOffice97Button.SetShowGlyph(Val: Boolean);
  966. begin
  967.   if fShowGlyph <> Val then
  968.   begin
  969.     fShowGlyph := Val;
  970.     if fAutoHeight then AdjustHeight;
  971.     Invalidate;
  972.   end;
  973. end;
  974.  
  975. procedure TOffice97Button.SetTransparent(Val: Boolean);
  976. begin
  977.   if fTransparent <> Val then
  978.   begin
  979.     fTransparent := Val;
  980.     Invalidate;
  981.   end;
  982. end;
  983.  
  984. procedure TOffice97Button.SetTransparentColor(Val: TColor);
  985. begin
  986.   if fTransparentColor <> Val then
  987.   begin
  988.     fTransparentColor := Val;
  989.     Invalidate;
  990.   end;
  991. end;
  992.  
  993. procedure TOffice97Button.SetUseCustomGlyphs(Val: Boolean);
  994. begin
  995.   if fUseCustomGlyphs <> Val then
  996.   begin
  997.     fUseCustomGlyphs := Val;
  998.     if fAutoHeight then AdjustHeight;
  999.     Invalidate;
  1000.   end;
  1001. end;
  1002.  
  1003. procedure TOffice97Button.SetWordWrap(Val: Boolean);
  1004. begin
  1005.   if fWordWrap <> Val then
  1006.   begin
  1007.     fWordWrap := Val;
  1008.     if fAutoHeight then AdjustHeight;
  1009.     Invalidate;
  1010.   end;
  1011. end;
  1012.  
  1013. procedure TOffice97Button.SetHoverFont(Val: TFont);
  1014. begin
  1015.   fHoverFont.Assign(Val);
  1016. end;
  1017.  
  1018. procedure TOffice97Button.HoverFontChanged(Sender: TObject);
  1019. begin
  1020.   Invalidate;
  1021. end;
  1022.  
  1023. procedure TOffice97Button.ShowAbout(Val: TOffBtnAbout);
  1024. begin
  1025.   if fAbout <> Val then
  1026.   begin
  1027.     if Val = abNone then fAbout := Val else
  1028.     begin
  1029.       fAbout := abNone;
  1030.       MessageDlg(StrPas(CopyRightStr), mtInformation, [mbOk], 0);
  1031.     end;
  1032.     Invalidate;
  1033.   end;
  1034. end;
  1035.  
  1036. { End of component configuration routines }
  1037.  
  1038. { Thanks to Kambiz for adding auto height adjustment to this procedure }
  1039. function TOffice97Button.CurrentGlyph: TBitmap;
  1040. begin
  1041.   { Default to inactive glyph (Or custom inactive glyph, if set)
  1042.     If nessacary, work out the glyph (Or custom glyph, if set)
  1043.     to display }
  1044.   case fState of
  1045.     bsActive:
  1046.     begin
  1047.       if not fUseCustomGlyphs then Result := fActive
  1048.         else
  1049.       begin
  1050.         if fCustomActive.Empty then Result := fCustomInactive
  1051.           else Result := fCustomActive;
  1052.       end;
  1053.     end;
  1054.     bsDown:
  1055.     begin
  1056.       if not fUseCustomGlyphs then Result := fDownActive
  1057.         else
  1058.       begin
  1059.         if fCustomDownActive.Empty then Result := fCustomInactive
  1060.           else Result := fCustomDownActive;
  1061.       end;
  1062.     end
  1063.     else
  1064.     begin
  1065.       if not fUseCustomGlyphs then Result := fInactive
  1066.         else Result := fCustomInactive;
  1067.     end;
  1068.   end;
  1069.   if not Enabled then
  1070.   begin
  1071.     if not fUseCustomGlyphs then Result := fDisabled
  1072.       else
  1073.     begin
  1074.       if fCustomDisabled.Empty then
  1075.         Result := CreateDisabledBitmap(fCustomInactive,clBlack)
  1076.       else
  1077.         Result := fCustomDisabled;
  1078.     end;
  1079.   end;
  1080. end;
  1081.  
  1082. { This procedure draws an Office 97 style frame }
  1083. procedure TOffice97Button.DrawFrame;
  1084. var
  1085.   rClient: TRect;
  1086. begin
  1087.   rClient := ClientRect;
  1088.   with fControl.Canvas do
  1089.   begin
  1090.     with rClient do
  1091.     begin
  1092.       Pen.Color := fInactiveColor;
  1093.       Pen.Style := psSolid;
  1094.       { Draw the appropriate state frame }
  1095.       case fState of
  1096.         bsActive:
  1097.           begin
  1098.             PolyLine([Point(Right-8,1),Point(8,1),Point(7,2),
  1099.               Point(6,2),Point(2,6),Point(2,7),Point(1,8),
  1100.               Point(1,Bottom-8),Point(2,Bottom-7),
  1101.               Point(2,Bottom-6),Point(5,Bottom-3)]);
  1102.             Pixels[5,Bottom-3] := fInactiveColor;
  1103.             Pixels[7,Bottom-2] := fInactiveColor;
  1104.             PolyLine([Point(5,Bottom-5),Point(6,Bottom-4),
  1105.               Point(7,Bottom-4),Point(8,Bottom-3),
  1106.               Point(Right-8,Bottom-3),Point(Right-3,Bottom-8),
  1107.               Point(Right-3,8),Point(Right-2,7)]);
  1108.             Pixels[Right-2,7] := fInactiveColor;
  1109.             Pixels[Right-7,Bottom-2] := fInactiveColor;
  1110.             PolyLine([Point(Right-5,Bottom-3),
  1111.               Point(Right-3,Bottom-5)]);
  1112.             Pixels[Right-3,Bottom-5] := fInactiveColor;
  1113.             PolyLine([Point(Right-6,Bottom-4),
  1114.               Point(Right-4,Bottom-6)]);
  1115.             Pixels[Right-4,Bottom-6] := fInactiveColor;
  1116.             Pixels[Right-2,Bottom-7] := fInactiveColor;
  1117.             Pixels[Right-2,7] := fInactiveColor;
  1118.             PolyLine([Point(Right-4,6),Point(Right-5,5)]);
  1119.             Pixels[Right-5,5] := fInactiveColor;
  1120.             PolyLine([Point(Right-3,5),Point(Right-6,2)]);
  1121.             Pixels[Right-6,2] := fInactiveColor;
  1122.             Pen.Color := fActiveColor;
  1123.             PolyLine([Point(8,2),Point(7,3),Point(6,3),
  1124.               Point(3,6),Point(3,7),Point(2,8),
  1125.               Point(2,Bottom-8),Point(3,Bottom-7),
  1126.               Point(3,Bottom-6),Point(6,Bottom-3),
  1127.               Point(7,Bottom-3),Point(8,Bottom-2),
  1128.               Point(Right-8,Bottom-2),Point(Right-7,Bottom-3),
  1129.               Point(Right-6,Bottom-3),Point(Right-3,Bottom-6),
  1130.               Point(Right-3,Bottom-7),Point(Right-2,Bottom-8),
  1131.               Point(Right-2,8),Point(Right-3,7),
  1132.               Point(Right-3,6),Point(Right-7,2),
  1133.               Point(8,2)]);
  1134.             Pixels[8,2] := fActiveColor;
  1135.             Pen.Color := fActiveOutlineColor;
  1136.             PolyLine([Point(Right-7,3),Point(8,3),
  1137.               Point(3,8),Point(3,Bottom-8)]);
  1138.             Pixels[3,Bottom-8] := fActiveOutlineColor;
  1139.             PolyLine([Point(Right-6,5),Point(Right-6,4),
  1140.               Point(8,4),Point(4,8),Point(4,Bottom-6),
  1141.               Point(5,Bottom-6)]);
  1142.             Pixels[5,Bottom-6] := fActiveOutlineColor;
  1143.             PolyLine([Point(6,4),Point(4,6)]);
  1144.             Pixels[4,6] := fActiveOutlineColor;
  1145.           end;
  1146.         bsDown:
  1147.           begin
  1148.             PolyLine([Point(Right-8,1),Point(8,1),
  1149.               Point(7,2),Point(6,2),Point(2,6),Point(2,7),
  1150.               Point(1,8),Point(1,Bottom-8),Point(2,Bottom-7),
  1151.               Point(2,Bottom-6),Point(4,Bottom-4),
  1152.               Point(5,Bottom-4),Point(6,Bottom-3),
  1153.               Point(7,Bottom-3),Point(8,Bottom-2),
  1154.               Point(Right-8,Bottom-2),Point(Right-7,Bottom-3),
  1155.               Point(Right-6,Bottom-3),Point(Right-3,Bottom-6),
  1156.               Point(Right-3,Bottom-7),Point(Right-2,Bottom-8),
  1157.               Point(Right-2,8),Point(Right-3,7),
  1158.               Point(Right-3,6)]);
  1159.             Pixels[Right-3,6] := fInactiveColor;
  1160.             Pixels[8,3] := fInactiveColor;
  1161.             PolyLine([Point(6,4),Point(4,6)]);
  1162.             Pixels[4,6] := fInactiveColor;
  1163.             PolyLine([Point(3,8),Point(3,Bottom-8)]);
  1164.             Pixels[3,Bottom-8] := fInactiveColor;
  1165.             Pixels[4,Bottom-6] := fInactiveColor;
  1166.             PolyLine([Point(Right-4,4),Point(Right-6,2)]);
  1167.             Pixels[Right-6,2] := fInactiveColor;
  1168.             Pixels[Right-7,3] := fInactiveColor;
  1169.             Pen.Color := fActiveColor;
  1170.             PolyLine([Point(Right-4,5),Point(Right-7,2),
  1171.               Point(8,2),Point(7,3),Point(6,3),Point(3,6),
  1172.               Point(3,7),Point(2,8),Point(2,Bottom-8),
  1173.               Point(3,Bottom-7),Point(3,Bottom-6),
  1174.               Point(4,Bottom-5)]);
  1175.             Pixels[4,Bottom-5] := fActiveColor;
  1176.             Pen.Color := fActiveOutlineColor;
  1177.             PolyLine([Point(7,5),Point(5,7),
  1178.               Point(5,Bottom-5)]);
  1179.             Pixels[5,Bottom-5] := fActiveOutlineColor;
  1180.             PolyLine([Point(Right-8,3),Point(9,3)]);
  1181.             Pixels[9,3] := fActiveOutlineColor;
  1182.             PolyLine([Point(5,Bottom-3),Point(6,Bottom-2),
  1183.               Point(7,Bottom-2),Point(7,Bottom-1),
  1184.               Point(Right-6,Bottom-1),Point(Right-1,Bottom-6),
  1185.               Point(Right-1,8),Point(Right-2,7),
  1186.               Point(Right-2,6),Point(Right-3,5),
  1187.               Point(Right-4,6),Point(Right-5,5),
  1188.               Point(Right-6,5),Point(Right-6,4),Point(7,4),
  1189.               Point(4,7),Point(4,Bottom-7)]);
  1190.             Pixels[4,Bottom-7] := fActiveOutlineColor;
  1191.             PolyLine([Point(Right-4,Bottom-2),
  1192.               Point(Right-1,Bottom-5)]);
  1193.             Pixels[Right-1,Bottom-5] := fActiveOutlineColor;
  1194.             PolyLine([Point(Right-7,Bottom-2),
  1195.               Point(Right-6,Bottom-2),Point(Right-2,Bottom-6),
  1196.               Point(Right-2,Bottom-7)]);
  1197.             Pixels[Right-2,Bottom-7] := fActiveOutlineColor;
  1198.           end;
  1199.         bsDownAndOut,bsInactive:
  1200.           begin
  1201.             PolyLine([Point(8,2),Point(7,3),Point(6,3),
  1202.               Point(3,6),Point(3,7),Point(2,8),
  1203.               Point(2,Bottom-8),Point(3,Bottom-7),
  1204.               Point(3,Bottom-6),Point(6,Bottom-3),
  1205.               Point(7,Bottom-3),Point(8,Bottom-2),
  1206.               Point(Right-8,Bottom-2),Point(Right-7,Bottom-3),
  1207.               Point(Right-6,Bottom-3),Point(Right-3,Bottom-6),
  1208.               Point(Right-3,Bottom-7),Point(Right-2,Bottom-8),
  1209.               Point(Right-2,8),Point(Right-3,7),
  1210.               Point(Right-3,6),Point(Right-6,3),
  1211.               Point(Right-7,3),Point(Right-8,2),Point(8,2)]);
  1212.             Pixels[8,2] := fInactiveColor;
  1213.           end;
  1214.       end;
  1215.     end;
  1216.   end;
  1217. end;
  1218.  
  1219. { This procedure draws an Office 2000 style frame }
  1220. procedure TOffice97Button.DrawOffice2000Frame;
  1221. var
  1222.   rClient: TRect;
  1223. begin
  1224.   rClient := ClientRect;
  1225.   with fControl.Canvas do
  1226.   begin
  1227.     with rClient do
  1228.     begin
  1229.       Pen.Color := fInactiveColor;
  1230.       Pen.Style := psSolid;
  1231.       { Draw the appropriate state frame }
  1232.       case fState of
  1233.         bsActive:
  1234.           begin
  1235.             Pixels[Right-2,3] := fInactiveColor;
  1236.             Pixels[2,Bottom-3] := fInactiveColor;
  1237.             Pen.Color := fActiveColor;
  1238.             PolyLine([Point(Right-2,4),Point(Right-2,Bottom-4),
  1239.               Point(Right-4,Bottom-2),Point(3,Bottom-2)]);
  1240.             Pixels[3,Bottom-2] := fActiveColor;
  1241.             Pen.Color := fActiveOutlineColor;
  1242.             PolyLine([Point(Right-3,2),Point(Right-4,1),
  1243.               Point(3,1),Point(1,3),Point(1,Bottom-4)]);
  1244.             Pixels[1,Bottom-4] := fActiveOutlineColor;
  1245.             Pen.Color := fActiveOutlineColor2;
  1246.             PolyLine([Point(3,0),Point(0,3),
  1247.               Point(0,Bottom-4),Point(3,Bottom-1),
  1248.               Point(Right-4,Bottom-1),Point(Right-1,Bottom-4),
  1249.               Point(Right-1,3),Point(Right-4,0),Point(3,0)]);
  1250.           end;
  1251.         bsDown:
  1252.           begin
  1253.             Pixels[Right-3,2] := fInactiveColor;
  1254.             Pixels[1,Bottom-4] := fInactiveColor;
  1255.             Pen.Color := fActiveColor;
  1256.             PolyLine([Point(Right-4,1),Point(3,1),
  1257.               Point(1,3),Point(1,Bottom-5)]);
  1258.             Pixels[1,Bottom-5] := fActiveColor;
  1259.             Pen.Color := fActiveOutlineColor;
  1260.             PolyLine([Point(Right-2,2),Point(Right-1,3),
  1261.               Point(Right-1,Bottom-4),Point(Right-4,Bottom-1),
  1262.               Point(3,Bottom-1),Point(1,Bottom-3)]);
  1263.             Pixels[1,Bottom-3] := fActiveOutlineColor;
  1264.             Pen.Color := fActiveOutlineColor2;
  1265.             PolyLine([Point(Right-3,1),Point(Right-4,0),
  1266.               Point(3,0),Point(0,3),Point(0,Bottom-4)]);
  1267.             Pixels[0,Bottom-4] := fActiveOutlineColor2;
  1268.             PolyLine([Point(Right-2,3),Point(Right-2,Bottom-4),
  1269.               Point(Right-4,Bottom-2),Point(3,Bottom-2),
  1270.               Point(2,Bottom-3)]);
  1271.             Pixels[2,Bottom-3] := fActiveOutlineColor2;
  1272.           end;
  1273.         bsDownAndOut,bsInactive:
  1274.           begin
  1275.             PolyLine([Point(3,1),Point(1,3),
  1276.               Point(1,Bottom-4),Point(3,Bottom-2),
  1277.               Point(Right-4,Bottom-2),Point(Right-2,Bottom-4),
  1278.               Point(Right-2,3),Point(Right-4,1),Point(3,1)]);
  1279.           end;
  1280.       end;
  1281.     end;
  1282.   end;
  1283. end;
  1284.  
  1285. { Thanks to Kambiz for adding bi-directional support to this procedure }
  1286. procedure TOffice97Button.Layout(var txtRect, bitRect: TRect);
  1287. var
  1288.   dBit, hBit, vBit, hTxt, vTxt: Integer;
  1289.   GlyphPos: TGlyphPosition;
  1290. begin
  1291.   { Work out text canvas height and width }
  1292.   hTxt := txtRect.Right - txtRect.Left;
  1293.   vTxt := txtRect.Bottom - txtRect.Top;
  1294.   if fShowGlyph then
  1295.   begin
  1296.     GlyphPos := fGlyphPosition;
  1297.     { Work out glyph canvas height and width }
  1298.     hBit := bitRect.Right - bitRect.Left;
  1299.     vBit := bitRect.Bottom - bitRect.Top;
  1300.     { Position glyph canvas and text canvas }
  1301.     if fType = bsButton then
  1302.     begin
  1303.       {$IFDEF OFFBTND4}
  1304.       if UseRightToLeftAlignment then
  1305.       begin
  1306.         if GlyphPos = bsLeft then
  1307.           GlyphPos := bsRight
  1308.         else if GlyphPos = bsRight then
  1309.           GlyphPos := bsLeft
  1310.       end;
  1311.       {$ENDIF}
  1312.       case GlyphPos of
  1313.         bsTop, bsBottom:
  1314.         begin
  1315.           { bsTop positioning }
  1316.           bitRect.Left := ((Width - hBit - 1) div 2) + 1;
  1317.           txtRect.Left := ((Width - hTxt - 1) div 2) + 1;
  1318.           bitRect.Top := 6;
  1319.           txtRect.Top := ((Height - (vBit + vTxt) - 1) div 2) + vBit + 1;
  1320.           if GlyphPos = bsBottom then
  1321.           begin
  1322.             { Mirror top coordinates for bsBottom }
  1323.             bitRect.Top := Height - (bitRect.Top + vBit) - 1;
  1324.             txtRect.Top := Height - (txtRect.Top + vTxt) - 1;
  1325.           end;
  1326.         end;
  1327.         bsLeft, bsRight:
  1328.         begin
  1329.           { bsLeft positioning }
  1330.           bitRect.Top := ((Height - vBit - 1) div 2) + 1;
  1331.           txtRect.Top := ((Height - vTxt - 1) div 2) + 1;
  1332.           bitRect.Left := 6;
  1333.           txtRect.Left := ((Width - (hBit + hTxt) - 1) div 2) + hBit + 1;
  1334.           if GlyphPos = bsRight then
  1335.           begin
  1336.             { Mirror left coordinates for bsRight }
  1337.             bitRect.Left := Width - (bitRect.Left + hBit) - 1;
  1338.             txtRect.Left := Width - (txtRect.Left + hTxt) - 1;
  1339.           end;
  1340.         end;
  1341.       end;
  1342.     end
  1343.     else
  1344.     begin
  1345.       { bsTop positioning }
  1346.       dBit := fControl.Canvas.TextHeight(fCaption) - vBit;
  1347.       if dBit < 2 then
  1348.         bitRect.Top := 2
  1349.       else
  1350.         bitRect.Top := 2 + (dBit div 2);
  1351.       txtRect.Top := 2;
  1352.       bitRect.Left := 2;
  1353.       txtRect.Left := hBit + 7;
  1354.       {$IFDEF OFFBTND4}
  1355.       if UseRightToLeftAlignment then
  1356.       begin
  1357.         bitRect.Left := (Width - hBit) - bitRect.Left;
  1358.         txtRect.Left := (Width - hTxt) - txtRect.Left;
  1359.       end;
  1360.       {$ENDIF}
  1361.       if GlyphPos = bsBottom then
  1362.       begin
  1363.         { Mirror top coordinates for bsBottom }
  1364.         bitRect.Top := Height - (bitRect.Top + vBit) - 1;
  1365.         txtRect.Top := Height - (txtRect.Top + vTxt) - 1;
  1366.       end;
  1367.     end;
  1368.     { Set the glyph canvas height and width }
  1369.     bitRect.Right := bitRect.Left + hBit;
  1370.     bitRect.Bottom := bitRect.Top + vBit;
  1371.   end
  1372.   else
  1373.   begin
  1374.     { Center, or left justify, the text canvas }
  1375.     if fType = bsButton then
  1376.     begin
  1377.       txtRect.Top := ((Height - vTxt - 1) div 2) + 1;
  1378.       txtRect.Left := ((Width - hTxt - 1) div 2) + 1;
  1379.     end
  1380.     else
  1381.     begin
  1382.       txtRect.Top := 2;
  1383.       txtRect.Left := 2;
  1384.       {$IFDEF OFFBTND4}
  1385.       if UseRightToLeftAlignment then
  1386.         txtRect.Left := (Width - hTxt) - txtRect.Left;
  1387.       {$ENDIF}
  1388.     end;
  1389.   end;
  1390.   { Set the text canvas height and width }
  1391.   txtRect.Right := txtRect.Left + hTxt;
  1392.   txtRect.Bottom := txtRect.Top + vTxt;
  1393.   { Draw the focus using the appropriate style }
  1394.   with fControl.Canvas do
  1395.   begin
  1396.     if (fCaption <> '') and ((csDesigning in ComponentState)
  1397.       and Enabled) or (not(csDesigning in ComponentState)
  1398.         and (not fNoDots) and (Focused or (fFocused and
  1399.           not(Screen.ActiveControl is TOffice97Button)))) then
  1400.     begin
  1401.       if fType = bsButton then
  1402.         {$IFDEF WIN32}
  1403.         Windows.DrawFocusRect(Handle,Rect(txtRect.Left,txtRect.Top,txtRect.Right+1,txtRect.Bottom+1))
  1404.         {$ELSE}
  1405.         WinProcs.DrawFocusRect(Handle,Rect(txtRect.Left,txtRect.Top,txtRect.Right+1,txtRect.Bottom+1))
  1406.         {$ENDIF}
  1407.       else
  1408.         DrawOfficeFocusRect(txtRect,capWrap);
  1409.     end;
  1410.   end;
  1411.   { If control down, and control type is button, draw
  1412.     text and glyph down and to the right }
  1413.   if (fState = bsDown) and (fType = bsButton) then
  1414.   begin
  1415.     if fShowGlyph then OffsetRect(bitRect, 1, 1);
  1416.     OffsetRect(txtRect, 1, 1);
  1417.   end;
  1418. end;
  1419.  
  1420. procedure TOffice97Button.CalculateTxt(var txtRect: TRect;Glyph: TBitmap);
  1421. begin
  1422.   { If text is to be wordwrapped, the rectangle size must be
  1423.     based on the control size and glyph position - TextWidth and
  1424.     TextHeight give the size but they assume that the text won't
  1425.     be wordwrapped }
  1426.   if fType = bsButton then
  1427.   begin
  1428.     if fGlyphPosition in [bsLeft,bsRight] then
  1429.     begin
  1430.       tX := width - glyph.width - 18;
  1431.       if not fShowGlyph then inc(tX,glyph.width + 5);
  1432.     end
  1433.     else
  1434.       tX := width - 13;
  1435.   end
  1436.   else
  1437.   begin
  1438.     tX := width - glyph.width - 10;
  1439.     if not fShowGlyph then inc(tX,glyph.width + 5);
  1440.   end;
  1441.   with fControl.Canvas do
  1442.   begin
  1443.     { Wordwrap text and store the result in a string list }
  1444.     GetWrapText(fCaption,tX);
  1445.     if TextWidth(fCaption) > tX then
  1446.       txtRect := Rect(0, 0, tX, capLines*TextHeight('0'))
  1447.     else
  1448.     begin
  1449.       tX := TextWidth(fCaption);
  1450.       txtRect := Rect(0, 0, TextWidth(fCaption), TextHeight(fCaption));
  1451.     end;
  1452.   end;
  1453. end;
  1454.  
  1455. procedure TOffice97Button.WMEraseBkgnd(var Message: TWMEraseBkgnd);
  1456. begin
  1457.   Message.Result := 1;
  1458. end;
  1459.  
  1460. { Thanks to Kambiz for this procedure }
  1461. procedure TOffice97Button.AdjustHeight;
  1462. var
  1463.   txtRect: TRect;
  1464.   hBit, hTxt: Integer;
  1465. begin
  1466.   fControl := TBitmap.Create;
  1467.   fControl.Width := Width;
  1468.   fControl.Height := Height;
  1469.   fControl.Canvas.Font := Font;
  1470.   if not fWordWrap then
  1471.     hTxt := fControl.Canvas.TextHeight(fCaption)
  1472.   else
  1473.   begin
  1474.     CalculateTxt(txtRect, CurrentGlyph);
  1475.     hTxt := txtRect.Bottom;
  1476.   end;
  1477.   if fShowGlyph then
  1478.   begin
  1479.     hBit := CurrentGlyph.Height;
  1480.     if (fType = bsButton) and (fGlyphPosition in [bsTop,bsBottom]) then
  1481.       Inc(hTxt, hBit + 4)
  1482.     else if hBit > htxt then
  1483.       hTxt := hBit;
  1484.   end;
  1485.   if fType = bsButton then
  1486.     Height := hTxt + 10
  1487.   else
  1488.     Height := hTxt + 5;
  1489.   fControl.Free;
  1490. end;
  1491.  
  1492. { Thanks to Kambiz for adding bi-directional support to this procedure }
  1493. procedure TOffice97Button.Paint;
  1494. var
  1495.   Glyph: TBitmap;
  1496.   tmpRect,txtRect, bitRect, glyphRect: TRect;
  1497.   TempCap: array[0..255] of char;
  1498.   Count: Integer;
  1499.   DrawFlags: LongInt;
  1500. begin
  1501.   { Setup the offscreen bitmap }
  1502.   fControl := TBitmap.Create;
  1503.   fControl.Width := Width;
  1504.   fControl.Height := Height;
  1505.   with fControl.Canvas do
  1506.   begin
  1507.     { Fill control background }
  1508.     if fTransparent then
  1509.       CopyParentImage(Self, fControl.Canvas)
  1510.     else
  1511.     begin
  1512.       Brush.Color := Color;
  1513.       Brush.Style := bsSolid;
  1514.       FillRect(ClientRect);
  1515.     end;
  1516.     { Figure out size of text and display bitmaps }
  1517.     if not (Enabled and (fState in [bsActive, bsDown])) then
  1518.     begin
  1519.       Font := Self.Font;
  1520.       if not enabled then Font.Color := fInactiveColor;
  1521.     end
  1522.     else
  1523.       Font := fHoverFont;
  1524.     if fDefault then Font.Style := Font.Style + [fsBold];
  1525.     Glyph := CurrentGlyph;
  1526.     bitRect := Rect(0, 0, Glyph.Width, Glyph.Height);
  1527.     if not fWordWrap then
  1528.       txtRect := Rect(0, 0, TextWidth(fCaption), TextHeight(fCaption))
  1529.     else
  1530.       CalculateTxt(txtRect,Glyph);
  1531.     glyphRect := bitRect;
  1532.     { Calculate position of text and bitmap and draw focus }
  1533.     Layout(txtRect,bitRect);
  1534.     { Draw the caption }
  1535.     Brush.Style := bsClear;
  1536.     SetBkMode(Handle, {$IFDEF WIN32}Windows{$ELSE}WinTypes{$ENDIF}.TRANSPARENT);
  1537.     StrPCopy(TempCap, fCaption);
  1538.     if (not fWordWrap) or (capLines = 1) then
  1539.     begin
  1540.       { A single line caption }
  1541.       if fType = bsButton then
  1542.         DrawFlags := DT_CENTER
  1543.       else
  1544.         DrawFlags := DT_WORDBREAK;
  1545.       {$IFDEF OFFBTND4}
  1546.       DrawFlags := DrawTextBiDiModeFlags(DrawFlags);
  1547.       {$ENDIF}
  1548.       DrawText(Handle, TempCap, StrLen(TempCap), txtRect, DrawFlags);
  1549.     end
  1550.     else
  1551.       { A multiple line caption }
  1552.       for Count := 0 to capWrap.Count-1 do
  1553.       begin
  1554.         StrPCopy(TempCap, capWrap.Strings[Count]);
  1555.         tmpRect := Rect(0, 0, tX, TextHeight('0'));
  1556.         tmpRect.Left := txtRect.Left;
  1557.         tmpRect.Top := txtRect.Top+(Count*TextHeight('0'));
  1558.         tmpRect.Right := tmpRect.Left + tX;
  1559.         tmpRect.Bottom := tmpRect.Top + TextHeight('0');
  1560.         if fType = bsButton then
  1561.           DrawFlags := DT_CENTER
  1562.         else
  1563.           DrawFlags := 0;
  1564.         {$IFDEF OFFBTND4}
  1565.         DrawFlags := DrawTextBiDiModeFlags(DrawFlags);
  1566.         {$ENDIF}
  1567.         DrawText(Handle, TempCap, StrLen(TempCap), tmpRect, DrawFlags);
  1568.       end;
  1569.     { Draw the glyph, if required }
  1570.     if fShowGlyph then
  1571.     begin
  1572.       if fAutoTransparency then
  1573.         DrawTransparentBitmap(fControl.Canvas, bitRect.Left, bitRect.Top,
  1574.           Glyph, Glyph.Canvas.Pixels[0, Glyph.Height-1])
  1575.       else
  1576.         DrawTransparentBitmap(fControl.Canvas, bitRect.Left, bitRect.Top,
  1577.           Glyph, fTransparentColor);
  1578.     end;
  1579.     { Finally, draw control frame if it is a button type }
  1580.     if fType = bsButton then
  1581.     begin
  1582.       { Work out which frame style to use }
  1583.       if fOffice2000Look then DrawOffice2000Frame else
  1584.         DrawFrame;
  1585.     end;
  1586.   end;
  1587.   { Now copy the bitmap to the screen and free it }
  1588.   Canvas.CopyRect(Rect(0,0,Width,Height), fControl.Canvas, Rect(0,0,Width,Height));
  1589.   fControl.Free;
  1590. end;
  1591.  
  1592. { Start of mouse routines
  1593.  
  1594.   FindDragTarget is much better than using PtInRect as it takes into
  1595.   account the Z order of controls }
  1596.  
  1597. procedure TOffice97Button.WMLButtonDown(var Message: TWMLButtonDown);
  1598. var
  1599.   InControl: Boolean;
  1600.   oState: TOffBtnState;
  1601.   Temp: TPoint;
  1602. begin
  1603.   Inherited;
  1604.   oState := fState;
  1605.   Temp := ClientToScreen(Point(Message.XPos,Message.YPos));
  1606.   InControl := FindDragTarget(Temp, True) = Self;
  1607.   if InControl then
  1608.   begin
  1609.     MouseCapture := True;
  1610.     fState := bsDown;
  1611.   end;
  1612.   if oState <> fState then Invalidate;
  1613. end;
  1614.  
  1615. procedure TOffice97Button.WMMouseMove(var Message: TWMMouseMove);
  1616. var
  1617.   InControl: Boolean;
  1618.   oState: TOffBtnState;
  1619.   Temp: TPoint;
  1620. begin
  1621.   Inherited;
  1622.   oState := fState;
  1623.   Temp := ClientToScreen(Point(Message.XPos,Message.YPos));
  1624.   InControl := FindDragTarget(Temp, True) = Self;
  1625.   if (fState = bsDown) and (not InControl) then
  1626.     fState := bsDownAndOut;
  1627.   if (fState = bsDownAndOut) and (InControl) then
  1628.     fState := bsDown;
  1629.   case fState of
  1630.     bsInActive:  if InControl then
  1631.                  begin
  1632.                    fState := bsActive;
  1633.                    if Assigned(fMouseEnter) then fMouseEnter(Self);
  1634.                    MouseCapture := True;
  1635.                  end;
  1636.     bsActive:    if not InControl then
  1637.                  begin
  1638.                    fState := bsInActive;
  1639.                    if Assigned(fMouseExit) then fMouseExit(Self);
  1640.                    MouseCapture := False;
  1641.                  end;
  1642.   end;
  1643.   if oState <> fState then Invalidate;
  1644. end;
  1645.  
  1646. procedure TOffice97Button.WMLButtonUp(var Message: TWMLButtonUp);
  1647. var
  1648.   InControl: Boolean;
  1649.   oState: TOffBtnState;
  1650.   Temp: TPoint;
  1651. begin
  1652.   Inherited;
  1653.   oState := fState;
  1654.   Temp := ClientToScreen(Point(Message.XPos,Message.YPos));
  1655.   InControl := FindDragTarget(Temp, True) = Self;
  1656.   { If we are using a modal form, we release the mouse capture }
  1657.   if (InControl) and (fModalResult = mrNone) then
  1658.   begin
  1659.     fState := bsActive;
  1660.     MouseCapture := True;
  1661.   end
  1662.   else
  1663.   begin
  1664.     fState := bsInactive;
  1665.     MouseCapture := False;
  1666.   end;
  1667.   if oState <> fState then Invalidate;
  1668. end;
  1669.  
  1670. { This procedure ensures that the control state is correct when
  1671.   the popup menu is displayed }
  1672. procedure TOffice97Button.WMRButtonDown(var Message: TWMRButtonDown);
  1673. var
  1674.   InControl: Boolean;
  1675.   oState: TOffBtnState;
  1676.   Temp: TPoint;
  1677. begin
  1678.   Inherited;
  1679.   oState := fState;
  1680.   Temp := ClientToScreen(Point(Message.XPos,Message.YPos));
  1681.   InControl := FindDragTarget(Temp, True) = Self;
  1682.   if (InControl) and (PopupMenu <> nil) then
  1683.   begin
  1684.     fState := bsInactive;
  1685.     MouseCapture := False;
  1686.   end;
  1687.   if oState <> fState then Invalidate;
  1688. end;
  1689.  
  1690. { End of mouse routines }
  1691.  
  1692. procedure Register;
  1693. begin
  1694.   RegisterComponents('Standard', [TOffice97Button]);
  1695. end;
  1696.  
  1697. end.
  1698.