1 { $Id: $}
2 { --------------------------------------------
3 cocoatabcontrols.pas - Cocoa internal classes
4 --------------------------------------------
5
6 This unit contains the private classhierarchy for the Cocoa implemetations
7
8 *****************************************************************************
9 This file is part of the Lazarus Component Library (LCL)
10
11 See the file COPYING.modifiedLGPL.txt, included in this distribution,
12 for details about the license.
13 *****************************************************************************
14 }
15 unit CocoaTabControls;
16
17 {$mode objfpc}{$H+}
18 {$modeswitch objectivec1}
19 {$modeswitch objectivec2}
20 {$interfaces corba}
21 {$include cocoadefines.inc}
22
23 interface
24
25 uses
26 // rtl+ftl
27 Types, Classes, SysUtils,
28 CGGeometry,
29 // Libs
30 MacOSAll, CocoaAll, CocoaUtils, //CocoaGDIObjects,
31 cocoa_extra, CocoaPrivate;
32
33 type
34
35 ITabControlCallback = interface(ICommonCallback)
36 procedure willSelectTabViewItem(aTabIndex: Integer);
37 procedure didSelectTabViewItem(aTabIndex: Integer);
38 end;
39
40 { TCocoaTabPage }
41
42 TCocoaTabPage = objcclass(NSTabViewItem)
43 public
44 callback: ICommonCallback;
lclGetCallbacknull45 function lclGetCallback: ICommonCallback; override;
46 procedure lclClearCallback; override;
lclFramenull47 function lclFrame: TRect; override;
lclClientFramenull48 function lclClientFrame: TRect; override;
49 procedure setLabel(label__: NSString); override;
50 end;
51
52 { TCocoaTabControl }
53
54 TCocoaTabControl = objcclass(NSTabView, NSTabViewDelegateProtocol)
55 private
56 prevarr : NSButton;
57 nextarr : NSButton;
58
59 public
60 leftmost : Integer; // index of the left-most tab shown
61 ignoreChange: Boolean;
62 callback: ITabControlCallback;
63
64 fulltabs : NSMutableArray; // the full list of NSTabViewItems
65 lclEnabled: Boolean;
66 // cocoa
allocnull67 class function alloc: id; override;
68 procedure setFrame(aframe: NSRect); override;
69 // lcl
lclIsEnablednull70 function lclIsEnabled: Boolean; override;
71 procedure lclSetEnabled(AEnabled: Boolean); override;
lclGetCallbacknull72 function lclGetCallback: ICommonCallback; override;
73 procedure lclClearCallback; override;
lclClientFramenull74 function lclClientFrame: TRect; override;
lclGetFrameToLayoutDeltanull75 function lclGetFrameToLayoutDelta: TRect; override;
76 // NSTabViewDelegateProtocol
tabView_shouldSelectTabViewItemnull77 function tabView_shouldSelectTabViewItem(tabView: NSTabView; tabViewItem: NSTabViewItem): Boolean; message 'tabView:shouldSelectTabViewItem:';
78 procedure tabView_willSelectTabViewItem(tabView: NSTabView; tabViewItem: NSTabViewItem); message 'tabView:willSelectTabViewItem:';
79 procedure tabView_didSelectTabViewItem(tabView: NSTabView; tabViewItem: NSTabViewItem); message 'tabView:didSelectTabViewItem:';
80 procedure tabViewDidChangeNumberOfTabViewItems(TabView: NSTabView); message 'tabViewDidChangeNumberOfTabViewItems:';
81 // mouse events
82 procedure mouseDown(event: NSEvent); override;
83 procedure mouseUp(event: NSEvent); override;
84 procedure rightMouseDown(event: NSEvent); override;
85 procedure rightMouseUp(event: NSEvent); override;
86 procedure rightMouseDragged(event: NSEvent); override;
87 procedure otherMouseDown(event: NSEvent); override;
88 procedure otherMouseUp(event: NSEvent); override;
89 procedure otherMouseDragged(event: NSEvent); override;
90 procedure mouseDragged(event: NSEvent); override;
91 procedure mouseMoved(event: NSEvent); override;
92 // lcl
93 procedure exttabInsertTabViewItem_atIndex(lTabPage: NSTabViewItem; AIndex: integer);
94 message 'exttabInsertTabViewItem:atIndex:';
95 procedure exttabRemoveTabViewItem(lTabPage: NSTabViewItem);
96 message 'exttabRemoveTabViewItem:';
exttabIndexOfTabViewItemnull97 function exttabIndexOfTabViewItem(lTabPage: NSTabViewItem): NSInteger;
98 message 'exttabIndexOfTabViewItem:';
99 procedure extTabPrevButtonClick(sender: id);
100 message 'extTabPrevButtonClick:';
101 procedure extTabNextButtonClick(sender: id);
102 message 'extTabNextButtonClick:';
103 procedure extselectTabViewItemAtIndex(index: NSInteger);
104 message 'extselectTabViewItemAtIndex:';
105 end;
106
107 { TCocoaTabPageView }
108
109 TCocoaTabPageView = objcclass(TCocoaCustomControl)
110 public
111 tabView: TCocoaTabControl;
112 tabPage: TCocoaTabPage;
113 procedure setFrame(arect: NSRect); override;
114 end;
115
IndexOfTabnull116 function IndexOfTab(ahost: TCocoaTabControl; atab: NSTabViewItem): Integer;
117
attemptsnull118 // Hack: The function attempts to determine the tabs view
119 // if the view is found it would return its frame rect in LCL coordinates
120 // if the view cannot be determinted, the function returns false
121 // This is implemented as ObjC method, because "prevarr" and "nextarr"
122 // are private methods.
123 // It's unknown, if it's safe to cache the result, so the search is performed
124 // everytime
125 function GetTabsRect(tabs: TCocoaTabControl; var r: TRect): Boolean;
126
127 implementation
128
GetTabsRectnull129 function GetTabsRect(tabs: TCocoaTabControl; var r: TRect): Boolean;
130 var
131 i : integer;
132 sv : NSView;
133 f : NSRect;
134 begin
135 Result:=Assigned(tabs);
136 if not Result then Exit;
137
138 for i:=0 to Integer(tabs.subviews.count)-1 do
139 begin
140 sv:=NSView(tabs.subviews.objectAtIndex(i));
141 if not Assigned(sv)
142 or (sv = tabs.nextarr)
143 or (sv = tabs.prevarr)
144 or (sv.isKindOfClass(TCocoaTabPageView))
145 then Continue;
146
147 f := sv.frame;
148 if tabs.isFlipped then
149 r := NSRectToRect( f )
150 else
151 NSToLCLRect( f, tabs.frame.size.height, r );
152 Result := true;
153 Exit;
154 end;
155 Result:=false;
156 end;
157
AllocArrowButtonnull158 function AllocArrowButton(isPrev: Boolean): NSButton;
159 var
160 btn : NSButton;
161 r : NSRect;
162 begin
163 btn:=NSButton(NSButton.alloc).initWithFrame(NSZeroRect);
164 btn.setBezelStyle(NSRegularSquareBezelStyle);
165 btn.setButtonType(NSMomentaryLightButton);
166
167 if isPrev then
168 btn.setImage( NSImage.imageNamed( NSImageNameLeftFacingTriangleTemplate ))
169 else
170 btn.setImage( NSImage.imageNamed( NSImageNameRightFacingTriangleTemplate ));
171
172 {$ifdef BOOLFIX}
173 btn.setBordered_(Ord(false));
174 {$else}
175 btn.setBordered(false);
176 {$endif}
177 btn.setTitle(NSString.string_);
178 btn.sizeToFit();
179 if not isPrev then btn.setAutoresizingMask(NSViewMinXMargin);
180 Result:=btn;
181 end;
182
183 const
184 arrow_hofs = 12;
185 arrow_vofs = 20;
186
187 procedure PlaceButton(isPrev: Boolean; abtn: NSButton; dst: NSTabView);
188 var
189 org: NSPoint;
190 begin
191 if not assigned(abtn) then Exit;
192
193 if isPrev then org:=NSMakePoint(arrow_hofs, arrow_vofs)
194 else org:=NSMakePoint(dst.frame.size.width - abtn.frame.size.width - arrow_hofs , arrow_vofs);
195
196 abtn.setFrameOrigin(org);
197 end;
198
199
200 procedure AllocPrevNext(aview: TCocoaTabControl);
201 begin
202 aview.prevarr := AllocArrowButton(true);
203 aview.addSubview(aview.prevarr);
204 aview.nextarr := AllocArrowButton(false);
205 aview.addSubview(aview.nextarr);
206 aview.prevarr.setTarget(aview);
207 aview.prevarr.setAction( ObjCSelector('extTabPrevButtonClick:'));
208 aview.nextarr.setTarget(aview);
209 aview.nextarr.setAction( ObjCSelector('extTabNextButtonClick:'));
210
211
212 PlaceButton(true, aview.prevarr, aview);
213 PlaceButton(false, aview.nextarr, aview);
214 end;
215
216 procedure RemoveAllTabs(aview: TCocoaTabControl);
217 var
218 arr: NSArray;
219 i : integer;
220 begin
221 arr := aview.tabViewItems;
222 for i := Integer(arr.count) - 1 downto 0 do
223 aview.removeTabViewItem( arr.objectAtIndex(i) );
224 end;
225
226 procedure AttachAllTabs(aview: TCocoaTabControl);
227 var
228 i : integer;
229 begin
230 RemoveAllTabs(aview);
231 for i := 0 to aview.fulltabs.count - 1 do
232 aview.insertTabViewItem_atIndex( aview.fulltabs.objectAtIndex(i), i);
233 end;
234
235 procedure ReviseTabs(aview: TCocoaTabControl; out ShowPrev,ShowNext: Boolean);
236 var
237 minw: double;
238 i: integer;
239 arr: NSArray;
240 vi : NSTabViewItem;
241 sz : NSSize;
242 x,y: integer;
243 lw : double;
244 tbext : double;
245 lwid : array of double;
246 xd : double;
247 j : integer;
248 ofs : integer;
249 frw: double;
250 sel: NSTabViewItem;
251 v : NSView;
252 begin
253 ShowPrev := false;
254 ShowNext := false;
255
256 sel := aview.selectedTabViewItem;
257 try
258 if (aview.fulltabs.count>aview.tabViewItems.count) then
259 AttachAllTabs(aview);
260
261 minw := aview.minimumSize.width;
262 if (minw<aview.frame.size.width) then Exit;
263
264 arr := aview.tabViewItems;
265
266 lw := 0;
267 SetLength(lwid, arr.count);
268 for i := 0 to arr.count - 1 do
269 begin
270 vi := NSTabViewItem( arr.objectAtIndex(i) );
271 sz := vi.sizeOfLabel(false);
272 lw := lw + sz.width;
273 lwid[i] := sz.width;
274 end;
275
276 tbext := (minw - lw) / arr.count;
277 for i:=0 to length(lwid)-1 do
278 lwid[i] := lwid[i] + tbext;
279
280 ofs := aview.leftmost;
281 if ofs>=length(lwid) then ofs:=length(lwid)-1;
282 if (ofs < 0) then Exit;
283 ShowPrev := ofs > 0;
284
285
286 xd := lwid[ofs];
287 frw := aview.frame.size.width;
288 frw := frw - ((arrow_hofs + aview.nextarr.frame.size.width) * 2);
289 if frw<0 then frw := 0;
290
291 //aview.prevarr.isHidden((aview.leftmost=0));
292
293 for i := ofs+1 to length(lwid)-1 do begin
294 if xd + lwid[i] > frw then begin
295 //aview.nextarr.isHidden((aview.leftmost=0));
296 for j:=length(lwid)-1 downto i do
297 aview.removeTabViewItem( arr.objectAtIndex(j));
298 ShowNext := true;
299 Break;
300 end;
301 xd := xd + lwid[i];
302 end;
303
304 if not ShowNext then begin
305 // shown all right-side tabs, there might be a tab, that can be shown on the left
306 while (ofs>0) and (xd+lwid[ofs]<frw) do begin
307 xd := xd + lwid[ofs];
308 dec(ofs);
309 end;
310 aview.leftmost:=ofs;
311 end;
312
313 for i := ofs - 1 downto 0 do
314 aview.removeTabViewItem( arr.objectAtIndex(i));
315
316 // todo: automatic resizing still has its effect on the tabs.
317 // the content page fails to pick up the proper size and place
318 // and it seems that the content of the tab is shifted.
319 // Needs investiage and a fix.
320
321 finally
322 if (aview.indexOfTabViewItem(sel)<>NSNotFound) then
323 aview.selectTabViewItem(sel);
324 end;
325 end;
326
327 procedure UpdateTabAndArrowVisibility(aview: TCocoaTabControl);
328 var
329 showNext : Boolean;
330 showPrev : Boolean;
331 begin
332 ReviseTabs(aview, showPrev, showNExt);
333 if Assigned(aview.prevarr) then
334 {$ifdef BOOLFIX}
335 aview.prevarr.setHidden_(Ord(not showPrev));
336 {$else}
337 aview.prevarr.setHidden(not showPrev);
338 {$endif}
339 if Assigned(aview.nextarr) then
340 {$ifdef BOOLFIX}
341 aview.nextarr.setHidden_(Ord(not showNext));
342 {$else}
343 aview.nextarr.setHidden(not showNext);
344 {$endif}
345 end;
346
IndexOfTabnull347 function IndexOfTab(ahost: TCocoaTabControl; atab: NSTabViewItem): Integer;
348 var
349 idx : NSUInteger;
350 begin
351 idx := ahost.fulltabs.indexOfObject(atab);
352 if idx=NSUIntegerMax then Result:=-1
353 else begin
354 if idx>MaxInt then Result:=-1
355 else Result:=Integer(idx);
356 end;
357 end;
358
359 { TCocoaTabPageView }
360
361 procedure TCocoaTabPageView.setFrame(arect: NSRect);
362 begin
363 // It's possible for a tab page view to go in negative height.
364 // However, automatic resizing flags (for whatever reason) prevent
365 // TCocoaTabPageView to go into negative height (remaining at 0 pixels)
366 // The code below makes sure that resizing is actually happening
367 if Assigned(superView) and (superView.frame.size.height < arect.size.height) then
368 arect.size.height := superView.frame.size.height;
369
370 inherited setFrame(arect);
371 end;
372
373 { TCocoaTabPage }
374
lclGetCallbacknull375 function TCocoaTabPage.lclGetCallback: ICommonCallback;
376 begin
377 Result := callback;
378 end;
379
380 procedure TCocoaTabPage.lclClearCallback;
381 begin
382 callback := nil;
383 end;
384
lclFramenull385 function TCocoaTabPage.lclFrame: TRect;
386 var
387 svh: CGFloat;
388 lParent: NSTabView;
389 begin
390 lParent := tabView;
391 if lParent <> nil then
392 begin
393 svh := lParent.contentRect.size.height;
394 NSToLCLRect(lParent.contentRect, svh, Result);
395 end
396 else
397 begin
398 svh := tabView.frame.size.height;
399 NSToLCLRect(tabView.contentRect, svh, Result);
400 end;
401 {$IFDEF COCOA_DEBUG_TABCONTROL}
402 WriteLn('[TCocoaTabPage.lclFrame] '+dbgs(Result)+' '+NSStringToString(Self.label_));
403 {$ENDIF}
404 end;
405
lclClientFramenull406 function TCocoaTabPage.lclClientFrame: TRect;
407 begin
408 Result := lclFrame();
409 end;
410
411 procedure TCocoaTabPage.setLabel(label__: NSString);
412 begin
413 inherited setLabel(label__);
414 //todo: revise the parent labels
415 end;
416
417 { TCocoaTabControl }
418
419 class function TCocoaTabControl.alloc: id;
420 begin
421 Result := inherited alloc;
422 TCocoaTabControl(Result).fulltabs := NSMutableArray(NSMutableArray.alloc).init;
423 end;
424
425 procedure TCocoaTabControl.setFrame(aframe: NSRect);
426 begin
427 inherited setFrame(aframe);
428
429 if not Assigned(nextarr) then
430 AllocPrevNext( self );
431
432 UpdateTabAndArrowVisibility(self);
433 end;
434
435 procedure TCocoaTabControl.extselectTabViewItemAtIndex(index: NSInteger);
436 var
437 idx : integer;
438 itm : NSTabViewItem;
439 i : NSUInteger;
440 begin
441 if (index<0) or (index>=fulltabs.count) then Exit;
442 itm := NSTabViewItem(fulltabs.objectAtIndex(index));
443
444 i := tabViewItems.indexOfObject(itm);
445 if i <> NSNotFound then
446 begin
447 inherited selectTabViewItemAtIndex(NSInteger(i));
448 end
449 else begin
450 leftmost := index;
451 UpdateTabAndArrowVisibility(self);
452 i := tabViewItems.indexOfObject(itm);
453 inherited selectTabViewItemAtIndex(NSInteger(i));
454 end;
455 end;
456
lclIsEnablednull457 function TCocoaTabControl.lclIsEnabled: Boolean;
458 begin
459 Result:=lclEnabled and ((Assigned(superview) and superview.lclIsEnabled) or not Assigned(superview));
460 end;
461
462 procedure TCocoaTabControl.lclSetEnabled(AEnabled: Boolean);
463 begin
464 lclEnabled := AEnabled;
465 inherited lclSetEnabled(AEnabled);
466 end;
467
lclGetCallbacknull468 function TCocoaTabControl.lclGetCallback: ICommonCallback;
469 begin
470 Result := callback;
471 end;
472
473 procedure TCocoaTabControl.lclClearCallback;
474 begin
475 callback := nil;
476 end;
477
lclClientFramenull478 function TCocoaTabControl.lclClientFrame: TRect;
479 var
480 r : TRect;
481 f : NSRect;
482 begin
483 case tabViewType of
484 NSNoTabsNoBorder:
485 begin
486 f := frame;
487 f.origin.x := 0;
488 f.origin.y := 0;
489 Result := NSRectToRect( f );
490 end;
491 else
492 if isFlipped then
493 Result:=NSRectToRect( contentRect )
494 else
495 NSToLCLRect( contentRect, frame.size.height, Result );
496 end;
497
498 //if tabs are hidden, frame layout should not be taken into account
499 //r:=lclGetFrameToLayoutDelta;
500 //Types.OffsetRect(Result, -r.Left, -r.Top);
501 end;
502
lclGetFrameToLayoutDeltanull503 function TCocoaTabControl.lclGetFrameToLayoutDelta: TRect;
504 begin
505 case tabViewType of
506 NSNoTabsNoBorder: begin
507 Result.Left := 0;
508 Result.Top := 0;
509 Result.Bottom := 0;
510 Result.Right := 0;
511 end;
512 else
513 Result.Bottom := -10;
514 Result.Top := 6;
515 Result.Left := 7;
516 Result.Right := -7;
517 end;
518 end;
519
tabView_shouldSelectTabViewItemnull520 function TCocoaTabControl.tabView_shouldSelectTabViewItem(tabView: NSTabView;
521 tabViewItem: NSTabViewItem): Boolean;
522 begin
523 Result := True;
524 end;
525
526 procedure TCocoaTabControl.tabView_willSelectTabViewItem(tabView: NSTabView;
527 tabViewItem: NSTabViewItem);
528 begin
529 if ignoreChange then Exit;
530 if Assigned(callback) then
531 begin
532 callback.willSelectTabViewItem( IndexOfTab( self, tabViewItem) );
533 end;
534 end;
535
536 procedure TCocoaTabControl.tabView_didSelectTabViewItem(tabView: NSTabView;
537 tabViewItem: NSTabViewItem);
538 begin
539 //it's called together with "willSelect"
540
541 if Assigned(callback) then
542 begin
543 // Expected LCL Focus changing goes as following:
544 // First page becomes visible
545 // Then focus is switching to the control of the page
546 // In Cocoa world, first "willSelect" runs,
547 // then "firstResponder" changes to Window
548 // then the views are reorded and the new View becomes a part
549 // of views chain (and attaches to the window
550 // the view is made "firstResponder"
551 // and finally "didSelect" is fired
552 callback.didSelectTabViewItem( IndexOfTab( self, tabViewItem) );
553 end;
554
555 // The recent clean up, drove the workaround below unnecessary
556 // (at least the problem is not observed)
557 // The issue, is that the controls are being placed incorrectly, below
558 // the actual height of the control. Refactoring, removed direct LCL bindings.
559 // And it seemed to helped with returning invalid control bounds?!
560
561 // Update the coordinates of all children of this tab
562 // Fixes bug 31914: TPageControl problems with Cocoa
563 {lTabView := tabViewItem.view.subViews.objectAtIndex(0);
564 for i := 0 to lTabView.subViews.count-1 do
565 begin
566 lCurSubview := lTabView.subViews.objectAtIndex(i);
567 lCurCallback := lCurSubview.lclGetCallback();
568 if Assigned(lCurCallback) then
569 begin
570 lLCLControl := TWinControl(lCurCallback.GetTarget());
571 lBounds := Classes.Bounds(lLCLControl.Left, lLCLControl.Top, lLCLControl.Width, lLCLControl.Height);
572 lCurSubview.lclSetFrame(lBounds);
573 end;
574 end;}
575 end;
576
577 procedure TCocoaTabControl.tabViewDidChangeNumberOfTabViewItems(
578 TabView: NSTabView);
579 begin
580
581 end;
582
583 procedure TCocoaTabControl.mouseDown(event: NSEvent);
584 var
585 itm : NSTabViewItem;
586 begin
587 itm := self.tabViewItemAtPoint( self.convertPoint_fromView(event.locationInWindow, nil ));
588 if Assigned(itm) then
589 begin
590 inherited mouseDown(event);
591 Exit;
592 end;
593
594 if not (Assigned(callback) and callback.MouseUpDownEvent(event, false, true)) then
595 begin
596 inherited mouseDown(event);
597
598 if Assigned(callback) then
599 begin
600 callback.MouseUpDownEvent(event, True);
601 end;
602 end
603 end;
604
605 procedure TCocoaTabControl.mouseUp(event: NSEvent);
606 begin
607 if not Assigned(callback) then callback.MouseUpDownEvent(event);
608 inherited mouseUp(event);
609 end;
610
611 procedure TCocoaTabControl.rightMouseDown(event: NSEvent);
612 begin
613 if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
614 inherited rightMouseDown(event);
615 end;
616
617 procedure TCocoaTabControl.rightMouseUp(event: NSEvent);
618 begin
619 if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
620 inherited rightMouseUp(event);
621 end;
622
623 procedure TCocoaTabControl.rightMouseDragged(event: NSEvent);
624 begin
625 if not Assigned(callback) or not callback.MouseMove(event) then
626 inherited rightMouseDragged(event);
627 end;
628
629 procedure TCocoaTabControl.otherMouseDown(event: NSEvent);
630 begin
631 if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
632 inherited otherMouseDown(event);
633 end;
634
635 procedure TCocoaTabControl.otherMouseUp(event: NSEvent);
636 begin
637 if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
638 inherited otherMouseUp(event);
639 end;
640
641 procedure TCocoaTabControl.otherMouseDragged(event: NSEvent);
642 begin
643 if not Assigned(callback) or not callback.MouseMove(event) then
644 inherited otherMouseDragged(event);
645 end;
646
647 procedure TCocoaTabControl.mouseDragged(event: NSEvent);
648 begin
649 if not Assigned(callback) or not callback.MouseMove(event) then
650 inherited mouseDragged(event);
651 end;
652
653 procedure TCocoaTabControl.mouseMoved(event: NSEvent);
654 begin
655 if Assigned(callback) then callback.MouseMove(event);
656 inherited mouseMoved(event);
657 end;
658
659 procedure TCocoaTabControl.exttabInsertTabViewItem_atIndex(
660 lTabPage: NSTabViewItem; AIndex: integer);
661 begin
662 if AIndex>fulltabs.count then AIndex:=fulltabs.count;
663 fulltabs.insertObject_atIndex(lTabPage, AIndex);
664
665 UpdateTabAndArrowVisibility(self);
666 end;
667
668 procedure TCocoaTabControl.exttabRemoveTabViewItem(lTabPage: NSTabViewItem);
669 var
670 idx : NSInteger;
671 begin
672 idx := indexOfTabViewItem(lTabPage);
673 if (idx>=0) and (idx<>NSNotFound) then
674 removeTabViewItem(lTabPage);
675
676 fulltabs.removeObject(lTabPage);
677
678 UpdateTabAndArrowVisibility(self);
679 end;
680
exttabIndexOfTabViewItemnull681 function TCocoaTabControl.exttabIndexOfTabViewItem(lTabPage: NSTabViewItem
682 ): NSInteger;
683 begin
684 Result := fulltabs.indexOfObject(lTabPage);
685 end;
686
687 procedure TCocoaTabControl.extTabPrevButtonClick(sender: id);
688 begin
689 if leftmost = 0 then Exit;
690
691 leftmost := leftmost - 1;
692 UpdateTabAndArrowVisibility(self);
693 end;
694
695 procedure TCocoaTabControl.extTabNextButtonClick(sender: id);
696 begin
697 if leftmost = fulltabs.count - 1 then Exit;
698
699 leftmost := leftmost + 1;
700 UpdateTabAndArrowVisibility(self);
701 end;
702
703
704 end.
705
706