cocoa: reimplement form using NSPanel, reimplement modality using form enabling/disabling

git-svn-id: trunk@34706 -
This commit is contained in:
paul 2012-01-11 07:07:25 +00:00
parent e51a29d78d
commit 76ea22831e
3 changed files with 249 additions and 171 deletions

View File

@ -211,6 +211,7 @@ begin
lcNeedMininimizeAppWithMainForm, lcNeedMininimizeAppWithMainForm,
lcApplicationTitle, lcApplicationTitle,
lcFormIcon, lcFormIcon,
lcModalWindow,
lcReceivesLMClearCutCopyPasteReliably: lcReceivesLMClearCutCopyPasteReliably:
Result := LCL_CAPABILITY_NO; Result := LCL_CAPABILITY_NO;
lcAntialiasingEnabledByDefault: lcAntialiasingEnabledByDefault:

View File

@ -149,12 +149,18 @@ type
{ IWindowCallback } { IWindowCallback }
IWindowCallback = interface(ICommonCallBack) IWindowCallback = interface(ICommonCallBack)
function CanActivate: Boolean;
procedure Activate; procedure Activate;
procedure Deactivate; procedure Deactivate;
procedure CloseQuery(var CanClose: Boolean); procedure CloseQuery(var CanClose: Boolean);
procedure Close; procedure Close;
procedure Resize; procedure Resize;
procedure Move; procedure Move;
function GetEnabled: Boolean;
procedure SetEnabled(AValue: Boolean);
property Enabled: Boolean read GetEnabled write SetEnabled;
end; end;
{ TCocoaMenu } { TCocoaMenu }
@ -235,9 +241,9 @@ type
procedure resetCursorRects; override; procedure resetCursorRects; override;
end; end;
{ TCocoaWindow } { TCocoaPanel }
TCocoaWindow = objcclass(NSWindow, NSWindowDelegateProtocol) TCocoaPanel = objcclass(NSPanel, NSWindowDelegateProtocol)
protected protected
function windowShouldClose(sender : id): LongBool; message 'windowShouldClose:'; function windowShouldClose(sender : id): LongBool; message 'windowShouldClose:';
procedure windowWillClose(notification: NSNotification); message 'windowWillClose:'; procedure windowWillClose(notification: NSNotification); message 'windowWillClose:';
@ -248,6 +254,7 @@ type
public public
callback: IWindowCallback; callback: IWindowCallback;
function acceptsFirstResponder: Boolean; override; function acceptsFirstResponder: Boolean; override;
function canBecomeKeyWindow: Boolean; override;
function becomeFirstResponder: Boolean; override; function becomeFirstResponder: Boolean; override;
function resignFirstResponder: Boolean; override; function resignFirstResponder: Boolean; override;
function lclGetCallback: ICommonCallback; override; function lclGetCallback: ICommonCallback; override;
@ -414,6 +421,160 @@ begin
AView.setAutoresizingMask(NSViewMinYMargin or NSViewMaxXMargin); AView.setAutoresizingMask(NSViewMinYMargin or NSViewMaxXMargin);
end; end;
{ TCocoaPanel }
function TCocoaPanel.windowShouldClose(sender: id): LongBool;
var
canClose: Boolean;
begin
canClose := True;
callback.CloseQuery(canClose);
Result := canClose;
end;
procedure TCocoaPanel.windowWillClose(notification: NSNotification);
begin
callback.Close;
end;
procedure TCocoaPanel.windowDidBecomeKey(notification: NSNotification);
begin
callback.Activate;
end;
procedure TCocoaPanel.windowDidResignKey(notification: NSNotification);
begin
callback.Deactivate;
end;
procedure TCocoaPanel.windowDidResize(notification: NSNotification);
begin
callback.Resize;
end;
procedure TCocoaPanel.windowDidMove(notification: NSNotification);
begin
callback.Move;
end;
function TCocoaPanel.acceptsFirstResponder: Boolean;
begin
Result := True;
end;
function TCocoaPanel.canBecomeKeyWindow: Boolean;
begin
Result := callback.CanActivate;
end;
function TCocoaPanel.becomeFirstResponder: Boolean;
begin
Result := inherited becomeFirstResponder;
callback.BecomeFirstResponder;
end;
function TCocoaPanel.resignFirstResponder: Boolean;
begin
Result := inherited resignFirstResponder;
callback.ResignFirstResponder;
end;
function TCocoaPanel.lclGetCallback: ICommonCallback;
begin
Result := callback;
end;
procedure TCocoaPanel.mouseDown(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited mouseDown(event);
end;
procedure TCocoaPanel.mouseUp(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited mouseUp(event);
end;
procedure TCocoaPanel.rightMouseDown(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited rightMouseUp(event);
end;
procedure TCocoaPanel.rightMouseUp(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited rightMouseDown(event);
end;
procedure TCocoaPanel.otherMouseDown(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited otherMouseDown(event);
end;
procedure TCocoaPanel.otherMouseUp(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited otherMouseUp(event);
end;
procedure TCocoaPanel.mouseDragged(event: NSEvent);
begin
if not callback.MouseMove(event) then
inherited mouseDragged(event);
end;
procedure TCocoaPanel.mouseEntered(event: NSEvent);
begin
inherited mouseEntered(event);
end;
procedure TCocoaPanel.mouseExited(event: NSEvent);
begin
inherited mouseExited(event);
end;
procedure TCocoaPanel.mouseMoved(event: NSEvent);
begin
if not callback.MouseMove(event) then
inherited mouseMoved(event);
end;
procedure TCocoaPanel.sendEvent(event: NSEvent);
var
Message: NSMutableDictionary;
Handle: HWND;
Msg: Cardinal;
WP: WParam;
LP: LParam;
Result: NSNumber;
Obj: NSObject;
begin
if event.type_ = NSApplicationDefined then
begin
// event which we get through PostMessage or SendMessage
if event.subtype = LCLEventSubTypeMessage then
begin
// extract message data
Message := NSMutableDictionary(event.data1);
Handle := NSNumber(Message.objectForKey(NSMessageWnd)).unsignedIntegerValue;
Msg := NSNumber(Message.objectForKey(NSMessageMsg)).unsignedLongValue;
WP := NSNumber(Message.objectForKey(NSMessageWParam)).integerValue;
LP := NSNumber(Message.objectForKey(NSMessageLParam)).integerValue;
// deliver message and set result
Obj := NSObject(Handle);
// todo: check that Obj is still a valid NSView/NSWindow
Result := NSNumber.numberWithInteger(Obj.lclDeliverMessage(Msg, WP, LP));
Message.setObject_forKey(Result, NSMessageResult);
Result.release;
end;
end
else
inherited sendEvent(event);
end;
{ TCocoaScrollView } { TCocoaScrollView }
function TCocoaScrollView.acceptsFirstResponder: Boolean; function TCocoaScrollView.acceptsFirstResponder: Boolean;
@ -602,6 +763,7 @@ end;
procedure TCocoaButton.mouseDragged(event: NSEvent); procedure TCocoaButton.mouseDragged(event: NSEvent);
begin begin
if not callback.MouseMove(event) then
inherited mouseDragged(event); inherited mouseDragged(event);
end; end;
@ -617,6 +779,7 @@ end;
procedure TCocoaButton.mouseMoved(event: NSEvent); procedure TCocoaButton.mouseMoved(event: NSEvent);
begin begin
if not callback.MouseMove(event) then
inherited mouseMoved(event); inherited mouseMoved(event);
end; end;
@ -683,155 +846,6 @@ begin
inherited resetCursorRects; inherited resetCursorRects;
end; end;
{ TCocoaWindow }
function TCocoaWindow.windowShouldClose(sender: id): LongBool;
var
canClose: Boolean;
begin
canClose := True;
callback.CloseQuery(canClose);
Result := canClose;
end;
procedure TCocoaWindow.windowWillClose(notification: NSNotification);
begin
callback.Close;
end;
procedure TCocoaWindow.windowDidBecomeKey(notification: NSNotification);
begin
callback.Activate;
end;
procedure TCocoaWindow.windowDidResignKey(notification: NSNotification);
begin
callback.Deactivate;
end;
procedure TCocoaWindow.windowDidResize(notification: NSNotification);
begin
callback.Resize;
end;
procedure TCocoaWindow.windowDidMove(notification: NSNotification);
begin
callback.Move;
end;
function TCocoaWindow.acceptsFirstResponder: Boolean;
begin
Result := True;
end;
function TCocoaWindow.becomeFirstResponder: Boolean;
begin
Result := inherited becomeFirstResponder;
callback.BecomeFirstResponder;
end;
function TCocoaWindow.resignFirstResponder: Boolean;
begin
Result := inherited resignFirstResponder;
callback.ResignFirstResponder;
end;
function TCocoaWindow.lclGetCallback: ICommonCallback;
begin
Result := callback;
end;
procedure TCocoaWindow.mouseUp(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited mouseUp(event);
end;
procedure TCocoaWindow.rightMouseDown(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited rightMouseDown(event);
end;
procedure TCocoaWindow.rightMouseUp(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited rightMouseUp(event);
end;
procedure TCocoaWindow.otherMouseDown(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited otherMouseDown(event);
end;
procedure TCocoaWindow.otherMouseUp(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited otherMouseUp(event);
end;
procedure TCocoaWindow.mouseDown(event: NSEvent);
begin
if not callback.MouseUpDownEvent(event) then
inherited mouseDown(event);
end;
procedure TCocoaWindow.mouseDragged(event: NSEvent);
begin
if not callback.MouseMove(event) then
inherited mouseDragged(event);
end;
procedure TCocoaWindow.mouseMoved(event: NSEvent);
begin
if not callback.MouseMove(event) then
inherited mouseMoved(event);
end;
procedure TCocoaWindow.sendEvent(event: NSEvent);
var
Message: NSMutableDictionary;
Handle: HWND;
Msg: Cardinal;
WP: WParam;
LP: LParam;
Result: NSNumber;
Obj: NSObject;
begin
if event.type_ = NSApplicationDefined then
begin
// event which we get through PostMessage or SendMessage
if event.subtype = LCLEventSubTypeMessage then
begin
// extract message data
Message := NSMutableDictionary(event.data1);
Handle := NSNumber(Message.objectForKey(NSMessageWnd)).unsignedIntegerValue;
Msg := NSNumber(Message.objectForKey(NSMessageMsg)).unsignedLongValue;
WP := NSNumber(Message.objectForKey(NSMessageWParam)).integerValue;
LP := NSNumber(Message.objectForKey(NSMessageLParam)).integerValue;
// deliver message and set result
Obj := NSObject(Handle);
// todo: check that Obj is still a valid NSView/NSWindow
Result := NSNumber.numberWithInteger(Obj.lclDeliverMessage(Msg, WP, LP));
Message.setObject_forKey(Result, NSMessageResult);
Result.release;
end;
end
else
inherited sendEvent(event);
end;
procedure TCocoaWindow.mouseEntered(event: NSEvent);
begin
inherited mouseEntered(event);
end;
procedure TCocoaWindow.mouseExited(event: NSEvent);
begin
inherited mouseExited(event);
end;
{ TCocoaSecureTextField } { TCocoaSecureTextField }
function TCocoaSecureTextField.acceptsFirstResponder: Boolean; function TCocoaSecureTextField.acceptsFirstResponder: Boolean;
@ -1263,12 +1277,24 @@ begin
end; end;
function LCLWindowExtension.lclIsEnabled: Boolean; function LCLWindowExtension.lclIsEnabled: Boolean;
var
Callback: ICommonCallback;
begin begin
Callback := lclGetCallback;
if Assigned(Callback) then
Result := IWindowCallback(Callback).Enabled
else
Result := contentView.lclIsEnabled; Result := contentView.lclIsEnabled;
end; end;
procedure LCLWindowExtension.lclSetEnabled(AEnabled: Boolean); procedure LCLWindowExtension.lclSetEnabled(AEnabled: Boolean);
var
Callback: ICommonCallback;
begin begin
Callback := lclGetCallback;
if Assigned(Callback) then
IWindowCallback(Callback).Enabled := AEnabled
else
contentView.lclSetEnabled(AEnabled); contentView.lclSetEnabled(AEnabled);
end; end;

View File

@ -42,12 +42,18 @@ type
TLCLWindowCallback = class(TLCLCommonCallBack, IWindowCallback) TLCLWindowCallback = class(TLCLCommonCallBack, IWindowCallback)
public public
function CanActivate: Boolean; virtual;
procedure Activate; virtual; procedure Activate; virtual;
procedure Deactivate; virtual; procedure Deactivate; virtual;
procedure CloseQuery(var CanClose: Boolean); virtual; procedure CloseQuery(var CanClose: Boolean); virtual;
procedure Close; virtual; procedure Close; virtual;
procedure Resize; virtual; procedure Resize; virtual;
procedure Move; virtual; procedure Move; virtual;
function GetEnabled: Boolean; virtual;
procedure SetEnabled(AValue: Boolean); virtual;
property Enabled: Boolean read GetEnabled write SetEnabled;
end; end;
@ -127,7 +133,7 @@ type
private private
protected protected
public public
// class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
end; end;
{ TCocoaWSScreen } { TCocoaWSScreen }
@ -152,8 +158,44 @@ implementation
uses uses
CocoaInt; CocoaInt;
{ TCocoaWSHintWindow }
class function TCocoaWSHintWindow.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): TLCLIntfHandle;
var
win: TCocoaPanel;
cnt: TCocoaCustomControl;
const
WinMask = NSBorderlessWindowMask or NSUtilityWindowMask;
begin
win := TCocoaPanel(TCocoaPanel.alloc);
if not Assigned(win) then
begin
Result := 0;
Exit;
end;
win := TCocoaPanel(win.initWithContentRect_styleMask_backing_defer(CreateParamsToNSRect(AParams), WinMask, NSBackingStoreBuffered, False));
win.enableCursorRects;
TCocoaPanel(win).callback := TLCLWindowCallback.Create(win, AWinControl);
win.setDelegate(win);
win.setAcceptsMouseMovedEvents(True);
cnt := TCocoaCustomControl.alloc.init;
cnt.callback := TCocoaPanel(win).callback;
win.setContentView(cnt);
Result := TLCLIntfHandle(win);
end;
{ TLCLWindowCallback } { TLCLWindowCallback }
function TLCLWindowCallback.CanActivate: Boolean;
begin
Result := Enabled;
end;
procedure TLCLWindowCallback.Activate; procedure TLCLWindowCallback.Activate;
begin begin
LCLSendActivateMsg(Target, True, false); LCLSendActivateMsg(Target, True, false);
@ -167,7 +209,7 @@ end;
procedure TLCLWindowCallback.CloseQuery(var CanClose: Boolean); procedure TLCLWindowCallback.CloseQuery(var CanClose: Boolean);
begin begin
// Message results : 0 - do nothing, 1 - destroy window // Message results : 0 - do nothing, 1 - destroy window
CanClose:=LCLSendCloseQueryMsg(Target)>0; CanClose := LCLSendCloseQueryMsg(Target) > 0;
end; end;
procedure TLCLWindowCallback.Close; procedure TLCLWindowCallback.Close;
@ -185,6 +227,16 @@ begin
boundsDidChange; boundsDidChange;
end; end;
function TLCLWindowCallback.GetEnabled: Boolean;
begin
Result := NSWindow(Owner).contentView.lclIsEnabled;
end;
procedure TLCLWindowCallback.SetEnabled(AValue: Boolean);
begin
NSWindow(Owner).contentView.lclSetEnabled(AValue);
end;
{ TCocoaWSCustomForm } { TCocoaWSCustomForm }
@ -234,13 +286,13 @@ end;
class function TCocoaWSCustomForm.CreateHandle(const AWinControl: TWinControl; class function TCocoaWSCustomForm.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): TLCLIntfHandle; const AParams: TCreateParams): TLCLIntfHandle;
var var
win: TCocoaWindow; win: TCocoaPanel;
cnt: TCocoaCustomControl; cnt: TCocoaCustomControl;
ns: NSString; ns: NSString;
const const
WinMask = NSTitledWindowMask or NSClosableWindowMask or NSMiniaturizableWindowMask or NSResizableWindowMask; WinMask= NSTitledWindowMask or NSClosableWindowMask or NSMiniaturizableWindowMask or NSResizableWindowMask;
begin begin
win := TCocoaWindow(TCocoaWindow.alloc); win := TCocoaPanel(TCocoaPanel.alloc);
if not Assigned(win) then if not Assigned(win) then
begin begin
@ -248,9 +300,9 @@ begin
Exit; Exit;
end; end;
win := TCocoaWindow(win.initWithContentRect_styleMask_backing_defer(CreateParamsToNSRect(AParams), WinMask, NSBackingStoreBuffered, False)); win := TCocoaPanel(win.initWithContentRect_styleMask_backing_defer(CreateParamsToNSRect(AParams), WinMask, NSBackingStoreBuffered, False));
win.enableCursorRects; win.enableCursorRects;
TCocoaWindow(win).callback := TLCLWindowCallback.Create(win, AWinControl); TCocoaPanel(win).callback := TLCLWindowCallback.Create(win, AWinControl);
win.setDelegate(win); win.setDelegate(win);
ns := NSStringUtf8(AWinControl.Caption); ns := NSStringUtf8(AWinControl.Caption);
win.setTitle(ns); win.setTitle(ns);
@ -258,7 +310,7 @@ begin
win.setAcceptsMouseMovedEvents(True); win.setAcceptsMouseMovedEvents(True);
cnt := TCocoaCustomControl.alloc.init; cnt := TCocoaCustomControl.alloc.init;
cnt.callback := TCocoaWindow(win).callback; cnt.callback := TCocoaPanel(win).callback;
win.setContentView(cnt); win.setContentView(cnt);
if (AParams.Style and WS_CHILD) = 0 then if (AParams.Style and WS_CHILD) = 0 then
@ -278,14 +330,14 @@ class function TCocoaWSCustomForm.GetText(const AWinControl: TWinControl; var AT
begin begin
Result := AWinControl.HandleAllocated; Result := AWinControl.HandleAllocated;
if Result then if Result then
AText := NSStringToString(TCocoaWindow(AWinControl.Handle).title); AText := NSStringToString(NSWindow(AWinControl.Handle).title);
end; end;
class function TCocoaWSCustomForm.GetTextLen(const AWinControl: TWinControl; var ALength: Integer): Boolean; class function TCocoaWSCustomForm.GetTextLen(const AWinControl: TWinControl; var ALength: Integer): Boolean;
begin begin
Result := AWinControl.HandleAllocated; Result := AWinControl.HandleAllocated;
if Result then if Result then
ALength := TCocoaWindow(AWinControl.Handle).title.length; ALength := NSWindow(AWinControl.Handle).title.length;
end; end;
class procedure TCocoaWSCustomForm.SetText(const AWinControl: TWinControl; const AText: String); class procedure TCocoaWSCustomForm.SetText(const AWinControl: TWinControl; const AText: String);
@ -294,21 +346,20 @@ var
begin begin
if not AWinControl.HandleAllocated then Exit; if not AWinControl.HandleAllocated then Exit;
ns := NSStringUtf8(AText); ns := NSStringUtf8(AText);
TCocoaWindow(AWinControl.Handle).setTitle(ns); NSwindow(AWinControl.Handle).setTitle(ns);
ns.release; ns.release;
end; end;
class procedure TCocoaWSCustomForm.CloseModal(const ACustomForm: TCustomForm); class procedure TCocoaWSCustomForm.CloseModal(const ACustomForm: TCustomForm);
begin begin
if ACustomForm.HandleAllocated then // if ACustomForm.HandleAllocated then
if CocoaWidgetSet.NSApp.modalWindow = NSWindow(ACustomForm.Handle) then // NSPanel(ACustomForm.Handle).setStyleMask(NSwindow(ACustomForm.Handle).styleMask and not NSDocModalWindowMask);
CocoaWidgetSet.NSApp.stopModal;
end; end;
class procedure TCocoaWSCustomForm.ShowModal(const ACustomForm: TCustomForm); class procedure TCocoaWSCustomForm.ShowModal(const ACustomForm: TCustomForm);
begin begin
if ACustomForm.HandleAllocated then // if ACustomForm.HandleAllocated then
CocoaWidgetSet.NSApp.runModalForWindow(NSWindow(ACustomForm.Handle)); // NSPanel(ACustomForm.Handle).setStyleMask(NSwindow(ACustomForm.Handle).styleMask or NSDocModalWindowMask);
end; end;
class procedure TCocoaWSCustomForm.SetAlphaBlend(const ACustomForm: TCustomForm; const AlphaBlend: Boolean; const Alpha: Byte); class procedure TCocoaWSCustomForm.SetAlphaBlend(const ACustomForm: TCustomForm; const AlphaBlend: Boolean; const Alpha: Byte);