home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 April / Chip_1997-04_cd.bin / prezent / cb / data.z / TABS.PAS < prev    next >
Pascal/Delphi Source File  |  1997-01-16  |  36KB  |  1,321 lines

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