A menu is an *array* of these structures. The structure is designed so it is relatively easy to define an entire hierarchy of menus with a C initialization constant. Example:
![]() |
Fl_Menu popup[] = { {"&alpha", FL_ALT+'a', the_cb, (void*)1}, {"&beta", FL_ALT+'b', the_cb, (void*)2}, {"gamma", FL_ALT+'c', the_cb, (void*)3, FL_MENU_DIVIDER}, {"&strange", 0, strange_cb}, {"&charm", 0, charm_cb}, {"&truth", 0, truth_cb}, {"b&eauty", 0, beauty_cb}, {"sub&menu", 0, 0, 0, FL_SUBMENU}, {"one"}, {"two"}, {"three"}, {0}, {"inactive", FL_ALT+'i', 0, 0, FL_MENU_INACTIVE|FL_MENU_DIVIDER}, {"invisible",FL_ALT+'i', 0, 0, FL_MENU_INVISIBLE}, {"check", FL_ALT+'i', 0, 0, FL_MENU_CHECK|FL_MENU_BOX}, {"box", FL_ALT+'i', 0, 0, FL_MENU_BOX}, {0}}; |
FL_SUBMENU
in
the flags field, and ends with a label() that is null. You can nest
menus to any depth. A pointer to the first item in the submenu can be
treated as an Fl_Menu array itself. It is also possible to make
seperate submenu arrays with FL_SUBMENU_POINTER
flags.
Unfortunately all the fields have to be initialized by position. You don't need to give values for unused fields, the remaining ones get zero as their default value.
struct Fl_Menu { const char* text; // label() ulong shortcut_; Fl_Callback* callback_; void* user_data_; int flags; uchar labeltype_; uchar labelfont_; uchar labelsize_; uchar labelcolor_; }; enum { // values for flags: FL_MENU_INACTIVE = 1, FL_MENU_BOX = 2, FL_MENU_CHECK = 4, FL_MENU_RADIO = 8, FL_MENU_INVISIBLE = 0x10, FL_SUBMENU_POINTER = 0x20, FL_SUBMENU = 0x40, FL_MENU_DIVIDER = 0x80, FL_MENU_HORIZONTAL = 0x100 };
You should not use the member names to refer to the Fl_Menu structure, instead use the methods described below.
const char* Fl_Menu::label() const;
void Fl_Menu::label(const char*);
void Fl_Menu::label(uchar,const char*);
uchar Fl_Menu::labeltype() const;
void Fl_Menu::labeltype(uchar);
uchar Fl_Menu::labelcolor() const;
void Fl_Menu::labelcolor(uchar);
uchar Fl_Menu::labelfont() const;
void Fl_Menu::labelfont(uchar);
uchar Fl_Menu::labelsize() const;
void Fl_Menu::labelsize(uchar);
static void Fl_Menu::textfont(uchar x);
static void Fl_Menu::textsize(uchar x);
static uchar Fl_Menu::textfont();
static uchar Fl_Menu::textsize();
typedef void (Fl_Callback)(Fl_Widget*, void*);
Fl_Callback* Fl_Menu::callback() const;
void Fl_Menu::callback(Fl_Callback*, void* = 0);
void* Fl_Menu::user_data() const;
void Fl_Menu::user_data(void*);
void Fl_Menu::callback(void (*)(Fl_Widget*, long), long = 0);
long Fl_Menu::argument() const;
void Fl_Menu::argument(long);
void Fl_Menu::callback(void (*)(Fl_Widget*));
void Fl_Menu::do_callback(Fl_Widget*);
void Fl_Menu::do_callback(Fl_Widget*, void*);
void Fl_Menu::do_callback(Fl_Widget*, long);
ulong Fl_Menu::shortcut() const;
void Fl_Menu::shortcut(ulong);
Sets exactly what key combination will trigger the menu item. The
value is a logical 'or' of a key and a set of shift flags, for
instance FL_ALT+'a'
or FL_ALT+FL_F+10
or
just 'a'. A value of zero disables the shortcut.
The key can be any value returned by Fl::event_key(), but will usually be an ascii letter. Use a lower-case letter unless you require the shift key to be held down.
The shift flags can be any set of values accepted by Fl::event_state(). If the bit is on that shift key must be pushed. Meta, Alt, Ctrl, and Shift must be off if they are not in the shift flags (zero for the other bits indicates a "don't care" setting).
int Fl_Menu::submenu() const;
int Fl_Menu::checkbox() const;
int Fl_Menu::radio() const;
int Fl_Menu::value() const;
void Fl_Menu::set();
void Fl_Menu::setonly();
void Fl_Menu::clear();
int Fl_Menu::visible() const;
void Fl_Menu::show();
void Fl_Menu::hide();
int Fl_Menu::active() const;
void Fl_Menu::activate();
void Fl_Menu::deactivate();
There are several methods on an Fl_Menu defined, these are designed so that a pointer to the first item in the array can be considered a pointer to a "menu" object. However it is important to remember that this is an array:
const Fl_Menu* Fl_Menu::popup(int x, int y, int w, int h,
const Fl_Menu* picked = 0, const char* title = 0) const;
picked may be a pointer to any item in the menu, or in any submenu of it. picked may be null in which case the menu pops up so that the cursor is outside it.
The x,y,w,h define the bounding box of the button that brings up the menu, in root window space. If picked is non-zero that item is centered in this box. If picked is zero the menu appears below this button, like a pull-down. The menu is made at least w wide. Pass the mouse position as x,y and w,h of zero for a "popup" menu.
The title, if nonzero, puts a small title box above the menu, GL style.
const Fl_Menu* Fl_Menu::popup(int x, int y, const char *title =
0) const;
popup(x,y,0,0,0,title)
.
const Fl_Menu* Fl_Menu::test_shortcut() const;
int Fl_Menu::size();
const Fl_Menu* Fl_Menu::next(int=1) const;
Fl_Menu* Fl_Menu::next(int=1);
int Fl_Menu::add(const char* label, ulong
shortcut, Fl_Callback* callback=0, void* user_data=0, int
flags=0);
If an item exists already with that name then it is replaced with this new one. Otherwise this new one is added to the end of the correct menu or submenu. The return value is the offset into the array that the new entry was placed at.
No bounds checking is done, the table must be big enough for all the entries you plan to add. Don't forget that there is a null terminator on the end, and the first time a item is added to a submenu three items are added (the title and the null terminator, as well as the actual menu item)
This was designed to make a tcl command that would build a menu. Here is all that is necessary to make a tcl-driven menu builder:
static void menu_cb(Fl_Widget *,void* d) { char *cmd = (char *)d; if (Tcl_Eval(interp,cmd)) fl_message(interp->result); } #define MAXMENUSIZE 256 static Fl_Menu menu[MAXMENUSIZE]; static int menuCmd(ClientData, Tcl_Interp *interp, int argc, char** argv) { if (argc != 3 && argc != 4) { interp->result = "usage: menu name ?shortcut? command"; return TCL_ERROR; } char *text = argv[1]; ulong shortcut = (argc==4) ? fl_old_shortcut(argv[2]) : 0; char *cmd = strdup((argc==4) ? argv[3] : argv[2]); menu->add(text, shortcut, menu_cb, cmd, 0); return 0; } // add "menuCmd" to tcl as a command