CtrlLib: OSX Main application menu support

git-svn-id: svn://ultimatepp.org/upp/trunk@12341 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2018-10-07 17:49:53 +00:00
parent 50a1091ebc
commit 576df3b593
7 changed files with 333 additions and 6 deletions

View file

@ -177,6 +177,7 @@ struct MMImp {
tw->placefocus = false;
}
Upp::Ctrl::SyncAppIcon();
Upp::TopWindow::SyncMainMenu(false);
}
static void ResignKey(Upp::Ctrl *ctrl)

View file

@ -25,11 +25,7 @@ bool TopWindow::IsTopMost() const
void TopWindow::GuiPlatformConstruct()
{
}
void TopWindow::GuiPlatformDestruct()
{
}
END_UPP_NAMESPACE
#endif

View file

@ -7,4 +7,13 @@ protected:
dword GetMMStyle() const;
virtual void MMClose() { WhenClose(); }
static TopWindow *GetMenuTopWindow();
static void SyncMainMenu(bool force);
void *menubar = NULL;
public:
void SetMainMenu(Event<Bar&> menu);
//$ };

View file

@ -65,6 +65,8 @@ file
MenuImp.h,
MenuItem.cpp,
MenuBar.cpp,
NSMenuKeys.i,
MacMenu.mm,
ToolButton.cpp,
ToolBar.cpp,
ToolTip.cpp,

246
uppsrc/CtrlLib/MacMenu.mm Normal file
View file

@ -0,0 +1,246 @@
#include <CtrlLib/CtrlLib.h>
#include <CtrlCore/CocoMM.h>
namespace Upp {
struct CocoMenuBar;
};
@interface CocoMenu : NSMenu<NSMenuDelegate>
{
@public
Upp::Ptr<Upp::CocoMenuBar> ptr;
Upp::Event<Upp::Bar&> proc;
}
-(void)cocoMenuAction:(id)sender;
@end
namespace Upp {
struct CocoMenuBar : public Bar {
CocoMenu *cocomenu;
int lock = 0;
struct Item : Bar::Item {
NSMenuItem *nsitem;
Event<> cb;
One<CocoMenuBar> submenu;
virtual Item& Text(const char *text);
virtual Item& Key(dword key);
virtual Item& Image(const class Image& img);
virtual Item& Check(bool check);
virtual Item& Radio(bool check);
virtual Item& Enable(bool _enable = true);
virtual Item& Bold(bool bold = true);
Item& Label(const char *text);
Item& RightLabel(const char *text);
Item& Key(KeyInfo& (*key)());
Item() { nsitem = [NSMenuItem new]; }
~Item() { [nsitem release]; }
};
Array<Item> item;
Item& AddItem() {
Item& m = item.Add();
[cocomenu addItem:m.nsitem];
return m;
}
virtual bool IsMenuBar() const { return true; }
virtual Item& AddItem(Event<> cb) {
Item& m = AddItem();
m.cb = cb;
m.nsitem.target = cocomenu;
m.nsitem.action = @selector(cocoMenuAction:);
return m;
}
virtual Item& AddSubMenu(Event<Bar&> proc) {
Item& m = AddItem();
m.submenu.Create();
m.submenu->cocomenu->proc = proc;
m.nsitem.action = @selector(cocoMenuAction:);
m.nsitem.submenu = m.submenu->cocomenu;
return m;
}
virtual void AddCtrl(Ctrl *ctrl, int gapsize) { NEVER(); }
virtual void AddCtrl(Ctrl *ctrl, Size sz) { NEVER(); }
virtual bool IsEmpty() const;
virtual void Separator();
void MenuAction(id item);
void Set(Event<Bar&> bar);
CocoMenuBar() {
cocomenu = [CocoMenu new];
cocomenu.autoenablesItems = NO;
cocomenu->ptr = this;
cocomenu.delegate = cocomenu;
}
~CocoMenuBar() {
[cocomenu release];
}
};
void CocoMenuBar::Set(Event<Bar&> bar)
{
if(lock) return;
lock++;
bar(*this);
lock--;
}
void CocoMenuBar::MenuAction(id sender)
{
for(const Item& m : item)
if(m.nsitem == sender) {
m.cb();
break;
}
}
void CocoMenuBar::Separator()
{
[cocomenu addItem:[NSMenuItem separatorItem]];
}
CocoMenuBar::Item& CocoMenuBar::Item::Text(const char *text)
{
NSString *s = [NSString stringWithUTF8String:text];
nsitem.title = s;
if(submenu)
submenu->cocomenu.title = s;
return *this;
}
CocoMenuBar::Item& CocoMenuBar::Item::Key(dword key)
{
static Tuple2<int, int> code[] = {
#include "NSMenuKeys.i"
};
auto *v = FindTuple(code, __countof(code), key & ~(K_CTRL|K_SHIFT|K_ALT|K_OPTION));
if(v) {
unichar chr = v->b;
nsitem.keyEquivalent = [NSString stringWithCharacters:&chr length:1];
nsitem.keyEquivalentModifierMask = (key & K_CTRL ? NSEventModifierFlagCommand : 0) |
(key & K_SHIFT ? NSEventModifierFlagShift : 0) |
(key & K_ALT ? NSEventModifierFlagControl : 0) |
(key & K_OPTION ? NSEventModifierFlagOption : 0);
}
return *this;
}
CocoMenuBar::Item& CocoMenuBar::Item::Image(const class Image& img)
{
nsitem.image = GetNSImage(img);
return *this;
}
CocoMenuBar::Item& CocoMenuBar::Item::Check(bool check)
{
nsitem.state = check ? NSControlStateValueOn : NSControlStateValueOff;
return *this;
}
CocoMenuBar::Item& CocoMenuBar::Item::Radio(bool check)
{
return Check(check);
}
CocoMenuBar::Item& CocoMenuBar::Item::Enable(bool enable)
{
nsitem.enabled = enable;
return *this;
}
CocoMenuBar::Item& CocoMenuBar::Item::Bold(bool bold)
{
return *this;
}
bool CocoMenuBar::IsEmpty() const
{
return item.GetCount() == 0;
}
}
@implementation CocoMenu
-(void)cocoMenuAction:(id)sender {
if(ptr)
ptr->MenuAction(sender);
}
- (void)menuWillOpen:(NSMenu *)menu {
CocoMenu *m = (CocoMenu *)menu;
if(m && m->ptr && proc) {
[m removeAllItems];
proc(*m->ptr);
}
}
-(void)submenuAction:(id)sender {
if(ptr)
proc(*ptr);
[super submenuAction:sender];
}
@end
namespace Upp {
void TopWindow::GuiPlatformDestruct()
{
if(menubar)
delete (CocoMenuBar *)menubar;
}
void TopWindow::SetMainMenu(Event<Bar&> menu)
{
if(!menubar)
menubar = new CocoMenuBar;
CocoMenuBar& bar = *(CocoMenuBar *)menubar;
bar.Set(menu);
SyncMainMenu(true);
}
TopWindow *TopWindow::GetMenuTopWindow()
{
Ctrl *q = GetFocusCtrl();
if(!q)
return NULL;
q = q->GetTopCtrl();
while(q) {
TopWindow *w = dynamic_cast<TopWindow *>(q);
if(w && w->menubar)
return w;
q = q->GetOwner();
}
return NULL;
}
void TopWindow::SyncMainMenu(bool force)
{
TopWindow *w = GetMenuTopWindow();
static TopWindow *current;
if(w != current || force) {
current = w;
if(current) {
CocoMenuBar& bar = *(CocoMenuBar *)current->menubar;
[NSApp setMainMenu:bar.cocomenu];
}
}
}
};

