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