home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kompon / d23456 / TB97.ZIP / Source / TB97Tlbr.pas < prev    next >
Pascal/Delphi Source File  |  2001-02-26  |  35KB  |  1,115 lines

  1. unit TB97Tlbr;
  2.  
  3. {
  4.   Toolbar97
  5.   Copyright (C) 1998-2001 by Jordan Russell
  6.   For conditions of distribution and use, see LICENSE.TXT.
  7.  
  8.   TCustomToolbar97, TToolbar97, TToolbarSep97
  9.  
  10.   $Id: TB97Tlbr.pas,v 1.3 2001/02/26 17:52:42 jr Exp $
  11. }
  12.  
  13. interface
  14.  
  15. {$I TB97Ver.inc}
  16.  
  17. uses
  18.   Windows, Messages, Classes, Controls, Graphics,
  19.   TB97;
  20.  
  21. type
  22.   { TCustomToolbar97 }
  23.  
  24.   TToolbarParams = record
  25.     InitializeOrderByPosition, DesignOrderByPosition: Boolean;
  26.   end;
  27.  
  28.   TCustomToolbar97 = class(TCustomToolWindow97)
  29.   private
  30.     FToolbarParams: TToolbarParams;
  31.     FFloatingRightX: Integer;
  32.     FOrderListDirty: Boolean;
  33.     SizeData: Pointer;
  34.  
  35.     { Lists }
  36.     SlaveInfo,         { List of slave controls. Items are pointers to TSlaveInfo's }
  37.     GroupInfo,         { List of the control "groups". List items are pointers to TGroupInfo's }
  38.     LineSeps,          { List of the Y locations of line separators. Items are casted in TLineSep's }
  39.     OrderList: TList;  { List of the child controls, arranged using the current "OrderIndex" values }
  40.  
  41.     { Property access methods }
  42.     function GetOrderedControls (Index: Integer): TControl;
  43.     function GetOrderIndex (Control: TControl): Integer;
  44.     procedure SetFloatingWidth (Value: Integer);
  45.     procedure SetOrderIndex (Control: TControl; Value: Integer);
  46.  
  47.     { Internal }
  48.     procedure CleanOrderList;
  49.     procedure SetControlVisible (const Control: TControl;
  50.       const LeftOrRight: Boolean);
  51.     function ShouldControlBeVisible (const Control: TControl;
  52.       const LeftOrRight: Boolean): Boolean;
  53.     procedure FreeGroupInfo (const List: TList);
  54.     procedure BuildGroupInfo (const List: TList; const TranslateSlave: Boolean;
  55.       const OldDockType, NewDockType: TDockType);
  56.  
  57.     { Messages }
  58.     procedure CMControlListChange (var Message: TCMControlListChange); message CM_CONTROLLISTCHANGE;
  59.     procedure WMWindowPosChanging (var Message: TWMWindowPosChanging); message WM_WINDOWPOSCHANGING;
  60.   protected
  61.     property ToolbarParams: TToolbarParams read FToolbarParams;
  62.  
  63.     procedure Paint; override;
  64.  
  65.     procedure BuildPotentialSizesList (SizesList: TList); dynamic;
  66.     function ChildControlTransparent (Ctl: TControl): Boolean; override;
  67.     procedure GetParams (var Params: TToolWindowParams); override;
  68.     procedure GetToolbarParams (var Params: TToolbarParams); dynamic;
  69.     procedure ResizeBegin (ASizeHandle: TToolWindowSizeHandle); override;
  70.     procedure ResizeTrack (var Rect: TRect; const OrigRect: TRect); override;
  71.     procedure ResizeEnd (Accept: Boolean); override;
  72.  
  73.     procedure GetBarSize (var ASize: Integer; const DockType: TDockType); override;
  74.     procedure GetMinimumSize (var AClientWidth, AClientHeight: Integer); override;
  75.     procedure InitializeOrdering; override;
  76.     function OrderControls (CanMoveControls: Boolean; PreviousDockType: TDockType;
  77.       DockingTo: TDock97): TPoint; override;
  78.   public
  79.     property OrderedControls[Index: Integer]: TControl read GetOrderedControls;
  80.     property OrderIndex[Control: TControl]: Integer read GetOrderIndex write SetOrderIndex;
  81.     property FloatingWidth: Integer read FFloatingRightX write SetFloatingWidth;
  82.  
  83.     constructor Create (AOwner: TComponent); override;
  84.     destructor Destroy; override;
  85.     procedure ReadPositionData (const ReadIntProc: TPositionReadIntProc;
  86.       const ReadStringProc: TPositionReadStringProc; const ExtraData: Pointer); override;
  87.     procedure WritePositionData (const WriteIntProc: TPositionWriteIntProc;
  88.       const WriteStringProc: TPositionWriteStringProc; const ExtraData: Pointer); override;
  89.  
  90.     procedure SetSlaveControl (const ATopBottom, ALeftRight: TControl);
  91.   end;
  92.  
  93.   { TToolbar97 }
  94.  
  95.   TToolbar97 = class(TCustomToolbar97)
  96.   published
  97.     property ActivateParent;
  98.     property BorderStyle;
  99.     property Caption;
  100.     property Color;
  101.     property CloseButton;
  102.     property CloseButtonWhenDocked;
  103.     property DefaultDock;
  104.     property DockableTo;
  105.     property DockedTo;
  106.     property DockMode;
  107.     property DockPos;
  108.     property DockRow;
  109.     property DragHandleStyle;
  110.     property FloatingMode;
  111.     property Font;
  112.     property FullSize;
  113.     property HideWhenInactive;
  114.     property LastDock;
  115.     property ParentFont;
  116.     property ParentShowHint;
  117.     property PopupMenu;
  118.     property ShowCaption;
  119.     property ShowHint;
  120.     property TabOrder;
  121.     property UseLastDock;
  122.     property Version;
  123.     property Visible;
  124.  
  125.     property OnClose;
  126.     property OnCloseQuery;
  127.     property OnDragDrop;
  128.     property OnDragOver;
  129.     property OnMouseDown;
  130.     property OnMouseMove;
  131.     property OnMouseUp;
  132.     property OnMove;
  133.     property OnRecreated;
  134.     property OnRecreating;
  135.     property OnDockChanged;
  136.     property OnDockChanging;
  137.     property OnDockChangingEx;
  138.     property OnDockChangingHidden;
  139.     property OnResize;
  140.     property OnVisibleChanged;
  141.   end;
  142.  
  143.   { TToolbarSep97 }
  144.  
  145.   TToolbarSepSize = 1..MaxInt;
  146.  
  147.   TToolbarSep97 = class(TGraphicControl)
  148.   private
  149.     FBlank: Boolean;
  150.     FSizeHorz, FSizeVert: TToolbarSepSize;
  151.     procedure SetBlank (Value: Boolean);
  152.     procedure SetSizeHorz (Value: TToolbarSepSize);
  153.     procedure SetSizeVert (Value: TToolbarSepSize);
  154.   protected
  155.     procedure MouseDown (Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  156.     procedure Paint; override;
  157.     procedure SetParent (AParent: TWinControl); override;
  158.   public
  159.     constructor Create (AOwner: TComponent); override;
  160.   published
  161.     { These two properties don't need to be stored since it automatically gets
  162.       resized based on the setting of SizeHorz and SizeVert }
  163.     property Width stored False;
  164.     property Height stored False;
  165.     property Blank: Boolean read FBlank write SetBlank default False;
  166.     property SizeHorz: TToolbarSepSize read FSizeHorz write SetSizeHorz default 6;
  167.     property SizeVert: TToolbarSepSize read FSizeVert write SetSizeVert default 6;
  168.     property Visible;
  169.   end;
  170.  
  171.  
  172. {$IFOPT J+}
  173.   {$DEFINE _TB97_OPT_J}
  174.   {$J-}  { don't let the following typed constants be modified }
  175. {$ENDIF}
  176. const
  177.   tb97DefaultBarWidthHeight = 8;
  178.  
  179.   tb97TopMarginFloating = 2;
  180.   tb97TopMarginDocked = 0;
  181.   tb97TopMargin: array[Boolean] of Integer = (tb97TopMarginFloating, tb97TopMarginDocked);
  182.   tb97BottomMarginFloating = 1;
  183.   tb97BottomMarginDocked = 0;
  184.   tb97BottomMargin: array[Boolean] of Integer = (tb97BottomMarginFloating, tb97BottomMarginDocked);
  185.   tb97LeftMarginFloating = 4;
  186.   tb97LeftMarginDocked = 0;
  187.   tb97LeftMargin: array[Boolean] of Integer = (tb97LeftMarginFloating, tb97LeftMarginDocked);
  188.   tb97RightMarginFloating = 4;
  189.   tb97RightMarginDocked = 0;
  190.   tb97RightMargin: array[Boolean] of Integer = (tb97RightMarginFloating, tb97RightMarginDocked);
  191.   tb97LineSpacing = 6;
  192. {$IFDEF _TB97_OPT_J}
  193.   {$J+}
  194.   {$UNDEF _TB97_OPT_J}
  195. {$ENDIF}
  196.  
  197. implementation
  198.  
  199. uses
  200.   SysUtils, TB97Cmn, TB97Cnst;
  201.  
  202. const
  203.   { Constants for registry values. Do not localize! }
  204.   { TCustomToolbar97 specific }
  205.   rvFloatRightX = 'FloatRightX';
  206.  
  207. type
  208.   { Used internally by the TCustomToolbar97.Resize* procedures }
  209.   PToolbar97SizeData = ^TToolbar97SizeData;
  210.   TToolbar97SizeData = record
  211.     SizeHandle: TToolWindowSizeHandle;
  212.     NewSizes: TList;  { List of valid new sizes. Items are casted into TSmallPoints }
  213.     CurRightX: Integer;
  214.     DisableSensCheck, OpSide: Boolean;
  215.     SizeSens: Integer;
  216.   end;
  217.  
  218.   { Used in TCustomToolbar97.GroupInfo lists }
  219.   PGroupInfo = ^TGroupInfo;
  220.   TGroupInfo = record
  221.     GroupWidth,           { Width in pixels of the group, if all controls were
  222.                             lined up left-to-right }
  223.     GroupHeight: Integer; { Heights in pixels of the group, if all controls were
  224.                             lined up top-to-bottom }
  225.     Members: TList;
  226.   end;
  227.  
  228.   { Used in TCustomToolbar97.SlaveInfo lists }
  229.   PSlaveInfo = ^TSlaveInfo;
  230.   TSlaveInfo = record
  231.     LeftRight,
  232.     TopBottom: TControl;
  233.   end;
  234.  
  235.   { Used in TCustomToolbar97.LineSeps lists }
  236.   TLineSep = packed record
  237.     Y: SmallInt;
  238.     Blank: Boolean;
  239.     Unused: Boolean;
  240.   end;
  241.  
  242.   { Use by CompareControls }
  243.   PCompareExtra = ^TCompareExtra;
  244.   TCompareExtra = record
  245.     Toolbar: TCustomToolbar97;
  246.     ComparePositions: Boolean;
  247.     CurDockType: TDockType;
  248.   end;
  249.  
  250.  
  251. { TCustomToolbar97 }
  252.  
  253. constructor TCustomToolbar97.Create (AOwner: TComponent);
  254. begin
  255.   inherited;
  256.   GetToolbarParams (FToolbarParams);
  257.   GroupInfo := TList.Create;
  258.   SlaveInfo := TList.Create;
  259.   LineSeps := TList.Create;
  260.   OrderList := TList.Create;
  261. end;
  262.  
  263. destructor TCustomToolbar97.Destroy;
  264. var
  265.   I: Integer;
  266. begin
  267.   OrderList.Free;
  268.   LineSeps.Free;
  269.   if Assigned(SlaveInfo) then begin
  270.     for I := SlaveInfo.Count-1 downto 0 do
  271.       FreeMem (SlaveInfo.Items[I]);
  272.     SlaveInfo.Free;
  273.   end;
  274.   FreeGroupInfo (GroupInfo);
  275.   GroupInfo.Free;
  276.   inherited;
  277. end;
  278.  
  279. procedure TCustomToolbar97.ReadPositionData (const ReadIntProc: TPositionReadIntProc;
  280.   const ReadStringProc: TPositionReadStringProc; const ExtraData: Pointer);
  281. begin
  282.   inherited;
  283.   FFloatingRightX := ReadIntProc(Name, rvFloatRightX, 0, ExtraData);
  284. end;
  285.  
  286. procedure TCustomToolbar97.WritePositionData (const WriteIntProc: TPositionWriteIntProc;
  287.   const WriteStringProc: TPositionWriteStringProc; const ExtraData: Pointer);
  288. begin
  289.   inherited;
  290.   WriteIntProc (Name, rvFloatRightX, FFloatingRightX, ExtraData);
  291. end;
  292.  
  293. procedure TCustomToolbar97.GetMinimumSize (var AClientWidth, AClientHeight: Integer);
  294. begin
  295.   AClientWidth := 0;
  296.   AClientHeight := 0;
  297. end;
  298.  
  299. procedure TCustomToolbar97.CleanOrderList;
  300. { TCustomToolbar97 uses a CM_CONTROLLISTCHANGE handler to detect when new
  301.   controls are added to the toolbar. The handler adds the new controls to
  302.   OrderList, which can be manipulated by the application using the OrderIndex
  303.   property.
  304.   The only problem is, the VCL relays CM_CONTROLLISTCHANGE messages
  305.   to all parents of a control, not just the immediate parent. In pre-1.76
  306.   versions of Toolbar97, OrderList contained not only the immediate children
  307.   of the toolbar, but their children too. So this caused the OrderIndex
  308.   property to return unexpected results.
  309.   What this method does is clear out all controls in OrderList that aren't
  310.   immediate children of the toolbar. (A check of Parent can't be put into the
  311.   CM_CONTROLLISTCHANGE handler because that message is sent before a new
  312.   Parent is assigned.) }
  313. var
  314.   I: Integer;
  315. begin
  316.   if not FOrderListDirty then
  317.     Exit;
  318.   I := 0;
  319.   while I < OrderList.Count do begin
  320.     if TControl(OrderList.List[I]).Parent <> Self then
  321.       OrderList.Delete (I)
  322.     else
  323.       Inc (I);
  324.   end;
  325.   FOrderListDirty := False;
  326. end;
  327.  
  328. function CompareControls (const Item1, Item2, ExtraData: Pointer): Integer; far;
  329. begin
  330.   with PCompareExtra(ExtraData)^ do
  331.     if ComparePositions then begin
  332.       if CurDockType <> dtLeftRight then
  333.         Result := TControl(Item1).Left - TControl(Item2).Left
  334.       else
  335.         Result := TControl(Item1).Top - TControl(Item2).Top;
  336.     end
  337.     else
  338.       with Toolbar.OrderList do
  339.         Result := IndexOf(Item1) - IndexOf(Item2);
  340. end;
  341.  
  342. procedure TCustomToolbar97.InitializeOrdering;
  343. var
  344.   Extra: TCompareExtra;
  345. begin
  346.   inherited;
  347.   { Initialize order of items in OrderList }
  348.   if ToolbarParams.InitializeOrderByPosition then begin
  349.     with Extra do begin
  350.       Toolbar := Self;
  351.       ComparePositions := True;
  352.       CurDockType := GetDockTypeOf(DockedTo);
  353.     end;
  354.     CleanOrderList;
  355.     ListSortEx (OrderList, CompareControls, @Extra);
  356.   end;
  357. end;
  358.  
  359. procedure TCustomToolbar97.GetBarSize (var ASize: Integer; const DockType: TDockType);
  360. var
  361.   I: Integer;
  362. begin
  363.   ASize := tb97DefaultBarWidthHeight;
  364.   for I := 0 to ControlCount-1 do
  365.     if not(Controls[I] is TToolbarSep97) then
  366.       with Controls[I] do begin
  367.         if ShouldControlBeVisible(Controls[I], DockType = dtLeftRight) then begin
  368.           if DockType = dtLeftRight then begin
  369.             if Width > ASize then ASize := Width;
  370.           end
  371.           else begin
  372.             if Height > ASize then ASize := Height;
  373.           end;
  374.         end;
  375.       end;
  376. end;
  377.  
  378. procedure TCustomToolbar97.GetParams (var Params: TToolWindowParams);
  379. begin
  380.   inherited;
  381.   with Params do begin
  382.     CallAlignControls := False;
  383.     ResizeEightCorner := False;
  384.     ResizeClipCursor := False;
  385.   end;
  386. end;
  387.  
  388. procedure TCustomToolbar97.GetToolbarParams (var Params: TToolbarParams);
  389. begin
  390.   with Params do begin
  391.     InitializeOrderByPosition := True;
  392.     DesignOrderByPosition := True;
  393.   end;
  394. end;
  395.  
  396. procedure TCustomToolbar97.Paint;
  397. var
  398.   S: Integer;
  399. begin
  400.   inherited;
  401.   { Long separators when not docked }
  402.   if not Docked then
  403.     for S := 0 to LineSeps.Count-1 do begin
  404.       with TLineSep(LineSeps[S]) do begin
  405.         if Blank then Continue;
  406.         Canvas.Pen.Color := clBtnShadow;
  407.         Canvas.MoveTo (1, Y-4);  Canvas.LineTo (ClientWidth-1, Y-4);
  408.         Canvas.Pen.Color := clBtnHighlight;
  409.         Canvas.MoveTo (1, Y-3);  Canvas.LineTo (ClientWidth-1, Y-3);
  410.       end;
  411.     end;
  412. end;
  413.  
  414. function ControlVisibleOrDesigning (AControl: TControl): Boolean;
  415. begin
  416.   Result := AControl.Visible or (csDesigning in AControl.ComponentState);
  417. end;
  418.  
  419. procedure TCustomToolbar97.SetControlVisible (const Control: TControl;
  420.   const LeftOrRight: Boolean);
  421. { If Control is a master or slave control, it automatically adjusts the
  422.   Visible properties of both the master and slave control based on the value
  423.   of LeftOrRight }
  424. var
  425.   I: Integer;
  426. begin
  427.   for I := 0 to SlaveInfo.Count-1 do
  428.     with PSlaveInfo(SlaveInfo[I])^ do
  429.       if (TopBottom = Control) or (LeftRight = Control) then begin
  430.         if Assigned(TopBottom) then TopBottom.Visible := not LeftOrRight;
  431.         if Assigned(LeftRight) then LeftRight.Visible := LeftOrRight;
  432.         Exit;
  433.       end;
  434. end;
  435.  
  436. function TCustomToolbar97.ShouldControlBeVisible (const Control: TControl;
  437.   const LeftOrRight: Boolean): Boolean;
  438. { If Control is a master or slave control, it returns the appropriate visibility
  439.   setting based on the value of LeftOrRight, otherwise it simply returns the
  440.   current Visible setting }
  441. var
  442.   I: Integer;
  443. begin
  444.   for I := 0 to SlaveInfo.Count-1 do
  445.     with PSlaveInfo(SlaveInfo[I])^ do
  446.       if TopBottom = Control then begin
  447.         Result := not LeftOrRight;
  448.         Exit;
  449.       end
  450.       else
  451.       if LeftRight = Control then begin
  452.         Result := LeftOrRight;
  453.         Exit;
  454.       end;
  455.   Result := ControlVisibleOrDesigning(Control);
  456. end;
  457.  
  458. procedure TCustomToolbar97.FreeGroupInfo (const List: TList);
  459. var
  460.   I: Integer;
  461.   L: PGroupInfo;
  462. begin
  463.   if List = nil then Exit;
  464.   for I := List.Count-1 downto 0 do begin
  465.     L := List.Items[I];
  466.     if Assigned(L) then begin
  467.       L^.Members.Free;
  468.       FreeMem (L);
  469.     end;
  470.     List.Delete (I);
  471.   end;
  472. end;
  473.  
  474. procedure TCustomToolbar97.BuildGroupInfo (const List: TList;
  475.   const TranslateSlave: Boolean; const OldDockType, NewDockType: TDockType);
  476. var
  477.   I: Integer;
  478.   GI: PGroupInfo;
  479.   Children: TList; {items casted into TControls}
  480.   C: TControl;
  481.   NewGroup: Boolean;
  482.   Extra: TCompareExtra;
  483. begin
  484.   FreeGroupInfo (List);
  485.   if ControlCount = 0 then Exit;
  486.  
  487.   Children := TList.Create;
  488.   try
  489.     for I := 0 to ControlCount-1 do 
  490.       if (not TranslateSlave and ControlVisibleOrDesigning(Controls[I])) or
  491.          (TranslateSlave and ShouldControlBeVisible(Controls[I], NewDockType = dtLeftRight)) then
  492.         Children.Add (Controls[I]);
  493.  
  494.     with Extra do begin
  495.       Toolbar := Self;
  496.       CurDockType := OldDockType;
  497.       ComparePositions := (csDesigning in ComponentState) and
  498.         ToolbarParams.DesignOrderByPosition;
  499.     end;
  500.     if Extra.ComparePositions then begin
  501.       CleanOrderList;
  502.       ListSortEx (OrderList, CompareControls, @Extra);
  503.     end;
  504.     ListSortEx (Children, CompareControls, @Extra);
  505.  
  506.     GI := nil;
  507.     NewGroup := True;
  508.     for I := 0 to Children.Count-1 do begin
  509.       if NewGroup then begin
  510.         NewGroup := False;
  511.         GI := AllocMem(SizeOf(TGroupInfo));
  512.         { Note: AllocMem initializes the newly allocated data to zero }
  513.         GI^.Members := TList.Create;
  514.         List.Add (GI);
  515.       end;
  516.       C := Children[I];
  517.       GI^.Members.Add (C);
  518.       if C is TToolbarSep97 then
  519.         NewGroup := True
  520.       else begin
  521.         with C do begin
  522.           Inc (GI^.GroupWidth, Width);
  523.           Inc (GI^.GroupHeight, Height);
  524.         end;
  525.       end;
  526.     end;
  527.   finally
  528.     Children.Free;
  529.   end;
  530. end;
  531.  
  532. function TCustomToolbar97.OrderControls (CanMoveControls: Boolean;
  533.   PreviousDockType: TDockType; DockingTo: TDock97): TPoint;
  534. { This arranges the controls on the toolbar }
  535. var
  536.   NewDockType: TDockType;
  537.   NewDocked: Boolean;
  538.   RightX, I: Integer;
  539.   CurBarSize, DockRowSize: Integer;
  540.   GInfo: TList;
  541.   AllowWrap: Boolean;
  542.   MinPosPixels, MinRowPixels, CurPosPixel, CurLinePixel, G: Integer;
  543.   GoToNewLine: Boolean;
  544.   GI: PGroupInfo;
  545.   Member: TControl;
  546.   MemberIsSep: Boolean;
  547.   GroupPosSize, MemberPosSize: Integer;
  548.   PreviousSep: TToolbarSep97;  PrevMinPosPixels: Integer;
  549.   NewLineSep: TLineSep;
  550. label 1;
  551. begin
  552.   NewDockType := GetDockTypeOf(DockingTo);
  553.   NewDocked := Assigned(DockingTo);
  554.  
  555.   RightX := FFloatingRightX;
  556.   if (NewDockType <> dtNotDocked) or (RightX = 0) then
  557.     RightX := High(RightX)
  558.   else begin
  559.     { Make sure RightX isn't less than the smallest sized control + margins,
  560.       in case one of the *LoadToolbarPositions functions happened to read
  561.       a value too small. }
  562.     for I := 0 to ControlCount-1 do
  563.       if not(Controls[I] is TToolbarSep97) then
  564.         with Controls[I] do
  565.           if Width + (tb97LeftMarginFloating+tb97RightMarginFloating) > RightX then
  566.             RightX := Width + (tb97LeftMarginFloating+tb97RightMarginFloating);
  567.   end;
  568.  
  569.   if CanMoveControls and (SlaveInfo.Count <> 0) then
  570.     for I := 0 to ControlCount-1 do
  571.       if not(Controls[I] is TToolbarSep97) then
  572.         SetControlVisible (Controls[I], NewDockType = dtLeftRight);
  573.  
  574.   GetBarSize (CurBarSize, NewDockType);
  575.   if (DockingTo <> nil) and (DockingTo = DockedTo) then
  576.     GetDockRowSize (DockRowSize)
  577.   else
  578.     DockRowSize := CurBarSize;
  579.  
  580.   if CanMoveControls then
  581.     GInfo := GroupInfo
  582.   else
  583.     GInfo := TList.Create;
  584.   try
  585.     BuildGroupInfo (GInfo, not CanMoveControls, PreviousDockType, NewDockType);
  586.  
  587.     if CanMoveControls then
  588.       LineSeps.Clear;
  589.  
  590.     CurLinePixel := tb97TopMargin[NewDocked];
  591.     MinPosPixels := tb97LeftMargin[NewDocked];
  592.     if GInfo.Count <> 0 then begin
  593.       AllowWrap := not NewDocked;
  594.       CurPosPixel := MinPosPixels;
  595.       GoToNewLine := False;
  596.       PreviousSep := nil;  PrevMinPosPixels := 0;
  597.       for G := 0 to GInfo.Count-1 do begin
  598.         GI := PGroupInfo(GInfo[G]);
  599.  
  600.         if NewDockType <> dtLeftRight then
  601.           GroupPosSize := GI^.GroupWidth
  602.         else
  603.           GroupPosSize := GI^.GroupHeight;
  604.         if AllowWrap and
  605.            (GoToNewLine or (CurPosPixel+GroupPosSize+tb97RightMargin[NewDocked] > RightX)) then begin
  606.           GoToNewLine := False;
  607.           CurPosPixel := tb97LeftMargin[NewDocked];
  608.           if (G <> 0) and (PGroupInfo(GInfo[G-1])^.Members.Count <> 0) then begin
  609.             Inc (CurLinePixel, CurBarSize + tb97LineSpacing);
  610.             if Assigned(PreviousSep) then begin
  611.               MinPosPixels := PrevMinPosPixels;
  612.               if CanMoveControls then begin
  613.                 PreviousSep.Width := 0;
  614.  
  615.                 LongInt(NewLineSep) := 0;
  616.                 NewLineSep.Y := CurLinePixel;
  617.                 NewLineSep.Blank := PreviousSep.Blank;
  618.                 LineSeps.Add (Pointer(NewLineSep));
  619.               end;
  620.             end;
  621.           end;
  622.         end;
  623.         if CurPosPixel > MinPosPixels then MinPosPixels := CurPosPixel;
  624.         for I := 0 to GI^.Members.Count-1 do begin
  625.           Member := TControl(GI^.Members[I]);
  626.           MemberIsSep := Member is TToolbarSep97;
  627.           with Member do begin
  628.             if not MemberIsSep then begin
  629.               if NewDockType <> dtLeftRight then
  630.                 MemberPosSize := Width
  631.               else
  632.                 MemberPosSize := Height;
  633.             end
  634.             else begin
  635.               if NewDockType <> dtLeftRight then
  636.                 MemberPosSize := TToolbarSep97(Member).SizeHorz
  637.               else
  638.                 MemberPosSize := TToolbarSep97(Member).SizeVert;
  639.             end;
  640.             { If RightX is passed, proceed to next line }
  641.             if AllowWrap and not MemberIsSep and
  642.                (CurPosPixel+MemberPosSize+tb97RightMargin[NewDocked] > RightX) then begin
  643.               CurPosPixel := tb97LeftMargin[NewDocked];
  644.               Inc (CurLinePixel, CurBarSize);
  645.               GoToNewLine := True;
  646.             end;
  647.             if NewDockType <> dtLeftRight then begin
  648.               if not MemberIsSep then begin
  649.                 if CanMoveControls then
  650.                   SetBounds (CurPosPixel, CurLinePixel+((DockRowSize-Height) div 2), Width, Height);
  651.                 Inc (CurPosPixel, Width);
  652.               end
  653.               else begin
  654.                 if CanMoveControls then
  655.                   SetBounds (CurPosPixel, CurLinePixel, TToolbarSep97(Member).SizeHorz, DockRowSize);
  656.                 Inc (CurPosPixel, TToolbarSep97(Member).SizeHorz);
  657.               end;
  658.             end
  659.             else begin
  660.               if not MemberIsSep then begin
  661.                 if CanMoveControls then
  662.                   SetBounds (CurLinePixel+((DockRowSize-Width) div 2), CurPosPixel, Width, Height);
  663.                 Inc (CurPosPixel, Height);
  664.               end
  665.               else begin
  666.                 if CanMoveControls then
  667.                   SetBounds (CurLinePixel, CurPosPixel, DockRowSize, TToolbarSep97(Member).SizeVert);
  668.                 Inc (CurPosPixel, TToolbarSep97(Member).SizeVert);
  669.               end;
  670.             end;
  671.             PrevMinPosPixels := MinPosPixels;
  672.             if not MemberIsSep then
  673.               PreviousSep := nil
  674.             else
  675.               PreviousSep := TToolbarSep97(Member);
  676.             if CurPosPixel > MinPosPixels then MinPosPixels := CurPosPixel;
  677.           end;
  678.         end;
  679.       end;
  680.     end
  681.     else
  682.       Inc (MinPosPixels, tb97DefaultBarWidthHeight);
  683.  
  684.     if csDesigning in ComponentState then
  685.       Invalidate;
  686.   finally
  687.     if not CanMoveControls then begin
  688.       FreeGroupInfo (GInfo);
  689.       GInfo.Free;
  690.     end;
  691.   end;
  692.  
  693.   Inc (MinPosPixels, tb97RightMargin[NewDocked]);
  694.   MinRowPixels := CurLinePixel + CurBarSize + tb97BottomMargin[NewDocked];
  695.   if NewDockType <> dtLeftRight then begin
  696.     Result.X := MinPosPixels;
  697.     Result.Y := MinRowPixels;
  698.   end
  699.   else begin
  700.     Result.X := MinRowPixels;
  701.     Result.Y := MinPosPixels;
  702.   end;
  703. end;
  704.  
  705. procedure TCustomToolbar97.CMControlListChange (var Message: TCMControlListChange);
  706. { The VCL sends this message is sent whenever a child control is inserted into
  707.   or deleted from the toolbar }
  708. var
  709.   I: Integer;
  710. begin
  711.   inherited;
  712.   with Message, OrderList do begin
  713.     { Delete any previous occurances of Control in OrderList. There shouldn't
  714.       be any if Inserting=True, but just to be safe, check anyway. }
  715.     while True do begin
  716.       I := IndexOf(Control);
  717.       if I = -1 then Break;
  718.       Delete (I);
  719.     end;
  720.     if Inserting then begin
  721.       Add (Control);
  722.       FOrderListDirty := True;
  723.     end;
  724.   end;
  725. end;
  726.  
  727. function CompareNewSizes (const Item1, Item2, ExtraData: Pointer): Integer; far;
  728. begin
  729.   { Sorts in descending order }
  730.   if ExtraData = nil then
  731.     Result := TSmallPoint(Item2).X - TSmallPoint(Item1).X
  732.   else
  733.     Result := TSmallPoint(Item2).Y - TSmallPoint(Item1).Y;
  734. end;
  735.  
  736. procedure TCustomToolbar97.BuildPotentialSizesList (SizesList: TList);
  737. var
  738.   MinX, SaveFloatingRightX: Integer;
  739.   X, LastY: Integer;
  740.   S: TPoint;
  741.   S2: TSmallPoint;
  742. begin
  743.   MinX := tb97LeftMarginFloating + tb97RightMarginFloating;
  744.   SaveFloatingRightX := FFloatingRightX;
  745.   try
  746.     { Add the widest size to the list }
  747.     FFloatingRightX := 0;
  748.     S := OrderControls(False, dtNotDocked, nil);
  749.     SizesList.Add (Pointer(PointToSmallPoint(S)));
  750.     { Calculate and add rest of sizes to the list }
  751.     LastY := S.Y;
  752.     X := S.X-1;
  753.     while X >= MinX do begin
  754.       FFloatingRightX := X;
  755.       S := OrderControls(False, dtNotDocked, nil);
  756.       if S.X > X then  { if it refuses to go any smaller }
  757.         Break
  758.       else
  759.       if X = S.X then begin
  760.         if (S.Y = LastY) and (SizesList.Count > 1) then
  761.           SizesList.Delete (SizesList.Count-1);
  762.         S2 := PointToSmallPoint(S);
  763.         if SizesList.IndexOf(Pointer(S2)) = -1 then
  764.           SizesList.Add (Pointer(S2));
  765.         LastY := S.Y;
  766.         Dec (X);
  767.       end
  768.       else
  769.         X := S.X;
  770.     end;
  771.   finally
  772.     FFloatingRightX := SaveFloatingRightX;
  773.   end;
  774. end;
  775.  
  776. procedure TCustomToolbar97.ResizeBegin (ASizeHandle: TToolWindowSizeHandle);
  777. const
  778.   MaxSizeSens = 12;
  779. var
  780.   I, NewSize: Integer;
  781.   S, N: TSmallPoint;
  782.   P: TPoint;
  783. begin
  784.   inherited;
  785.  
  786.   SizeData := AllocMem(SizeOf(TToolbar97SizeData));
  787.  
  788.   with PToolbar97SizeData(SizeData)^ do begin
  789.     SizeHandle := ASizeHandle;
  790.     CurRightX := FFloatingRightX;
  791.     DisableSensCheck := False;
  792.     OpSide := False;
  793.  
  794.     NewSizes := TList.Create;
  795.     BuildPotentialSizesList (NewSizes);
  796.     for I := 0 to NewSizes.Count-1 do begin
  797.       P := SmallPointToPoint(TSmallPoint(NewSizes.List[I]));
  798.       AddFloatingNCAreaToSize (P);
  799.       NewSizes.List[I] := Pointer(PointToSmallPoint(P));
  800.     end;
  801.     ListSortEx (NewSizes, CompareNewSizes,
  802.       Pointer(Ord(ASizeHandle in [twshTop, twshBottom])));
  803.  
  804.     SizeSens := MaxSizeSens;
  805.     { Adjust sensitivity if it's too high }
  806.     for I := 0 to NewSizes.Count-1 do begin
  807.       Pointer(S) := NewSizes[I];
  808.       if (S.X = Width) and (S.Y = Height) then begin
  809.         if I > 0 then begin
  810.           Pointer(N) := NewSizes[I-1];
  811.           if ASizeHandle in [twshLeft, twshRight] then
  812.             NewSize := N.X - S.X - 1
  813.           else
  814.             NewSize := N.Y - S.Y - 1;
  815.           if NewSize < SizeSens then SizeSens := NewSize;
  816.         end;
  817.         if I < NewSizes.Count-1 then begin
  818.           Pointer(N) := NewSizes[I+1];
  819.           if ASizeHandle in [twshLeft, twshRight] then
  820.             NewSize := S.X - N.X - 1
  821.           else
  822.             NewSize := S.Y - N.Y - 1;
  823.           if NewSize < SizeSens then SizeSens := NewSize;
  824.         end;
  825.         Break;
  826.       end;
  827.     end;
  828.     if SizeSens < 0 then SizeSens := 0;
  829.   end;
  830. end;
  831.  
  832. procedure TCustomToolbar97.ResizeTrack (var Rect: TRect; const OrigRect: TRect);
  833. var
  834.   Pos: TPoint;
  835.   NCXDiff: Integer;
  836.   NewOpSide: Boolean;
  837.   Reverse: Boolean;
  838.   I: Integer;
  839.   P: TSmallPoint;
  840. begin
  841.   inherited;
  842.  
  843.   with PToolbar97SizeData(SizeData)^ do begin
  844.     GetCursorPos (Pos);
  845.  
  846.     NCXDiff := ClientToScreen(Point(0, 0)).X - Left;
  847.     Dec (Pos.X, Left);  Dec (Pos.Y, Top);
  848.     if SizeHandle = twshLeft then
  849.       Pos.X := Width-Pos.X
  850.     else
  851.     if SizeHandle = twshTop then
  852.       Pos.Y := Height-Pos.Y;
  853.  
  854.     { Adjust Pos to make up for the "sizing sensitivity", as seen in Office 97 }
  855.     if SizeHandle in [twshLeft, twshRight] then
  856.       NewOpSide := Pos.X < Width
  857.     else
  858.       NewOpSide := Pos.Y < Height;
  859.     if (not DisableSensCheck) or (OpSide <> NewOpSide) then begin
  860.       DisableSensCheck := False;
  861.       OpSide := NewOpSide;
  862.       if SizeHandle in [twshLeft, twshRight] then begin
  863.         if (Pos.X >= Width-SizeSens) and (Pos.X < Width+SizeSens) then
  864.           Pos.X := Width;
  865.       end
  866.       else begin
  867.         if (Pos.Y >= Height-SizeSens) and (Pos.Y < Height+SizeSens) then
  868.           Pos.Y := Height;
  869.       end;
  870.     end;
  871.  
  872.     Rect := OrigRect;
  873.  
  874.     if SizeHandle in [twshLeft, twshRight] then
  875.       Reverse := Pos.X > Width
  876.     else
  877.       Reverse := Pos.Y > Height;
  878.     if not Reverse then
  879.       I := NewSizes.Count-1
  880.     else
  881.       I := 0;
  882.     while True do begin
  883.       if (not Reverse and (I < 0)) or
  884.          (Reverse and (I >= NewSizes.Count)) then
  885.         Break;
  886.       Pointer(P) := NewSizes[I];
  887.       if SizeHandle in [twshLeft, twshRight] then begin
  888.         if (not Reverse and ((I = NewSizes.Count-1) or (Pos.X >= P.X))) or
  889.            (Reverse and ((I = 0) or (Pos.X < P.X))) then begin
  890.           if I = 0 then
  891.             CurRightX := 0
  892.           else
  893.             CurRightX := P.X - NCXDiff*2;
  894.           if SizeHandle = twshRight then
  895.             Rect.Right := Rect.Left + P.X
  896.           else
  897.             Rect.Left := Rect.Right - P.X;
  898.           Rect.Bottom := Rect.Top + P.Y;
  899.           DisableSensCheck := not EqualRect(Rect, OrigRect);
  900.         end;
  901.       end
  902.       else begin
  903.         if (not Reverse and ((I = NewSizes.Count-1) or (Pos.Y >= P.Y))) or
  904.            (Reverse and ((I = 0) or (Pos.Y < P.Y))) then begin
  905.           if I = NewSizes.Count-1 then
  906.             CurRightX := 0
  907.           else
  908.             CurRightX := P.X - NCXDiff*2;
  909.           if SizeHandle = twshBottom then
  910.             Rect.Bottom := Rect.Top + P.Y
  911.           else
  912.             Rect.Top := Rect.Bottom - P.Y;
  913.           Rect.Right := Rect.Left + P.X;
  914.           DisableSensCheck := not EqualRect(Rect, OrigRect);
  915.         end;
  916.       end;
  917.       if not Reverse then
  918.         Dec (I)
  919.       else
  920.         Inc (I);
  921.     end;
  922.   end;
  923. end;
  924.  
  925. procedure TCustomToolbar97.ResizeEnd (Accept: Boolean);
  926. begin
  927.   inherited;
  928.   if Assigned(SizeData) then begin
  929.     with PToolbar97SizeData(SizeData)^ do begin
  930.       if Accept then
  931.         FFloatingRightX := CurRightX;
  932.       NewSizes.Free;
  933.     end;
  934.     FreeMem (SizeData);
  935.   end;
  936. end;
  937.  
  938. function TCustomToolbar97.GetOrderedControls (Index: Integer): TControl;
  939. begin
  940.   CleanOrderList;
  941.   Result := OrderList[Index];
  942. end;
  943.  
  944. function TCustomToolbar97.GetOrderIndex (Control: TControl): Integer;
  945. begin
  946.   CleanOrderList;
  947.   Result := OrderList.IndexOf(Control);
  948.   if Result = -1 then
  949.     raise EInvalidOperation.CreateFmt(STB97ToolbarControlNotChildOfToolbar,
  950.       [Control.Name]);
  951. end;
  952.  
  953. procedure TCustomToolbar97.SetOrderIndex (Control: TControl; Value: Integer);
  954. var
  955.   OldIndex: Integer;
  956. begin
  957.   CleanOrderList;
  958.   with OrderList do begin
  959.     OldIndex := IndexOf(Control);
  960.     if OldIndex = -1 then
  961.       raise EInvalidOperation.CreateFmt(STB97ToolbarControlNotChildOfToolbar,
  962.         [Control.Name]);
  963.     if Value < 0 then Value := 0;
  964.     if Value >= Count then Value := Count-1;
  965.     if Value <> OldIndex then begin
  966.       Delete (OldIndex);
  967.       Insert (Value, Control);
  968.       ArrangeControls;
  969.     end;
  970.   end;
  971. end;
  972.  
  973. procedure TCustomToolbar97.SetFloatingWidth (Value: Integer);
  974. begin
  975.   if FFloatingRightX <> Value then begin
  976.     FFloatingRightX := Value;
  977.     ArrangeControls;
  978.   end;
  979. end;
  980.  
  981. procedure TCustomToolbar97.SetSlaveControl (const ATopBottom, ALeftRight: TControl);
  982. var
  983.   NewVersion: PSlaveInfo;
  984. begin
  985.   GetMem (NewVersion, SizeOf(TSlaveInfo));
  986.   with NewVersion^ do begin
  987.     TopBottom := ATopBottom;
  988.     LeftRight := ALeftRight;
  989.   end;
  990.   SlaveInfo.Add (NewVersion);
  991.   ArrangeControls;
  992. end;
  993.  
  994. function TCustomToolbar97.ChildControlTransparent (Ctl: TControl): Boolean;
  995. begin
  996.   Result := Ctl is TToolbarSep97;
  997. end;
  998.  
  999. procedure TCustomToolbar97.WMWindowPosChanging (var Message: TWMWindowPosChanging);
  1000. var
  1001.   R: TRect;
  1002. begin
  1003.   inherited;
  1004.   { When floating, invalidate the toolbar when resized so that the vertical
  1005.     separators get redrawn.
  1006.     Note to self: The Invalidate call must be in the WM_WINDOWPOSCHANGING
  1007.     handler. If it's in WM_SIZE or WM_WINDOWPOSCHANGED there can be repainting
  1008.     problems in rare cases (refer to Toolbar97 1.65a's implementation). }
  1009.   if not Docked and HandleAllocated then
  1010.     with Message.WindowPos^ do
  1011.       if flags and SWP_DRAWFRAME <> 0 then
  1012.         Invalidate
  1013.       else
  1014.         if flags and SWP_NOSIZE = 0 then begin
  1015.           GetWindowRect (Handle, R);
  1016.           if (R.Right-R.Left <> cx) or (R.Bottom-R.Top <> cy) then
  1017.             Invalidate;
  1018.         end;
  1019. end;
  1020.  
  1021.  
  1022. { TToolbarSep97 }
  1023.  
  1024. constructor TToolbarSep97.Create (AOwner: TComponent);
  1025. begin
  1026.   inherited;
  1027.   FSizeHorz := 6;
  1028.   FSizeVert := 6;
  1029.   ControlStyle := ControlStyle - [csOpaque, csCaptureMouse];
  1030. end;
  1031.  
  1032. procedure TToolbarSep97.SetParent (AParent: TWinControl);
  1033. begin
  1034.   if (AParent <> nil) and not(AParent is TCustomToolbar97) then
  1035.     raise EInvalidOperation.Create(STB97SepParentNotAllowed);
  1036.   inherited;
  1037. end;
  1038.  
  1039. procedure TToolbarSep97.SetBlank (Value: Boolean);
  1040. begin
  1041.   if FBlank <> Value then begin
  1042.     FBlank := Value;
  1043.     Invalidate;
  1044.   end;
  1045. end;
  1046.  
  1047. procedure TToolbarSep97.SetSizeHorz (Value: TToolbarSepSize);
  1048. begin
  1049.   if FSizeHorz <> Value then begin
  1050.     FSizeHorz := Value;
  1051.     if Parent is TCustomToolbar97 then
  1052.       TCustomToolbar97(Parent).ArrangeControls;
  1053.   end;
  1054. end;
  1055.  
  1056. procedure TToolbarSep97.SetSizeVert (Value: TToolbarSepSize);
  1057. begin
  1058.   if FSizeVert <> Value then begin
  1059.     FSizeVert := Value;
  1060.     if Parent is TCustomToolbar97 then
  1061.       TCustomToolbar97(Parent).ArrangeControls;
  1062.   end;
  1063. end;
  1064.  
  1065. procedure TToolbarSep97.Paint;
  1066. var
  1067.   R: TRect;
  1068.   Z: Integer;
  1069. begin
  1070.   inherited;
  1071.   if not(Parent is TCustomToolbar97) then Exit;
  1072.  
  1073.   with Canvas do begin
  1074.     { Draw dotted border in design mode }
  1075.     if csDesigning in ComponentState then begin
  1076.       Pen.Style := psDot;
  1077.       Pen.Color := clBtnShadow;
  1078.       Brush.Style := bsClear;
  1079.       R := ClientRect;
  1080.       Rectangle (R.Left, R.Top, R.Right, R.Bottom);
  1081.       Pen.Style := psSolid;
  1082.     end;
  1083.  
  1084.     if not FBlank then
  1085.       if GetDockTypeOf(TCustomToolbar97(Parent).DockedTo) <> dtLeftRight then begin
  1086.         Z := Width div 2;
  1087.         Pen.Color := clBtnShadow;
  1088.         MoveTo (Z-1, 0);  LineTo (Z-1, Height);
  1089.         Pen.Color := clBtnHighlight;
  1090.         MoveTo (Z, 0);  LineTo (Z, Height);
  1091.       end
  1092.       else begin
  1093.         Z := Height div 2;
  1094.         Pen.Color := clBtnShadow;
  1095.         MoveTo (0, Z-1);  LineTo (Width, Z-1);
  1096.         Pen.Color := clBtnHighlight;
  1097.         MoveTo (0, Z);  LineTo (Width, Z);
  1098.       end;
  1099.   end;
  1100. end;
  1101.  
  1102. procedure TToolbarSep97.MouseDown (Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1103. var
  1104.   P: TPoint;
  1105. begin
  1106.   inherited;
  1107.   if not(Parent is TCustomToolbar97) then Exit;
  1108.  
  1109.   { Relay the message to the parent toolbar }
  1110.   P := Parent.ScreenToClient(ClientToScreen(Point(X, Y)));
  1111.   TCustomToolbar97(Parent).MouseDown (Button, Shift, P.X, P.Y);
  1112. end;
  1113.  
  1114. end.
  1115.