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

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {     Delphi VCL Extensions (RX)                        }
  4. {                                                       }
  5. {     Copyright (c) 1997 Master-Bank                    }
  6. {     Copyright (c) 1998 Ritting Information Systems    }
  7. {                                                       }
  8. {*******************************************************}
  9. unit RxGrdCpt;
  10. {$I RX.INC}
  11. interface
  12. {$IFDEF WIN32}
  13. uses Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs, Menus,
  14.   RxHook, VclUtils;
  15. type
  16.   THideDirection = (hdLeftToRight, hdRightToLeft);
  17.   TRxCaption = class;
  18.   TRxCaptionList = class;
  19. { TRxGradientCaption }
  20.   TRxGradientCaption = class(TComponent)
  21.   private
  22.     FActive: Boolean;
  23.     FWindowActive: Boolean;
  24.     FSaveRgn: HRgn;
  25.     FRgnChanged: Boolean;
  26.     FWinHook: TRxWindowHook;
  27.     FStartColor: TColor;
  28.     FCaptions: TRxCaptionList;
  29.     FFont: TFont;
  30.     FDefaultFont: Boolean;
  31.     FPopupMenu: TPopupMenu;
  32.     FClicked: Boolean;
  33.     FHideDirection: THideDirection;
  34.     FGradientInactive: Boolean;
  35.     FGradientActive: Boolean;
  36.     FFontInactiveColor: TColor;
  37.     FFormCaption: string;
  38.     FGradientSteps: Integer;
  39.     FOnActivate: TNotifyEvent;
  40.     FOnDeactivate: TNotifyEvent;
  41.     procedure SetHook;
  42.     procedure ReleaseHook;
  43.     procedure CheckToggleHook;
  44.     function GetActive: Boolean;
  45.     procedure SetActive(Value: Boolean);
  46.     procedure SetStartColor(Value: TColor);
  47.     procedure DrawGradientCaption(DC: HDC);
  48.     procedure CalculateGradientParams(var R: TRect; var Icons: TBorderIcons);
  49.     function GetForm: TForm;
  50.     function GetFormCaption: string;
  51.     procedure SetFormCaption(const Value: string);
  52.     procedure BeforeMessage(Sender: TObject; var Msg: TMessage;
  53.       var Handled: Boolean);
  54.     procedure AfterMessage(Sender: TObject; var Msg: TMessage;
  55.       var Handled: Boolean);
  56.     function CheckMenuPopup(X, Y: Integer): Boolean;
  57.     procedure SetFont(Value: TFont);
  58.     procedure FontChanged(Sender: TObject);
  59.     procedure SetDefaultFont(Value: Boolean);
  60.     procedure SetFontDefault;
  61.     function IsFontStored: Boolean;
  62.     function GetTextWidth: Integer;
  63.     procedure SetCaptions(Value: TRxCaptionList);
  64.     procedure SetGradientActive(Value: Boolean);
  65.     procedure SetGradientInactive(Value: Boolean);
  66.     procedure SetGradientSteps(Value: Integer);
  67.     procedure SetFontInactiveColor(Value: TColor);
  68.     procedure SetHideDirection(Value: THideDirection);
  69.     procedure SetPopupMenu(Value: TPopupMenu);
  70.   protected
  71.     procedure Loaded; override;
  72.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  73. {$IFDEF RX_D4}
  74.     function IsRightToLeft: Boolean;
  75. {$ENDIF}
  76.     property Form: TForm read GetForm;
  77.     property TextWidth: Integer read GetTextWidth;
  78.   public
  79.     constructor Create(AOwner: TComponent); override;
  80.     destructor Destroy; override;
  81.     procedure MoveCaption(FromIndex, ToIndex: Integer);
  82.     procedure Update;
  83.     procedure Clear;
  84.   published
  85.     property Active: Boolean read GetActive write SetActive default True;
  86.     property Captions: TRxCaptionList read FCaptions write SetCaptions;
  87.     property DefaultFont: Boolean read FDefaultFont write SetDefaultFont default True;
  88.     property FormCaption: string read GetFormCaption write SetFormCaption;
  89.     property FontInactiveColor: TColor read FFontInactiveColor
  90.       write SetFontInactiveColor default clInactiveCaptionText;
  91.     property Font: TFont read FFont write SetFont stored IsFontStored;
  92.     property GradientActive: Boolean read FGradientActive
  93.       write SetGradientActive default True;
  94.     property GradientInactive: Boolean read FGradientInactive
  95.       write SetGradientInactive default False;
  96.     property GradientSteps: Integer read FGradientSteps write SetGradientSteps
  97.       default 64;
  98.     property HideDirection: THideDirection read FHideDirection
  99.       write SetHideDirection default hdLeftToRight;
  100.     property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
  101.     property StartColor: TColor read FStartColor write SetStartColor
  102.       default clWindowText;
  103.     property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
  104.     property OnDeactivate: TNotifyEvent read FOnDeactivate write FOnDeactivate;
  105.   end;
  106. { TRxCaptionList }
  107.   TRxCaptionList = class(TCollection)
  108.   private
  109.     FParent: TRxGradientCaption;
  110.     function GetCaption(Index: Integer): TRxCaption;
  111.     procedure SetCaption(Index: Integer; Value: TRxCaption);
  112.   protected
  113. {$IFDEF RX_D3}
  114.     function GetOwner: TPersistent; override;
  115. {$ENDIF}
  116.     procedure Update(Item: TCollectionItem); override;
  117.   public
  118.     constructor Create(AParent: TRxGradientCaption);
  119.     function Add: TRxCaption;
  120.     procedure RestoreDefaults;
  121.     property Parent: TRxGradientCaption read FParent;
  122.     property Items[Index: Integer]: TRxCaption read GetCaption write SetCaption; default;
  123.   end;
  124. { TRxCaption }
  125.   TRxCaption = class(TCollectionItem)
  126.   private
  127.     FCaption: string;
  128.     FFont: TFont;
  129.     FParentFont: Boolean;
  130.     FVisible: Boolean;
  131.     FGlueNext: Boolean;
  132.     FInactiveColor: TColor;
  133.     procedure SetCaption(const Value: string);
  134.     procedure SetFont(Value: TFont);
  135.     procedure SetParentFont(Value: Boolean);
  136.     procedure FontChanged(Sender: TObject);
  137.     function IsFontStored: Boolean;
  138.     function GetTextWidth: Integer;
  139.     procedure SetVisible(Value: Boolean);
  140.     procedure SetInactiveColor(Value: TColor);
  141.     procedure SetGlueNext(Value: Boolean);
  142.   protected
  143.     function GetParentCaption: TRxGradientCaption;
  144.     property TextWidth: Integer read GetTextWidth;
  145.   public
  146.     constructor Create(Collection: TCollection); override;
  147.     destructor Destroy; override;
  148.     procedure Assign(Source: TPersistent); override;
  149.     procedure RestoreDefaults; virtual;
  150.     property GradientCaption: TRxGradientCaption read GetParentCaption;
  151.   published
  152.     property Caption: string read FCaption write SetCaption;
  153.     property Font: TFont read FFont write SetFont stored IsFontStored;
  154.     property ParentFont: Boolean read FParentFont write SetParentFont
  155.       default True;
  156.     property InactiveColor: TColor read FInactiveColor write SetInactiveColor
  157.       default clInactiveCaptionText;
  158.     property GlueNext: Boolean read FGlueNext write SetGlueNext default False;
  159.     property Visible: Boolean read FVisible write SetVisible default True;
  160.   end;
  161. function GradientFormCaption(AForm: TCustomForm;
  162.   AStartColor: TColor): TRxGradientCaption;
  163. {$ENDIF WIN32}
  164. implementation
  165. {$IFDEF WIN32}
  166. uses SysUtils, AppUtils;
  167. function GradientFormCaption(AForm: TCustomForm;
  168.   AStartColor: TColor): TRxGradientCaption;
  169. begin
  170.   Result := TRxGradientCaption.Create(AForm);
  171.   with Result do
  172.     try
  173.       FStartColor := AStartColor;
  174.       FormCaption := AForm.Caption;
  175.       Update;
  176.     except
  177.       Free;
  178.       raise;
  179.     end;
  180. end;
  181. { TRxCaptionList }
  182. constructor TRxCaptionList.Create(AParent: TRxGradientCaption);
  183. begin
  184.   inherited Create(TRxCaption);
  185.   FParent := AParent;
  186. end;
  187. function TRxCaptionList.Add: TRxCaption;
  188. begin
  189.   Result := TRxCaption(inherited Add);
  190. end;
  191. function TRxCaptionList.GetCaption(Index: Integer): TRxCaption;
  192. begin
  193.   Result := TRxCaption(inherited Items[Index]);
  194. end;
  195. {$IFDEF RX_D3}
  196. function TRxCaptionList.GetOwner: TPersistent;
  197. begin
  198.   Result := FParent;
  199. end;
  200. {$ENDIF}
  201. procedure TRxCaptionList.RestoreDefaults;
  202. var
  203.   I: Integer;
  204. begin
  205.   BeginUpdate;
  206.   try
  207.     for I := 0 to Count-1 do
  208.       Items[I].RestoreDefaults;
  209.   finally
  210.     EndUpdate;
  211.   end;
  212. end;
  213. procedure TRxCaptionList.SetCaption(Index: Integer; Value: TRxCaption);
  214. begin
  215.   Items[Index].Assign(Value);
  216. end;
  217. procedure TRxCaptionList.Update(Item: TCollectionItem);
  218. begin
  219.   if (FParent <> nil) and not (csLoading in FParent.ComponentState) then
  220.     if FParent.Active then FParent.Update;
  221. end;
  222. { TRxCaption }
  223. constructor TRxCaption.Create(Collection: TCollection);
  224. var
  225.   Parent: TRxGradientCaption;
  226. begin
  227.   Parent := nil;
  228.   if Assigned(Collection) and (Collection is TRxCaptionList) then
  229.     Parent := TRxCaptionList(Collection).Parent;
  230.   try
  231.     inherited Create(Collection);
  232.     FFont := TFont.Create;
  233.     if Assigned(Parent) then begin
  234.       FFont.Assign(Parent.Font);
  235.       FFont.Color := Parent.Font.Color;
  236.     end
  237.     else FFont.Color := clCaptionText;
  238.     FFont.OnChange := FontChanged;
  239.     FCaption := '';
  240.     FParentFont := True;
  241.     FVisible := True;
  242.     FGlueNext := False;
  243.     FInactiveColor := clInactiveCaptionText;
  244.   finally
  245.     if Assigned(Parent) then Changed(False);
  246.   end;
  247. end;
  248. destructor TRxCaption.Destroy;
  249. begin
  250.   FFont.Free;
  251.   FFont := nil;
  252.   inherited Destroy;
  253. end;
  254. procedure TRxCaption.Assign(Source: TPersistent);
  255. begin
  256.   if Source is TRxCaption then begin
  257.     if Assigned(Collection) then Collection.BeginUpdate;
  258.     try
  259.       RestoreDefaults;
  260.       Caption := TRxCaption(Source).Caption;
  261.       ParentFont := TRxCaption(Source).ParentFont;
  262.       if not ParentFont then
  263.         Font.Assign(TRxCaption(Source).Font);
  264.       InactiveColor := TRxCaption(Source).InactiveColor;
  265.       GlueNext := TRxCaption(Source).GlueNext;
  266.       Visible := TRxCaption(Source).Visible;
  267.     finally
  268.       if Assigned(Collection) then Collection.EndUpdate;
  269.     end;
  270.   end
  271.   else inherited Assign(Source);
  272. end;
  273. procedure TRxCaption.RestoreDefaults;
  274. begin
  275.   FInactiveColor := clInactiveCaptionText;
  276.   FVisible := True;
  277.   ParentFont := True;
  278. end;
  279. function TRxCaption.GetParentCaption: TRxGradientCaption;
  280. begin
  281.   if Assigned(Collection) and (Collection is TRxCaptionList) then
  282.     Result := TRxCaptionList(Collection).Parent
  283.   else
  284.     Result := nil;
  285. end;
  286. procedure TRxCaption.SetCaption(const Value: string);
  287. begin
  288.   FCaption := Value;
  289.   Changed(False);
  290. end;
  291. procedure TRxCaption.FontChanged(Sender: TObject);
  292. begin
  293.   FParentFont := False;
  294.   Changed(False);
  295. end;
  296. procedure TRxCaption.SetFont(Value: TFont);
  297. begin
  298.   FFont.Assign(Value);
  299. end;
  300. procedure TRxCaption.SetParentFont(Value: Boolean);
  301. begin
  302.   if Value and (GradientCaption <> nil) then begin
  303.     FFont.OnChange := nil;
  304.     try
  305.       FFont.Assign(GradientCaption.Font);
  306.     finally
  307.       FFont.OnChange := FontChanged;
  308.     end;
  309.   end;
  310.   FParentFont := Value;
  311.   Changed(False);
  312. end;
  313. function TRxCaption.IsFontStored: Boolean;
  314. begin
  315.   Result := not FParentFont;
  316. end;
  317. function TRxCaption.GetTextWidth: Integer;
  318. var
  319.   Canvas: TCanvas;
  320.   PS: TPaintStruct;
  321. begin
  322.   BeginPaint(Application.Handle, PS);
  323.   try
  324.     Canvas := TCanvas.Create;
  325.     try
  326.       Canvas.Handle := PS.hDC;
  327.       Canvas.Font := FFont;
  328.       Result := Canvas.TextWidth(FCaption);
  329.     finally
  330.       Canvas.Free;
  331.     end;
  332.   finally
  333.     EndPaint(Application.Handle, PS);
  334.   end;
  335. end;
  336. procedure TRxCaption.SetVisible(Value: Boolean);
  337. begin
  338.   if FVisible <> Value then begin
  339.     FVisible := Value;
  340.     Changed(False);
  341.   end;
  342. end;
  343. procedure TRxCaption.SetInactiveColor(Value: TColor);
  344. begin
  345.   if FInactiveColor <> Value then begin
  346.     FInactiveColor := Value;
  347.     if (GradientCaption = nil) or not GradientCaption.FWindowActive then
  348.       Changed(False);
  349.   end;
  350. end;
  351. procedure TRxCaption.SetGlueNext(Value: Boolean);
  352. begin
  353.   if FGlueNext <> Value then begin
  354.     FGlueNext := Value;
  355.     Changed(False);
  356.   end;
  357. end;
  358. {$IFNDEF RX_D4}
  359. const
  360.   COLOR_GRADIENTACTIVECAPTION   =    27;
  361.   COLOR_GRADIENTINACTIVECAPTION =    28;
  362.   SPI_GETGRADIENTCAPTIONS       = $1008;
  363. {$ENDIF}
  364. const
  365.   clGradientActiveCaption = TColor(COLOR_GRADIENTACTIVECAPTION or $80000000);
  366.   clGradientInactiveCaption = TColor(COLOR_GRADIENTINACTIVECAPTION or $80000000);
  367. function SysGradient: Boolean;
  368. var
  369.   Info: BOOL;
  370. begin
  371.   if SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, SizeOf(Info), @Info, 0) then
  372.     Result := Info
  373.   else Result := False;
  374. end;
  375. { TRxGradientCaption }
  376. constructor TRxGradientCaption.Create(AOwner: TComponent);
  377. begin
  378.   inherited Create(AOwner);
  379.   FGradientSteps := 64;
  380.   FGradientActive := True;
  381.   FActive := True;
  382.   FCaptions := TRxCaptionList.Create(Self);
  383.   FWinHook := TRxWindowHook.Create(Self);
  384.   FWinHook.BeforeMessage := BeforeMessage;
  385.   FWinHook.AfterMessage := AfterMessage;
  386.   FStartColor := clWindowText;
  387.   FFontInactiveColor := clInactiveCaptionText;
  388.   FFormCaption := '';
  389.   FFont := TFont.Create;
  390.   SetFontDefault;
  391. end;
  392. destructor TRxGradientCaption.Destroy;
  393. begin
  394.   FOnDeactivate := nil;
  395.   FOnActivate := nil;
  396.   if not (csDesigning in ComponentState) then
  397.     ReleaseHook;
  398.   FCaptions.Free;
  399.   FCaptions := nil;
  400.   FFont.Free;
  401.   FFont := nil;
  402.   inherited Destroy;
  403. end;
  404. procedure TRxGradientCaption.Loaded;
  405. var
  406.   Loading: Boolean;
  407. begin
  408.   Loading := csLoading in ComponentState;
  409.   inherited Loaded;
  410.   if not (csDesigning in ComponentState) then begin
  411.     if Loading and (Owner is TCustomForm) then Update;
  412.   end;
  413. end;
  414. procedure TRxGradientCaption.Notification(AComponent: TComponent;
  415.   Operation: TOperation);
  416. begin
  417.   inherited Notification(AComponent, Operation);
  418.   if (AComponent = PopupMenu) and (Operation = opRemove) then
  419.     PopupMenu := nil;
  420. end;
  421. procedure TRxGradientCaption.SetPopupMenu(Value: TPopupMenu);
  422. begin
  423.   FPopupMenu := Value;
  424.   if Value <> nil then Value.FreeNotification(Self);
  425. end;
  426. procedure TRxGradientCaption.SetCaptions(Value: TRxCaptionList);
  427. begin
  428.   Captions.Assign(Value);
  429. end;
  430. procedure TRxGradientCaption.SetDefaultFont(Value: Boolean);
  431. begin
  432.   if FDefaultFont <> Value then begin
  433.     if Value then SetFontDefault;
  434.     FDefaultFont := Value;
  435.     if Active then Update;
  436.   end;
  437. end;
  438. procedure TRxGradientCaption.SetFontDefault;
  439. var
  440.   NCMetrics: TNonClientMetrics;
  441. begin
  442.   with FFont do begin
  443.     OnChange := nil;
  444.     try
  445.       NCMetrics.cbSize := SizeOf(NCMetrics);
  446.       if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NCMetrics, 0) then
  447.       begin
  448.         if (Owner is TForm) and
  449.           ((Owner as TForm).BorderStyle in [bsToolWindow, bsSizeToolWin]) then
  450.           Handle := CreateFontIndirect(NCMetrics.lfSmCaptionFont)
  451.         else
  452.           Handle := CreateFontIndirect(NCMetrics.lfCaptionFont);
  453.       end
  454.       else begin
  455.         Name := 'MS Sans Serif';
  456.         Size := 8;
  457.         Style := [fsBold];
  458.       end;
  459.       Color := clCaptionText;
  460. {$IFNDEF VER90}
  461.       Charset := DEFAULT_CHARSET;
  462. {$ENDIF}
  463.     finally
  464.       OnChange := FontChanged;
  465.     end;
  466.   end;
  467.   FDefaultFont := True;
  468. end;
  469. function TRxGradientCaption.IsFontStored: Boolean;
  470. begin
  471.   Result := not DefaultFont;
  472. end;
  473. function TRxGradientCaption.GetForm: TForm;
  474. begin
  475.   if Owner is TCustomForm then
  476.     Result := TForm(Owner as TCustomForm)
  477.   else
  478.     Result := nil;
  479. end;
  480. function TRxGradientCaption.GetFormCaption: string;
  481. begin
  482.   if (Form <> nil) and (csDesigning in ComponentState) then
  483.     FFormCaption := Form.Caption;
  484.   Result := FFormCaption;
  485. end;
  486. procedure TRxGradientCaption.SetFormCaption(const Value: string);
  487. begin
  488.   if FFormCaption <> Value then begin
  489.     FFormCaption := Value;
  490.     if (Form <> nil) and (csDesigning in ComponentState) then
  491.       Form.Caption := FFormCaption;
  492.     if Active then Update;
  493.   end;
  494. end;
  495. procedure TRxGradientCaption.SetHook;
  496. begin
  497.   if not (csDesigning in ComponentState) and (Owner <> nil) and
  498.     (Owner is TCustomForm) then
  499.     FWinHook.WinControl := Form;
  500. end;
  501. procedure TRxGradientCaption.ReleaseHook;
  502. begin
  503.   FWinHook.WinControl := nil;
  504. end;
  505. procedure TRxGradientCaption.CheckToggleHook;
  506. begin
  507.   if Active then SetHook
  508.   else ReleaseHook;
  509. end;
  510. function TRxGradientCaption.CheckMenuPopup(X, Y: Integer): Boolean;
  511. begin
  512.   Result := False;
  513.   if not (csDesigning in ComponentState) and Assigned(FPopupMenu) and
  514.     FPopupMenu.AutoPopup then
  515.   begin
  516.     FPopupMenu.PopupComponent := Self;
  517.     if Form <> nil then begin
  518.       Form.SendCancelMode(nil);
  519.       FPopupMenu.Popup(X, Y);
  520.       Result := True;
  521.     end;
  522.   end;
  523. end;
  524. procedure TRxGradientCaption.BeforeMessage(Sender: TObject; var Msg: TMessage;
  525.   var Handled: Boolean);
  526. var
  527.   DrawRgn: HRgn;
  528.   R: TRect;
  529.   Icons: TBorderIcons;
  530. begin
  531.   if Active then begin
  532.     case Msg.Msg of
  533.       WM_NCACTIVATE:
  534.         begin
  535.           FWindowActive := (Msg.wParam <> 0);
  536.         end;
  537.       WM_NCRBUTTONDOWN:
  538.         if Assigned(FPopupMenu) and FPopupMenu.AutoPopup then begin
  539.           FClicked := True;
  540.           Msg.Result := 0;
  541.           Handled := True;
  542.         end;
  543.       WM_NCRBUTTONUP:
  544.         with TWMMouse(Msg) do
  545.           if FClicked then begin
  546.             FClicked := False;
  547.             if CheckMenuPopup(XPos, YPos) then begin
  548.               Result := 0;
  549.               Handled := True;
  550.             end;
  551.           end;
  552.       WM_NCPAINT:
  553.         begin
  554.           FSaveRgn := Msg.wParam;
  555.           FRgnChanged := False;
  556.           CalculateGradientParams(R, Icons);
  557.           if RectInRegion(FSaveRgn, R) then begin
  558.             DrawRgn := CreateRectRgn(R.Left, R.Top, R.Right, R.Bottom);
  559.             try
  560.               Msg.WParam := CreateRectRgn(0, 0, 1, 1);
  561.               FRgnChanged := True;
  562.               CombineRgn(Msg.WParam, FSaveRgn, DrawRgn, RGN_DIFF);
  563.             finally
  564.               DeleteObject(DrawRgn);
  565.             end;
  566.           end;
  567.         end;
  568.     end;
  569.   end;
  570. end;
  571. procedure TRxGradientCaption.AfterMessage(Sender: TObject; var Msg: TMessage;
  572.   var Handled: Boolean);
  573. var
  574.   DC: HDC;
  575.   S: string;
  576. begin
  577.   if Active then begin
  578.     case Msg.Msg of
  579.       WM_NCACTIVATE:
  580.         begin
  581.           DC := GetWindowDC(Form.Handle);
  582.           try
  583.             DrawGradientCaption(DC);
  584.           finally
  585.             ReleaseDC(Form.Handle, DC);
  586.           end;
  587.         end;
  588.       WM_NCPAINT:
  589.         begin
  590.           if FRgnChanged then begin
  591.             DeleteObject(Msg.WParam);
  592.             Msg.WParam := FSaveRgn;
  593.             FRgnChanged := False;
  594.           end;
  595.           DC := GetWindowDC(Form.Handle);
  596.           try
  597.             DrawGradientCaption(DC);
  598.           finally
  599.             ReleaseDC(Form.Handle, DC);
  600.           end;
  601.         end;
  602.       WM_GETTEXT:
  603.         { Delphi doesn't send WM_SETTEXT to form's window procedure,
  604.           so we need to handle WM_GETTEXT to redraw non-client area
  605.           when form's caption changed }
  606.         begin
  607.           if csDesigning in ComponentState then begin
  608.             SetString(S, PChar(Msg.LParam), Msg.Result);
  609.             if AnsiCompareStr(S, FFormCaption) <> 0 then begin
  610.               FormCaption := S;
  611.               PostMessage(Form.Handle, WM_NCPAINT, 0, 0);
  612.             end;
  613.           end;
  614.         end;
  615.     end;
  616.   end;
  617. end;
  618. procedure TRxGradientCaption.SetStartColor(Value: TColor);
  619. begin
  620.   if FStartColor <> Value then begin
  621.     FStartColor := Value;
  622.     if Active then Update;
  623.   end;
  624. end;
  625. function TRxGradientCaption.GetActive: Boolean;
  626. begin
  627.   Result := FActive;
  628.   if not (csDesigning in ComponentState) then
  629.     Result := Result and NewStyleControls and (Owner is TCustomForm);
  630. end;
  631. procedure TRxGradientCaption.SetActive(Value: Boolean);
  632. begin
  633.   if FActive <> Value then begin
  634.     FActive := Value;
  635.     FClicked := False;
  636.     Update;
  637.     if ([csDestroying, csReading] * ComponentState = []) then begin
  638.       if FActive then begin
  639.         if Assigned(FOnActivate) then FOnActivate(Self);
  640.       end
  641.       else begin
  642.         if Assigned(FOnDeactivate) then FOnDeactivate(Self);
  643.       end;
  644.     end;
  645.   end;
  646. end;
  647. procedure TRxGradientCaption.Clear;
  648. begin
  649.   if FCaptions <> nil then FCaptions.Clear;
  650. end;
  651. procedure TRxGradientCaption.MoveCaption(FromIndex, ToIndex: Integer);
  652. begin
  653.   Captions[FromIndex].Index := ToIndex;
  654. end;
  655. procedure TRxGradientCaption.Update;
  656. var
  657.   Rgn: HRgn;
  658. begin
  659.   if not (csDesigning in ComponentState) and (Owner is TCustomForm) and
  660.     not (csLoading in ComponentState) then
  661.   begin
  662.     CheckToggleHook;
  663.     FWindowActive := False;
  664.     if (Form <> nil) and Form.HandleAllocated and Form.Visible then begin
  665.       if Active then begin
  666.         FWindowActive := (GetActiveWindow = Form.Handle) and
  667.           IsForegroundTask;
  668.       end;
  669.       with Form do
  670.         Rgn := CreateRectRgn(Left, Top, Left + Width, Top + Height);
  671.       try
  672.         SendMessage(Form.Handle, WM_NCPAINT, Rgn, 0);
  673.       finally
  674.         DeleteObject(Rgn);
  675.       end;
  676.     end;
  677.   end;
  678. end;
  679. procedure TRxGradientCaption.CalculateGradientParams(var R: TRect;
  680.   var Icons: TBorderIcons);
  681. var
  682.   I: TBorderIcon;
  683.   BtnCount: Integer;
  684. begin
  685.   GetWindowRect(Form.Handle, R);
  686.   Icons := Form.BorderIcons;
  687.   case Form.BorderStyle of
  688.     bsDialog: Icons := Icons * [biSystemMenu, biHelp];
  689.     bsToolWindow, bsSizeToolWin: Icons := Icons * [biSystemMenu];
  690.     else begin
  691.       if not (biSystemMenu in Icons) then
  692.         Icons := Icons - [biMaximize, biMinimize];
  693.       if (Icons * [biMaximize, biMinimize] <> []) then
  694.         Icons := Icons - [biHelp];
  695.     end;
  696.   end;
  697.   BtnCount := 0;
  698.   for I := Low(TBorderIcon) to High(TBorderIcon) do
  699.     if I in Icons then Inc(BtnCount);
  700.   if (biMinimize in Icons) and not (biMaximize in Icons) then
  701.     Inc(BtnCount)
  702.   else if not (biMinimize in Icons) and (biMaximize in Icons) then
  703.     Inc(BtnCount);
  704.   case Form.BorderStyle of
  705.     bsToolWindow, bsSingle, bsDialog:
  706.       InflateRect(R, -GetSystemMetrics(SM_CXFIXEDFRAME),
  707.         -GetSystemMetrics(SM_CYFIXEDFRAME));
  708.     bsSizeable, bsSizeToolWin:
  709.       InflateRect(R, -GetSystemMetrics(SM_CXSIZEFRAME),
  710.         -GetSystemMetrics(SM_CYSIZEFRAME));
  711.   end;
  712.   if Form.BorderStyle in [bsToolWindow, bsSizeToolWin] then begin
  713.     R.Bottom := R.Top + GetSystemMetrics(SM_CYSMCAPTION) - 1;
  714.     Dec(R.Right, BtnCount * GetSystemMetrics(SM_CXSMSIZE));
  715.   end
  716.   else begin
  717.     R.Bottom := R.Top + GetSystemMetrics(SM_CYCAPTION) - 1;
  718.     Dec(R.Right, BtnCount * GetSystemMetrics(SM_CXSIZE));
  719.   end;
  720. end;
  721. {$IFDEF RX_D4}
  722. function TRxGradientCaption.IsRightToLeft: Boolean;
  723. var
  724.   F: TForm;
  725. begin
  726.   F := Form;
  727.   if F <> nil then Result := F.IsRightToLeft
  728.   else Result := Application.IsRightToLeft;
  729. end;
  730. {$ENDIF}
  731. procedure TRxGradientCaption.DrawGradientCaption(DC: HDC);
  732. var
  733.   R, DrawRect: TRect;
  734.   Icons: TBorderIcons;
  735.   C: TColor;
  736.   Ico: HIcon;
  737.   Image: TBitmap;
  738.   S: string;
  739.   IconCreated, DrawNext: Boolean;
  740.   I, J, SumWidth: Integer;
  741.   procedure SetCaptionFont(Index: Integer);
  742.   begin
  743.     if (Index < 0) or Captions[Index].ParentFont then
  744.       Image.Canvas.Font.Assign(Self.Font)
  745.     else Image.Canvas.Font.Assign(Captions[Index].Font);
  746.     if not FWindowActive then begin
  747.       if Index < 0 then
  748.         Image.Canvas.Font.Color := FFontInactiveColor
  749.       else
  750.         Image.Canvas.Font.Color := Captions[Index].InactiveColor;
  751.     end;
  752.   end;
  753.   function DrawStr(GluePrev, GlueNext: Boolean; PrevIndex: Integer): Boolean;
  754.   const
  755.     Points = '...';
  756.   var
  757.     Text: string;
  758.     Flags: Longint;
  759.   begin
  760.     if Length(S) > 0 then begin
  761.       Text := MinimizeText(S, Image.Canvas, R.Right - R.Left);
  762.       if GlueNext and (Text = S) then begin
  763.         if (Image.Canvas.TextWidth(Text + '.') >= R.Right - R.Left) then begin
  764.           if GluePrev then Text := Points
  765.           else Text := Text + Points;
  766.         end;
  767.       end;
  768.       if (Text <> Points) or GluePrev then begin
  769.         if (Text = Points) and GluePrev then begin
  770.           SetCaptionFont(-1);
  771.           if PrevIndex > 0 then begin
  772.             if FWindowActive then
  773.               Image.Canvas.Font.Color := Captions[PrevIndex].Font.Color
  774.             else
  775.               Image.Canvas.Font.Color := Captions[PrevIndex].InactiveColor;
  776.           end;
  777.         end;
  778.         Flags := DT_VCENTER or DT_SINGLELINE or DT_NOPREFIX;
  779. {$IFDEF RX_D4}
  780.         if IsRightToLeft then
  781.           Flags := Flags or DT_RIGHT or DT_RTLREADING else
  782. {$ENDIF}
  783.         Flags := Flags or DT_LEFT;
  784.         DrawText(Image.Canvas.Handle, PChar(Text), -1, R, Flags);
  785. {$IFDEF RX_D4}
  786.         if IsRightToLeft then
  787.           Dec(R.Right, Image.Canvas.TextWidth(Text)) else
  788. {$ENDIF}
  789.         Inc(R.Left, Image.Canvas.TextWidth(Text));
  790.       end;
  791.       Result := (Text = S);
  792.     end
  793.     else Result := True;
  794.   end;
  795. begin
  796.   if Form.BorderStyle = bsNone then Exit;
  797.   Image := TBitmap.Create;
  798.   try
  799.     CalculateGradientParams(R, Icons);
  800.     GetWindowRect(Form.Handle, DrawRect);
  801.     OffsetRect(R, -DrawRect.Left, -DrawRect.Top);
  802.     DrawRect := R;
  803.     Image.Width := WidthOf(R);
  804.     Image.Height := HeightOf(R);
  805.     R := Rect(-Image.Width div 4, 0, Image.Width, Image.Height);
  806.     if SysGradient then begin
  807.       if FWindowActive then C := clGradientActiveCaption
  808.       else C := clGradientInactiveCaption;
  809.     end
  810.     else begin
  811.       if FWindowActive then C := clActiveCaption
  812.       else C := clInactiveCaption;
  813.     end;
  814.     if (FWindowActive and GradientActive) or
  815.       (not FWindowActive and GradientInactive) then
  816.     begin
  817.       GradientFillRect(Image.Canvas, R, FStartColor, C, fdLeftToRight,
  818.         FGradientSteps);
  819.     end
  820.     else begin
  821.       Image.Canvas.Brush.Color := C;
  822.       Image.Canvas. FillRect(R);
  823.     end;
  824.     R.Left := 0;
  825.     if (biSystemMenu in Icons) and (Form.BorderStyle in [bsSizeable,
  826.       bsSingle]) then
  827.     begin
  828.       IconCreated := False;
  829.       if Form.Icon.Handle <> 0 then
  830.         Ico := Form.Icon.Handle
  831.       else if Application.Icon.Handle <> 0 then begin
  832.         Ico := LoadImage(HInstance, 'MAINICON', IMAGE_ICON,
  833.           GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
  834.         IconCreated := Ico <> 0;
  835.         if not IconCreated then Ico := Application.Icon.Handle;
  836.       end
  837.       else Ico := LoadIcon(0, IDI_APPLICATION);
  838.       DrawIconEx(Image.Canvas.Handle, R.Left + 1 + (R.Bottom + R.Top -
  839.         GetSystemMetrics(SM_CXSMICON)) div 2, (R.Bottom + R.Top -
  840.         GetSystemMetrics(SM_CYSMICON)) div 2, Ico,
  841.         GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  842.         0, 0, DI_NORMAL);
  843.       if IconCreated then DestroyIcon(Ico);
  844.       Inc(R.Left, R.Bottom - R.Top);
  845.     end;
  846.     if (FFormCaption <> '') or ((Captions <> nil) and (Captions.Count > 0)) then
  847.     begin
  848.       SumWidth := 2;
  849.       SetBkMode(Image.Canvas.Handle, TRANSPARENT);
  850.       Inc(R.Left, 2);
  851.       if FHideDirection = hdLeftToRight then begin
  852.         for I := 0 to Captions.Count - 1 do
  853.           if Captions[I].Visible then
  854.             SumWidth := SumWidth + Captions[I].TextWidth;
  855.         SumWidth := SumWidth + TextWidth;
  856.         J := 0;
  857.         while (SumWidth > (R.Right - R.Left)) and (J < Captions.Count) do
  858.         begin
  859.           SumWidth := SumWidth - Captions[J].TextWidth;
  860.           while (J < Captions.Count - 1) and Captions[J].GlueNext do begin
  861.             SumWidth := SumWidth - Captions[J + 1].TextWidth;
  862.             Inc(J);
  863.           end;
  864.           Inc(J);
  865.         end;
  866.         for I := J to Captions.Count do begin
  867.           if I < Captions.Count then begin
  868.             if Captions[I].Visible then begin
  869.               S := Captions[I].Caption;
  870.               SetCaptionFont(I);
  871.             end
  872.             else S := '';
  873.           end
  874.           else begin
  875.             S := FFormCaption;
  876.             SetCaptionFont(-1);
  877.           end;
  878.           DrawStr(I = Captions.Count, False, -1);
  879.         end;
  880.       end
  881.       else begin
  882.         DrawNext := True;
  883.         J := 0;
  884.         if Captions <> nil then begin
  885.           while (SumWidth < (R.Right - R.Left)) and (J < Captions.Count) do
  886.           begin
  887.             if Captions[J].Visible then begin
  888.               SumWidth := SumWidth + Captions[J].TextWidth;
  889.               while Captions[J].GlueNext and (J < Captions.Count - 1) do
  890.               begin
  891.                 SumWidth := SumWidth + Captions[J + 1].TextWidth;
  892.                 Inc(J);
  893.               end;
  894.             end;
  895.             Inc(J);
  896.           end;
  897.           for I := 0 to J - 1 do begin
  898.             if Captions[I].Visible and DrawNext then begin
  899.               S := Captions[I].Caption;
  900.               if S <> '' then begin
  901.                 SetCaptionFont(I);
  902.                 DrawNext := DrawStr(((I > 0) and Captions[I - 1].GlueNext) or
  903.                   (I = 0), Captions[I].GlueNext, I - 1) and
  904.                   (Captions[I].GlueNext or (R.Right > R.Left));
  905.               end;
  906.             end;
  907.           end;
  908.         end;
  909.         if (R.Right > R.Left) and DrawNext and (FFormCaption <> '') then
  910.         begin
  911.           S := FFormCaption;
  912.           SetCaptionFont(-1);
  913.           DrawStr(False, False, -1);
  914.         end;
  915.       end;
  916.     end;
  917.     BitBlt(DC, DrawRect.Left, DrawRect.Top, Image.Width, Image.Height,
  918.       Image.Canvas.Handle, 0, 0, SRCCOPY);
  919.   finally
  920.     Image.Free;
  921.   end;
  922. end;
  923. procedure TRxGradientCaption.SetFont(Value: TFont);
  924. begin
  925.   FFont.Assign(Value);
  926. end;
  927. procedure TRxGradientCaption.FontChanged(Sender: TObject);
  928. var
  929.   I: Integer;
  930. begin
  931.   FDefaultFont := False;
  932.   if (Captions <> nil) then begin
  933.     Captions.BeginUpdate;
  934.     try
  935.       for I := 0 to Captions.Count - 1 do
  936.         if Captions[I].ParentFont then Captions[I].SetParentFont(True);
  937.     finally
  938.       Captions.EndUpdate;
  939.     end;
  940.   end
  941.   else if Active then Update;
  942. end;
  943. function TRxGradientCaption.GetTextWidth: Integer;
  944. var
  945.   Canvas: TCanvas;
  946.   PS: TPaintStruct;
  947. begin
  948.   BeginPaint(Application.Handle, PS);
  949.   try
  950.     Canvas := TCanvas.Create;
  951.     try
  952.       Canvas.Handle := PS.hDC;
  953.       Canvas.Font := FFont;
  954.       Result := Canvas.TextWidth(FFormCaption);
  955.     finally
  956.       Canvas.Free;
  957.     end;
  958.   finally
  959.     EndPaint(Application.Handle, PS);
  960.   end;
  961. end;
  962. procedure TRxGradientCaption.SetGradientSteps(Value: Integer);
  963. begin
  964.   if FGradientSteps <> Value then begin
  965.     FGradientSteps := Value;
  966.     if Active and ((FWindowActive and GradientActive) or
  967.       (not FWindowActive and GradientInactive)) then Update;
  968.   end;
  969. end;
  970. procedure TRxGradientCaption.SetGradientActive(Value: Boolean);
  971. begin
  972.   if FGradientActive <> Value then begin
  973.     FGradientActive := Value;
  974.     if Active and FWindowActive then Update;
  975.   end;
  976. end;
  977. procedure TRxGradientCaption.SetGradientInactive(Value: Boolean);
  978. begin
  979.   if FGradientInactive <> Value then begin
  980.     FGradientInactive := Value;
  981.     if Active and not FWindowActive then Update;
  982.   end;
  983. end;
  984. procedure TRxGradientCaption.SetFontInactiveColor(Value: TColor);
  985. begin
  986.   if FFontInactiveColor <> Value then begin
  987.     FFontInactiveColor := Value;
  988.     if Active and not FWindowActive then Update;
  989.   end;
  990. end;
  991. procedure TRxGradientCaption.SetHideDirection(Value: THideDirection);
  992. begin
  993.   if FHideDirection <> Value then begin
  994.     FHideDirection := Value;
  995.     if Active then Update;
  996.   end;
  997. end;
  998. {$ENDIF WIN32}
  999. end.