Cocoa: decouple CocoaCustomControl from CocoaPrivate unit to CocoaCustomControl unit

This commit is contained in:
rich2014 2024-08-23 00:32:37 +08:00
parent 4d3547a91c
commit f484dd2af3
13 changed files with 567 additions and 521 deletions

View File

@ -0,0 +1,443 @@
unit CocoaCustomControl;
{$mode objfpc}{$H+}
{$modeswitch objectivec2}
{$interfaces corba}
interface
uses
Classes, SysUtils,
Forms,
MacOSAll, CocoaAll, CocoaPrivate, CocoaCallback,
CocoaCursor, Cocoa_Extra, CocoaUtils;
type
{ TCocoaCustomControl }
TCocoaCustomControl = objcclass(NSControl, NSTextInputClientProtocol)
private
fstr : NSString;
isdrawing : integer;
faileddraw : Boolean;
_inIME: Boolean;
private
function getWindowEditor(): NSTextView; message 'getWindowEditor';
procedure DoCallInputClientInsertText(nsText:NSString); message 'DoCallInputClientInsertText:';
public
callback: ICommonCallback;
auxMouseByParent: Boolean;
procedure dealloc; override;
function acceptsFirstResponder: LCLObjCBoolean; override;
procedure drawRect(dirtyRect: NSRect); override;
function lclGetCallback: ICommonCallback; override;
procedure lclClearCallback; override;
function lclIsMouseInAuxArea(Event: NSevent): Boolean; override;
// mouse
function acceptsFirstMouse(event: NSEvent): LCLObjCBoolean; override;
procedure mouseDown(event: NSEvent); override;
procedure mouseUp(event: NSEvent); override;
procedure rightMouseDown(event: NSEvent); override;
procedure rightMouseUp(event: NSEvent); override;
procedure rightMouseDragged(event: NSEvent); override;
procedure otherMouseDown(event: NSEvent); override;
procedure otherMouseUp(event: NSEvent); override;
procedure otherMouseDragged(event: NSEvent); override;
procedure mouseDragged(event: NSEvent); override;
procedure mouseEntered(event: NSEvent); override;
procedure mouseExited(event: NSEvent); override;
procedure mouseMoved(event: NSEvent); override;
procedure scrollWheel(event: NSEvent); override;
// nsview
procedure setFrame(aframe: NSRect); override;
// value
procedure setStringValue(avalue: NSString); override;
function stringValue: NSString; override;
procedure addSubView(aview: NSView); override;
public
// NSTextInputClientProtocol related.
// implements a base NSTextInputClient for non-editable LCL CustomControl,
// like Form, Grid, ListView, that are not system control and not FullEditControl.
// 1. when using IME in these controls, a temporary and one-time editor is shown
// at the bottom of the control, supporting IME such as Chinese.
// 2. refers to MacOS Finder, when using IME in the file list view,
// a small window will pop up at the bottom of the screen for input.
// the text can then be used for filename starting character match.
// 3. it is useful for implementing IME support for controls that do not
// have a text input window.
procedure keyDown(theEvent: NSEvent); override;
procedure insertText_replacementRange (aString: id; replacementRange: NSRange);
procedure setMarkedText_selectedRange_replacementRange (aString: id; selectedRange: NSRange; replacementRange: NSRange);
procedure unmarkText;
function selectedRange: NSRange;
function markedRange: NSRange;
function hasMarkedText: LCLObjCBoolean;
function attributedSubstringForProposedRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
function validAttributesForMarkedText: NSArray;
function firstRectForCharacterRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSRect;
function characterIndexForPoint (aPoint: NSPoint): NSUInteger;
procedure doCommandBySelector (aSelector: SEL); override;
end;
implementation
{ TCocoaCustomControl }
function TCocoaCustomControl.getWindowEditor(): NSTextView;
begin
Result:= NSTextView( self.window.fieldEditor_forObject(true,nil) );
end;
procedure TCocoaCustomControl.setStringValue(avalue: NSString);
begin
if Assigned(fstr) then fstr.release;
if ASsigned(avalue) then
fstr:=avalue.copyWithZone(nil)
else
fstr:=nil;
inherited setStringValue(avalue);
end;
function TCocoaCustomControl.stringValue: NSString;
begin
Result:=fstr;
end;
procedure TCocoaCustomControl.addSubView(aview: NSView);
var
mask: NSUInteger;
begin
inherited addSubView(aview);
if Assigned(aview) then
begin
// forcing LCL compatible "auto-move" mode. Sticking to left/top corner
if not autoresizesSubviews then
{$ifdef BOOLFIX}
setAutoresizesSubviews_(Ord(true));
{$else}
setAutoresizesSubviews(true);
{$endif}
if self.isFlipped then
mask:= NSViewMaxYMargin or NSViewMaxXMargin
else
mask:= NSViewMinYMargin or NSViewMaxXMargin;
aview.setAutoresizingMask(mask);
end;
end;
procedure TCocoaCustomControl.keyDown(theEvent: NSEvent);
var
textView: NSView;
isFirst: Boolean;
begin
if (not _inIME) and (theEvent.keyCode in
[kVK_Return, kVK_ANSI_KeypadEnter, kVK_Escape, kVK_Space]) then
begin
inherited;
exit;
end;
isFirst:= not _inIME;
inputContext.handleEvent(theEvent);
if _inIME and isFirst then
begin
textView:= getWindowEditor();
textView.setFrameSize( NSMakeSize(self.frame.size.width,16) );
self.addSubView( textView );
end
else if not _inIME then
inputContext.discardMarkedText;
end;
procedure TCocoaCustomControl.DoCallInputClientInsertText(nsText:NSString);
begin
if Assigned(callback) then
callback.InputClientInsertText(nsText.UTF8String);
nsText.release;
end;
// in TCocoaCustomControl, such as Form, Grid, ListView,
// after inputting text, another control may be focused.
// in insertText_replacementRange(), Cocoa/InputContext doesn't like it,
// so calling InputClientInsertText() asynchronously.
procedure TCocoaCustomControl.insertText_replacementRange(aString: id;
replacementRange: NSRange);
var
nsText: NSString;
begin
if not _inIME then exit;
unmarkText;
nsText:= getNSStringObject(aString).copy;
performSelector_withObject_afterDelay(ObjCSelector('DoCallInputClientInsertText:'), nsText, 0 );
end;
procedure TCocoaCustomControl.setMarkedText_selectedRange_replacementRange(
aString: id; selectedRange: NSRange; replacementRange: NSRange);
var
textView: NSTextView;
nsText: NSString;
begin
nsText:= getNSStringObject(aString);
if nsText.length > 0 then
begin
_inIME:= true;
textView:= getWindowEditor();
if Assigned(textView) then
textView.setMarkedText_selectedRange_replacementRange(aString,selectedRange,replacementRange);
end
else
unmarkText;
end;
function TCocoaCustomControl.hasMarkedText: LCLObjCBoolean;
begin
Result := _inIME;
end;
procedure TCocoaCustomControl.unmarkText;
var
textView: NSTextView;
begin
_inIME:= false;
textView:= getWindowEditor();
if Assigned(textView) then
textView.removeFromSuperview;
end;
function TCocoaCustomControl.firstRectForCharacterRange_actualRange(
aRange: NSRange; actualRange: NSRangePointer): NSRect;
var
point: NSPoint;
rect: NSRect;
begin
point:= self.convertPoint_toView(NSZeroPoint, nil);
rect:= NSMakeRect(point.x, point.y, 0, 16);
Result:= self.window.convertRectToScreen(rect);
end;
function TCocoaCustomControl.selectedRange: NSRange;
var
textView: NSText;
begin
textView:= getWindowEditor();
if not Assigned(textView) then
Result:= NSMakeRange( NSNotFound, 0 )
else
Result:= textView.selectedRange;
end;
function TCocoaCustomControl.markedRange: NSRange;
var
textView: NSTextView;
begin
textView:= getWindowEditor();
if not Assigned(textView) then
Result:= NSMakeRange( NSNotFound, 0 )
else
Result:= textView.markedRange;
end;
function TCocoaCustomControl.attributedSubstringForProposedRange_actualRange(
aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
begin
Result := nil;
end;
function TCocoaCustomControl.validAttributesForMarkedText: NSArray;
begin
Result := nil;
end;
function TCocoaCustomControl.characterIndexForPoint(aPoint: NSPoint
): NSUInteger;
begin
Result := 0;
end;
procedure TCocoaCustomControl.doCommandBySelector(aSelector: SEL);
begin
inherited doCommandBySelector(ASelector);
end;
procedure TCocoaCustomControl.dealloc;
begin
if Assigned(fstr) then fstr.release;
inherited dealloc;
end;
function TCocoaCustomControl.acceptsFirstResponder: LCLObjCBoolean;
begin
Result := True;
end;
function TCocoaCustomControl.acceptsFirstMouse(event: NSEvent): LCLObjCBoolean;
begin
// By default, a mouse-down event in a window that isnt the key window
// simply brings the window forward and makes it key; the event isnt sent
// to the NSView object over which the mouse click occurs. The NSView can
// claim an initial mouse-down event, however, by overriding acceptsFirstMouse: to return YES.
// see bug #33034
Result:=true;
end;
procedure TCocoaCustomControl.drawRect(dirtyRect: NSRect);
begin
if isdrawing=0 then faileddraw:=false;
inc(isdrawing);
inherited drawRect(dirtyRect);
// Implement Color property
if Assigned(callback) then
callback.DrawBackground(NSGraphicsContext.currentContext, bounds, dirtyRect);
if CheckMainThread and Assigned(callback) then
callback.Draw(NSGraphicsContext.currentContext, bounds, dirtyRect);
dec(isdrawing);
if (isdrawing=0) and (faileddraw) then
begin
// if the frame is changed during the Paint event,
// redrawing must be triggered to ensure that the
// correctly updated NSGraphicsContext is obtained.
// 1. for the new version of macOS, just set setNeedsDisplay()
// 2. for older versions of macOS, display() must be called by itself,
// and just setting by setNeedsDisplay() will not work.
if NSAppKitVersionNumber >= NSAppKitVersionNumber11_0 then
self.lclInvalidate
else
self.display;
end;
end;
function TCocoaCustomControl.lclGetCallback: ICommonCallback;
begin
Result := callback;
end;
procedure TCocoaCustomControl.lclClearCallback;
begin
callback := nil;
end;
function TCocoaCustomControl.lclIsMouseInAuxArea(Event: NSevent): Boolean;
begin
if auxMouseByParent and Assigned(superview) then
Result := superview.lclIsMouseInAuxArea(Event)
else
Result := false;
end;
procedure TCocoaCustomControl.mouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited mouseDown(event);
end;
procedure TCocoaCustomControl.mouseDragged(event: NSEvent);
begin
window.disableCursorRects;
if not Assigned(callback) or not callback.MouseMove(event) then
// calling inherited causes the drag event to be passed to the
// parent controls
//inherited mouseDragged(event);
;
end;
procedure TCocoaCustomControl.mouseEntered(event: NSEvent);
begin
inherited mouseEntered(event);
end;
procedure TCocoaCustomControl.mouseExited(event: NSEvent);
begin
inherited mouseExited(event);
end;
procedure TCocoaCustomControl.mouseMoved(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited mouseMoved(event);
end;
procedure TCocoaCustomControl.scrollWheel(event: NSEvent);
begin
if Assigned(self.lclGetTarget) and (self.lclGetTarget is TScrollingWinControl) then begin
inherited scrollWheel(event);
if Assigned(callback) then
callback.scrollWheel(event);
end else begin
if NOT Assigned(callback) or NOT callback.scrollWheel(event) then
inherited scrollWheel(event);
end;
end;
procedure TCocoaCustomControl.setFrame(aframe: NSRect);
begin
if NSEqualRects(aframe, frame) then Exit;
if isdrawing>0 then
faileddraw := true;
inherited setFrame(aframe);
// it actually should come from a notifcation
if Assigned(callback) then callback.frameDidChange(self);
end;
procedure TCocoaCustomControl.mouseUp(event: NSEvent);
begin
if not window.areCursorRectsEnabled then
begin
window.enableCursorRects;
window.resetCursorRects;
CursorHelper.SetCursorAtMousePos;
end;
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited mouseUp(event);
end;
procedure TCocoaCustomControl.rightMouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseDown(event);
end;
procedure TCocoaCustomControl.rightMouseUp(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseUp(event);
end;
procedure TCocoaCustomControl.rightMouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited rightMouseDragged(event);
end;
procedure TCocoaCustomControl.otherMouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseDown(event);
end;
procedure TCocoaCustomControl.otherMouseUp(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseUp(event);
end;
procedure TCocoaCustomControl.otherMouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited otherMouseDragged(event);
end;
end.

View File

@ -9,7 +9,7 @@ interface
uses
Classes, SysUtils,
LazUTF8,
CocoaAll, CocoaPrivate, CocoaUtils;
CocoaAll, CocoaPrivate, CocoaCustomControl, CocoaUtils;
type
{ ICocoaIMEControl }

View File

@ -112,92 +112,6 @@ type
procedure lclSetEnabled(AEnabled: Boolean); message 'lclSetEnabled:'; reintroduce;
end;
{ TCocoaCustomControl }
TCocoaCustomControl = objcclass(NSControl, NSTextInputClientProtocol)
private
fstr : NSString;
isdrawing : integer;
faileddraw : Boolean;
_inIME: Boolean;
private
function getWindowEditor(): NSTextView; message 'getWindowEditor';
procedure DoCallInputClientInsertText(nsText:NSString); message 'DoCallInputClientInsertText:';
public
callback: ICommonCallback;
auxMouseByParent: Boolean;
procedure dealloc; override;
function acceptsFirstResponder: LCLObjCBoolean; override;
procedure drawRect(dirtyRect: NSRect); override;
function lclGetCallback: ICommonCallback; override;
procedure lclClearCallback; override;
function lclIsMouseInAuxArea(Event: NSevent): Boolean; override;
// mouse
function acceptsFirstMouse(event: NSEvent): LCLObjCBoolean; override;
procedure mouseDown(event: NSEvent); override;
procedure mouseUp(event: NSEvent); override;
procedure rightMouseDown(event: NSEvent); override;
procedure rightMouseUp(event: NSEvent); override;
procedure rightMouseDragged(event: NSEvent); override;
procedure otherMouseDown(event: NSEvent); override;
procedure otherMouseUp(event: NSEvent); override;
procedure otherMouseDragged(event: NSEvent); override;
procedure mouseDragged(event: NSEvent); override;
procedure mouseEntered(event: NSEvent); override;
procedure mouseExited(event: NSEvent); override;
procedure mouseMoved(event: NSEvent); override;
procedure scrollWheel(event: NSEvent); override;
// nsview
procedure setFrame(aframe: NSRect); override;
// value
procedure setStringValue(avalue: NSString); override;
function stringValue: NSString; override;
procedure addSubView(aview: NSView); override;
public
// NSTextInputClientProtocol related.
// implements a base NSTextInputClient for non-editable LCL CustomControl,
// like Form, Grid, ListView, that are not system control and not FullEditControl.
// 1. when using IME in these controls, a temporary and one-time editor is shown
// at the bottom of the control, supporting IME such as Chinese.
// 2. refers to MacOS Finder, when using IME in the file list view,
// a small window will pop up at the bottom of the screen for input.
// the text can then be used for filename starting character match.
// 3. it is useful for implementing IME support for controls that do not
// have a text input window.
procedure keyDown(theEvent: NSEvent); override;
procedure insertText_replacementRange (aString: id; replacementRange: NSRange);
procedure setMarkedText_selectedRange_replacementRange (aString: id; selectedRange: NSRange; replacementRange: NSRange);
procedure unmarkText;
function selectedRange: NSRange;
function markedRange: NSRange;
function hasMarkedText: LCLObjCBoolean;
function attributedSubstringForProposedRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
function validAttributesForMarkedText: NSArray;
function firstRectForCharacterRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSRect;
function characterIndexForPoint (aPoint: NSPoint): NSUInteger;
procedure doCommandBySelector (aSelector: SEL); override;
end;
TStatusItemData = record
Text : NSString;
Width : Integer;
Align : TAlignment;
end;
TStatusItemDataArray = array of TStatusItemData;
TCocoaStatusBar = objcclass(TCocoaCustomControl)
public
//StatusBar : TStatusBar;
barcallback : IStatusBarCallback;
panelCell : NSCell;
procedure drawRect(dirtyRect: NSRect); override;
procedure dealloc; override;
end;
{ TCocoaGroupBox }
TCocoaGroupBox = objcclass(NSBox)
@ -455,362 +369,6 @@ begin
callback := nil;
end;
{ TCocoaCustomControl }
function TCocoaCustomControl.getWindowEditor(): NSTextView;
begin
Result:= NSTextView( self.window.fieldEditor_forObject(true,nil) );
end;
procedure TCocoaCustomControl.setStringValue(avalue: NSString);
begin
if Assigned(fstr) then fstr.release;
if ASsigned(avalue) then
fstr:=avalue.copyWithZone(nil)
else
fstr:=nil;
inherited setStringValue(avalue);
end;
function TCocoaCustomControl.stringValue: NSString;
begin
Result:=fstr;
end;
procedure TCocoaCustomControl.addSubView(aview: NSView);
var
mask: NSUInteger;
begin
inherited addSubView(aview);
if Assigned(aview) then
begin
// forcing LCL compatible "auto-move" mode. Sticking to left/top corner
if not autoresizesSubviews then
{$ifdef BOOLFIX}
setAutoresizesSubviews_(Ord(true));
{$else}
setAutoresizesSubviews(true);
{$endif}
if self.isFlipped then
mask:= NSViewMaxYMargin or NSViewMaxXMargin
else
mask:= NSViewMinYMargin or NSViewMaxXMargin;
aview.setAutoresizingMask(mask);
end;
end;
procedure TCocoaCustomControl.keyDown(theEvent: NSEvent);
var
textView: NSView;
isFirst: Boolean;
begin
if (not _inIME) and (theEvent.keyCode in
[kVK_Return, kVK_ANSI_KeypadEnter, kVK_Escape, kVK_Space]) then
begin
inherited;
exit;
end;
isFirst:= not _inIME;
inputContext.handleEvent(theEvent);
if _inIME and isFirst then
begin
textView:= getWindowEditor();
textView.setFrameSize( NSMakeSize(self.frame.size.width,16) );
self.addSubView( textView );
end
else if not _inIME then
inputContext.discardMarkedText;
end;
procedure TCocoaCustomControl.DoCallInputClientInsertText(nsText:NSString);
begin
if Assigned(callback) then
callback.InputClientInsertText(nsText.UTF8String);
nsText.release;
end;
// in TCocoaCustomControl, such as Form, Grid, ListView,
// after inputting text, another control may be focused.
// in insertText_replacementRange(), Cocoa/InputContext doesn't like it,
// so calling InputClientInsertText() asynchronously.
procedure TCocoaCustomControl.insertText_replacementRange(aString: id;
replacementRange: NSRange);
var
nsText: NSString;
begin
if not _inIME then exit;
unmarkText;
nsText:= getNSStringObject(aString).copy;
performSelector_withObject_afterDelay(ObjCSelector('DoCallInputClientInsertText:'), nsText, 0 );
end;
procedure TCocoaCustomControl.setMarkedText_selectedRange_replacementRange(
aString: id; selectedRange: NSRange; replacementRange: NSRange);
var
textView: NSTextView;
nsText: NSString;
begin
nsText:= getNSStringObject(aString);
if nsText.length > 0 then
begin
_inIME:= true;
textView:= getWindowEditor();
if Assigned(textView) then
textView.setMarkedText_selectedRange_replacementRange(aString,selectedRange,replacementRange);
end
else
unmarkText;
end;
function TCocoaCustomControl.hasMarkedText: LCLObjCBoolean;
begin
Result := _inIME;
end;
procedure TCocoaCustomControl.unmarkText;
var
textView: NSTextView;
begin
_inIME:= false;
textView:= getWindowEditor();
if Assigned(textView) then
textView.removeFromSuperview;
end;
function TCocoaCustomControl.firstRectForCharacterRange_actualRange(
aRange: NSRange; actualRange: NSRangePointer): NSRect;
var
point: NSPoint;
rect: NSRect;
begin
point:= self.convertPoint_toView(NSZeroPoint, nil);
rect:= NSMakeRect(point.x, point.y, 0, 16);
Result:= self.window.convertRectToScreen(rect);
end;
function TCocoaCustomControl.selectedRange: NSRange;
var
textView: NSText;
begin
textView:= getWindowEditor();
if not Assigned(textView) then
Result:= NSMakeRange( NSNotFound, 0 )
else
Result:= textView.selectedRange;
end;
function TCocoaCustomControl.markedRange: NSRange;
var
textView: NSTextView;
begin
textView:= getWindowEditor();
if not Assigned(textView) then
Result:= NSMakeRange( NSNotFound, 0 )
else
Result:= textView.markedRange;
end;
function TCocoaCustomControl.attributedSubstringForProposedRange_actualRange(
aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
begin
Result := nil;
end;
function TCocoaCustomControl.validAttributesForMarkedText: NSArray;
begin
Result := nil;
end;
function TCocoaCustomControl.characterIndexForPoint(aPoint: NSPoint
): NSUInteger;
begin
Result := 0;
end;
procedure TCocoaCustomControl.doCommandBySelector(aSelector: SEL);
begin
inherited doCommandBySelector(ASelector);
end;
procedure TCocoaCustomControl.dealloc;
begin
if Assigned(fstr) then fstr.release;
inherited dealloc;
end;
function TCocoaCustomControl.acceptsFirstResponder: LCLObjCBoolean;
begin
Result := True;
end;
function TCocoaCustomControl.acceptsFirstMouse(event: NSEvent): LCLObjCBoolean;
begin
// By default, a mouse-down event in a window that isnt the key window
// simply brings the window forward and makes it key; the event isnt sent
// to the NSView object over which the mouse click occurs. The NSView can
// claim an initial mouse-down event, however, by overriding acceptsFirstMouse: to return YES.
// see bug #33034
Result:=true;
end;
procedure TCocoaCustomControl.drawRect(dirtyRect: NSRect);
begin
if isdrawing=0 then faileddraw:=false;
inc(isdrawing);
inherited drawRect(dirtyRect);
// Implement Color property
if Assigned(callback) then
callback.DrawBackground(NSGraphicsContext.currentContext, bounds, dirtyRect);
if CheckMainThread and Assigned(callback) then
callback.Draw(NSGraphicsContext.currentContext, bounds, dirtyRect);
dec(isdrawing);
if (isdrawing=0) and (faileddraw) then
begin
// if the frame is changed during the Paint event,
// redrawing must be triggered to ensure that the
// correctly updated NSGraphicsContext is obtained.
// 1. for the new version of macOS, just set setNeedsDisplay()
// 2. for older versions of macOS, display() must be called by itself,
// and just setting by setNeedsDisplay() will not work.
if NSAppKitVersionNumber >= NSAppKitVersionNumber11_0 then
self.lclInvalidate
else
self.display;
end;
end;
function TCocoaCustomControl.lclGetCallback: ICommonCallback;
begin
Result := callback;
end;
procedure TCocoaCustomControl.lclClearCallback;
begin
callback := nil;
end;
function TCocoaCustomControl.lclIsMouseInAuxArea(Event: NSevent): Boolean;
begin
if auxMouseByParent and Assigned(superview) then
Result := superview.lclIsMouseInAuxArea(Event)
else
Result := false;
end;
procedure TCocoaCustomControl.mouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited mouseDown(event);
end;
procedure TCocoaCustomControl.mouseDragged(event: NSEvent);
begin
window.disableCursorRects;
if not Assigned(callback) or not callback.MouseMove(event) then
// calling inherited causes the drag event to be passed to the
// parent controls
//inherited mouseDragged(event);
;
end;
procedure TCocoaCustomControl.mouseEntered(event: NSEvent);
begin
inherited mouseEntered(event);
end;
procedure TCocoaCustomControl.mouseExited(event: NSEvent);
begin
inherited mouseExited(event);
end;
procedure TCocoaCustomControl.mouseMoved(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited mouseMoved(event);
end;
procedure TCocoaCustomControl.scrollWheel(event: NSEvent);
begin
if Assigned(self.lclGetTarget) and (self.lclGetTarget is TScrollingWinControl) then begin
inherited scrollWheel(event);
if Assigned(callback) then
callback.scrollWheel(event);
end else begin
if NOT Assigned(callback) or NOT callback.scrollWheel(event) then
inherited scrollWheel(event);
end;
end;
procedure TCocoaCustomControl.setFrame(aframe: NSRect);
begin
if NSEqualRects(aframe, frame) then Exit;
if isdrawing>0 then
faileddraw := true;
inherited setFrame(aframe);
// it actually should come from a notifcation
if Assigned(callback) then callback.frameDidChange(self);
end;
procedure TCocoaCustomControl.mouseUp(event: NSEvent);
begin
if not window.areCursorRectsEnabled then
begin
window.enableCursorRects;
window.resetCursorRects;
CursorHelper.SetCursorAtMousePos;
end;
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited mouseUp(event);
end;
procedure TCocoaCustomControl.rightMouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseDown(event);
end;
procedure TCocoaCustomControl.rightMouseUp(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseUp(event);
end;
procedure TCocoaCustomControl.rightMouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited rightMouseDragged(event);
end;
procedure TCocoaCustomControl.otherMouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseDown(event);
end;
procedure TCocoaCustomControl.otherMouseUp(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseUp(event);
end;
procedure TCocoaCustomControl.otherMouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited otherMouseDragged(event);
end;
{ LCLObjectExtension }
function LCLObjectExtension.lclIsEnabled: Boolean;
@ -1246,72 +804,6 @@ begin
Point.Y := Point.Y - dlt.Top;
end;
{ TCocoaStatusBar }
procedure TCocoaStatusBar.drawRect(dirtyRect: NSRect);
var
R : TRect;
i : Integer;
cs : NSString;
nr : NSRect;
dr : NSRect;
al : TAlignment;
x : Integer;
txt : string;
cnt : Integer;
w : Integer;
const
CocoaAlign: array [TAlignment] of Integer = (NSNaturalTextAlignment, NSRightTextAlignment, NSCenterTextAlignment);
begin
if not Assigned(barcallback) then Exit;
if not Assigned(panelCell) then Exit;
panelCell.setControlView(Self);
r := lclClientFrame();
nr.origin.y := 0;
nr.size.height := self.lclFrame.Height;
x:=0;
cnt := barcallback.GetBarsCount;
for i:=0 to cnt - 1 do begin
txt := '';
w := 0;
al := taLeftJustify;
if not barcallback.GetBarItem(i, txt, w, al) then Continue;
if i = cnt - 1 then w := r.Right - x;
nr.size.width := w;
nr.origin.x := x;
// dr - draw rect. should be 1 pixel wider
// and 1 pixel taller, than the actual rect.
// to produce a better visual effect
dr := nr;
dr.size.width := dr.size.width + 1;
dr.size.height := dr.size.height + 1;
dr.origin.y := dr.origin.y-1;
cs := NSStringUtf8(txt);
panelCell.setTitle(cs);
panelCell.setAlignment(CocoaAlign[al]);
panelCell.drawWithFrame_inView(dr, Self);
cs.release;
barcallback.DrawPanel(i, NSRectToRect(nr));
inc(x, w);
if x > r.Right then break; // no place left
end;
end;
procedure TCocoaStatusBar.dealloc;
begin
if Assigned(panelCell) then panelCell.release;
inherited;
end;
{ TCocoaProgressIndicator }
function TCocoaProgressIndicator.acceptsFirstResponder: LCLObjCBoolean;

View File

@ -0,0 +1,100 @@
unit CocoaStatusBar;
{$mode objfpc}{$H+}
{$modeswitch objectivec2}
{$interfaces corba}
interface
uses
Classes, SysUtils,
CocoaAll, CocoaPrivate, CocoaCallback, CocoaCustomControl, CocoaUtils;
type
TStatusItemData = record
Text : NSString;
Width : Integer;
Align : TAlignment;
end;
TStatusItemDataArray = array of TStatusItemData;
TCocoaStatusBar = objcclass(TCocoaCustomControl)
public
//StatusBar : TStatusBar;
barcallback : IStatusBarCallback;
panelCell : NSCell;
procedure drawRect(dirtyRect: NSRect); override;
procedure dealloc; override;
end;
implementation
{ TCocoaStatusBar }
procedure TCocoaStatusBar.drawRect(dirtyRect: NSRect);
var
R : TRect;
i : Integer;
cs : NSString;
nr : NSRect;
dr : NSRect;
al : TAlignment;
x : Integer;
txt : string;
cnt : Integer;
w : Integer;
const
CocoaAlign: array [TAlignment] of Integer = (NSNaturalTextAlignment, NSRightTextAlignment, NSCenterTextAlignment);
begin
if not Assigned(barcallback) then Exit;
if not Assigned(panelCell) then Exit;
panelCell.setControlView(Self);
r := lclClientFrame();
nr.origin.y := 0;
nr.size.height := self.lclFrame.Height;
x:=0;
cnt := barcallback.GetBarsCount;
for i:=0 to cnt - 1 do begin
txt := '';
w := 0;
al := taLeftJustify;
if not barcallback.GetBarItem(i, txt, w, al) then Continue;
if i = cnt - 1 then w := r.Right - x;
nr.size.width := w;
nr.origin.x := x;
// dr - draw rect. should be 1 pixel wider
// and 1 pixel taller, than the actual rect.
// to produce a better visual effect
dr := nr;
dr.size.width := dr.size.width + 1;
dr.size.height := dr.size.height + 1;
dr.origin.y := dr.origin.y-1;
cs := NSStringUtf8(txt);
panelCell.setTitle(cs);
panelCell.setAlignment(CocoaAlign[al]);
panelCell.drawWithFrame_inView(dr, Self);
cs.release;
barcallback.DrawPanel(i, NSRectToRect(nr));
inc(x, w);
if x > r.Right then break; // no place left
end;
end;
procedure TCocoaStatusBar.dealloc;
begin
if Assigned(panelCell) then panelCell.release;
inherited;
end;
end.

View File

@ -24,7 +24,8 @@ interface
uses
Types, Classes, SysUtils,
MacOSAll, CocoaAll, CocoaUtils, CocoaPrivate, CocoaCallback, CocoaConst;
MacOSAll, CocoaAll, CocoaUtils, CocoaPrivate, CocoaCallback, CocoaConst,
CocoaCustomControl;
type

View File

@ -24,9 +24,9 @@ interface
uses
Types, Classes, SysUtils,
MacOSAll, CocoaAll, CocoaUtils, CocoaCursor,
cocoa_extra, CocoaPrivate, CocoaCallback, CocoaTextEdits, CocoaScrollers,
LCLType, LCLProc;
LCLType, LCLProc,
MacOSAll, CocoaAll, CocoaPrivate, CocoaCallback, cocoa_extra, CocoaUtils,
CocoaCursor, CocoaCustomControl, CocoaTextEdits, CocoaScrollers;
type

View File

@ -15,7 +15,7 @@ uses
WSComCtrls,
MacOSAll, CocoaAll,
CocoaPrivate, CocoaCallback, CocoaWSCommon, CocoaGDIObjects, CocoaUtils,
CocoaTabControls, CocoaButtons;
CocoaTabControls, CocoaButtons, CocoaStatusBar;
type

View File

@ -12,7 +12,7 @@ uses
WSControls, LCLType, LCLMessageGlue, LMessages, LCLProc, LCLIntf, Graphics, Forms,
StdCtrls,
CocoaAll, CocoaInt, CocoaConfig, CocoaPrivate, CocoaCallback, CocoaUtils,
CocoaScrollers, CocoaWSScrollers, CocoaFullControlEdit,
CocoaCustomControl, CocoaScrollers, CocoaWSScrollers, CocoaFullControlEdit,
CocoaGDIObjects, CocoaCursor, CocoaCaret, cocoa_extra;
type

View File

@ -30,8 +30,8 @@ uses
// widgetset
WSExtCtrls, WSLCLClasses,
// LCL Cocoa
CocoaPrivate, CocoaMenus, CocoaWSCommon, CocoaGDIObjects, CocoaScrollers,
Cocoa_Extra, CocoaUtils, CocoaConfig;
CocoaPrivate, CocoaWSCommon, CocoaGDIObjects, CocoaConfig, Cocoa_Extra,
CocoaCustomControl, CocoaScrollers, CocoaMenus, CocoaUtils;
type

View File

@ -32,7 +32,7 @@ uses
// LCL Cocoa
CocoaInt, CocoaConfig, CocoaPrivate, CocoaCallback, CocoaUtils, CocoaWSCommon, CocoaMenus,
CocoaGDIObjects,
CocoaWindows, CocoaScrollers, CocoaWSScrollers, cocoa_extra;
CocoaWindows, CocoaCustomControl, CocoaScrollers, CocoaWSScrollers, cocoa_extra;
type
{ TLCLWindowCallback }

View File

@ -7,7 +7,7 @@ interface
uses
Classes, LCLType, Controls, Forms,
CocoaAll, CocoaPrivate, CocoaScrollers, CocoaUtils;
CocoaAll, CocoaPrivate, CocoaCustomControl, CocoaScrollers, CocoaUtils;
type
{ ASyncLCLControlAdjustSizer }

View File

@ -37,7 +37,7 @@ uses
CocoaPrivate, CocoaCallback, CocoaListControl, CocoaTables,
CocoaConst, CocoaConfig, CocoaWSCommon, CocoaUtils,
CocoaGDIObjects, CocoaButtons, CocoaTextEdits,
CocoaScrollers, CocoaWSScrollers, Cocoa_Extra;
CocoaCustomControl, CocoaScrollers, CocoaWSScrollers, Cocoa_Extra;
type

View File

@ -131,7 +131,7 @@ end;"/>
<License Value="modified LGPL-2
"/>
<Version Major="3" Minor="99"/>
<Files Count="542">
<Files Count="544">
<Item1>
<Filename Value="carbon/agl.pp"/>
<AddToUsesPkgSection Value="False"/>
@ -2678,6 +2678,16 @@ end;"/>
<AddToUsesPkgSection Value="False"/>
<UnitName Value="cocoafullcontroledit"/>
</Item542>
<Item543>
<Filename Value="cocoa/cocoacustomcontrol.pas"/>
<AddToUsesPkgSection Value="False"/>
<UnitName Value="CocoaCustomControl"/>
</Item543>
<Item544>
<Filename Value="cocoa/cocoastatusbar.pas"/>
<AddToUsesPkgSection Value="False"/>
<UnitName Value="CocoaStatusBar"/>
</Item544>
</Files>
<CompatibilityMode Value="True"/>
<LazDoc Paths="../../docs/xml/lcl"/>