mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
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:
parent
50a1091ebc
commit
576df3b593
7 changed files with 333 additions and 6 deletions
|
|
@ -177,6 +177,7 @@ struct MMImp {
|
|||
tw->placefocus = false;
|
||||
}
|
||||
Upp::Ctrl::SyncAppIcon();
|
||||
Upp::TopWindow::SyncMainMenu(false);
|
||||
}
|
||||
|
||||
static void ResignKey(Upp::Ctrl *ctrl)
|
||||
|
|
|
|||
|
|
@ -25,11 +25,7 @@ bool TopWindow::IsTopMost() const
|
|||
void TopWindow::GuiPlatformConstruct()
|
||||
{
|
||||
}
|
||||
|
||||
void TopWindow::GuiPlatformDestruct()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
//$ };
|
||||
|
|
@ -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
246
uppsrc/CtrlLib/MacMenu.mm
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -482,7 +482,7 @@ void MenuBar::Set(const Event<Bar&> menu)
|
|||
lock++;
|
||||
menu(*this);
|
||||
SyncBar();
|
||||
DistributeAccessKeys();
|
||||
DistributeAccessKeys();
|
||||
lock--;
|
||||
}
|
||||
|
||||
|
|
|
|||
73
uppsrc/CtrlLib/NSMenuKeys.i
Normal file
73
uppsrc/CtrlLib/NSMenuKeys.i
Normal 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 , ']' },
|
||||
Loading…
Add table
Add a link
Reference in a new issue