home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Vcl / tabs.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  36KB  |  1,328 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {                                                       }
  6. {       Copyright (c) 1995,99 Inprise Corporation       }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. {****************************************************************************}
  11. {                                                                            }
  12. { Limitation on Distribution of Programs Created with this Source Code File: }
  13. { ========================================================================== }
  14. {                                                                            }
  15. { For distribution of an application which you create with this Source       }
  16. { Code File, your application may not be a general-purpose, interactive      }
  17. { spreadsheet program, or a substitute for or generally competitive          }
  18. { with Quattro Pro.                                                          }
  19. {                                                                            }
  20. {****************************************************************************}
  21.  
  22. { Implements tab control }
  23.  
  24. unit Tabs;
  25.  
  26. {$T-,H+,X+}
  27.  
  28. interface
  29.  
  30. uses Windows, Classes, Graphics, Forms, Controls, Messages;
  31.  
  32. type
  33.   TScrollBtn = (sbLeft, sbRight);
  34.  
  35.   TScroller = class(TCustomControl)
  36.   private
  37.     { property usage }
  38.     FMin: Longint;
  39.     FMax: Longint;
  40.     FPosition: Longint;
  41.     FOnClick: TNotifyEvent;
  42.     FChange: Integer;
  43.  
  44.     { private usage }
  45.     Bitmap: TBitmap;
  46.     Pressed: Boolean;
  47.     Down: Boolean;
  48.     Current: TScrollBtn;
  49.     pWidth: Integer;
  50.     pHeight: Integer;
  51.  
  52.     { property access methods }
  53.     procedure SetMin(Value: Longint);
  54.     procedure SetMax(Value: Longint);
  55.     procedure SetPosition(Value: Longint);
  56.  
  57.     { private methods }
  58.     function CanScrollLeft: Boolean;
  59.     function CanScrollRight: Boolean;
  60.     procedure DoMouseDown(X: Integer);
  61.     procedure WMLButtonDown(var Message: TWMLButtonDown);
  62.       message WM_LBUTTONDOWN;
  63.     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk);
  64.       message WM_LBUTTONDBLCLK;
  65.     procedure WMMouseMove(var Message: TWMMouseMove);
  66.       message WM_MOUSEMOVE;
  67.     procedure WMLButtonUp(var Message: TWMLButtonUp);
  68.       message WM_LBUTTONUP;
  69.     procedure WMSize(var Message: TWMSize);
  70.       message WM_SIZE;
  71.   public
  72.     constructor Create(AOwner: TComponent); override;
  73.     destructor Destroy; override;
  74.     procedure Paint; override;
  75.   published
  76.     property OnClick: TNotifyEvent read FOnClick write FOnClick;
  77.     property Min: Longint read FMin write SetMin default 0;
  78.     property Max: Longint read FMax write SetMax default 0;
  79.     property Position: Longint read FPosition write SetPosition default 0;
  80.     property Change: Integer read FChange write FChange default 1;
  81.   end;
  82.  
  83.   TTabSet = class;
  84.  
  85.   TTabList = class(TStringList)
  86.   private
  87.     Tabs: TTabSet;
  88.   public
  89.     procedure Insert(Index: Integer; const S: string); override;
  90.     procedure Delete(Index: Integer); override;
  91.     function Add(const S: string): Integer; override;
  92.     procedure Put(Index: Integer; const S: string); override;
  93.     procedure Clear; override;
  94.     procedure AddStrings(Strings: TStrings); override;
  95.   end;
  96.  
  97.   { eash TEdgeType is made up of one or two of these parts }
  98.   TEdgePart = (epSelectedLeft, epUnselectedLeft, epSelectedRight,
  99.     epUnselectedRight);
  100.  
  101.   { represents the intersection between two tabs, or the edge of a tab }
  102.   TEdgeType = (etNone, etFirstIsSel, etFirstNotSel, etLastIsSel, etLastNotSel,
  103.     etNotSelToSel, etSelToNotSel, etNotSelToNotSel);
  104.  
  105.   TTabStyle = (tsStandard, tsOwnerDraw);
  106.  
  107.   TMeasureTabEvent = procedure(Sender: TObject; Index: Integer;
  108.     var TabWidth: Integer) of object;
  109.   TDrawTabEvent = procedure(Sender: TObject; TabCanvas: TCanvas; R: TRect;
  110.     Index: Integer; Selected: Boolean) of object;
  111.   TTabChangeEvent = procedure(Sender: TObject; NewTab: Integer;
  112.     var AllowChange: Boolean) of object;
  113.  
  114.   TTabSet = class(TCustomControl)
  115.   private
  116.     { property instance variables }
  117.     FStartMargin: Integer;
  118.     FEndMargin: Integer;
  119.     FTabs: TStrings;
  120.     FTabIndex: Integer;
  121.     FFirstIndex: Integer;
  122.     FVisibleTabs: Integer;
  123.     FSelectedColor: TColor;
  124.     FUnselectedColor: TColor;
  125.     FBackgroundColor: TColor;
  126.     FDitherBackground: Boolean;
  127.     FAutoScroll: Boolean;
  128.     FStyle: TTabStyle;
  129.     FOwnerDrawHeight: Integer;
  130.     FOnMeasureTab: TMeasureTabEvent;
  131.     FOnDrawTab: TDrawTabEvent;
  132.     FOnChange: TTabChangeEvent;
  133.  
  134.     { private instance variables }
  135.  
  136.     ImageList: TImageList;
  137.     MemBitmap: TBitmap;   { used for off-screen drawing }
  138.     BrushBitmap: TBitmap; { used for background pattern }
  139.  
  140.     TabPositions: TList;
  141.     FTabHeight: Integer;
  142.     Scroller: TScroller;
  143.     FDoFix: Boolean;
  144.  
  145.     { property access methods }
  146.     procedure SetSelectedColor(Value: TColor);
  147.     procedure SetUnselectedColor(Value: TColor);
  148.     procedure SetBackgroundColor(Value: TColor);
  149.     procedure SetDitherBackground(Value: Boolean);
  150.     procedure SetAutoScroll(Value: Boolean);
  151.     procedure SetStartMargin(Value: Integer);
  152.     procedure SetEndMargin(Value: Integer);
  153.     procedure SetTabIndex(Value: Integer);
  154.     procedure SetFirstIndex(Value: Integer);
  155.     procedure SetTabList(Value: TStrings);
  156. //    function GetTabCount: Integer;
  157. //    function GetTabName(Value: Integer): String;
  158. //    procedure SetTabName(Value: Integer; const AName: String);
  159.     procedure SetTabStyle(Value: TTabStyle);
  160.     procedure SetTabHeight(Value: Integer);
  161.  
  162.     { private methods }
  163.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  164.     procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
  165.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  166.     procedure PaintEdge(X, Y, H: Integer; Edge: TEdgeType);
  167.     procedure CreateBrushPattern(Bitmap: TBitmap);
  168.     function CalcTabPositions(Start, Stop: Integer; Canvas: TCanvas;
  169.       First: Integer): Integer;
  170.     procedure CreateScroller;
  171.     procedure InitBitmaps;
  172.     procedure DoneBitmaps;
  173.     procedure CreateEdgeParts;
  174.     procedure FixTabPos;
  175.     procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  176.     procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  177.     procedure ScrollClick(Sender: TObject);
  178.     procedure ReadIntData(Reader: TReader);
  179.     procedure ReadBoolData(Reader: TReader);
  180.   protected
  181.     procedure CreateParams(var Params: TCreateParams); override;
  182.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  183.       X, Y: Integer); override;
  184.     procedure Paint; override;
  185.     procedure DrawTab(TabCanvas: TCanvas; R: TRect; Index: Integer;
  186.       Selected: Boolean); virtual;
  187.     function CanChange(NewIndex: Integer): Boolean;
  188.     procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  189.     procedure MeasureTab(Index: Integer; var TabWidth: Integer); virtual;
  190.     procedure DefineProperties(Filer: TFiler); override;
  191.   public
  192.     constructor Create(AOwner: TComponent); override;
  193.     destructor Destroy; override;
  194.     function ItemAtPos(Pos: TPoint): Integer;
  195.     function ItemRect(Item: Integer): TRect;
  196.     procedure SelectNext(Direction: Boolean);
  197.     property Canvas;
  198.     property FirstIndex: Integer read FFirstIndex write SetFirstIndex default 0;
  199.   published
  200.     property Align;
  201.     property Anchors;
  202.     property AutoScroll: Boolean read FAutoScroll write SetAutoScroll default True;
  203.     property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor default clBtnFace;
  204.     property Constraints;
  205.     property DitherBackground: Boolean read FDitherBackground write SetDitherBackground default True;
  206.     property DragCursor;
  207.     property DragKind;
  208.     property DragMode;
  209.     property Enabled;
  210.     property EndMargin: Integer read FEndMargin write SetEndMargin default 5;
  211.     property Font;
  212.     property ParentShowHint;
  213.     property PopupMenu;
  214.     property ShowHint;
  215.     property StartMargin: Integer read FStartMargin write SetStartMargin default 5;
  216.     property SelectedColor: TColor read FSelectedColor write SetSelectedColor default clBtnFace;
  217.     property Style: TTabStyle read FStyle write SetTabStyle default tsStandard;
  218.     property TabHeight: Integer read FOwnerDrawHeight write SetTabHeight default 20;
  219.     property Tabs: TStrings read FTabs write SetTabList;
  220.     property TabIndex: Integer read FTabIndex write SetTabIndex default -1;
  221.     property UnselectedColor: TColor read FUnselectedColor write SetUnselectedColor default clWindow;
  222.     property Visible;
  223.     property VisibleTabs: Integer read FVisibleTabs;
  224.     property OnClick;
  225.     property OnChange: TTabChangeEvent read FOnChange write FOnChange;
  226.     property OnDragDrop;
  227.     property OnDragOver;
  228.     property OnDrawTab: TDrawTabEvent read FOnDrawTab write FOnDrawTab;
  229.     property OnEndDock;
  230.     property OnEndDrag;
  231.     property OnEnter;
  232.     property OnExit;
  233.     property OnMouseDown;
  234.     property OnMouseMove;
  235.     property OnMouseUp;
  236.     property OnMeasureTab: TMeasureTabEvent read FOnMeasureTab write FOnMeasureTab;
  237.     property OnStartDock;
  238.     property OnStartDrag;
  239.   end;
  240.  
  241. implementation
  242.  
  243. uses Consts, SysUtils;
  244.  
  245. {$R TABS.RES}
  246.  
  247. const
  248.   EdgeWidth = 9;  { This controls the angle of the tab edges }
  249.  
  250. type
  251.   TTabPos = packed record
  252.     Size, StartPos: Word;
  253.   end;
  254.  
  255. { TScroller }
  256.  
  257. constructor TScroller.Create(AOwner: TComponent);
  258. begin
  259.   inherited Create(AOwner);
  260.   ControlStyle := ControlStyle + [csOpaque];
  261.   Bitmap := TBitmap.Create;
  262.   pWidth := 24;
  263.   pHeight := 13;
  264.   FMin := 0;
  265.   FMax := 0;
  266.   FPosition := 0;
  267.   FChange := 1;
  268. end;
  269.  
  270. destructor TScroller.Destroy;
  271. begin
  272.   Bitmap.Free;
  273.   inherited Destroy;
  274. end;
  275.  
  276. procedure TScroller.Paint;
  277. begin
  278.   with Canvas do
  279.   begin
  280.     { paint left button }
  281.     if CanScrollLeft then
  282.     begin
  283.       if Down and (Current = sbLeft) then
  284.         Bitmap.Handle := LoadBitmap(HInstance, 'SBLEFTDN')
  285.       else Bitmap.Handle := LoadBitmap(HInstance, 'SBLEFT');
  286.     end
  287.     else
  288.       Bitmap.Handle := LoadBitmap(HInstance, 'SBLEFTDIS');
  289.     Draw(0, 0, Bitmap);
  290.  
  291.     { paint right button }
  292.     if CanScrollRight then
  293.     begin
  294.       if Down and (Current = sbRight) then
  295.         Bitmap.Handle := LoadBitmap(HInstance, 'SBRIGHTDN')
  296.       else Bitmap.Handle := LoadBitmap(HInstance, 'SBRIGHT');
  297.     end
  298.     else
  299.       Bitmap.Handle := LoadBitmap(HInstance, 'SBRIGHTDIS');
  300.     Draw((pWidth div 2) - 1, 0, Bitmap);
  301.   end;
  302. end;
  303.  
  304. procedure TScroller.WMSize(var Message: TWMSize);
  305. begin
  306.   inherited;
  307.   Width := pWidth - 1;
  308.   Height := pHeight;
  309. end;
  310.  
  311. procedure TScroller.SetMin(Value: Longint);
  312. begin
  313.   if Value < FMax then FMin := Value;
  314. end;
  315.  
  316. procedure TScroller.SetMax(Value: Longint);
  317. begin
  318.   if Value > FMin then FMax := Value;
  319. end;
  320.  
  321. procedure TScroller.SetPosition(Value: Longint);
  322. begin
  323.   if Value <> FPosition then
  324.   begin
  325.     if Value < Min then Value := Min;
  326.     if Value > Max then Value := Max;
  327.     FPosition := Value;
  328.     Invalidate;
  329.     if Assigned(FOnClick) then
  330.       FOnClick(Self);
  331.   end;
  332. end;
  333.  
  334. function TScroller.CanScrollLeft: Boolean;
  335. begin
  336.   Result := Position > Min;
  337. end;
  338.  
  339. function TScroller.CanScrollRight: Boolean;
  340. begin
  341.   Result := Position < Max;
  342. end;
  343.  
  344. procedure TScroller.DoMouseDown(X: Integer);
  345. begin
  346.   if X < pWidth div 2 then Current := sbLeft
  347.   else Current := sbRight;
  348.   case Current of
  349.     sbLeft: if not CanScrollLeft then Exit;
  350.     sbRight: if not CanScrollRight then Exit;
  351.   end;
  352.   Pressed := True;
  353.   Down := True;
  354.   Invalidate;
  355.   SetCapture(Handle);
  356. end;
  357.  
  358. procedure TScroller.WMLButtonDown(var Message: TWMLButtonDown);
  359. begin
  360.   DoMouseDown(Message.XPos);
  361. end;
  362.  
  363. procedure TScroller.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  364. begin
  365.   DoMouseDown(Message.XPos);
  366. end;
  367.  
  368. procedure TScroller.WMMouseMove(var Message: TWMMouseMove);
  369. var
  370.   P: TPoint;
  371.   R: TRect;
  372. begin
  373.   if Pressed then
  374.   begin
  375.     P := Point(Message.XPos, Message.YPos);
  376.     R := Rect(0, 0, pWidth div 2, pHeight);
  377.     if Current = sbRight then OffsetRect(R, pWidth div 2, 0);
  378.     if PtInRect(R, P) <> Down then
  379.     begin
  380.       Down := not Down;
  381.       Invalidate;
  382.     end;
  383.   end;
  384. end;
  385.  
  386. procedure TScroller.WMLButtonUp(var Message: TWMLButtonUp);
  387. var
  388.   NewPos: Longint;
  389. begin
  390.   ReleaseCapture;
  391.   Pressed := False;
  392.  
  393.   if Down then
  394.   begin
  395.     Down := False;
  396.     NewPos := Position;
  397.     case Current of
  398.       sbLeft: Dec(NewPos, Change);
  399.       sbRight: Inc(NewPos, Change);
  400.     end;
  401.     Position := NewPos;
  402.   end;
  403. end;
  404.  
  405.  
  406. { TTabList }
  407.  
  408. function TTabList.Add(const S: string): Integer;
  409. begin
  410.   Result := inherited Add(S);
  411.   if Tabs <> nil then
  412.     Tabs.Invalidate;
  413. end;
  414.  
  415. procedure TTabList.Insert(Index: Integer; const S: string);
  416. begin
  417.   inherited Insert(Index, S);
  418.   if Tabs <> nil then
  419.   begin
  420.     if Index <= Tabs.FTabIndex then Inc(Tabs.FTabIndex);
  421.     Tabs.Invalidate;
  422.   end;
  423. end;
  424.  
  425. procedure TTabList.Delete(Index: Integer);
  426. var
  427.   OldIndex: Integer;
  428. begin
  429.   OldIndex := Tabs.Tabindex;
  430.   inherited Delete(Index);
  431.  
  432.   if OldIndex < Count then Tabs.FTabIndex := OldIndex
  433.   else Tabs.FTabIndex := Count - 1;
  434.   Tabs.Invalidate;
  435.   Tabs.Invalidate;
  436.   if OldIndex = Index then Tabs.Click;  { deleted selected tab }
  437. end;
  438.  
  439. procedure TTabList.Put(Index: Integer; const S: string);
  440. begin
  441.   inherited Put(Index, S);
  442.   if Tabs <> nil then
  443.     Tabs.Invalidate;
  444. end;
  445.  
  446. procedure TTabList.Clear;
  447. begin
  448.   inherited Clear;
  449.   Tabs.FTabIndex := -1;
  450.   Tabs.Invalidate;
  451. end;
  452.  
  453. procedure TTabList.AddStrings(Strings: TStrings);
  454. begin
  455.   SendMessage(Tabs.Handle, WM_SETREDRAW, 0, 0);
  456.   inherited AddStrings(Strings);
  457.   SendMessage(Tabs.Handle, WM_SETREDRAW, 1, 0);
  458.   Tabs.Invalidate;
  459. end;
  460.  
  461. { TTabSet }
  462.  
  463. constructor TTabSet.Create(AOwner: TComponent);
  464. begin
  465.   inherited Create(AOwner);
  466.   ControlStyle := [csCaptureMouse, csDoubleClicks, csOpaque];
  467.   Width := 185;
  468.   Height := 21;
  469.  
  470.   TabPositions := TList.Create;
  471.   FTabHeight := 20;
  472.  
  473.   FTabs := TTabList.Create;
  474.   TTabList(FTabs).Tabs := Self;
  475.   InitBitmaps;
  476.  
  477.   CreateScroller;
  478.  
  479.   FTabIndex := -1;
  480.   FFirstIndex := 0;
  481.   FVisibleTabs := 0;  { set by draw routine }
  482.   FStartMargin := 5;
  483.   FEndMargin := 5;
  484.  
  485.   { initialize default values }
  486.   FSelectedColor := clBtnFace;
  487.   FUnselectedColor := clWindow;
  488.   FBackgroundColor := clBtnFace;
  489.   FDitherBackground := True;
  490.   CreateBrushPattern(BrushBitmap);
  491.   FAutoScroll := True;
  492.   FStyle := tsStandard;
  493.   FOwnerDrawHeight := 20;
  494.  
  495.   ParentFont := False;
  496.   Font.Name := DefFontData.Name;
  497.   Font.Height := DefFontData.Height;
  498.   Font.Style := [];
  499.  
  500.   { create the edge bitmaps }
  501.   CreateEdgeParts;
  502. end;
  503.  
  504. procedure TTabSet.CreateParams(var Params: TCreateParams);
  505. begin
  506.   inherited CreateParams(Params);
  507.   with Params.WindowClass do
  508.     style := style and not (CS_VREDRAW or CS_HREDRAW);
  509. end;
  510.  
  511. procedure TTabSet.CreateScroller;
  512. begin
  513.   Scroller := TScroller.Create(Self);
  514.   with Scroller do
  515.   begin
  516.     Parent := Self;
  517.     Top := 3;
  518.     Min := 0;
  519.     Max := 0;
  520.     Position := 0;
  521.     Visible := False;
  522.     OnClick := ScrollClick;
  523.   end;
  524. end;
  525.  
  526. procedure TTabSet.InitBitmaps;
  527. begin
  528.   MemBitmap := TBitmap.Create;
  529.   BrushBitmap := TBitmap.Create;
  530. end;
  531.  
  532. destructor TTabSet.Destroy;
  533. begin
  534.   FTabs.Free;
  535.   TabPositions.Free;
  536.   DoneBitmaps;
  537.   inherited Destroy;
  538. end;
  539.  
  540. procedure TTabSet.DoneBitmaps;
  541. begin
  542.   MemBitmap.Free;
  543.   BrushBitmap.Free;
  544.   ImageList.Free;
  545. end;
  546.  
  547. procedure TTabSet.ScrollClick(Sender: TObject);
  548. begin
  549.   FirstIndex := TScroller(Sender).Position;
  550. end;
  551.  
  552. { cache the tab position data, and return number of visible tabs }
  553. function TTabSet.CalcTabPositions(Start, Stop: Integer; Canvas: TCanvas;
  554.   First: Integer): Integer;
  555. var
  556.   Index: Integer;
  557.   TabPos: TTabPos;
  558.   W: Integer;
  559. begin
  560.   TabPositions.Count := 0;  { erase all previously cached data }
  561.   Index := First;
  562.   while (Start < Stop) and (Index < Tabs.Count) do
  563.     with Canvas do
  564.     begin
  565.       TabPos.StartPos := Start;
  566.       W := TextWidth(Tabs[Index]);
  567.  
  568.       { Owner }
  569.       if (FStyle = tsOwnerDraw) then MeasureTab(Index, W);
  570.  
  571.       TabPos.Size := W;
  572.       Inc(Start, TabPos.Size + EdgeWidth);    { next usable position }
  573.  
  574.       if Start <= Stop then
  575.       begin
  576.         TabPositions.Add(Pointer(TabPos));    { add to list }
  577.         Inc(Index);
  578.       end;
  579.     end;
  580.   Result := Index - First;
  581. end;
  582.  
  583. function TTabSet.ItemAtPos(Pos: TPoint): Integer;
  584. var
  585.   TabPos: TTabPos;
  586.   I: Integer;
  587. begin
  588.   Result := -1;
  589.   if (Pos.Y < 0) or (Pos.Y > ClientHeight) then Exit;
  590.   for I := 0 to TabPositions.Count - 1 do
  591.   begin
  592.     Pointer(TabPos) := TabPositions[I];
  593.     if (Pos.X >= TabPos.StartPos) and (Pos.X <= TabPos.StartPos + TabPos.Size) then
  594.     begin
  595.       Result := I;
  596.       Exit;
  597.     end;
  598.   end;
  599. end;
  600.  
  601. function TTabSet.ItemRect(Item: Integer): TRect;
  602. var
  603.   TabPos: TTabPos;
  604. begin
  605.   if (TabPositions.Count > 0) and (Item >= 0) and (Item < TabPositions.Count) then
  606.   begin
  607.     Pointer(TabPos) := TabPositions[Item];
  608.     Result := Rect(TabPos.StartPos, 0, TabPos.StartPos + TabPos.Size, FTabHeight);
  609.     InflateRect(Result, 1, -2);
  610.   end
  611.   else
  612.     Result := Rect(0, 0, 0, 0);
  613. end;
  614.  
  615. procedure TTabSet.Paint;
  616. var
  617.   TabStart, LastTabPos: Integer;
  618.   TabPos: TTabPos;
  619.   Tab: Integer;
  620.   Leading: TEdgeType;
  621.   Trailing: TEdgeType;
  622.   isFirst, isLast, isSelected, isPrevSelected: Boolean;
  623.   R: TRect;
  624. begin
  625.   if not HandleAllocated then Exit;
  626.  
  627.   { Set the size of the off-screen bitmap.  Make sure that it is tall enough to
  628.     display the entire tab, even if the screen won't display it all.  This is
  629.     required to avoid problems with using FloodFill. }
  630.   MemBitmap.Width := ClientWidth;
  631.   if ClientHeight < FTabHeight + 5 then MemBitmap.Height := FTabHeight + 5
  632.   else MemBitmap.Height := ClientHeight;
  633.  
  634.   MemBitmap.Canvas.Font := Self.Canvas.Font;
  635.  
  636.   TabStart := StartMargin + EdgeWidth;        { where does first text appear? }
  637.   LastTabPos := Width - EndMargin;            { tabs draw until this position }
  638.   Scroller.Left := Width - Scroller.Width - 2;
  639.  
  640.   { do initial calculations for how many tabs are visible }
  641.   FVisibleTabs := CalcTabPositions(TabStart, LastTabPos, MemBitmap.Canvas,
  642.     FirstIndex);
  643.  
  644.   { enable the scroller if FAutoScroll = True and not all tabs are visible }
  645.   if AutoScroll and (FVisibleTabs < Tabs.Count) then
  646.   begin
  647.     Dec(LastTabPos, Scroller.Width - 4);
  648.     { recalc the tab positions }
  649.     FVisibleTabs := CalcTabPositions(TabStart, LastTabPos, MemBitmap.Canvas,
  650.       FirstIndex);
  651.  
  652.     { set the scroller's range }
  653.     Scroller.Visible := True;
  654.     ShowWindow(Scroller.Handle, SW_SHOW);
  655.     Scroller.Min := 0;
  656.     Scroller.Max := Tabs.Count - VisibleTabs;
  657.     Scroller.Position := FirstIndex;
  658.   end
  659.   else
  660.     if VisibleTabs >= Tabs.Count then
  661.     begin
  662.       Scroller.Visible := False;
  663.       ShowWindow(Scroller.Handle, SW_HIDE);
  664.     end;
  665.  
  666.   if FDoFix then
  667.   begin
  668.     FixTabPos;
  669.     FVisibleTabs := CalcTabPositions(TabStart, LastTabPos, MemBitmap.Canvas,
  670.       FirstIndex);
  671.   end;
  672.   FDoFix := False;
  673.  
  674.   { draw background of tab area }
  675.   with MemBitmap.Canvas do
  676.   begin
  677.     Brush.Bitmap := BrushBitmap;
  678.     FillRect(Rect(0, 0, MemBitmap.Width, MemBitmap.Height));
  679.  
  680.     Pen.Width := 1;
  681.     Pen.Color := clBtnShadow;
  682.     MoveTo(0, 0);
  683.     LineTo(MemBitmap.Width + 1, 0);
  684.  
  685.     Pen.Color := clWindowFrame;
  686.     MoveTo(0, 1);
  687.     LineTo(MemBitmap.Width + 1, 1);
  688.   end;
  689.  
  690.   for Tab := 0 to TabPositions.Count - 1 do
  691.   begin
  692.     Pointer(TabPos) := TabPositions[Tab];
  693.  
  694.     isFirst := Tab = 0;
  695.     isLast := Tab = VisibleTabs - 1;
  696.     isSelected := Tab + FirstIndex = TabIndex;
  697.     isPrevSelected := (Tab + FirstIndex) - 1 = TabIndex;
  698.  
  699.     { Rule: every tab paints its leading edge, only the last tab paints a
  700.       trailing edge }
  701.     Trailing := etNone;
  702.  
  703.     if isLast then
  704.     begin
  705.       if isSelected then Trailing := etLastIsSel
  706.       else Trailing := etLastNotSel;
  707.     end;
  708.  
  709.     if isFirst then
  710.     begin
  711.       if isSelected then Leading := etFirstIsSel
  712.       else Leading := etFirstNotSel;
  713.     end
  714.     else  { not first }
  715.     begin
  716.       if isPrevSelected then Leading := etSelToNotSel
  717.       else
  718.         if isSelected then Leading := etNotSelToSel
  719.         else Leading := etNotSelToNotSel;
  720.     end;
  721.  
  722.     { draw leading edge }
  723.     if Leading <> etNone then
  724.       PaintEdge(TabPos.StartPos - EdgeWidth, 0, FTabHeight - 1, Leading);
  725.  
  726.     { set up the canvas }
  727.     R := Rect(TabPos.StartPos, 0, TabPos.StartPos + TabPos.Size, FTabHeight);
  728.     with MemBitmap.Canvas do
  729.     begin
  730.       if isSelected then Brush.Color := SelectedColor
  731.       else Brush.Color := UnselectedColor;
  732.       ExtTextOut(Handle, TabPos.StartPos, 2, ETO_OPAQUE, @R,
  733.         nil, 0, nil);
  734.     end;
  735.  
  736.     { restore font for drawing the text }
  737.     MemBitmap.Canvas.Font := Self.Canvas.Font;
  738.  
  739.     { Owner }
  740.     if (FStyle = tsOwnerDraw) then
  741.       DrawTab(MemBitmap.Canvas, R, Tab + FirstIndex, isSelected)
  742.     else
  743.     begin
  744.       with MemBitmap.Canvas do
  745.       begin
  746.         Inc(R.Top, 2);
  747.         DrawText(Handle, PChar(Tabs[Tab + FirstIndex]),
  748.           Length(Tabs[Tab + FirstIndex]), R, DT_CENTER);
  749.       end;
  750.     end;
  751.  
  752.     { draw trailing edge  }
  753.     if Trailing <> etNone then
  754.       PaintEdge(TabPos.StartPos + TabPos.Size, 0, FTabHeight - 1, Trailing);
  755.  
  756.     { draw connecting lines above and below the text }
  757.  
  758.     with MemBitmap.Canvas do
  759.     begin
  760.       Pen.Color := clWindowFrame;
  761.       MoveTo(TabPos.StartPos, FTabHeight - 1);
  762.       LineTo(TabPos.StartPos + TabPos.Size, FTabHeight - 1);
  763.  
  764.       if isSelected then
  765.       begin
  766.         Pen.Color := clBtnShadow;
  767.         MoveTo(TabPos.StartPos, FTabHeight - 2);
  768.         LineTo(TabPos.StartPos + TabPos.Size, FTabHeight - 2);
  769.       end
  770.       else
  771.       begin
  772.         Pen.Color := clWindowFrame;
  773.         MoveTo(TabPos.StartPos, 1);
  774.         LineTo(TabPos.StartPos + TabPos.Size, 1);
  775.  
  776.         Pen.Color := clBtnShadow;
  777.         MoveTo(TabPos.StartPos, 0);
  778.         LineTo(TabPos.StartPos + TabPos.Size + 1, 0);
  779.       end;
  780.     end;
  781.   end;
  782.  
  783.   { draw onto the screen }
  784.   Canvas.Draw(0, 0, MemBitmap);
  785. end;
  786.  
  787. procedure TTabSet.CreateEdgeParts;
  788. var
  789.   H: Integer;
  790.   Working: TBitmap;
  791.   EdgePart: TEdgePart;
  792.   MaskColor: TColor;
  793.  
  794.   procedure DrawUL(Canvas: TCanvas);
  795.   begin
  796.     with Canvas do
  797.     begin
  798.       Pen.Color := clBtnShadow;
  799.       PolyLine([Point(0, 0), Point(EdgeWidth + 1, 0)]);
  800.  
  801.       Pen.Color := UnselectedColor;
  802.       Brush.Color := UnselectedColor;
  803.       Polygon([Point(3,1), Point(EdgeWidth - 1, H), Point(EdgeWidth, H),
  804.         Point(EdgeWidth, 1), Point(3, 1)]);
  805.  
  806.       Pen.Color := clWindowFrame;
  807.       PolyLine([Point(0, 1), Point(EdgeWidth + 1, 1), Point(3, 1),
  808.         Point(EdgeWidth - 1, H), Point(EdgeWidth, H)]);
  809.     end;
  810.   end;
  811.  
  812.   procedure DrawSR(Canvas: TCanvas);
  813.   begin
  814.     with Canvas do
  815.     begin
  816.       Pen.Color := SelectedColor;
  817.       Brush.Color := SelectedColor;
  818.       Polygon([Point(EdgeWidth - 3, 1), Point(2, H), Point(0, H),
  819.         Point(0, 0), Point(EdgeWidth + 1, 0)]);
  820.  
  821.       Pen.Color := clBtnShadow;
  822.       PolyLine([Point(EdgeWidth - 3, 0), Point(EdgeWidth + 1, 0),
  823.         Point(EdgeWidth - 3, 1), Point(1, H), Point(0, H - 2)]);
  824.  
  825.       Pen.Color := clWindowFrame;
  826.       PolyLine([Point(EdgeWidth, 1), Point(EdgeWidth - 2, 1), Point(2, H),
  827.         Point(-1, H)]);
  828.     end;
  829.   end;
  830.  
  831.   procedure DrawSL(Canvas: TCanvas);
  832.   begin
  833.     with Canvas do
  834.     begin
  835.       Pen.Color := SelectedColor;
  836.       Brush.Color := SelectedColor;
  837.       Polygon([Point(3, 0), Point(EdgeWidth - 1, H), Point(EdgeWidth, H),
  838.         Point(EdgeWidth, 0), Point(3, 0)]);
  839.  
  840.       Pen.Color := clBtnShadow;
  841.       PolyLine([Point(0, 0), Point(4, 0)]);
  842.  
  843.       Pen.Color := clBtnHighlight;
  844.       PolyLine([Point(4, 1), Point(EdgeWidth, H + 1)]);
  845.  
  846.       Pen.Color := clWindowFrame;
  847.       PolyLine([Point(0, 1), Point(3, 1), Point(EdgeWidth - 1, H),
  848.         Point(EdgeWidth, H)]);
  849.     end;
  850.   end;
  851.  
  852.   procedure DrawUR(Canvas: TCanvas);
  853.   begin
  854.     with Canvas do
  855.     begin
  856.       Pen.Color := clBtnShadow;
  857.       PolyLine([Point(-1, 0), Point(EdgeWidth + 1, 0)]);
  858.  
  859.       Pen.Color := UnselectedColor;
  860.       Brush.Color := UnselectedColor;
  861.       Polygon([Point(EdgeWidth - 3, 1), Point(1, H), Point(0, H),
  862.         Point(0, 1), Point(EdgeWidth - 3, 1)]);
  863.  
  864.       { workaround for bug in S3 driver }
  865.       Pen.Color := clBtnShadow;
  866.       PolyLine([Point(-1, 0), Point(EdgeWidth + 1, 0)]);
  867.  
  868.       Pen.Color := clWindowFrame;
  869.       PolyLine([Point(0, 1), Point(EdgeWidth + 1, 1), Point(EdgeWidth - 2, 1),
  870.         Point(2, H), Point(-1, H)]);
  871.     end;
  872.   end;
  873.  
  874. var
  875.   TempList: TImageList;
  876.   SaveHeight: Integer;
  877. begin
  878.   MemBitmap.Canvas.Font := Font;
  879.  
  880.   { Owner }
  881.   SaveHeight := FTabHeight;
  882.   try
  883.     if FStyle = tsOwnerDraw then FTabHeight := FOwnerDrawHeight
  884.     else FTabHeight := MemBitmap.Canvas.TextHeight('T') + 4;
  885.  
  886.     H := FTabHeight - 1;
  887.  
  888.     TempList := TImageList.CreateSize(EdgeWidth, FTabHeight); {exceptions}
  889.   except
  890.     FTabHeight := SaveHeight;
  891.     raise;
  892.   end;
  893.   ImageList.Free;
  894.   ImageList := TempList;
  895.  
  896.   Working := TBitmap.Create;
  897.   try
  898.     Working.Width := EdgeWidth;
  899.     Working.Height := FTabHeight;
  900.     MaskColor := clOlive;
  901.  
  902.     for EdgePart := Low(TEdgePart) to High(TEdgePart) do
  903.     begin
  904.       with Working.Canvas do
  905.       begin
  906.         Brush.Color := MaskColor;
  907.         Brush.Style := bsSolid;
  908.         FillRect(Rect(0, 0, EdgeWidth, FTabHeight));
  909.       end;
  910.       case EdgePart of
  911.         epSelectedLeft: DrawSL(Working.Canvas);
  912.         epUnselectedLeft: DrawUL(Working.Canvas);
  913.         epSelectedRight: DrawSR(Working.Canvas);
  914.         epUnselectedRight: DrawUR(Working.Canvas);
  915.       end;
  916.       ImageList.AddMasked(Working, MaskColor);
  917.     end;
  918.   finally
  919.     Working.Free;
  920.   end;
  921. end;
  922.  
  923. procedure TTabSet.PaintEdge(X, Y, H: Integer; Edge: TEdgeType);
  924. begin
  925.   MemBitmap.Canvas.Brush.Color := clWhite;
  926.   MemBitmap.Canvas.Font.Color := clBlack;
  927.   case Edge of
  928.     etFirstIsSel:
  929.       ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epSelectedLeft));
  930.     etLastIsSel:
  931.       ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epSelectedRight));
  932.     etFirstNotSel:
  933.       ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epUnselectedLeft));
  934.     etLastNotSel:
  935.       ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epUnselectedRight));
  936.     etNotSelToSel:
  937.       begin
  938.         ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epUnselectedRight));
  939.          ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epSelectedLeft));
  940.       end;
  941.     etSelToNotSel:
  942.       begin
  943.         ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epUnselectedLeft));
  944.          ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epSelectedRight));
  945.       end;
  946.     etNotSelToNotSel:
  947.       begin
  948.         ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epUnselectedLeft));
  949.          ImageList.Draw(MemBitmap.Canvas, X, Y, Ord(epUnselectedRight));
  950.       end;
  951.   end;
  952. end;
  953.  
  954. procedure TTabSet.CreateBrushPattern(Bitmap: TBitmap);
  955. var
  956.   X, Y: Integer;
  957. begin
  958.   Bitmap.Width := 8;
  959.   Bitmap.Height := 8;
  960.   with Bitmap.Canvas do
  961.   begin
  962.     Brush.Style := bsSolid;
  963.     Brush.Color := FBackgroundColor;
  964.     FillRect(Rect(0, 0, Width, Height));
  965.     if FDitherBackground then
  966.       for Y := 0 to 7 do
  967.         for X := 0 to 7 do
  968.           if (Y mod 2) = (X mod 2) then  { toggles between even/odd pixles }
  969.             Pixels[X, Y] := clWhite;     { on even/odd rows }
  970.   end;
  971. end;
  972.  
  973. procedure TTabSet.FixTabPos;
  974. var
  975.   FLastVisibleTab: Integer;
  976.  
  977.   function GetRightSide: Integer;
  978.   begin
  979.     Result := Width - EndMargin;
  980.     if AutoScroll and (FVisibleTabs < Tabs.Count - 1) then
  981.       Dec(Result, Scroller.Width + 4);
  982.   end;
  983.  
  984.   function ReverseCalcNumTabs(Start, Stop: Integer; Canvas: TCanvas;
  985.     Last: Integer): Integer;
  986.   var
  987.     W: Integer;
  988.   begin
  989.     if HandleAllocated then
  990.     begin
  991.       Result := Last;
  992.       while (Start >= Stop) and (Result >= 0) do
  993.         with Canvas do
  994.         begin
  995.           W := TextWidth(Tabs[Result]);
  996.           if (FStyle = tsOwnerDraw) then MeasureTab(Result, W);
  997.           Dec(Start, W + EdgeWidth);    { next usable position }
  998.           if Start >= Stop then Dec(Result);
  999.         end;
  1000.      if (Start < Stop) or (Result < 0) then Inc(Result);
  1001.     end else Result := FFirstIndex;
  1002.   end;
  1003.  
  1004. begin
  1005.   if Tabs.Count > 0 then
  1006.   begin
  1007.     FLastVisibleTab := FFirstIndex + FVisibleTabs - 1;
  1008.     if FTabIndex > FLastVisibleTab then
  1009.       FFirstIndex := ReverseCalcNumTabs(GetRightSide, StartMargin + EdgeWidth,
  1010.         Canvas, FTabIndex)
  1011.     else if (FTabIndex >= 0) and (FTabIndex < FFirstIndex) then
  1012.       FFirstIndex := FTabIndex;
  1013.   end;
  1014. end;
  1015.  
  1016. procedure TTabSet.SetSelectedColor(Value: TColor);
  1017. begin
  1018.   if Value <> FSelectedColor then
  1019.   begin
  1020.     FSelectedColor := Value;
  1021.     CreateEdgeParts;
  1022.     Invalidate;
  1023.   end;
  1024. end;
  1025.  
  1026. procedure TTabSet.SetUnselectedColor(Value: TColor);
  1027. begin
  1028.   if Value <> FUnselectedColor then
  1029.   begin
  1030.     FUnselectedColor := Value;
  1031.     CreateEdgeParts;
  1032.     Invalidate;
  1033.   end;
  1034. end;
  1035.  
  1036. procedure TTabSet.SetBackgroundColor(Value: TColor);
  1037. begin
  1038.   if Value <> FBackgroundColor then
  1039.   begin
  1040.     FBackgroundColor := Value;
  1041.     CreateBrushPattern(BrushBitmap);
  1042.     MemBitmap.Canvas.Brush.Style := bsSolid;
  1043.     Invalidate;
  1044.   end;
  1045. end;
  1046.  
  1047. procedure TTabSet.SetDitherBackground(Value: Boolean);
  1048. begin
  1049.   if Value <> FDitherBackground then
  1050.   begin
  1051.     FDitherBackground := Value;
  1052.     CreateBrushPattern(BrushBitmap);
  1053.     MemBitmap.Canvas.Brush.Style := bsSolid;
  1054.     Invalidate;
  1055.   end;
  1056. end;
  1057.  
  1058. procedure TTabSet.SetAutoScroll(Value: Boolean);
  1059. begin
  1060.   if Value <> FAutoScroll then
  1061.   begin
  1062.     FAutoScroll := Value;
  1063.     Scroller.Visible := False;
  1064.     ShowWindow(Scroller.Handle, SW_HIDE);
  1065.     Invalidate;
  1066.   end;
  1067. end;
  1068.  
  1069. procedure TTabSet.SetStartMargin(Value: Integer);
  1070. begin
  1071.   if Value <> FStartMargin then
  1072.   begin
  1073.     FStartMargin := Value;
  1074.     Invalidate;
  1075.   end;
  1076. end;
  1077.  
  1078. procedure TTabSet.SetEndMargin(Value: Integer);
  1079. begin
  1080.   if Value <> FEndMargin then
  1081.   begin
  1082.     FEndMargin := Value;
  1083.     Invalidate;
  1084.   end;
  1085. end;
  1086.  
  1087. function TTabSet.CanChange(NewIndex: Integer): Boolean;
  1088. begin
  1089.   Result := True;
  1090.   if Assigned(FOnChange) then
  1091.     FOnChange(Self, NewIndex, Result);
  1092. end;
  1093.  
  1094. procedure TTabSet.SetTabIndex(Value: Integer);
  1095. begin
  1096.   if Value <> FTabIndex then
  1097.   begin
  1098.     if (Value < -1) or (Value >= Tabs.Count) then
  1099.       raise Exception.CreateRes(@SInvalidTabIndex);
  1100.     if CanChange(Value) then
  1101.     begin
  1102.       FTabIndex := Value;
  1103.       FixTabPos;
  1104.       Click;
  1105.       Invalidate;
  1106.     end;
  1107.   end;
  1108. end;
  1109.  
  1110. procedure TTabSet.SelectNext(Direction: Boolean);
  1111. var
  1112.   NewIndex: Integer;
  1113. begin
  1114.   if Tabs.Count > 1 then
  1115.   begin
  1116.     NewIndex := TabIndex;
  1117.     if Direction then
  1118.       Inc(NewIndex)
  1119.     else Dec(NewIndex);
  1120.     if NewIndex = Tabs.Count then
  1121.       NewIndex := 0
  1122.     else if NewIndex < 0 then
  1123.       NewIndex := Tabs.Count - 1;
  1124.     SetTabIndex(NewIndex);
  1125.   end;
  1126. end;
  1127.  
  1128. procedure TTabSet.SetFirstIndex(Value: Integer);
  1129. begin
  1130.   if (Value >= 0) and (Value < Tabs.Count) then
  1131.   begin
  1132.     FFirstIndex := Value;
  1133.     Invalidate;
  1134.   end;
  1135. end;
  1136.  
  1137. procedure TTabSet.SetTabList(Value: TStrings);
  1138. begin
  1139.   FTabs.Assign(Value);
  1140.   FTabIndex := -1;
  1141.   if FTabs.Count > 0 then TabIndex := 0
  1142.   else Invalidate;
  1143. end;
  1144.  
  1145. {function TTabSet.GetTabCount: Integer;
  1146. begin
  1147.   Result := FTabs.Count;
  1148. end;
  1149.  
  1150. function TTabSet.GetTabName(Value: Integer): String;
  1151. begin
  1152.   if (Value >= 0) and (Value < Tabs.Count) then Result := Tabs[Value]
  1153.   else Result := '';
  1154. end;
  1155.  
  1156. procedure TTabSet.SetTabName(Value: Integer; const AName: String);
  1157. begin
  1158.   if (Value >= 0) and (Value < Tabs.Count) and (GetTabName(Value) <> AName) then
  1159.     Tabs[Value] := AName;
  1160. end;}
  1161.  
  1162. procedure TTabSet.SetTabStyle(Value: TTabStyle);
  1163. begin
  1164.   if Value <> FStyle then
  1165.   begin
  1166.     FStyle := Value;
  1167.     CreateEdgeParts;
  1168.     Invalidate;
  1169.   end;
  1170. end;
  1171.  
  1172. procedure TTabSet.SetTabHeight(Value: Integer);
  1173. var
  1174.   SaveHeight: Integer;
  1175. begin
  1176.   if Value <> FOwnerDrawHeight then
  1177.   begin
  1178.     SaveHeight := FOwnerDrawHeight;
  1179.     try
  1180.       FOwnerDrawHeight := Value;
  1181.       CreateEdgeParts;
  1182.       Invalidate;
  1183.     except
  1184.       FOwnerDrawHeight := SaveHeight;
  1185.       raise;
  1186.     end;
  1187.   end;
  1188. end;
  1189.  
  1190. procedure TTabSet.DrawTab(TabCanvas: TCanvas; R: TRect; Index: Integer;
  1191.   Selected: Boolean);
  1192. begin
  1193.   if Assigned(FOnDrawTab) then
  1194.     FOnDrawTab(Self, TabCanvas, R, Index, Selected);
  1195. end;
  1196.  
  1197. procedure TTabSet.GetChildren(Proc: TGetChildProc; Root: TComponent);
  1198. begin
  1199. end;
  1200.  
  1201. procedure TTabSet.MeasureTab(Index: Integer; var TabWidth: Integer);
  1202. begin
  1203.   if Assigned(FOnMeasureTab) then
  1204.     FOnMeasureTab(Self, Index, TabWidth);
  1205. end;
  1206.  
  1207. procedure TTabSet.MouseDown(Button: TMouseButton; Shift: TShiftState;
  1208.   X, Y: Integer);
  1209. var
  1210.   TabPos: TTabPos;
  1211.   I: Integer;
  1212.   Extra: Integer;
  1213.   MinLeft: Integer;
  1214.   MaxRight: Integer;
  1215. begin
  1216.   inherited MouseDown(Button, Shift, X, Y);
  1217.   if (Button = mbLeft) and (Y <= FTabHeight) then
  1218.   begin
  1219.     if Y < FTabHeight div 2 then Extra := EdgeWidth div 3
  1220.     else Extra := EdgeWidth div 2;
  1221.  
  1222.     for I := 0 to TabPositions.Count - 1 do
  1223.     begin
  1224.       Pointer(TabPos) := TabPositions[I];
  1225.       MinLeft := TabPos.StartPos - Extra;
  1226.       MaxRight := TabPos.StartPos + TabPos.Size + Extra;
  1227.       if (X >= MinLeft) and (X <= MaxRight) then
  1228.       begin
  1229.         SetTabIndex(FirstIndex + I);
  1230.         Break;
  1231.       end;
  1232.     end;
  1233.   end;
  1234. end;
  1235.  
  1236. procedure TTabSet.WMSize(var Message: TWMSize);
  1237. var
  1238.   NumVisTabs, LastTabPos: Integer;
  1239.  
  1240.   function CalcNumTabs(Start, Stop: Integer; Canvas: TCanvas;
  1241.     First: Integer): Integer;
  1242.   var
  1243.     W: Integer;
  1244.   begin
  1245.     Result := First;
  1246.     while (Start < Stop) and (Result < Tabs.Count) do
  1247.       with Canvas do
  1248.       begin
  1249.         W := TextWidth(Tabs[Result]);
  1250.         if (FStyle = tsOwnerDraw) then MeasureTab(Result, W);
  1251.         Inc(Start, W + EdgeWidth);    { next usable position }
  1252.         if Start <= Stop then Inc(Result);
  1253.       end;
  1254.   end;
  1255.  
  1256. begin
  1257.   inherited;
  1258.   if Tabs.Count > 1 then
  1259.   begin
  1260.     LastTabPos := Width - EndMargin;
  1261.     NumVisTabs := CalcNumTabs(StartMargin + EdgeWidth, LastTabPos, Canvas, 0);
  1262.     if (FTabIndex = Tabs.Count) or (NumVisTabs > FVisibleTabs) or
  1263.       (NumVisTabs = Tabs.Count) then FirstIndex := Tabs.Count - NumVisTabs;
  1264.     FDoFix := True;
  1265.   end;
  1266.   Invalidate;
  1267. end;
  1268.  
  1269. procedure TTabSet.CMSysColorChange(var Message: TMessage);
  1270. begin
  1271.   inherited;
  1272.   CreateEdgeParts;
  1273.   CreateBrushPattern(BrushBitmap);
  1274.   MemBitmap.Canvas.Brush.Style := bsSolid;
  1275.   { Windows follows this message with a WM_PAINT }
  1276. end;
  1277.  
  1278. procedure TTabSet.CMFontChanged(var Message: TMessage);
  1279. begin
  1280.   inherited;
  1281.   Canvas.Font := Font;
  1282.   CreateEdgeParts;
  1283.   Invalidate;
  1284. end;
  1285.  
  1286. procedure TTabSet.WMGetDlgCode(var Message: TWMGetDlgCode);
  1287. begin
  1288.   Message.Result := DLGC_WANTALLKEYS;
  1289. end;
  1290.  
  1291. procedure TTabSet.CMDialogChar(var Message: TCMDialogChar);
  1292. var
  1293.   I: Integer;
  1294. begin
  1295.   for I := 0 to FTabs.Count - 1 do
  1296.   begin
  1297.     if IsAccel(Message.CharCode, FTabs[I]) then
  1298.     begin
  1299.       Message.Result := 1;
  1300.       if FTabIndex <> I then
  1301.         SetTabIndex(I);
  1302.       Exit;
  1303.     end;
  1304.   end;
  1305.   inherited;
  1306. end;
  1307.  
  1308. procedure TTabSet.DefineProperties(Filer: TFiler);
  1309. begin
  1310.   { Can be removed after version 1.0 }
  1311.   if Filer is TReader then inherited DefineProperties(Filer);
  1312.   Filer.DefineProperty('TabOrder', ReadIntData, nil, False);
  1313.   Filer.DefineProperty('TabStop', ReadBoolData, nil, False);
  1314. end;
  1315.  
  1316. procedure TTabSet.ReadIntData(Reader: TReader);
  1317. begin
  1318.   Reader.ReadInteger;
  1319. end;
  1320.  
  1321. procedure TTabSet.ReadBoolData(Reader: TReader);
  1322. begin
  1323.   Reader.ReadBoolean;
  1324. end;
  1325.  
  1326. end.
  1327.  
  1328.