home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / RUNIMAGE / DELPHI30 / SOURCE / VCL / TABS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-03  |  35.3 KB  |  1,320 lines

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