2
// "$Id: Fl_Menu_.cxx,v 1.7.2.8.2.9 2004/04/11 04:38:57 easysw Exp $"
4
// Common menu code for the Fast Light Tool Kit (FLTK).
6
// Copyright 1998-2004 by Bill Spitzak and others.
8
// This library is free software; you can redistribute it and/or
9
// modify it under the terms of the GNU Library General Public
10
// License as published by the Free Software Foundation; either
11
// version 2 of the License, or (at your option) any later version.
13
// This library is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
// Library General Public License for more details.
18
// You should have received a copy of the GNU Library General Public
19
// License along with this library; if not, write to the Free Software
20
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23
// Please report all bugs and problems to "fltk-bugs@fltk.org".
26
// This is a base class for all items that have a menu:
27
// Fl_Menu_Bar, Fl_Menu_Button, Fl_Choice
28
// This provides storage for a menu item, functions to add/modify/delete
29
// items, and a call for when the user picks a menu item.
31
// More code in Fl_Menu_add.cxx
34
#include <FL/Fl_Menu_.H>
39
// Set 'pathname' of specified menuitem
40
// If finditem==NULL, mvalue() is used (the most recently picked menuitem)
43
// -1 : item not found (name="")
44
// -2 : 'name' not large enough (name="")
46
#define SAFE_STRCAT(s) \
47
{ len += strlen(s); if ( len >= namelen ) { *name='\0'; return(-2); } else strcat(name,(s)); }
48
int Fl_Menu_::item_pathname(char *name, int namelen, const Fl_Menu_Item *finditem) const {
50
finditem = finditem ? finditem : mvalue();
52
for ( int t=0; t<size(); t++ ) {
53
const Fl_Menu_Item *m = &(menu()[t]);
54
if ( m->submenu() ) { // submenu? descend
55
if ( *name ) SAFE_STRCAT("/");
56
SAFE_STRCAT(m->label());
58
if ( m->label() ) { // menu item?
59
if ( m == finditem ) { // found? tack on itemname, done.
61
SAFE_STRCAT(m->label());
64
} else { // end of submenu? pop
65
char *ss = strrchr(name, '/');
66
if ( ss ) { *ss = 0; len = strlen(name); } // "File/Edit" -> "File"
67
else { name[0] = '\0'; len = 0; } // "File" -> ""
73
return(-1); // item not found
76
// FIND MENU ITEM INDEX, GIVEN MENU PATHNAME
78
// Will also return submenus, eg. "Edit"
79
// Returns NULL if not found.
82
Fl_Menu_::find_item(const char *name)
84
char menupath[1024] = ""; // File/Export
86
for ( int t=0; t < size(); t++ ) {
87
Fl_Menu_Item *m = menu_ + t;
91
if (menupath[0]) strlcat(menupath, "/", sizeof(menupath));
92
strlcat(menupath, m->label(), sizeof(menupath));
93
if (!strcmp(menupath, name)) return m;
96
// END OF SUBMENU? Pop back one level.
97
char *ss = strrchr(menupath, '/');
103
char itempath[1024]; // eg. Edit/Copy
104
strcpy(itempath, menupath);
105
if (itempath[0]) strlcat(itempath, "/", sizeof(itempath));
106
strlcat(itempath, m->label(), sizeof(itempath));
107
if (!strcmp(itempath, name)) return m;
111
return (const Fl_Menu_Item *)0;
114
int Fl_Menu_::value(const Fl_Menu_Item* m) {
116
if (value_ != m) {value_ = m; return 1;}
120
// When user picks a menu item, call this. It will do the callback.
121
// Unfortunatly this also casts away const for the checkboxes, but this
122
// was necessary so non-checkbox menus can really be declared const...
123
const Fl_Menu_Item* Fl_Menu_::picked(const Fl_Menu_Item* v) {
126
if (!v->value()) { // they are turning on a radio item
128
((Fl_Menu_Item*)v)->setonly();
131
} else if (v->flags & FL_MENU_TOGGLE) {
133
((Fl_Menu_Item*)v)->flags ^= FL_MENU_VALUE;
135
} else if (v != value_) { // normal item
139
if (when()&(FL_WHEN_CHANGED|FL_WHEN_RELEASE)) {
140
if (changed() || when()&FL_WHEN_NOT_CHANGED) {
142
if (value_ && value_->callback_) value_->do_callback((Fl_Widget*)this);
150
// turn on one of a set of radio buttons
151
void Fl_Menu_Item::setonly() {
152
flags |= FL_MENU_RADIO | FL_MENU_VALUE;
154
for (j = this; ; ) { // go down
155
if (j->flags & FL_MENU_DIVIDER) break; // stop on divider lines
157
if (!j->text || !j->radio()) break; // stop after group
160
for (j = this-1; ; j--) { // go up
161
if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break;
166
Fl_Menu_::Fl_Menu_(int X,int Y,int W,int H,const char* l)
167
: Fl_Widget(X,Y,W,H,l) {
168
set_flag(SHORTCUT_LABEL);
170
when(FL_WHEN_RELEASE_ALWAYS);
173
selection_color(FL_SELECTION_COLOR);
174
textfont(FL_HELVETICA);
175
textsize((uchar)FL_NORMAL_SIZE);
180
int Fl_Menu_::size() const {
181
if (!menu_) return 0;
182
return menu_->size();
185
void Fl_Menu_::menu(const Fl_Menu_Item* m) {
187
value_ = menu_ = (Fl_Menu_Item*)m;
190
// this version is ok with new Fl_Menu_add code with fl_menu_array_owner:
192
void Fl_Menu_::copy(const Fl_Menu_Item* m, void* ud) {
194
Fl_Menu_Item* newMenu = new Fl_Menu_Item[n];
195
memcpy(newMenu, m, n*sizeof(Fl_Menu_Item));
197
alloc = 1; // make destructor free array, but not strings
198
// for convienence, provide way to change all the user data pointers:
199
if (ud) for (; n--;) {
200
if (newMenu->callback_) newMenu->user_data_ = ud;
205
Fl_Menu_::~Fl_Menu_() {
209
// Fl_Menu::add() uses this to indicate the owner of the dynamically-
210
// expanding array. We must not free this array:
211
Fl_Menu_* fl_menu_array_owner = 0;
213
void Fl_Menu_::clear() {
215
if (alloc>1) for (int i = size(); i--;)
216
if (menu_[i].text) free((void*)menu_[i].text);
217
if (this == fl_menu_array_owner)
218
fl_menu_array_owner = 0;
228
// End of "$Id: Fl_Menu_.cxx,v 1.7.2.8.2.9 2004/04/11 04:38:57 easysw Exp $".