1 { $Id: $}
2 {                  --------------------------------------------
3                   cocoaprivate.pp  -  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 CocoaPrivate;
16 
17 {$mode objfpc}{$H+}
18 {$modeswitch objectivec1}
19 {$modeswitch objectivec2}
20 {$interfaces corba}
21 {$include cocoadefines.inc}
22 
23 {.$DEFINE COCOA_DEBUG_SETBOUNDS}
24 {.$DEFINE COCOA_SPIN_DEBUG}
25 {.$DEFINE COCOA_SPINEDIT_INSIDE_CONTAINER}
26 {.$DEFINE COCOA_SUPERVIEW_HEIGHT}
27 
28 interface
29 
30 uses
31   // rtl+ftl
32   Types, Classes, SysUtils,
33   CGGeometry,
34   // Libs
35   MacOSAll, CocoaAll, CocoaUtils, CocoaGDIObjects,
36   cocoa_extra,
37   // LCL
38   LCLType;
39 
40 const
41   SPINEDIT_DEFAULT_STEPPER_WIDTH = 15;
42   SPINEDIT_EDIT_SPACING_FOR_SELECTION = 4;
43   STATUSBAR_DEFAULT_HEIGHT = 18;
44 
45 type
46   // Some components might be using CocoaPrivate for use of LCLObjCBoolean
47   // Thus this declaration needs to be here.
48   LCLObjCBoolean = cocoa_extra.LCLObjCBoolean;
49 
50   { ICommonCallback }
51 
52   ICommonCallback = interface
53     // mouse events
MouseUpDownEventnull54     function MouseUpDownEvent(Event: NSEvent; AForceAsMouseUp: Boolean = False; AOverrideBlock: Boolean = False): Boolean;
55     procedure MouseClick;
MouseMovenull56     function MouseMove(Event: NSEvent): Boolean;
57 
58     // KeyEvXXX methods were introduced to allow a better control
59     // over when Cocoa keys processing is being called.
60     // (The initial KeyEvent() replicates Carbon implementation, and it's not
61     // suitable for Cocoa, due to the use of OOP and the extual "inherited Key..."needs to be called
62     // where for Carbon there's a special fucntion to call the "next event handler" present)
63     //
64     // The desired use is as following:
65     // Call KeyEvPrepare and pass NSEvent object
66     // after that call KeyEvBefore and pass a flag if AllowCocoaHandle
67     //
68     // The call would populate the flag. If it's "True" you should call "inherited" method (to let Cocoa handle the key).
69     // If the flag returned "False", you should not call inherited.
70     //
71     // No matter what the flag value was you should call KeyEvAfter.
72     procedure KeyEvBefore(Event: NSEvent; out AllowCocoaHandle: boolean);
73     procedure KeyEvAfter;
74     procedure KeyEvAfterDown(out AllowCocoaHandle: boolean);
75     procedure KeyEvHandled;
76     procedure SetTabSuppress(ASuppress: Boolean);
77 
78     function scrollWheel(Event: NSEvent): Boolean;
79     function CanFocus: Boolean;
80     // size, pos events
81     procedure frameDidChange(sender: id);
82     procedure boundsDidChange(sender: id);
83     // misc events
84     procedure Draw(ctx: NSGraphicsContext; const bounds, dirty: NSRect);
85     procedure DrawBackground(ctx: NSGraphicsContext; const bounds, dirty: NSRect);
86     procedure DrawOverlay(ctx: NSGraphicsContext; const bounds, dirty: NSRect);
87     function ResetCursorRects: Boolean;
88     procedure BecomeFirstResponder;
89     procedure ResignFirstResponder;
90     procedure DidBecomeKeyNotification;
91     procedure DidResignKeyNotification;
92     procedure SendOnChange;
93     procedure SendOnTextChanged;
94     procedure scroll(isVert: Boolean; Pos: Integer; AScrollPart: NSScrollerPart = NSScrollerNoPart);
95     // non event methods
96     function DeliverMessage(Msg: Cardinal; WParam: WParam; LParam: LParam): LResult;
97     function GetPropStorage: TStringList;
98     function GetContext: TCocoaContext;
99     function GetTarget: TObject;
100     function GetHasCaret: Boolean;
101     function GetCallbackObject: TObject;
102     procedure SetHasCaret(AValue: Boolean);
103     function GetIsOpaque: Boolean;
104     procedure SetIsOpaque(AValue: Boolean);
105     function GetShouldBeEnabled: Boolean;
106     // the method is called, when handle is being destroyed.
107     // the callback object to stay alive a little longer than LCL object (Target)
108     // thus it needs to know that LCL object has been destroyed.
109     // After this called has been removed, any Cocoa events should not be
110     // forwarded to LCL target
111     procedure RemoveTarget;
112 
113     procedure InputClientInsertText(const utf8: string);
114 
115     // properties
116     property HasCaret: Boolean read GetHasCaret write SetHasCaret;
117     property IsOpaque: Boolean read GetIsOpaque write SetIsOpaque;
118   end;
119 
120   { LCLObjectExtension }
121 
122   LCLObjectExtension = objccategory(NSObject)
123     function lclIsEnabled: Boolean; message 'lclIsEnabled';
124     procedure lclSetEnabled(AEnabled: Boolean); message 'lclSetEnabled:';
125     function lclIsVisible: Boolean; message 'lclIsVisible';
126     procedure lclSetVisible(AVisible: Boolean); message 'lclSetVisible:';
127     function lclWindowState: Integer; message 'lclWindowState';
128 
129     procedure lclInvalidateRect(const r: TRect); message 'lclInvalidateRect:';
130     procedure lclInvalidate; message 'lclInvalidate';
131     procedure lclUpdate; message 'lclUpdate';
132 
133     // Returns the position of the view or window, in the immediate
134     // parent (view or screen), relative to its client coordinates system
135     // Left and Top are always returned in LCL coordinate system.
136     procedure lclRelativePos(var Left, Top: Integer); message 'lclRelativePos::';
137     procedure lclLocalToScreen(var X, Y: Integer); message 'lclLocalToScreen::';
138     procedure lclScreenToLocal(var X, Y: Integer); message 'lclScreenToLocal::';
139     function lclParent: id; message 'lclParent';
140     function lclFrame: TRect; message 'lclFrame';
141     procedure lclSetFrame(const r: TRect); message 'lclSetFrame:';
142 
143     // returns rectangle describing deltas to get "Layout" rectangle from "Frame" rectangle
144     //   left, top  - return offsets from top-left corner of the control (not reversed as in Cocoa coordinates)
145     //                    (values are typically positive)
146     //   right, bottom -  offsets for bottom-right corner
147     //                    (typically negative)
148     function lclGetFrameToLayoutDelta: TRect; message 'lclGetFrameToLayoutDelta';
149 
150     function lclClientFrame: TRect; message 'lclClientFrame';
151     function lclGetCallback: ICommonCallback; message 'lclGetCallback';
152     procedure lclClearCallback; message 'lclClearCallback';
153     function lclGetPropStorage: TStringList; message 'lclGetPropStorage';
154     function lclGetTarget: TObject; message 'lclGetTarget';
155     function lclDeliverMessage(Msg: Cardinal; WParam: WParam; LParam: LParam): LResult; message 'lclDeliverMessage:::';
156     function lclContentView: NSView; message 'lclContentView';
157     procedure lclOffsetMousePos(var Point: NSPoint); message 'lclOffsetMousePos:';
158     procedure lclExpectedKeys(var wantTabs, wantArrows, wantReturn, wantAll: Boolean); message 'lclExpectedKeys::::';
159     function lclIsMouseInAuxArea(Event: NSEvent): Boolean; message 'lclMouseInAuxArea:';
160   end;
161 
162   { LCLViewExtension }
163 
164   LCLViewExtension = objccategory(NSView)
165     function lclInitWithCreateParams(const AParams: TCreateParams): id; message 'lclInitWithCreateParams:';
166     function lclIsEnabled: Boolean; message 'lclIsEnabled'; reintroduce;
167     procedure lclSetEnabled(AEnabled: Boolean); message 'lclSetEnabled:'; reintroduce;
168 
169     function lclIsVisible: Boolean; message 'lclIsVisible'; reintroduce;
170     procedure lclSetVisible(AVisible: Boolean); message 'lclSetVisible:'; reintroduce;
171     function lclIsPainting: Boolean; message 'lclIsPainting';
172     procedure lclInvalidateRect(const r: TRect); message 'lclInvalidateRect:'; reintroduce;
173     procedure lclInvalidate; message 'lclInvalidate'; reintroduce;
174     procedure lclUpdate; message 'lclUpdate'; reintroduce;
175     procedure lclRelativePos(var Left, Top: Integer); message 'lclRelativePos::'; reintroduce;
176     procedure lclLocalToScreen(var X, Y: Integer); message 'lclLocalToScreen::'; reintroduce;
177     procedure lclScreenToLocal(var X, Y: Integer); message 'lclScreenToLocal::'; reintroduce;
178     function lclParent: id; message 'lclParent'; reintroduce;
179     function lclFrame: TRect; message 'lclFrame'; reintroduce;
180     procedure lclSetFrame(const r: TRect); message 'lclSetFrame:'; reintroduce;
181     function lclClientFrame: TRect; message 'lclClientFrame'; reintroduce;
182     function lclContentView: NSView; message 'lclContentView'; reintroduce;
183     procedure lclOffsetMousePos(var Point: NSPoint); message 'lclOffsetMousePos:'; reintroduce;
184   end;
185 
186   { LCLControlExtension }
187 
188   LCLControlExtension = objccategory(NSControl)
189     function lclIsEnabled: Boolean; message 'lclIsEnabled'; reintroduce;
190     procedure lclSetEnabled(AEnabled: Boolean); message 'lclSetEnabled:'; reintroduce;
191   end;
192 
193   { TCocoaCustomControl }
194 
195   TCocoaCustomControl = objcclass(NSControl, NSTextInputClientProtocol)
196   private
197     fstr : NSString;
198 
199     isdrawing   : integer;
200     faileddraw  : Boolean;
201   public
202     callback: ICommonCallback;
203     auxMouseByParent: Boolean;
204     procedure dealloc; override;
205     function acceptsFirstResponder: LCLObjCBoolean; override;
206     procedure drawRect(dirtyRect: NSRect); override;
207     function lclGetCallback: ICommonCallback; override;
208     procedure lclClearCallback; override;
209     function lclIsMouseInAuxArea(Event: NSevent): Boolean; override;
210     // mouse
211     function acceptsFirstMouse(event: NSEvent): LCLObjCBoolean; override;
212     procedure mouseDown(event: NSEvent); override;
213     procedure mouseUp(event: NSEvent); override;
214     procedure rightMouseDown(event: NSEvent); override;
215     procedure rightMouseUp(event: NSEvent); override;
216     procedure rightMouseDragged(event: NSEvent); override;
217     procedure otherMouseDown(event: NSEvent); override;
218     procedure otherMouseUp(event: NSEvent); override;
219     procedure otherMouseDragged(event: NSEvent); override;
220     procedure mouseDragged(event: NSEvent); override;
221     procedure mouseEntered(event: NSEvent); override;
222     procedure mouseExited(event: NSEvent); override;
223     procedure mouseMoved(event: NSEvent); override;
224     procedure scrollWheel(event: NSEvent); override;
225     // nsview
226     procedure setFrame(aframe: NSRect); override;
227     // other
228     procedure resetCursorRects; override;
229     // value
230     procedure setStringValue(avalue: NSString); override;
231     function stringValue: NSString; override;
232     procedure addSubView(aview: NSView); override;
233 
234     // this is parts of
235     procedure insertText_replacementRange (aString: id; replacementRange: NSRange);
236     procedure doCommandBySelector (aSelector: SEL); override;
237     procedure setMarkedText_selectedRange_replacementRange (aString: id; selectedRange: NSRange; replacementRange: NSRange);
238     procedure unmarkText;
239     function selectedRange: NSRange;
240     function markedRange: NSRange;
241     function hasMarkedText: LCLObjCBoolean;
242     function attributedSubstringForProposedRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
243     function validAttributesForMarkedText: NSArray;
244     function firstRectForCharacterRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSRect;
245     function characterIndexForPoint (aPoint: NSPoint): NSUInteger;
246   end;
247 
248   TStatusItemData = record
249     Text  : NSString;
250     Width : Integer;
251     Align : TAlignment;
252   end;
253 
254   TStatusItemDataArray = array of TStatusItemData;
255 
256   { TCocoaStatusBar }
257 
258   IStatusBarCallback = interface {(ICommonCallback) // not needed to inherit from ICommonCallback}
259     function GetBarsCount: Integer;
260     //todo: consider the use Cocoa native types, instead of FPC TAlignment
261     function GetBarItem(idx: Integer; var txt: String;
262       var width: Integer; var align: TAlignment): Boolean;
263     procedure DrawPanel(idx: Integer; const r: TRect);
264   end;
265 
266   TCocoaStatusBar = objcclass(TCocoaCustomControl)
267   public
268     //StatusBar : TStatusBar;
269     barcallback : IStatusBarCallback;
270     panelCell   : NSCell;
271     procedure drawRect(dirtyRect: NSRect); override;
272     procedure dealloc; override;
273   end;
274 
275   { TCocoaGroupBox }
276 
277   TCocoaGroupBox = objcclass(NSBox)
278   public
279     callback: ICommonCallback;
280     function acceptsFirstResponder: LCLObjCBoolean; override;
281     function lclGetCallback: ICommonCallback; override;
282     procedure lclClearCallback; override;
283     procedure resetCursorRects; override;
284     function lclClientFrame: TRect; override;
285     function lclContentView: NSView; override;
286     function lclGetFrameToLayoutDelta: TRect; override;
287   end;
288 
289 
290 const
291   PROGRESS_REG_HEIGHT   = 16; // no longer applies on later macOS version
292   PROGRESS_SMALL_HEIGHT = 10;
293 
294 type
295   { TCocoaProgressIndicator }
296 
297   TCocoaProgressIndicator = objcclass(NSProgressIndicator)
298     callback: ICommonCallback;
299     function acceptsFirstResponder: LCLObjCBoolean; override;
300     function lclGetCallback: ICommonCallback; override;
301     procedure lclClearCallback; override;
302     procedure resetCursorRects; override;
303     function lclGetFrameToLayoutDelta: TRect; override;
304     procedure lclSetFrame(const r: TRect); override;
305     // mouse
306     function acceptsFirstMouse(event: NSEvent): LCLObjCBoolean; override;
307     procedure mouseDown(event: NSEvent); override;
308     procedure mouseUp(event: NSEvent); override;
309     procedure rightMouseDown(event: NSEvent); override;
310     procedure rightMouseUp(event: NSEvent); override;
311     procedure rightMouseDragged(event: NSEvent); override;
312     procedure otherMouseDown(event: NSEvent); override;
313     procedure otherMouseUp(event: NSEvent); override;
314     procedure otherMouseDragged(event: NSEvent); override;
315     procedure mouseDragged(event: NSEvent); override;
316     procedure mouseMoved(event: NSEvent); override;
317     procedure scrollWheel(event: NSEvent); override;
318   end;
319 
320   { TManualTicks }
321 
322   TManualTicks = class(TObject)
323     count : integer;
324     //todo: keep sorted and do binary search
325     ticks : array of Integer;
326     draw  : Boolean;
327     function AddTick(atick: integer): Boolean;
328   end;
329 
330   { TCocoaSlider }
331 
332   TCocoaSlider = objcclass(NSSlider)
333     callback  : ICommonCallback;
334     intval    : Integer;
335     man       : TManualTicks;
336 
337     procedure dealloc; override;
338     procedure drawRect(dirtyRect: NSRect); override;
339 
340     function acceptsFirstResponder: LCLObjCBoolean; override;
341     function lclGetCallback: ICommonCallback; override;
342     procedure lclClearCallback; override;
343     procedure resetCursorRects; override;
344     //
345     procedure SnapToInteger(AExtraFactor: Integer = 0); message 'SnapToInteger:';
346     procedure sliderAction(sender: id); message 'sliderAction:';
347     // mouse
348     function acceptsFirstMouse(event: NSEvent): LCLObjCBoolean; override;
349     procedure mouseDown(event: NSEvent); override;
350     procedure mouseUp(event: NSEvent); override;
351     procedure rightMouseDown(event: NSEvent); override;
352     procedure rightMouseUp(event: NSEvent); override;
353     procedure rightMouseDragged(event: NSEvent); override;
354     procedure otherMouseDown(event: NSEvent); override;
355     procedure otherMouseUp(event: NSEvent); override;
356     procedure otherMouseDragged(event: NSEvent); override;
357     procedure mouseDragged(event: NSEvent); override;
358     procedure mouseMoved(event: NSEvent); override;
359     procedure scrollWheel(event: NSEvent); override;
360 
361     procedure lclAddManTick(atick : integer); message 'lclAddManTick:';
362     procedure lclSetManTickDraw(adraw: Boolean); message 'lclSetManTickDraw:';
363     procedure lclExpectedKeys(var wantTabs, wantArrows, wantReturn, wantAll: Boolean); override;
364   end;
365 
366   TCocoaSliderCell = objcclass(NSSliderCell)
367   end;
368 
369 procedure SetViewDefaults(AView: NSView);
370 function CheckMainThread: Boolean;
371 function GetNSViewSuperViewHeight(view: NSView): CGFloat;
372 
373 procedure SetNSControlSize(ctrl: NSView; newHeight, miniHeight, smallHeight: Integer; AutoChangeFont: Boolean);
374 
375 // these constants are missing from CocoaAll for some reason
376 const
377   NSTextAlignmentLeft      = 0;
378   NSTextAlignmentRight     = 1; // it's 2 for iOS and family
379   NSTextAlignmentCenter    = 2; // it's 1 for iOS and family
380   NSTextAlignmentJustified = 3;
381   NSTextAlignmentNatural   = 4;
382 
383 var
384   // todo: this should be a threadvar
385   TrackedControl : NSObject = nil;
386 
387 function isCallbackForSameObject(cb1, cb2: ICommonCallback): Boolean;
388 
389 function NSViewIsLCLEnabled(v: NSView): Boolean;
390 function NSObjectIsLCLEnabled(obj: NSObject): Boolean;
391 function NSViewCanFocus(v: NSView): Boolean;
392 
393 implementation
394 
395 function NSObjectIsLCLEnabled(obj: NSObject): Boolean;
396 begin
397   if obj.isKindOfClass(NSView) then
398     Result := NSViewIsLCLEnabled(NSView(obj))
399   else
400     Result := obj.lclIsEnabled;
401 end;
402 
403 function NSViewIsLCLEnabled(v: NSView): Boolean;
404 begin
405   Result := true;
406   while Assigned(v) do
407   begin
408     if not v.lclIsEnabled then begin
409       Result := false;
410       break;
411     end;
412     v:=v.superview;
413   end;
414 end;
415 
416 function NSViewCanFocus(v: NSView): Boolean;
417 var
418   cb: ICommonCallback;
419 begin
420   if Assigned(v) then
421   begin
422     cb := v.lclGetCallback;
423     if Assigned(cb) then
424       Result := cb.CanFocus
425     else
426       Result := true;
427   end
428   else
429     Result := false;
430 end;
431 
432 function isCallbackForSameObject(cb1, cb2: ICommonCallback): Boolean;
433 begin
434   Result := Assigned(cb1) and Assigned(cb2);
435   if Result then
436     Result := (cb1 = cb2) or (cb1.GetTarget = cb2.GetTarget);
437 end;
438 
439 procedure SetViewDefaults(AView: NSView);
440 begin
441   if not Assigned(AView) then Exit;
442   AView.setAutoresizingMask(NSViewMinYMargin or NSViewMaxXMargin);
443 end;
444 
445 function CheckMainThread: Boolean;
446 begin
447   Result := NSThread.currentThread.isMainThread;
448 end;
449 
450 function GetNSViewSuperViewHeight(view: NSView): CGFloat;
451 begin
452   Result := -1;
453   if not Assigned(view) then Exit;
454   if not Assigned(view.superview) then Exit;
455   //if view.superview.isKindOfClass_(TCocoaTabPageView) then
456     //Result := TCocoaTabPageView(view.superview).tabview.contentRect.size.height
457   //else
458     Result := view.superview.frame.size.height;
459   {$IFDEF COCOA_SUPERVIEW_HEIGHT}
460   WriteLn(Format('GetNSViewSuperViewHeight Result=%f', [Result]));
461   {$ENDIF}
462 end;
463 
464 { TManualTicks }
465 
AddTicknull466 function TManualTicks.AddTick(atick: integer): Boolean;
467 var
468   i : integer;
469 begin
470   //todo: must be a binary search
471   for i:=0 to length(ticks)-1 do
472     if ticks[i]=atick then begin
473       Result:=false;
474       Exit;
475     end;
476 
477   // adding new tick
478   if length(ticks)=count then begin
479     if count=0 then SetLength(ticks, 8)
480     else SetLength(ticks, count * 2);
481   end;
482   ticks[count]:=atick;
483   inc(count);
484   Result := true;
485 end;
486 
487 { TCocoaGroupBox }
488 
lclClientFramenull489 function TCocoaGroupBox.lclClientFrame: TRect;
490 var
491   v : NSView;
492 begin
493   v:=contentView;
494   if not Assigned(v) then
495     Result := inherited lclClientFrame
496   else
497     if v.isFlipped then
498       Result := NSRectToRect( v.frame )
499     else
500       NSToLCLRect(v.frame, frame.size.height, Result);
501 end;
502 
lclContentViewnull503 function TCocoaGroupBox.lclContentView: NSView;
504 begin
505   Result := NSView(contentView);
506 end;
507 
lclGetFrameToLayoutDeltanull508 function TCocoaGroupBox.lclGetFrameToLayoutDelta: TRect;
509 begin
510   Result.Left := 3;
511   Result.Right := -3;
512   Result.Top := 0;
513   Result.Bottom := -4;
514 end;
515 
acceptsFirstRespondernull516 function TCocoaGroupBox.acceptsFirstResponder: LCLObjCBoolean;
517 begin
518   Result := True;
519 end;
520 
lclGetCallbacknull521 function TCocoaGroupBox.lclGetCallback: ICommonCallback;
522 begin
523   Result := callback;
524 end;
525 
526 procedure TCocoaGroupBox.lclClearCallback;
527 begin
528   callback := nil;
529 end;
530 
531 procedure TCocoaGroupBox.resetCursorRects;
532 begin
533   if not Assigned(callback) or not callback.resetCursorRects then
534     inherited resetCursorRects;
535 end;
536 
537 { TCocoaCustomControl }
538 
539 procedure TCocoaCustomControl.setStringValue(avalue: NSString);
540 begin
541   if Assigned(fstr) then fstr.release;
542   if ASsigned(avalue) then
543     fstr:=avalue.copyWithZone(nil)
544   else
545     fstr:=nil;
546   inherited setStringValue(avalue);
547 end;
548 
stringValuenull549 function TCocoaCustomControl.stringValue: NSString;
550 begin
551   Result:=fstr;
552 end;
553 
554 procedure TCocoaCustomControl.addSubView(aview: NSView);
555 begin
556   inherited addSubView(aview);
557 
558   if Assigned(aview) then
559   begin
560     // forcing LCL compatible "auto-move" mode. Sticking to left/top corner
561     if not autoresizesSubviews then
562       {$ifdef BOOLFIX}
563       setAutoresizesSubviews_(Ord(true));
564       {$else}
565       setAutoresizesSubviews(true);
566       {$endif}
567     aview.setAutoresizingMask(NSViewMaxXMargin or NSViewMinYMargin);
568   end;
569 end;
570 
571 procedure TCocoaCustomControl.insertText_replacementRange(aString: id;
572   replacementRange: NSRange);
573 begin
574   lclGetCallback.InputClientInsertText(NSStringToString(NSString(astring)));
575 end;
576 
577 procedure TCocoaCustomControl.doCommandBySelector(aSelector: SEL);
578 begin
579   inherited doCommandBySelector(ASelector);
580 end;
581 
582 procedure TCocoaCustomControl.setMarkedText_selectedRange_replacementRange(
583   aString: id; selectedRange: NSRange; replacementRange: NSRange);
584 begin
585 
586 end;
587 
588 procedure TCocoaCustomControl.unmarkText;
589 begin
590 end;
591 
selectedRangenull592 function TCocoaCustomControl.selectedRange: NSRange;
593 begin
594   Result := NSMakeRange(0,0);
595 end;
596 
markedRangenull597 function TCocoaCustomControl.markedRange: NSRange;
598 begin
599   Result := NSMakeRange(0,0);
600 end;
601 
hasMarkedTextnull602 function TCocoaCustomControl.hasMarkedText: LCLObjCBoolean;
603 begin
604   Result := false;
605 end;
606 
attributedSubstringForProposedRange_actualRangenull607 function TCocoaCustomControl.attributedSubstringForProposedRange_actualRange(
608   aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
609 begin
610   Result := nil;
611 end;
612 
validAttributesForMarkedTextnull613 function TCocoaCustomControl.validAttributesForMarkedText: NSArray;
614 begin
615   Result := nil;
616 end;
617 
firstRectForCharacterRange_actualRangenull618 function TCocoaCustomControl.firstRectForCharacterRange_actualRange(
619   aRange: NSRange; actualRange: NSRangePointer): NSRect;
620 begin
621   Result := NSMakeRect(0,0,0,0);
622 end;
623 
characterIndexForPointnull624 function TCocoaCustomControl.characterIndexForPoint(aPoint: NSPoint
625   ): NSUInteger;
626 begin
627   Result := 0;
628 end;
629 
630 procedure TCocoaCustomControl.dealloc;
631 begin
632   if Assigned(fstr) then fstr.release;
633   inherited dealloc;
634 end;
635 
acceptsFirstRespondernull636 function TCocoaCustomControl.acceptsFirstResponder: LCLObjCBoolean;
637 begin
638   Result := True;
639 end;
640 
acceptsFirstMousenull641 function TCocoaCustomControl.acceptsFirstMouse(event: NSEvent): LCLObjCBoolean;
642 begin
643   // By default, a mouse-down event in a window that isn’t the key window
644   // simply brings the window forward and makes it key; the event isn’t sent
645   // to the NSView object over which the mouse click occurs. The NSView can
646   // claim an initial mouse-down event, however, by overriding acceptsFirstMouse: to return YES.
647   // see bug #33034
648   Result:=true;
649 end;
650 
651 procedure TCocoaCustomControl.drawRect(dirtyRect: NSRect);
652 begin
653   if isdrawing=0 then faileddraw:=false;
654   inc(isdrawing);
655   inherited drawRect(dirtyRect);
656 
657   // Implement Color property
658   if Assigned(callback) then
659     callback.DrawBackground(NSGraphicsContext.currentContext, bounds, dirtyRect);
660 
661   if CheckMainThread and Assigned(callback) then
662     callback.Draw(NSGraphicsContext.currentContext, bounds, dirtyRect);
663   dec(isdrawing);
664 
665   if (isdrawing=0) and (faileddraw) then
666   begin
667     // Similar to Carbon. Cocoa doesn't welcome changing a framerects during paint event
668     // If such thing happens, the results are pretty much inpredicatable. #32970
669     // TreeView tries to updatedScrollBars during paint event. That sometimes is causing
670     // the frame to be changed (i.e. scroll bar showed or hidden, resized the client rect)
671     // as a result, the final image is shown up-side-down.
672     //
673     // Below is an attempt to prevent graphical artifacts and to redraw
674     // the control again.
675     inherited drawRect(dirtyRect);
676 
677     if Assigned(callback) then
678       callback.DrawBackground(NSGraphicsContext.currentContext, bounds, dirtyRect);
679 
680     if CheckMainThread and Assigned(callback) then
681       callback.Draw(NSGraphicsContext.currentContext, bounds, dirtyRect);
682   end;
683 end;
684 
TCocoaCustomControl.lclGetCallbacknull685 function TCocoaCustomControl.lclGetCallback: ICommonCallback;
686 begin
687   Result := callback;
688 end;
689 
690 procedure TCocoaCustomControl.lclClearCallback;
691 begin
692   callback := nil;
693 end;
694 
TCocoaCustomControl.lclIsMouseInAuxAreanull695 function TCocoaCustomControl.lclIsMouseInAuxArea(Event: NSevent): Boolean;
696 begin
697   if auxMouseByParent and Assigned(superview) then
698     Result := superview.lclIsMouseInAuxArea(Event)
699   else
700     Result := false;
701 end;
702 
703 procedure TCocoaCustomControl.mouseDown(event: NSEvent);
704 begin
705   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
706     inherited mouseDown(event);
707 end;
708 
709 procedure TCocoaCustomControl.mouseDragged(event: NSEvent);
710 begin
711   if not Assigned(callback) or not callback.MouseMove(event) then
712     // calling inherited causes the drag event to be passed to the
713     // parent controls
714 
715     //inherited mouseDragged(event);
716     ;
717 end;
718 
719 procedure TCocoaCustomControl.mouseEntered(event: NSEvent);
720 begin
721   inherited mouseEntered(event);
722 end;
723 
724 procedure TCocoaCustomControl.mouseExited(event: NSEvent);
725 begin
726   inherited mouseExited(event);
727 end;
728 
729 procedure TCocoaCustomControl.mouseMoved(event: NSEvent);
730 begin
731   if not Assigned(callback) or not callback.MouseMove(event) then
732     inherited mouseMoved(event);
733 end;
734 
735 procedure TCocoaCustomControl.scrollWheel(event: NSEvent);
736 begin
737   if not Assigned(callback) or not callback.scrollWheel(event) then
738     inherited scrollWheel(event);
739 end;
740 
741 procedure TCocoaCustomControl.setFrame(aframe: NSRect);
742 begin
743   if NSEqualRects(aframe, frame) then Exit;
744   if isdrawing>0 then
745     faileddraw := true;
746 
747   inherited setFrame(aframe);
748   // it actually should come from a notifcation
749   if Assigned(callback) then callback.frameDidChange(self);
750 end;
751 
752 procedure TCocoaCustomControl.mouseUp(event: NSEvent);
753 begin
754   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
755     inherited mouseUp(event);
756 end;
757 
758 procedure TCocoaCustomControl.rightMouseDown(event: NSEvent);
759 begin
760   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
761     inherited rightMouseDown(event);
762 end;
763 
764 procedure TCocoaCustomControl.rightMouseUp(event: NSEvent);
765 begin
766   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
767     inherited rightMouseUp(event);
768 end;
769 
770 procedure TCocoaCustomControl.rightMouseDragged(event: NSEvent);
771 begin
772   if not Assigned(callback) or not callback.MouseMove(event) then
773     inherited rightMouseDragged(event);
774 end;
775 
776 procedure TCocoaCustomControl.otherMouseDown(event: NSEvent);
777 begin
778   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
779     inherited otherMouseDown(event);
780 end;
781 
782 procedure TCocoaCustomControl.otherMouseUp(event: NSEvent);
783 begin
784   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
785     inherited otherMouseUp(event);
786 end;
787 
788 procedure TCocoaCustomControl.otherMouseDragged(event: NSEvent);
789 begin
790   if not Assigned(callback) or not callback.MouseMove(event) then
791     inherited otherMouseDragged(event);
792 end;
793 
794 procedure TCocoaCustomControl.resetCursorRects;
795 begin
796   if not Assigned(callback) or not callback.resetCursorRects then
797     inherited resetCursorRects;
798 end;
799 
800 { LCLObjectExtension }
801 
LCLObjectExtension.lclIsEnablednull802 function LCLObjectExtension.lclIsEnabled: Boolean;
803 begin
804   Result := False;
805 end;
806 
807 procedure LCLObjectExtension.lclSetEnabled(AEnabled: Boolean);
808 begin
809 end;
810 
LCLObjectExtension.lclIsVisiblenull811 function LCLObjectExtension.lclIsVisible: Boolean;
812 begin
813   Result := False;
814 end;
815 
816 procedure LCLObjectExtension.lclSetVisible(AVisible: Boolean);
817 begin
818 end;
819 
LCLObjectExtension.lclWindowStatenull820 function LCLObjectExtension.lclWindowState: Integer;
821 begin
822   Result := SIZE_RESTORED;
823 end;
824 
825 procedure LCLObjectExtension.lclInvalidateRect(const r: TRect);
826 begin
827 end;
828 
829 procedure LCLObjectExtension.lclInvalidate;
830 begin
831 end;
832 
833 procedure LCLObjectExtension.lclUpdate;
834 begin
835 end;
836 
837 procedure LCLObjectExtension.lclRelativePos(var Left,Top: Integer);
838 begin
839 end;
840 
841 procedure LCLObjectExtension.lclLocalToScreen(var X,Y: Integer);
842 begin
843 end;
844 
845 procedure LCLObjectExtension.lclScreenToLocal(var X, Y: Integer);
846 begin
847 end;
848 
LCLObjectExtension.lclParentnull849 function LCLObjectExtension.lclParent:id;
850 begin
851   Result:=nil;
852 end;
853 
LCLObjectExtension.lclFramenull854 function LCLObjectExtension.lclFrame:TRect;
855 begin
856   FillChar(Result, sizeof(Result), 0);
857 end;
858 
859 procedure LCLObjectExtension.lclSetFrame(const r:TRect);
860 begin
861 
862 end;
863 
LCLObjectExtension.lclGetFrameToLayoutDeltanull864 function LCLObjectExtension.lclGetFrameToLayoutDelta: TRect;
865 begin
866   Result.Top := 0;
867   Result.Left := 0;
868   Result.Right := 0;
869   Result.Bottom := 0;
870 end;
871 
LCLObjectExtension.lclClientFramenull872 function LCLObjectExtension.lclClientFrame:TRect;
873 begin
874   FillChar(Result, sizeof(Result), 0);
875 end;
876 
LCLObjectExtension.lclGetCallbacknull877 function LCLObjectExtension.lclGetCallback: ICommonCallback;
878 begin
879   Result := nil;
880 end;
881 
882 procedure LCLObjectExtension.lclClearCallback;
883 begin
884 end;
885 
LCLObjectExtension.lclGetPropStoragenull886 function LCLObjectExtension.lclGetPropStorage: TStringList;
887 var
888   Callback: ICommonCallback;
889 begin
890   Callback := lclGetCallback;
891   if Assigned(Callback) then
892     Result := Callback.GetPropStorage
893   else
894     Result := nil;
895 end;
896 
LCLObjectExtension.lclGetTargetnull897 function LCLObjectExtension.lclGetTarget: TObject;
898 var
899   Callback: ICommonCallback;
900 begin
901   Callback := lclGetCallback;
902   if Assigned(Callback) then
903     Result := Callback.GetTarget
904   else
905     Result := nil;
906 end;
907 
LCLObjectExtension.lclDeliverMessagenull908 function LCLObjectExtension.lclDeliverMessage(Msg: Cardinal; WParam: WParam; LParam: LParam): LResult;
909 var
910   Callback: ICommonCallback;
911 begin
912   Callback := lclGetCallback;
913   if Assigned(Callback) then
914     Result := Callback.DeliverMessage(Msg, WParam, LParam)
915   else
916     Result := 0;
917 end;
918 
LCLObjectExtension.lclContentViewnull919 function LCLObjectExtension.lclContentView: NSView;
920 begin
921   Result := nil;
922 end;
923 
924 procedure LCLObjectExtension.lclOffsetMousePos(var Point: NSPoint);
925 begin
926 
927 end;
928 
929 procedure LCLObjectExtension.lclExpectedKeys(var wantTabs, wantArrows,
930   wantReturn, wantAll: Boolean);
931 begin
932   wantTabs := false;
933   wantArrows := false;
934   wantReturn := false;
935   wantAll := false;
936 end;
937 
938 { The method should return TRUE, if mouse is located above an auxilary area
939   of a (composited) control, and thus MOUSE MOVE event should not be propagated
940   to LCL. For example, controls with Scrollbars should not report mouse events
941   if mouse cursor is above ScrollBar and scroll bar is visible. (ScrollBar = Auxillary area)
942 
943   By default, the whole area is considered to be non-auxillary and must be
944   reported to LCL.
945   }
LCLObjectExtension.lclIsMouseInAuxAreanull946 function LCLObjectExtension.lclIsMouseInAuxArea(Event: NSEvent): Boolean;
947 begin
948   Result := false;
949 end;
950 
951 { LCLControlExtension }
952 
RectToViewCoordnull953 function RectToViewCoord(view: NSView; const r: TRect): NSRect;
954 var
955   b: NSRect;
956 begin
957   b := view.bounds;
958   Result.origin.x := r.Left;
959   Result.size.width := r.Right - r.Left;
960   Result.size.height := r.Bottom - r.Top;
961   if Assigned(view) and (view.isFlipped) then
962     Result.origin.y := r.Top
963   else
964     Result.origin.y := b.size.height - r.Bottom;
965 end;
966 
LCLControlExtension.lclIsEnablednull967 function LCLControlExtension.lclIsEnabled:Boolean;
968 begin
969   Result := IsEnabled;
970 end;
971 
972 procedure LCLControlExtension.lclSetEnabled(AEnabled:Boolean);
973 begin
974   {$ifdef BOOLFIX}
975   SetEnabled_( Ord(AEnabled and NSViewIsLCLEnabled(self.superview) ));
976   {$else}
977   SetEnabled( AEnabled and NSViewIsLCLEnabled(self.superview) );
978   {$endif}
979   inherited lclSetEnabled(AEnabled);
980 end;
981 
LCLViewExtension.lclInitWithCreateParamsnull982 function LCLViewExtension.lclInitWithCreateParams(const AParams: TCreateParams): id;
983 var
984   p: NSView;
985   ns: NSRect;
986   {$IFDEF COCOA_DEBUG_SETBOUNDS}
987   pstr: string;
988   {$ENDIF}
989 begin
990   p := nil;
991   if (AParams.WndParent <> 0) then
992     p := NSView(AParams.WndParent).lclContentView;
993 
994   if Assigned(p) then
995     LCLToNSRect(Types.Bounds(AParams.X, AParams.Y, AParams.Width, AParams.Height),
996       p.frame.size.height, ns)
997   else
998     ns := GetNSRect(AParams.X, AParams.Y, AParams.Width, AParams.Height);
999 
1000   {$IFDEF COCOA_DEBUG_SETBOUNDS}
1001   if Assigned(p) then
1002   begin
1003     pstr := NSStringToString(p.className);
1004     if NSStringToString(NSObject(AParams.WndParent).className) = 'TCocoaTabPage' then
1005       pstr := pstr + ' ' + NSStringToString(TCocoaTabPage(AParams.WndParent).label_);
1006   end
1007   else
1008     pstr := '';
1009   WriteLn(Format('[LCLViewExtension.lclInitWithCreateParams] Class=%s Caption=%s ParentClass=%s ParentClassView=%s rect=%d %d %d %d Visible=%d',
1010     [NSStringToString(Self.className), AParams.Caption,
1011      NSStringToString(NSObject(AParams.WndParent).className), pstr,
1012      Round(ns.Origin.x), Round(ns.Origin.y), Round(ns.size.width), Round(ns.size.height),
1013      AParams.Style and WS_VISIBLE]));
1014   {$ENDIF}
1015 
1016   Result := initWithFrame(ns);
1017   if not Assigned(Result) then
1018     Exit;
1019 
1020   {$ifdef BOOLFIX}
1021   setHidden_(Ord(AParams.Style and WS_VISIBLE = 0));
1022   {$else}
1023   setHidden(AParams.Style and WS_VISIBLE = 0);
1024   {$endif}
1025 
1026   if Assigned(p) then
1027     p.lclContentView.addSubview(Result);
1028   SetViewDefaults(Result);
1029 end;
1030 
LCLViewExtension.lclIsEnablednull1031 function LCLViewExtension.lclIsEnabled: Boolean;
1032 begin
1033   Result := true;
1034 end;
1035 
1036 procedure LCLViewExtension.lclSetEnabled(AEnabled: Boolean);
1037 var
1038   cb : ICommonCallback;
1039   obj : NSObject;
1040 begin
1041   for obj in subviews do begin
1042     cb := obj.lclGetCallback;
1043     obj.lclSetEnabled(AEnabled and ((not Assigned(cb)) or cb.GetShouldBeEnabled) );
1044   end;
1045 end;
1046 
LCLViewExtension.lclIsVisiblenull1047 function LCLViewExtension.lclIsVisible: Boolean;
1048 begin
1049   Result := not isHidden;
1050 end;
1051 
1052 procedure LCLViewExtension.lclSetVisible(AVisible: Boolean);
1053 begin
1054   {$ifdef BOOLFIX}
1055   setHidden_(Ord(not AVisible));
1056   {$else}
1057   setHidden(not AVisible);
1058   {$endif}
1059   {$IFDEF COCOA_DEBUG_SETBOUNDS}
1060   WriteLn(Format('LCLViewExtension.lclSetVisible: %s AVisible=%d',
1061     [NSStringToString(Self.ClassName), Integer(AVisible)]));
1062   {$ENDIF}
1063 end;
1064 
LCLViewExtension.lclIsPaintingnull1065 function LCLViewExtension.lclIsPainting: Boolean;
1066 begin
1067   Result := Assigned(lclGetCallback) and Assigned(lclGetCallback.GetContext);
1068 end;
1069 
1070 procedure LCLViewExtension.lclInvalidateRect(const r:TRect);
1071 var
1072   view : NSView;
1073 begin
1074   view:=lclContentView;
1075   if Assigned(view) then
1076     view.setNeedsDisplayInRect(RectToViewCoord(view, r))
1077   else
1078     self.setNeedsDisplayInRect(RectToViewCoord(Self, r));
1079   //todo: it might be necessary to always invalidate self
1080   //      just need to get offset of the contentView relative for self
1081 end;
1082 
1083 procedure LCLViewExtension.lclInvalidate;
1084 begin
1085   {$ifdef BOOLFIX}
1086   setNeedsDisplay__(Ord(True));
1087   {$else}
1088   setNeedsDisplay_(True);
1089   {$endif}
1090 end;
1091 
1092 procedure LCLViewExtension.lclUpdate;
1093 begin
1094   {$ifdef BOOLFIX}
1095   setNeedsDisplay__(Ord(True));
1096   {$else}
1097   setNeedsDisplay_(True);
1098   {$endif}
1099   //display;
1100 end;
1101 
1102 procedure LCLViewExtension.lclRelativePos(var Left, Top: Integer);
1103 var
1104   sv : NSView;
1105   fr : NSRect;
1106 begin
1107   Left := Round(frame.origin.x);
1108   sv := superview;
1109   if Assigned(sv) and (not sv.isFlipped) then
1110   begin
1111     fr := frame;
1112     Top := Round(sv.frame.size.height - fr.origin.y - fr.size.height);
1113   end
1114   else
1115     Top := Round(frame.origin.y);
1116 end;
1117 
1118 procedure LCLViewExtension.lclLocalToScreen(var X, Y:Integer);
1119 var
1120   P: NSPoint;
1121 
1122 begin
1123   // 1. convert to window base
1124   // Convert from View-lcl to View-cocoa
1125   P.x := X;
1126   if isFlipped then
1127     p.y := Y
1128   else
1129     P.y := frame.size.height-y;   // convert to Cocoa system
1130 
1131   // Convert from View-cocoa to Window-cocoa
1132   P := convertPoint_ToView(P, nil);
1133 
1134   // Convert from Window-cocoa to Window-lcl
1135   X := Round(P.X);
1136   Y := Round(window.frame.size.height-P.Y); // convert to LCL system
1137 
1138   // 2. convert window to screen
tonull1139   // Use window function to convert fomr Window-lcl to Screen-lcl
1140   window.lclLocalToScreen(X, Y);
1141 end;
1142 
1143 procedure LCLViewExtension.lclScreenToLocal(var X, Y: Integer);
1144 var
1145   P: NSPoint;
1146 begin
1147   // 1. convert from screen to window
tonull1148   // use window function to onvert from Screen-lcl to Window-lcl
1149   window.lclScreenToLocal(X, Y);
1150   // Convert from Window-lcl to Window-cocoa
1151   P.x := X;
1152   P.y := Round(window.frame.size.height-Y); // convert to Cocoa system
1153 
1154   // 2. convert from window to local
1155   //    Convert from Window-cocoa to View-cocoa
1156   P := convertPoint_FromView(P, nil);
1157 
1158   // Convert from View-cocoa to View-lcl
1159   X := Round(P.x);
1160   if isFlipped then
1161     Y := Round(p.y)
1162   else
1163     Y := Round(frame.size.height-P.y);   // convert to Cocoa system
1164 end;
1165 
LCLViewExtension.lclParentnull1166 function LCLViewExtension.lclParent:id;
1167 begin
1168   Result := superView;
1169 end;
1170 
LCLViewExtension.lclFramenull1171 function LCLViewExtension.lclFrame: TRect;
1172 var
1173   v: NSView;
1174 begin
1175   v := superview;
1176   if Assigned(v) and not v.isFlipped then
1177     NSToLCLRect(frame, v.frame.size.height, Result)
1178   else
1179     Result := NSRectToRect(frame);
1180   AddLayoutToFrame( lclGetFrameToLayoutDelta, Result);
1181 end;
1182 
1183 procedure LCLViewExtension.lclSetFrame(const r: TRect);
1184 var
1185   ns: NSRect;
1186   svHeight: CGFloat;
1187   rr : TRect;
1188 begin
1189   rr := r;
1190   SubLayoutFromFrame( lclGetFrameToLayoutDelta, rr);
1191 
1192   svHeight := GetNSViewSuperViewHeight(Self);
1193   if Assigned(superview) and not superview.isFlipped then
1194   begin
1195     LCLToNSRect(rr, svHeight, ns)
1196   end
1197   else
1198     ns := RectToNSRect(rr);
1199 
1200   {$IFDEF COCOA_DEBUG_SETBOUNDS}
1201   WriteLn(Format('LCLViewExtension.lclSetFrame: %s Bounds=%s height=%d ns_pos=%d %d ns_size=%d %d',
1202     [NSStringToString(Self.ClassName), dbgs(r), Round(svHeight),
1203      Round(ns.origin.x), Round(ns.origin.y), Round(ns.size.width), Round(ns.size.height)]));
1204   {$ENDIF}
1205   setFrame(ns);
1206 end;
1207 
LCLViewExtension.lclClientFramenull1208 function LCLViewExtension.lclClientFrame: TRect;
1209 begin
1210   Result := lclFrame;
1211   Types.OffsetRect(Result, -Result.Left, -Result.Top);
1212 end;
1213 
LCLViewExtension.lclContentViewnull1214 function LCLViewExtension.lclContentView: NSView;
1215 begin
1216   Result := self;
1217 end;
1218 
1219 procedure LCLViewExtension.lclOffsetMousePos(var Point: NSPoint);
1220 var
1221   es : NSScrollView;
1222   r  : NSRect;
1223   dlt : TRect;
1224 begin
1225   Point := convertPoint_fromView(Point, nil);
1226 
1227   es := enclosingScrollView;
1228   if es.documentView <> self then es := nil;
1229   if not isFlipped then
1230     Point.y := bounds.size.height - Point.y;
1231 
1232   if Assigned(es) then
1233   begin
1234     r := es.documentVisibleRect;
1235     if isFlipped then
1236       Point.y := Point.y - r.origin.y
1237     else
1238       Point.y := Point.y - (es.documentView.frame.size.height - r.size.height - r.origin.y);
1239     Point.X := Point.X - r.origin.x;
1240   end;
1241 
1242   dlt := lclGetFrameToLayoutDelta;
1243   Point.X := Point.X - dlt.Left;
1244   Point.Y := Point.Y - dlt.Top;
1245 end;
1246 
1247 { TCocoaStatusBar }
1248 
1249 procedure TCocoaStatusBar.drawRect(dirtyRect: NSRect);
1250 var
1251   R    : TRect;
1252   i    : Integer;
1253   cs   : NSString;
1254   nr   : NSRect;
1255   dr   : NSRect;
1256   al   : TAlignment;
1257   x    : Integer;
1258   txt  : string;
1259   cnt  : Integer;
1260   w    : Integer;
1261 const
1262   CocoaAlign: array [TAlignment] of Integer = (NSNaturalTextAlignment, NSRightTextAlignment, NSCenterTextAlignment);
1263 begin
1264   if not Assigned(barcallback) then Exit;
1265 
1266   if not Assigned(panelCell) then Exit;
1267 
1268   panelCell.setControlView(Self);
1269 
1270   r := lclClientFrame();
1271   nr.origin.y := 0;
1272   nr.size.height := self.lclFrame.Height;
1273 
1274   x:=0;
1275   cnt := barcallback.GetBarsCount;
1276   for i:=0 to cnt - 1 do begin
1277 
1278     txt := '';
1279     w := 0;
1280     al := taLeftJustify;
1281 
1282     if not barcallback.GetBarItem(i, txt, w, al) then Continue;
1283 
1284     if i = cnt - 1 then w := r.Right - x;
1285     nr.size.width := w;
1286     nr.origin.x := x;
1287 
1288     // dr - draw rect. should be 1 pixel wider
1289     // and 1 pixel taller, than the actual rect.
1290     // to produce a better visual effect
1291     dr := nr;
1292     dr.size.width := dr.size.width + 1;
1293     dr.size.height := dr.size.height + 1;
1294     dr.origin.y := dr.origin.y-1;
1295 
1296     cs := NSStringUtf8(txt);
1297     panelCell.setTitle(cs);
1298     panelCell.setAlignment(CocoaAlign[al]);
1299     panelCell.drawWithFrame_inView(dr, Self);
1300     cs.release;
1301     barcallback.DrawPanel(i, NSRectToRect(nr));
1302     inc(x, w);
1303     if x > r.Right then break; // no place left
1304   end;
1305 end;
1306 
1307 procedure TCocoaStatusBar.dealloc;
1308 begin
1309   if Assigned(panelCell) then panelCell.release;
1310   inherited;
1311 end;
1312 
1313 { TCocoaProgressIndicator }
1314 
TCocoaProgressIndicator.acceptsFirstRespondernull1315 function TCocoaProgressIndicator.acceptsFirstResponder: LCLObjCBoolean;
1316 begin
1317   Result:=True;
1318 end;
1319 
lclGetCallbacknull1320 function TCocoaProgressIndicator.lclGetCallback: ICommonCallback;
1321 begin
1322   Result:=callback;
1323 end;
1324 
1325 procedure TCocoaProgressIndicator.lclClearCallback;
1326 begin
1327   callback:=nil;
1328 end;
1329 
1330 procedure TCocoaProgressIndicator.resetCursorRects;
1331 begin
1332   if not callback.resetCursorRects then
1333     inherited resetCursorRects;
1334 end;
1335 
lclGetFrameToLayoutDeltanull1336 function TCocoaProgressIndicator.lclGetFrameToLayoutDelta: TRect;
1337 begin
1338   case controlSize of
1339     NSSmallControlSize, NSMiniControlSize:
1340     begin
1341       Result.Left := 1;
1342       Result.Right := -1;
1343       Result.Top := 0;
1344       Result.Bottom := -2;
1345     end;
1346   else
1347     Result.Left := 2;
1348     Result.Right := -2;
1349     Result.Top := 0;
1350     Result.Bottom := -4;
1351   end;
1352 end;
1353 
1354 procedure TCocoaProgressIndicator.lclSetFrame(const r: TRect);
1355 begin
1356   SetNSControlSize(self, r.Bottom - r.Top, 0, PROGRESS_SMALL_HEIGHT, true);
1357   inherited lclSetFrame(r);
1358 end;
1359 
TCocoaProgressIndicator.acceptsFirstMousenull1360 function TCocoaProgressIndicator.acceptsFirstMouse(event: NSEvent): LCLObjCBoolean;
1361 begin
1362   Result:=true;
1363 end;
1364 
1365 procedure TCocoaProgressIndicator.mouseDown(event: NSEvent);
1366 begin
1367   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1368   begin
1369     inherited mouseDown(event);
1370 
1371     callback.MouseUpDownEvent(event, true);
1372   end;
1373 end;
1374 
1375 procedure TCocoaProgressIndicator.mouseUp(event: NSEvent);
1376 begin
1377   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1378     inherited mouseUp(event);
1379 end;
1380 
1381 procedure TCocoaProgressIndicator.rightMouseDown(event: NSEvent);
1382 begin
1383   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1384     inherited rightMouseDown(event);
1385 end;
1386 
1387 procedure TCocoaProgressIndicator.rightMouseUp(event: NSEvent);
1388 begin
1389   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1390     inherited rightMouseUp(event);
1391 end;
1392 
1393 procedure TCocoaProgressIndicator.rightMouseDragged(event: NSEvent);
1394 begin
1395   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1396     inherited rightMouseDragged(event);
1397 end;
1398 
1399 procedure TCocoaProgressIndicator.otherMouseDown(event: NSEvent);
1400 begin
1401   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1402     inherited otherMouseDown(event);
1403 end;
1404 
1405 procedure TCocoaProgressIndicator.otherMouseUp(event: NSEvent);
1406 begin
1407   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1408     inherited otherMouseUp(event);
1409 end;
1410 
1411 procedure TCocoaProgressIndicator.otherMouseDragged(event: NSEvent);
1412 begin
1413   if not Assigned(callback) or not callback.MouseMove(event) then
1414     inherited otherMouseDragged(event);
1415 end;
1416 
1417 procedure TCocoaProgressIndicator.mouseDragged(event: NSEvent);
1418 begin
1419   if not Assigned(callback) or not callback.MouseMove(event) then
1420     inherited mouseDragged(event);
1421 end;
1422 
1423 procedure TCocoaProgressIndicator.mouseMoved(event: NSEvent);
1424 begin
1425   if not Assigned(callback) or not callback.MouseMove(event) then
1426     inherited mouseMoved(event);
1427 end;
1428 
1429 procedure TCocoaProgressIndicator.scrollWheel(event: NSEvent);
1430 begin
1431   if not Assigned(callback) or not callback.scrollWheel(event) then
1432     inherited scrollWheel(event);
1433 end;
1434 
1435 
1436 { TCocoaSlider }
1437 
GetManTicksnull1438 function GetManTicks(slider: TCocoaSlider): TManualTicks;
1439 begin
1440   if not Assigned(slider.man) then
1441     slider.man := TManualTicks.Create;
1442   Result := slider.man;
1443 end;
1444 
1445 procedure TCocoaSlider.dealloc;
1446 begin
1447   man.Free;
1448   inherited dealloc;
1449 end;
1450 
1451 procedure TCocoaSlider.drawRect(dirtyRect: NSRect);
1452 var
1453   i  : integer;
1454   nr : NSRect;
1455   xr : NSRect;
1456   dr : NSRect;
1457   nm : integer;
1458   ctx : NSGraphicsContext;
1459   pth : NSBezierPath;
1460 begin
1461   if not Assigned(man) or (not man.draw) then begin
1462     inherited drawRect(dirtyRect);
1463     Exit;
1464   end;
1465 
1466   nm := round(maxValue - minValue);
1467   if nm = 0 then Exit;
1468   if numberOfTickMarks < 2 then Exit;
1469 
1470   nr := rectOfTickMarkAtIndex(0);
1471   xr := rectOfTickMarkAtIndex(1);
1472 
1473   ctx := NSGraphicsContext.currentContext;
1474   pth := NSBezierPath.bezierPath;
1475   NSColor.controlShadowColor.setFill;
1476   dr:=nr;
1477   dr.origin.y := dr.origin.y + 1;
1478   dr.size.height := dr.size.height - 1;
1479   for i := 0 to man.count - 1 do begin
1480     dr.origin.x := round(nr.origin.x + (xr.origin.x - nr.origin.x) * (man.ticks[i] - minValue) / nm);
1481     pth.fillRect(dr);
1482   end;
1483   inherited drawRect(dirtyRect);
1484 end;
1485 
TCocoaSlider.acceptsFirstRespondernull1486 function TCocoaSlider.acceptsFirstResponder: LCLObjCBoolean;
1487 begin
1488   Result := True;
1489 end;
1490 
lclGetCallbacknull1491 function TCocoaSlider.lclGetCallback: ICommonCallback;
1492 begin
1493   Result:=callback;
1494 end;
1495 
1496 procedure TCocoaSlider.lclClearCallback;
1497 begin
1498   callback := nil;
1499 end;
1500 
1501 procedure TCocoaSlider.resetCursorRects;
1502 begin
1503   if not callback.resetCursorRects then
1504     inherited resetCursorRects;
1505 end;
1506 
1507 procedure TCocoaSlider.SnapToInteger(AExtraFactor: Integer);
1508 begin
1509   setIntValue(Round(doubleValue() + AExtraFactor));
1510 end;
1511 
1512 procedure TCocoaSlider.sliderAction(sender: id);
1513 var
1514   newval: Integer;
1515 begin
1516   SnapToInteger();
1517   newval := intValue;
1518   if newval <> intval then begin
1519     intval := newval;
1520     // OnChange event
1521     if callback <> nil then
1522       callback.SendOnChange();
1523   end;
1524 end;
1525 
acceptsFirstMousenull1526 function TCocoaSlider.acceptsFirstMouse(event: NSEvent): LCLObjCBoolean;
1527 begin
1528   Result:=true;
1529 end;
1530 
1531 procedure TCocoaSlider.mouseDown(event: NSEvent);
1532 begin
1533   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1534   begin
1535     inherited mouseDown(event);
1536 
1537     callback.MouseUpDownEvent(event, true);
1538   end;
1539 end;
1540 
1541 procedure TCocoaSlider.mouseUp(event: NSEvent);
1542 begin
1543   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1544     inherited mouseUp(event);
1545 end;
1546 
1547 procedure TCocoaSlider.rightMouseDown(event: NSEvent);
1548 begin
1549   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1550     inherited rightMouseDown(event);
1551 end;
1552 
1553 procedure TCocoaSlider.rightMouseUp(event: NSEvent);
1554 begin
1555   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1556     inherited rightMouseUp(event);
1557 end;
1558 
1559 procedure TCocoaSlider.rightMouseDragged(event: NSEvent);
1560 begin
1561   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1562     inherited rightMouseDragged(event);
1563 end;
1564 
1565 procedure TCocoaSlider.otherMouseDown(event: NSEvent);
1566 begin
1567   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1568     inherited otherMouseDown(event);
1569 end;
1570 
1571 procedure TCocoaSlider.otherMouseUp(event: NSEvent);
1572 begin
1573   if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
1574     inherited otherMouseUp(event);
1575 end;
1576 
1577 procedure TCocoaSlider.otherMouseDragged(event: NSEvent);
1578 begin
1579   if not Assigned(callback) or not callback.MouseMove(event) then
1580     inherited otherMouseDragged(event);
1581 end;
1582 
1583 procedure TCocoaSlider.mouseDragged(event: NSEvent);
1584 begin
1585   if not Assigned(callback) or not callback.MouseMove(event) then
1586     inherited mouseDragged(event);
1587 end;
1588 
1589 procedure TCocoaSlider.mouseMoved(event: NSEvent);
1590 begin
1591   if not Assigned(callback) or not callback.MouseMove(event) then
1592     inherited mouseMoved(event);
1593 end;
1594 
1595 procedure TCocoaSlider.scrollWheel(event: NSEvent);
1596 begin
1597   if not Assigned(callback) or not callback.scrollWheel(event) then
1598     inherited scrollWheel(event);
1599 end;
1600 
1601 procedure TCocoaSlider.lclAddManTick(atick: integer);
1602 var
1603   mn : TManualTicks;
1604 begin
1605   mn := GetManTicks(self);
1606   if mn.AddTick(atick) then
1607   begin
1608     if mn.draw then self.setNeedsDisplay_(true);
1609   end;
1610 end;
1611 
1612 procedure TCocoaSlider.lclSetManTickDraw(adraw: Boolean);
1613 var
1614   mn : TManualTicks;
1615 begin
1616   mn := GetManTicks(self);
1617   if mn.draw=adraw then Exit;
1618   mn.draw:=adraw;
1619   self.setNeedsDisplay_(true);
1620 end;
1621 
1622 procedure TCocoaSlider.lclExpectedKeys(var wantTabs, wantArrows, wantReturn,
1623   wantAll: Boolean);
1624 begin
1625   wantTabs := false;
1626   wantArrows := true;
1627   wantReturn := false;
1628   wantAll := false;
1629 end;
1630 
1631 type
1632   NSViewControlSizeExt = objccategory external (NSView)
controlSizenull1633     function controlSize: Integer; message 'controlSize';
1634     procedure setControlSize(ASize: Integer); message 'setControlSize:';
cellnull1635     function cell: id; message 'cell';
1636     procedure setFont(afont: NSFont); message 'setFont:';
1637   end;
1638 
1639 procedure SetNSControlSize(ctrl: NSView; newHeight, miniHeight, smallHeight: Integer; AutoChangeFont: Boolean);
1640 var
1641   sz : NSControlSize;
1642 begin
1643   if (miniHeight>0) and (newHeight<=miniHeight) then
1644     sz:=NSMiniControlSize
1645   else if (smallHeight>0) and (newHeight<=smallHeight) then
1646     sz:=NSSmallControlSize
1647   else
1648     sz:=NSRegularControlSize;
1649 
1650   if ctrl.respondsToSelector(ObjCSelector('setControlSize:')) then
1651     ctrl.setControlSize(sz)
1652   else if ctrl.respondsToSelector(ObjCSelector('cell')) then
1653   begin
1654     if NSCell(ctrl.cell).controlSize<>sz then
1655         NSCell(ctrl.cell).setControlSize(sz);
1656   end;
1657   if AutoChangeFont and (ctrl.respondsToSelector(ObjCSelector('setFont:'))) then
1658     ctrl.setFont(NSFont.systemFontOfSize(NSFont.systemFontSizeForControlSize(sz)));
1659 end;
1660 
1661 
1662 end.
1663 
1664