View file

@ -482,7 +482,7 @@ void MenuBar::Set(const Event<Bar&> menu)
lock++;
menu(*this);
SyncBar();
DistributeAccessKeys();
DistributeAccessKeys();
lock--;
}

View file

@ -0,0 +1,73 @@
{ K_BACK, NSBackspaceCharacter },
{ K_TAB, NSTabCharacter },
{ K_SPACE, ' ' },
{ K_RETURN, NSCarriageReturnCharacter },
{ K_ESCAPE, 27 },
{ K_PAGEUP, NSPageUpFunctionKey },
{ K_PAGEDOWN, NSPageDownFunctionKey },
{ K_END, NSEndFunctionKey },
{ K_HOME, NSHomeFunctionKey },
{ K_LEFT, NSLeftArrowFunctionKey },
{ K_UP, NSUpArrowFunctionKey },
{ K_RIGHT, NSRightArrowFunctionKey },
{ K_DOWN, NSDownArrowFunctionKey },
{ K_INSERT, NSInsertFunctionKey }, // Code is this for external keyboard..
{ K_DELETE, NSDeleteFunctionKey },
{ K_F1, NSF1FunctionKey },
{ K_F2, NSF2FunctionKey },
{ K_F3, NSF3FunctionKey },
{ K_F4, NSF4FunctionKey },
{ K_F5, NSF5FunctionKey },
{ K_F6, NSF6FunctionKey },
{ K_F7, NSF7FunctionKey },
{ K_F8, NSF8FunctionKey },
{ K_F9, NSF9FunctionKey },
{ K_F10, NSF10FunctionKey },
{ K_F11, NSF11FunctionKey },
{ K_F12, NSF12FunctionKey },
{ K_A, 'a' },
{ K_B, 'b' },
{ K_C, 'c' },
{ K_D, 'd' },
{ K_E, 'e' },
{ K_F, 'f' },
{ K_G, 'g' },
{ K_H, 'h' },
{ K_I, 'i' },
{ K_J, 'j' },
{ K_K, 'k' },
{ K_L, 'l' },
{ K_M, 'm' },
{ K_N, 'n' },
{ K_O, 'o' },
{ K_P, 'p' },
{ K_Q, 'q' },
{ K_R, 'r' },
{ K_S, 's' },
{ K_T, 't' },
{ K_U, 'u' },
{ K_V, 'v' },
{ K_W, 'w' },
{ K_X, 'x' },
{ K_Y, 'y' },
{ K_Z, 'z' },
{ K_0, '0' },
{ K_1, '1' },
{ K_2, '2' },
{ K_3, '3' },
{ K_4, '4' },
{ K_5, '5' },
{ K_6, '6' },
{ K_7, '7' },
{ K_8, '8' },
{ K_9, '9' },
{ K_MINUS , '-' },
{ K_COMMA , ',' },
{ K_PERIOD , '.' },
{ K_SEMICOLON , ';' },
{ K_SLASH , '/' },
{ K_GRAVE , '\'' },
{ K_LBRACKET , '[' },
{ K_BACKSLASH , '\\' },
{ K_RBRACKET , ']' },