* Implemented cocoa TMainMenu support

* Implemented shortcut support in menus (Not all keys are supported yet)
 * Improved handling of sub-menus

git-svn-id: trunk@43792 -
This commit is contained in:
joost 2014-01-25 11:41:57 +00:00
parent a491cb1360
commit 58b46afe02
5 changed files with 125 additions and 19 deletions

View File

@ -112,6 +112,8 @@ type
procedure FreeStockItems;
procedure FreeSysColorBrushes;
procedure SetMainMenu(const AMenu: HMENU);
{todo:}
function DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor; override;
procedure DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor); override;

View File

@ -397,6 +397,12 @@ begin
DeleteAndNilObject(FSysColorBrushes[i]);
end;
procedure TCocoaWidgetSet.SetMainMenu(const AMenu: HMENU);
begin
if AMenu<>0 then
NSApp.setMainMenu(NSMenu(AMenu));
end;
{------------------------------------------------------------------------------
Method: TCocoaWidgetSet.GetAppHandle
Returns: Returns NSApp object, created via NSApplication.sharedApplication

View File

@ -6,8 +6,9 @@ unit CocoaUtils;
interface
uses
classes,
MacOSAll, CocoaAll,
Types, LCLType;
Types, LCLType, LCLProc, menus;
const
LCLEventSubTypeMessage = MaxShort - 1;
@ -61,6 +62,8 @@ function NSColorToRGB(const Color: NSColor): TColorRef; inline;
function NSColorToColorRef(const Color: NSColor): TColorRef;
function ColorToNSColor(const Color: TColorRef): NSColor; inline;
procedure ShortcutToKeyEquivalent(const AShortCut: TShortcut; out Key: string; out shiftKeyMask: NSUInteger);
implementation
const
@ -152,6 +155,29 @@ begin
((Color shr 16) and $FF) / $FF, 1);
end;
procedure ShortcutToKeyEquivalent(const AShortCut: TShortcut; out Key: string; out shiftKeyMask: NSUInteger);
var
w: word;
s: TShiftState;
begin
ShortCutToKey(AShortCut, w, s);
case w of
VK_DELETE: key := char(NSDeleteCharacter);
VK_OEM_2 : key := char(44);
else
key := lowercase(char(w and $ff));
end;
shiftKeyMask := 0;
if ssShift in s then
ShiftKeyMask := ShiftKeyMask + NSShiftKeyMask;
if ssAlt in s then
ShiftKeyMask := ShiftKeyMask + NSAlternateKeyMask;
if ssCtrl in s then
ShiftKeyMask := ShiftKeyMask + NSControlKeyMask;
if ssMeta in s then
ShiftKeyMask := ShiftKeyMask + NSCommandKeyMask;
end;
function CFStringToStr(AString: CFStringRef; Encoding: CFStringEncoding = DEFAULT_CFSTRING_ENCODING): String;
var
Str: Pointer;

View File

@ -246,7 +246,26 @@ begin
end;
procedure TLCLWindowCallback.Activate;
var
ACustForm: TCustomForm;
begin
ACustForm := Target as TCustomForm;
if (ACustForm.Menu <> nil) and
(ACustForm.Menu.HandleAllocated) then
begin
if NSObject(ACustForm.Menu.Handle).isKindOfClass_(TCocoaMenuItem) then
begin
if TCocoaMenuItem(ACustForm.Menu.Handle).hasSubmenu then
CocoaWidgetSet.SetMainMenu(HMENU(TCocoaMenuItem(ACustForm.Menu.Handle).submenu))
else
debugln('Warning: Menu does not have a valid handle.');
end
else
CocoaWidgetSet.SetMainMenu(ACustForm.Menu.Handle);
end
else
CocoaWidgetSet.SetMainMenu(0);
LCLSendActivateMsg(Target, WA_ACTIVE, false);
end;

View File

