home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 March / Chip_2002-03_cd1.bin / zkuste / delphi / kompon / d12456 / OFFBTN97.ZIP / OffBtn97 / OffBtn.pas next >
Pascal/Delphi Source File  |  2001-12-30  |  55KB  |  1,707 lines

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