diff --git a/documentation/Fl_Menu_.html b/documentation/Fl_Menu_.html
index 5f1c1ebc4..92651f4ad 100644
--- a/documentation/Fl_Menu_.html
+++ b/documentation/Fl_Menu_.html
@@ -24,10 +24,12 @@ Currently FLTK provides you with
Fl_Menu_Button,
Fl_Menu_Bar, and Fl_Choice
.
-
The class contains a pointer to an array of structures of type
-Fl_Menu_Item. These describe the contents of the menu.
- Usually the array is a large initialization constant, but there are
-methods to build it dynamically.
+
+The class contains a pointer to an array of structures of type Fl_Menu_Item. The
+array may either be supplied directly by the user program, or it may
+be "private": a dynamically allocated array managed by the Fl_Menu_.
+
Methods
@@ -68,26 +70,104 @@ methods to build it dynamically.
+
- Creates a new Fl_Menu_ widget using the given position, size,
-and label string. The default boxtype is FL_NO_BOX.
+
+Creates a new Fl_Menu_ widget using the given position, size,
+and label string. menu() is initialized to null.
+
- Destroys the menu and its items.
-
- Get or set the menu array directly. Setting it to NULL
- indicates that you want the widget to allocate its own array.
-
- Set the menu array to a copy of the passed array. This copy will be
- deleted when the Fl_Menu_ is deleted.
+
+If the menu array is private the memory it uses is freed.
+
+
+
+Returns a pointer to the array of Fl_Menu_Items. This will either be
+the value passed to menu(value) or the private copy.
+
+void Fl_Menu_::menu(const Fl_Menu_Item*)
+Set the menu array pointer directly. If the old menu is private it is
+deleted. NULL is allowed and acts the same as a zero-length
+menu. If you try to modify the array (with add(), replace(), or
+delete()) a private copy is automatically done.
+
+
+The menu is set to a private copy of the passed Fl_Menu_Item array.
+This is useful if you want to modify the flags of the menu items.
+
+
+Same as menu(NULL), set the array pointer to null, indicating
+a zero-length menu.
+
+
+
+This returns the number of Fl_Menu_Item structures that make up the
+menu, correctly counting submenus. This includes the "terminator"
+item at the end. To copy a menu array you need to copy
+size()*sizeof(Fl_Menu_Item) bytes. If the menu is
+NULL this returns zero (an empty menu will return 1).
+
+
+
+Adds a new menu item, with a title string, shortcut
+string, callback, argument to the callback, and flags. If
+the menu array was directly set with menu(x) then copy() is done to
+make a private array.
+
+Text is a string of the form "foo/bar/baz", this example
+will result in a submenu called "foo" and one in that called
+"bar" and and entry called "baz". The text is
+copied to new memory and can be freed. The other arguments (including
+the shortcut) are copied into the menu item unchanged.
+
+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.
+
+The return value is the index into the array that the entry was put.
+
+int Fl_Menu_::add(const char *)
+
+The passed string is split at any '|' characters and then
+add(s,0,0,0,0) is done with each section. This is often useful
+if you are just using the value, and is compatable with Forms
+and other GL programs.
+
+
+
+Changes the text of item n. This is the only way to get
+slash into an add()'ed menu item. If the menu array was directly set
+with menu(x) then copy() is done to make a private array.
+
+
+
+Deletes item n from the menu. If the menu array was directly
+set with menu(x) then copy() is done to make a private array.
+
+
+
+Changes the shortcut of item i to n.
+
+
+
+Changes the flags of item i. For a list of the flags, see Fl_Menu_Item.
+
The value is the index into menu() of the last item chosen by
the user. It is zero initially. You can set it as an integer, or set
it with a pointer to a menu item. The set routines return non-zero if
the new value is different than the old one.
+
Only call this in response to FL_SHORTCUT events. If the
@@ -102,56 +182,11 @@ have to be visible (ie the window it is in can be hidden, or it does
not have to be put in a window at all).
Currently there can be only one global()menu. Setting a new
one will replace the old one. There is no way to remove the
-global() setting (including destroying the menu).
+global() setting (so don't destroy the widget!)
Returns the title of the last item chosen, or of item i.
-
- This returns menu()->size(), which is
-the number of Fl_Menu_Item structures that make up this menu,
-correctly counting submenus. This includes the "terminator" item at
-the end. So to copy a menu you need to copy
-size()*sizeof(Fl_Menu_Item) bytes. If the menu is
-NULL this returns zero (an empty menu will return 1).
-
- The first form adds a new menu item, with a title string,
-shortcut string, callback, argument to the callback, and
-flags. If menu() was originally set with NULL then
-space is allocated for the new item. If instead you gave it an array
-then the array must have enough empty space for the new item. The
-title string is copied, but the shortcut is not.
-The second form splits the string at any | characters and then does
-add(s,0,0,0,0) with each section. This is often useful if you are
-just using the value, and is compatable with some Forms programs.
-Text is a string of the form "foo/bar/baz", this example will result
-in a submenu called "foo" and one in that called "bar" and and entry
-called "baz". The text is copied to new memory and can be freed. The
-other arguments are copied into the menu item unchanged.
-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)
-The return value is the index into the array that the entry was put.
-
- Delete all the menu items. Don't do this if you used menu(x)
- to set it to your own array. You should do this before destroying the
-Fl_Menu_ widget if it uses it's own array.
-
- Changes the text of item n. The passed string is copied.
-
- Deletes item n from the menu.
-
- Changes the shortcut of item i to n.
-
- Changes the flags of item i.
+
Get or set the current color of menu item labels.
diff --git a/documentation/Fl_Menu_Item.html b/documentation/Fl_Menu_Item.html
index 3ae3a389e..68edf053d 100644
--- a/documentation/Fl_Menu_Item.html
+++ b/documentation/Fl_Menu_Item.html
@@ -274,7 +274,7 @@ provided to position the menu. The menu is made at least W
found, the menu is aligned just below the rectangle (like a pulldown
menu).
The title and menubar arguments are used
-internally by the Fl_Menu_ widget.
+internally by the Fl_Menu_Bar widget.
This is designed to be called by a widgets handle() method in
diff --git a/src/Fl_Menu_.cxx b/src/Fl_Menu_.cxx
index 875eef964..0a608e07e 100644
--- a/src/Fl_Menu_.cxx
+++ b/src/Fl_Menu_.cxx
@@ -1,5 +1,5 @@
//
-// "$Id: Fl_Menu_.cxx,v 1.7.2.2 1999/04/08 19:13:02 carl Exp $"
+// "$Id: Fl_Menu_.cxx,v 1.7.2.3 1999/04/19 07:01:23 bill Exp $"
//
// Common menu code for the Fast Light Tool Kit (FLTK).
//
@@ -113,16 +113,13 @@ void Fl_Menu_::menu(const Fl_Menu_Item* m) {
}
void Fl_Menu_::copy(const Fl_Menu_Item* m, void* user_data) {
- int i, s = m->size(), n=s;
- for (i=0; n; n>>=1, i++);
- n = 1 << i;
+ int n = m->size();
Fl_Menu_Item* newMenu = new Fl_Menu_Item[n];
- memcpy(newMenu, m, s*sizeof(Fl_Menu_Item));
- memset(newMenu+s, 0, (n-s)*sizeof(Fl_Menu_Item));
+ memcpy(newMenu, m, n*sizeof(Fl_Menu_Item));
menu(newMenu);
- alloc = 1; // make destructor free it
+ alloc = 1; // make destructor free array, but not strings
// for convienence, provide way to change all the user data pointers:
- if (user_data) for (; s--;) {
+ if (user_data) for (; n--;) {
if (newMenu->callback_) newMenu->user_data_ = user_data;
newMenu++;
}
@@ -132,11 +129,18 @@ Fl_Menu_::~Fl_Menu_() {
clear();
}
+// Fl_Menu::add() uses this to indicate the owner of the dynamically-
+// expanding array. We must not free this array:
+Fl_Menu_* fl_menu_array_owner = 0;
+
void Fl_Menu_::clear() {
if (alloc) {
if (alloc>1) for (int i = size(); i--;)
if (menu_[i].text) free((void*)menu_[i].text);
- delete[] menu_;
+ if (this == fl_menu_array_owner)
+ fl_menu_array_owner = 0;
+ else
+ delete[] menu_;
menu_ = 0;
value_ = 0;
alloc = 0;
@@ -144,5 +148,5 @@ void Fl_Menu_::clear() {
}
//
-// End of "$Id: Fl_Menu_.cxx,v 1.7.2.2 1999/04/08 19:13:02 carl Exp $".
+// End of "$Id: Fl_Menu_.cxx,v 1.7.2.3 1999/04/19 07:01:23 bill Exp $".
//
diff --git a/src/Fl_Menu_add.cxx b/src/Fl_Menu_add.cxx
index 98786bd2d..255625e39 100644
--- a/src/Fl_Menu_add.cxx
+++ b/src/Fl_Menu_add.cxx
@@ -1,5 +1,5 @@
//
-// "$Id: Fl_Menu_add.cxx,v 1.9 1999/03/09 06:46:36 bill Exp $"
+// "$Id: Fl_Menu_add.cxx,v 1.9.2.1 1999/04/19 07:01:23 bill Exp $"
//
// Menu utilities for the Fast Light Tool Kit (FLTK).
//
@@ -24,12 +24,11 @@
//
// Methods to alter the menu in an Fl_Menu_ widget.
-// This code is seperated so that it is not linked in if not used.
-// These functions are for emulation of Forms and for dynamically
-// changing the menus. They are in this source file so they are
-// not linked in if not used, which is what will happen if the
-// the program only uses constant menu tables.
+// These are for Forms emulation and for dynamically changing the
+// menus. They are in this source file so they are not linked in if
+// not used, which is what will happen if the the program only uses
+// constant menu tables.
// Not at all guaranteed to be Forms compatable, especially with any
// string with a % sign in it!
@@ -38,34 +37,34 @@
#include
#include
-// always allocate this much initially:
-#define INITIAL_MENU_SIZE 15
+// If the array is this, we will double-reallocate as necessary:
+static Fl_Menu_Item* local_array = 0;
+static int local_array_alloc = 0; // number allocated
+static int local_array_size = 0; // == size(local_array)
+extern Fl_Menu_* fl_menu_array_owner; // in Fl_Menu_.cxx
-// if this local pointer is set, array is reallocated and put here:
-static Fl_Menu_Item** alloc;
+// For historical reasons there are matching methods that work on a
+// user-allocated array of Fl_Menu_Item. These methods are quite
+// depreciated and should not be used. These old methods use the
+// above pointers to detect if the array belongs to an Fl_Menu_
+// widget, and if so it reallocates as necessary.
-// Insert a single Fl_Menu_Item into an array at offset n. If ::alloc
-// is not zero, the array may be reallocated. This is done each time
-// it's size passes through a power of 2. The new (or old) array is
-// returned.
-// Notice that size does not count the trailing null item, so one more
-// item than you think must be copied.
+// Insert a single Fl_Menu_Item into an array of size at offset n,
+// if this is local_array it will be reallocated if needed.
static Fl_Menu_Item* insert(
Fl_Menu_Item* array, int size,
int n,
const char *text,
- int flags) {
- // If new size is a power of two, we reallocate to the next power
- // of two:
- if (alloc && size >= INITIAL_MENU_SIZE && !((size+1)&size)) {
- Fl_Menu_Item* newarray = new Fl_Menu_Item[(size+1)*2];
- memcpy(newarray, array, (size+1)*sizeof(Fl_Menu_Item));
- memset(newarray+size+1, 0, (size+1)*sizeof(Fl_Menu_Item));
- delete[] array;
- *alloc = array = newarray;
+ int flags
+) {
+ if (array == local_array && size >= local_array_alloc) {
+ local_array_alloc = 2*size;
+ Fl_Menu_Item* newarray = new Fl_Menu_Item[local_array_alloc];
+ memmove(newarray, array, size*sizeof(Fl_Menu_Item));
+ local_array = array = newarray;
}
// move all the later items:
- memmove(array+n+1, array+n, sizeof(Fl_Menu_Item)*(size-n+1));
+ memmove(array+n+1, array+n, sizeof(Fl_Menu_Item)*(size-n));
// create the new item:
Fl_Menu_Item* m = array+n;
m->text = text ? strdup(text) : 0;
@@ -85,15 +84,15 @@ int Fl_Menu_Item::add(
int shortcut,
Fl_Callback *cb,
void *data,
- int flags)
-{
+ int flags
+) {
Fl_Menu_Item *array = this;
Fl_Menu_Item *m = this;
const char *p;
char *q;
char buf[1024];
- int size = array->size();
+ int size = array==local_array ? local_array_size : array->size();
int flags1 = 0;
char* item;
for (;;) { /* do all the supermenus: */
@@ -145,25 +144,54 @@ int Fl_Menu_Item::add(
m->user_data_ = data;
m->flags = flags|flags1;
+ if (array == local_array) local_array_size = size;
return m-array;
}
int Fl_Menu_::add(const char *t, int s, Fl_Callback *c,void *v,int f) {
- int n = value_ ? value_ - menu_ : 0;
- if (!menu_) {
- alloc = 2; // indicates that the strings can be freed
- menu_ = new Fl_Menu_Item[INITIAL_MENU_SIZE+1];
- menu_[0].text = 0;
+ // make this widget own the local array:
+ if (this != fl_menu_array_owner) {
+ if (fl_menu_array_owner) {
+ Fl_Menu_* o = fl_menu_array_owner;
+ // the previous owner get's its own correctly-sized array:
+ int value_offset = o->value_-local_array;
+ int n = local_array_size;
+ Fl_Menu_Item* newMenu = o->menu_ = new Fl_Menu_Item[n];
+ memcpy(newMenu, local_array, n*sizeof(Fl_Menu_Item));
+ if (o->value_) o->value_ = newMenu+value_offset;
+ }
+ if (menu_) {
+ // this already has a menu array, use it as the local one:
+ delete[] local_array;
+ if (!alloc) copy(menu_); // duplicate a user-provided static array
+ // add to the menu's current array:
+ local_array_alloc = local_array_size = size();
+ local_array = menu_;
+ } else {
+ // start with a blank array:
+ alloc = 2; // indicates that the strings can be freed
+ if (local_array) {
+ menu_ = local_array;
+ } else {
+ local_array_alloc = 15;
+ local_array = menu_ = new Fl_Menu_Item[local_array_alloc];
+ }
+ menu_[0].text = 0;
+ local_array_size = 1;
+ }
+ fl_menu_array_owner = this;
}
- if (alloc) ::alloc = &menu_;
int r = menu_->add(t,s,c,v,f);
- ::alloc = 0;
- if (value_) value_ = menu_+n;
+ // if it rellocated array we must fix the pointer:
+ int value_offset = value_-menu_;
+ menu_ = local_array; // in case it reallocated it
+ if (value_) value_ = menu_+value_offset;
return r;
}
// This is a Forms (and SGI GL library) compatable add function, it
-// adds strings of the form "name\tshortcut|name\tshortcut|..."
+// adds many menu items, with '|' seperating the menu items, and tab
+// seperating the menu item names from an optional shortcut string.
int Fl_Menu_::add(const char *str) {
char buf[128];
int r = 0;
@@ -183,6 +211,7 @@ int Fl_Menu_::add(const char *str) {
void Fl_Menu_::replace(int i, const char *str) {
if (i<0 || i>=size()) return;
+ if (!alloc) copy(menu_);
if (alloc > 1) {
free((void *)menu_[i].text);
str = strdup(str);
@@ -193,10 +222,11 @@ void Fl_Menu_::replace(int i, const char *str) {
void Fl_Menu_::remove(int i) {
int n = size();
if (i<0 || i>=n) return;
+ if (!alloc) copy(menu_);
if (alloc > 1) free((void *)menu_[i].text);
memmove(&menu_[i],&menu_[i+1],(n-i)*sizeof(Fl_Menu_Item));
}
//
-// End of "$Id: Fl_Menu_add.cxx,v 1.9 1999/03/09 06:46:36 bill Exp $".
+// End of "$Id: Fl_Menu_add.cxx,v 1.9.2.1 1999/04/19 07:01:23 bill Exp $".
//
diff --git a/test/subwindow.cxx b/test/subwindow.cxx
index 52a3292bc..9560dd7d7 100644
--- a/test/subwindow.cxx
+++ b/test/subwindow.cxx
@@ -1,5 +1,5 @@
//
-// "$Id: subwindow.cxx,v 1.5 1999/02/03 08:43:35 bill Exp $"
+// "$Id: subwindow.cxx,v 1.5.2.1 1999/04/19 07:01:24 bill Exp $"
//
// Nested window test program for the Fast Light Tool Kit (FLTK).
//
@@ -165,10 +165,11 @@ int main(int, char **) {
popup = new Fl_Menu_Button(0,0,400,400);
popup->type(Fl_Menu_Button::POPUP3);
popup->add("This|is|a popup|menu");
+ popup->add(bigmess);
window->show();
return Fl::run();
}
//
-// End of "$Id: subwindow.cxx,v 1.5 1999/02/03 08:43:35 bill Exp $".
+// End of "$Id: subwindow.cxx,v 1.5.2.1 1999/04/19 07:01:24 bill Exp $".
//