@ -25,6 +25,8 @@ uses
// Libs
CocoaAll,
MacOSAll,
// RTL
sysutils,
// LCL
Controls, Forms, Menus, Graphics, LCLType, LMessages, LCLProc, Classes,
// Widgetset
@ -113,7 +115,7 @@ end;
------------------------------------------------------------------------------}
class function TCocoaWSMenu.CreateHandle(const AMenu: TMenu): HMENU;
begin
Result:=HMENU(TCocoaMenu.alloc.initWithTitle(NSString.alloc.initWithCString('hello world')));
Result:=HMENU(TCocoaMenu.alloc.init) ;
end;
{ TCocoaWSMenuItem }
@ -129,15 +131,25 @@ var
ParObj : NSObject;
Parent : TCocoaMenu;
item : NSMenuItem;
ns : NSString;
s : string;
begin
if not Assigned(AMenuItem) or (AMenuItem.Handle=0) or not Assigned(AMenuItem.Parent) or (AMenuItem.Parent.Handle=0) then Exit;
ParObj:=NSObject(AMenuItem.Parent.Handle);
if ParObj.isKindOfClass_(NSMenuItem) then
begin
item:=NSMenuItem(AMenuItem.Handle);
if not item.hasSubmenu then item.setSubmenu(TCocoaMenu.alloc.initWithTitle(NSSTR('')));
Parent:=TCocoaMenu(item.submenu);
if not NSMenuItem(ParObj).hasSubmenu then
begin
s := AMenuItem.Parent.Caption;
DeleteAmpersands(s);
ns := NSStringUtf8(pchar(s));
Parent := TCocoaMenu.alloc.initWithTitle(ns);
NSMenuItem(ParObj).setSubmenu(Parent);
ns.release;
end
else
Parent:=TCocoaMenu(NSMenuItem(ParObj).submenu);
end else if ParObj.isKindOfClass_(NSMenu) then
Parent:=TCocoaMenu(ParObj)
else
@ -157,7 +169,12 @@ end;
class function TCocoaWSMenuItem.CreateHandle(const AMenuItem: TMenuItem): HMENU;
var
item : NSMenuItem;
ANSMenu : NSMenu;
s : string;
ns : NSString;
nsKey : NSString;
key : string;
ShiftSt : NSUInteger;
begin
if not Assigned(AMenuItem) then Exit;
@ -165,10 +182,24 @@ begin
item := NSMenuItem.separatorItem
else
begin
ns := NSStringUtf8(AMenuItem.Caption);
s := AMenuItem.Caption;
DeleteAmpersands(s);
ShortcutToKeyEquivalent(AMenuItem.ShortCut, key, ShiftSt);
nsKey := NSString(CFStringCreateWithCString(nil, pointer(pchar(key)), kCFStringEncodingASCII));
ns := NSStringUtf8(s);
item := TCocoaMenuItem.alloc.initWithTitle_action_keyEquivalent(ns,
objcselector('lclItemSelected:'), NSString.alloc.init);
objcselector('lclItemSelected:'), nsKey);
item.setKeyEquivalentModifierMask(ShiftSt);
if AMenuItem.IsInMenuBar then
begin
ANSMenu := TCocoaMenu.alloc.initWithTitle(ns);
item.setSubmenu(ANSMenu);
end;
ns.release;
nsKey.release;
item.setTarget(item);
TCocoaMenuItem(item).menuItemCallback:=TLCLMenuItemCallback.Create(item, AMenuItem);
item.setEnabled(AMenuItem.Enabled);
@ -187,20 +218,29 @@ class procedure TCocoaWSMenuItem.DestroyHandle(const AMenuItem: TMenuItem);
var
callback: IMenuItemCallback;
callbackObject: TObject;
item: TCocoaMenuItem;
item : NSObject;
parItem : NSObject;
begin
if AMenuItem.Caption <> '-' then
begin
item := TCocoaMenuItem(AMenuItem.Handle);
callback := item.lclGetCallback;
if Assigned(callback) then
begin
callbackObject := callback.GetCallbackObject;
callback := nil;
item.lclClearCallback;
callbackObject.Free;
item:=NSObject(AMenuItem.Handle);
if item.isKindOfClass_(TCocoaMenuItem) then
begin
callback := TCocoaMenuItem(item).lclGetCallback;
if Assigned(callback) then
begin
callbackObject := callback.GetCallbackObject;
callback := nil;
TCocoaMenuItem(item).lclClearCallback;
callbackObject.Free;
end;
parItem := TCocoaMenuItem(Item).parentItem;
if assigned(parItem) and parItem.isKindOfClass_(NSMenuItem) then
NSMenuItem(paritem).submenu.removeItem(NSMenuItem(item));
Item.Release;
AMenuItem.Handle := 0;
end
end;
end;
end;
{------------------------------------------------------------------------------
@ -213,10 +253,15 @@ end;
class procedure TCocoaWSMenuItem.SetCaption(const AMenuItem: TMenuItem; const ACaption: string);
var
ns : NSString;
s: string;
begin
if not Assigned(AMenuItem) or (AMenuItem.Handle=0) then Exit;
ns:=NSStringUtf8(ACaption);
s := ACaption;
DeleteAmpersands(s);
ns:=NSStringUtf8(s);
NSMenuItem(AMenuItem.Handle).setTitle(ns);
if NSMenuItem(AMenuItem.Handle).hasSubmenu then
NSMenuItem(AMenuItem.Handle).submenu.setTitle(ns);
ns.release;
end;
@ -229,8 +274,16 @@ end;
------------------------------------------------------------------------------}
class procedure TCocoaWSMenuItem.SetShortCut(const AMenuItem: TMenuItem;
const ShortCutK1, ShortCutK2: TShortCut);
var
key: string;
ShiftState: NSUInteger;
ns: NSString;
begin
ShortcutToKeyEquivalent(ShortCutK1, key, ShiftState);
ns := NSString(CFStringCreateWithCString(nil, pointer(pchar(key)), kCFStringEncodingASCII));
TCocoaMenuItem(AMenuItem.Handle).setKeyEquivalentModifierMask(ShiftState);
TCocoaMenuItem(AMenuItem.Handle).setKeyEquivalent(ns);
ns.release;
end;
{------------------------------------------------------------------------------