Improvement of the Fl_Sys_Menu_Bar class in relation to STR #3047:
- menu shortcuts, including function keys, are correctly handled - the mac system menus and FLTK menus share Fl_Menu_Item's, thus many member functions of the parent Fl_Menu_ class apply equally to an Fl_Sys_Menu_Bar. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10099 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
f352740953
commit
b01cbd577b
@ -25,23 +25,24 @@
|
||||
#if defined(__APPLE__) || defined(FL_DOXYGEN)
|
||||
|
||||
/**
|
||||
@brief A class to create, modify and delete menus that appear on Mac OS X in the menu bar at the top of the screen.
|
||||
*
|
||||
* On other than Mac OS X platforms, Fl_Sys_Menu_Bar is a synonym of class Fl_Menu_Bar.
|
||||
*
|
||||
* You can configure a callback for the 'About' menu item to invoke your own code with fl_mac_set_about().
|
||||
\brief A class to create, modify and delete menus that appear on Mac OS X in the menu bar at the top of the screen.
|
||||
|
||||
On other than Mac OS X platforms, Fl_Sys_Menu_Bar is a synonym of class Fl_Menu_Bar.
|
||||
Some FLTK features are not supported by the Mac System menu:
|
||||
\li no symbolic labels
|
||||
\li no embossed labels
|
||||
\li no font sizes
|
||||
\li some calls of the parent class don't work
|
||||
|
||||
You can configure a callback for the 'About' menu item to invoke your own code with fl_mac_set_about().
|
||||
*
|
||||
*/
|
||||
class FL_EXPORT Fl_Sys_Menu_Bar : public Fl_Menu_Bar {
|
||||
protected:
|
||||
void draw();
|
||||
public:
|
||||
/**
|
||||
@brief The constructor.
|
||||
*
|
||||
* On Mac OS X, all arguments are unused. On other platforms they are used as by Fl_Menu_Bar::Fl_Menu_Bar().
|
||||
*/
|
||||
Fl_Sys_Menu_Bar(int x,int y,int w,int h,const char *l=0);
|
||||
~Fl_Sys_Menu_Bar();
|
||||
const Fl_Menu_Item *menu() const {return Fl_Menu_::menu();}
|
||||
void menu(const Fl_Menu_Item *m);
|
||||
int add(const char* label, int shortcut, Fl_Callback*, void *user_data=0, int flags=0);
|
||||
|
||||
@ -17,8 +17,7 @@
|
||||
//
|
||||
|
||||
/*
|
||||
* This code is a quick hack! It was written as a proof of concept.
|
||||
* It has been tested on the "menubar" sample program and provides
|
||||
* This code has been tested on the "menubar" sample program and provides
|
||||
* basic functionality.
|
||||
*
|
||||
* To use the System Menu Bar, simply replace the main Fl_Menu_Bar
|
||||
@ -29,8 +28,6 @@
|
||||
* - no symbolic labels
|
||||
* - no embossed labels
|
||||
* - no font sizes
|
||||
* - Shortcut Characters should be Latin letters only
|
||||
* - no disable main menus
|
||||
*
|
||||
* Many other calls of the parent class don't work.
|
||||
*/
|
||||
@ -66,20 +63,43 @@ static char *remove_ampersand(const char *s);
|
||||
extern void (*fl_lock_function)();
|
||||
extern void (*fl_unlock_function)();
|
||||
|
||||
/* Each MacOS system menu item contains a pointer to a record of type sys_menu_item defined below.
|
||||
The purpose of these records is to associate each MacOS system menu item with a relevant Fl_Menu_Item.
|
||||
If use_rank is YES, the "rank" field is used, and fl_sys_menu_bar->menu() + rank is the address
|
||||
of the relevant Fl_Menu_Item;
|
||||
Otherwise, the "item" field points to the relevant Fl_Menu_Item.
|
||||
This allows the MacOS system menu to use the same Fl_Menu_Item's as those used by FLTK menus,
|
||||
the address of which can be relocated by the FLTK menu logic.
|
||||
The "item" field is used for non-relocatable Fl_Menu_Item's associated to FL_SUBMENU_POINTER.
|
||||
Sending the getFlItem message to a MacOS system menu item (of class FLMenuItem) returns the address
|
||||
of the relevant Fl_Menu_Item.
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
int rank;
|
||||
const Fl_Menu_Item *item;
|
||||
};
|
||||
BOOL use_rank;
|
||||
} sys_menu_item;
|
||||
|
||||
|
||||
@interface FLMenuItem : NSMenuItem {
|
||||
}
|
||||
- (void) doCallback:(id)unused;
|
||||
- (void) directCallback:(id)unused;
|
||||
- (const Fl_Menu_Item*) getFlItem;
|
||||
- (void) setKeyEquivalent:(char)value;
|
||||
- (void) setKeyEquivalentModifierMask:(int)value;
|
||||
- (void) setFltkShortcut:(int)key;
|
||||
+ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu;
|
||||
@end
|
||||
|
||||
@implementation FLMenuItem
|
||||
- (const Fl_Menu_Item*) getFlItem
|
||||
// returns the Fl_Menu_Item corresponding to this system menu item
|
||||
{
|
||||
return (const Fl_Menu_Item *)[(NSData*)[self representedObject] bytes];
|
||||
sys_menu_item *smi = (sys_menu_item*)[(NSData*)[self representedObject] bytes];
|
||||
if (smi->use_rank) return fl_sys_menu_bar->menu() + smi->rank;
|
||||
return smi->item;
|
||||
}
|
||||
- (void) doCallback:(id)unused
|
||||
{
|
||||
@ -121,12 +141,6 @@ extern void (*fl_unlock_function)();
|
||||
if ( item && item->callback() ) item->do_callback(NULL);
|
||||
fl_unlock_function();
|
||||
}
|
||||
- (void) setKeyEquivalent:(char)key
|
||||
{
|
||||
NSString *equiv = [[NSString alloc] initWithBytes:&key length:1 encoding:NSASCIIStringEncoding];
|
||||
[super setKeyEquivalent:equiv];
|
||||
[equiv release];
|
||||
}
|
||||
- (void) setKeyEquivalentModifierMask:(int)value
|
||||
{
|
||||
NSUInteger macMod = 0;
|
||||
@ -136,6 +150,20 @@ extern void (*fl_unlock_function)();
|
||||
if ( value & FL_CTRL ) macMod |= NSControlKeyMask;
|
||||
[super setKeyEquivalentModifierMask:macMod];
|
||||
}
|
||||
- (void) setFltkShortcut:(int)key
|
||||
{
|
||||
// Separate key and modifier
|
||||
int mod = key;
|
||||
mod &= ~FL_KEY_MASK; // modifier(s)
|
||||
key &= FL_KEY_MASK; // key
|
||||
unichar mac_key = (unichar)key;
|
||||
if ( (key >= (FL_F+1)) && (key <= FL_F_Last) ) { // Handle function keys
|
||||
int fkey_num = (key - FL_F); // 1,2..
|
||||
mac_key = NSF1FunctionKey + fkey_num - 1;
|
||||
}
|
||||
[self setKeyEquivalent:[NSString stringWithCharacters:&mac_key length:1]];
|
||||
[self setKeyEquivalentModifierMask:mod];
|
||||
}
|
||||
+ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu
|
||||
{
|
||||
char *name = remove_ampersand(mitem->label());
|
||||
@ -144,7 +172,11 @@ extern void (*fl_unlock_function)();
|
||||
FLMenuItem *item = [[FLMenuItem alloc] initWithTitle:(NSString*)cfname
|
||||
action:@selector(doCallback:)
|
||||
keyEquivalent:@""];
|
||||
NSData *pointer = [NSData dataWithBytes:(void*)mitem length:sizeof(Fl_Menu_Item)];
|
||||
sys_menu_item smi;
|
||||
smi.rank = fl_sys_menu_bar->find_index(mitem); // ≥ 0 if mitem is in the menu items of fl_sys_menu_bar, -1 if not
|
||||
smi.use_rank = (smi.rank >= 0);
|
||||
if (!smi.use_rank) smi.item = mitem;
|
||||
NSData *pointer = [NSData dataWithBytes:&smi length:sizeof(smi)];
|
||||
[item setRepresentedObject:pointer];
|
||||
[menu addItem:item];
|
||||
CFRelease(cfname);
|
||||
@ -170,10 +202,8 @@ void fl_mac_set_about( Fl_Callback *cb, void *user_data, int shortcut)
|
||||
FLMenuItem *item = [[[FLMenuItem alloc] initWithTitle:(NSString*)cfname
|
||||
action:@selector(directCallback:)
|
||||
keyEquivalent:@""] autorelease];
|
||||
if (aboutItem.shortcut()) {
|
||||
[item setKeyEquivalent:(aboutItem.shortcut() & 0xff)];
|
||||
[item setKeyEquivalentModifierMask:aboutItem.shortcut()];
|
||||
}
|
||||
if (aboutItem.shortcut())
|
||||
[item setFltkShortcut:aboutItem.shortcut()];
|
||||
NSData *pointer = [NSData dataWithBytes:&aboutItem length:sizeof(Fl_Menu_Item)];
|
||||
[item setRepresentedObject:pointer];
|
||||
[appleMenu insertItem:item atIndex:0];
|
||||
@ -192,13 +222,8 @@ static void setMenuShortcut( NSMenu* mh, int miCnt, const Fl_Menu_Item *m )
|
||||
return;
|
||||
if ( m->flags & FL_SUBMENU_POINTER )
|
||||
return;
|
||||
char key = m->shortcut_ & 0xff;
|
||||
if ( !isalnum( key ) )
|
||||
return;
|
||||
|
||||
FLMenuItem* menuItem = (FLMenuItem*)[mh itemAtIndex:miCnt];
|
||||
[menuItem setKeyEquivalent:(m->shortcut_ & 0xff)];
|
||||
[menuItem setKeyEquivalentModifierMask:m->shortcut_];
|
||||
[menuItem setFltkShortcut:(m->shortcut_)];
|
||||
}
|
||||
|
||||
|
||||
@ -281,7 +306,7 @@ static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *m
|
||||
else if ( mm->flags & FL_SUBMENU_POINTER )
|
||||
{
|
||||
const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_;
|
||||
createSubMenu( submenu, smm, mm );
|
||||
createSubMenu( submenu, smm, mm);
|
||||
}
|
||||
if ( flags & FL_MENU_DIVIDER ) {
|
||||
[submenu addItem:[NSMenuItem separatorItem]];
|
||||
@ -358,7 +383,7 @@ int Fl_Sys_Menu_Bar::add(const char* label, int shortcut, Fl_Callback *cb, void
|
||||
{
|
||||
fl_open_display();
|
||||
int rank = Fl_Menu_::add(label, shortcut, cb, user_data, flags);
|
||||
convertToMenuBar(Fl_Menu_::menu());
|
||||
update();
|
||||
return rank;
|
||||
}
|
||||
|
||||
@ -374,7 +399,7 @@ int Fl_Sys_Menu_Bar::insert(int index, const char* label, int shortcut, Fl_Callb
|
||||
{
|
||||
fl_open_display();
|
||||
int rank = Fl_Menu_::insert(index, label, shortcut, cb, user_data, flags);
|
||||
convertToMenuBar(Fl_Menu_::menu());
|
||||
update();
|
||||
return rank;
|
||||
}
|
||||
|
||||
@ -387,7 +412,7 @@ void Fl_Sys_Menu_Bar::clear()
|
||||
int Fl_Sys_Menu_Bar::clear_submenu(int index)
|
||||
{
|
||||
int retval = Fl_Menu_::clear_submenu(index);
|
||||
if (retval != -1) convertToMenuBar(Fl_Menu_::menu());
|
||||
if (retval != -1) update();
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -399,7 +424,7 @@ int Fl_Sys_Menu_Bar::clear_submenu(int index)
|
||||
void Fl_Sys_Menu_Bar::remove(int rank)
|
||||
{
|
||||
Fl_Menu_::remove(rank);
|
||||
convertToMenuBar(Fl_Menu_::menu());
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
@ -412,7 +437,7 @@ void Fl_Sys_Menu_Bar::remove(int rank)
|
||||
void Fl_Sys_Menu_Bar::replace(int rank, const char *name)
|
||||
{
|
||||
Fl_Menu_::replace(rank, name);
|
||||
convertToMenuBar(Fl_Menu_::menu());
|
||||
update();
|
||||
}
|
||||
|
||||
/** Updates the system menu.
|
||||
@ -430,14 +455,33 @@ void Fl_Sys_Menu_Bar::update()
|
||||
void Fl_Sys_Menu_Bar::draw() {
|
||||
}
|
||||
|
||||
static int process_sys_menu_shortcuts(int event)
|
||||
{
|
||||
if (event != FL_SHORTCUT || !fl_sys_menu_bar) return 0;
|
||||
// have the system menu process the shortcut, highlighting the corresponding menu if found
|
||||
return [[NSApp mainMenu] performKeyEquivalent:[NSApp currentEvent]];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The constructor.
|
||||
On Mac OS X, all arguments are unused. On other platforms they are used as by Fl_Menu_Bar::Fl_Menu_Bar().
|
||||
*/
|
||||
Fl_Sys_Menu_Bar::Fl_Sys_Menu_Bar(int x,int y,int w,int h,const char *l)
|
||||
: Fl_Menu_Bar(x,y,w,h,l)
|
||||
{
|
||||
deactivate(); // don't let the old area take events
|
||||
fl_sys_menu_bar = this;
|
||||
Fl::add_handler(process_sys_menu_shortcuts);
|
||||
}
|
||||
|
||||
/** The destructor */
|
||||
Fl_Sys_Menu_Bar::~Fl_Sys_Menu_Bar()
|
||||
{
|
||||
fl_sys_menu_bar = 0;
|
||||
clear();
|
||||
Fl::remove_handler(process_sys_menu_shortcuts);
|
||||
}
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user