source: rtems-graphics-toolkit/fltk-1.1.10/src/Fl_Menu_add.cxx @ 513eea1

Last change on this file since 513eea1 was 513eea1, checked in by Joel Sherrill <joel.sherrill@…>, on 01/09/10 at 22:43:24

2010-01-08 Joel Sherrill <joel.sherrill@…>

fltk 1.1.10. imported

  • ORIGIN: Updated.
  • Property mode set to 100644
File size: 8.0 KB
Line 
1//
2// "$Id$"
3//
4// Menu utilities for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2005 by Bill Spitzak and others.
7//
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.
12//
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.
17//
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
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25//     http://www.fltk.org/str.php
26//
27
28// Methods to alter the menu in an Fl_Menu_ widget.
29
30// These are for Forms emulation and for dynamically changing the
31// menus.  They are in this source file so they are not linked in if
32// not used, which is what will happen if the the program only uses
33// constant menu tables.
34
35// Not at all guaranteed to be Forms compatable, especially with any
36// string with a % sign in it!
37
38#include <FL/Fl_Menu_.H>
39#include "flstring.h"
40#include <stdio.h>
41#include <stdlib.h>
42
43// If the array is this, we will double-reallocate as necessary:
44static Fl_Menu_Item* local_array = 0;
45static int local_array_alloc = 0; // number allocated
46static int local_array_size = 0; // == size(local_array)
47extern Fl_Menu_* fl_menu_array_owner; // in Fl_Menu_.cxx
48
49// For historical reasons there are matching methods that work on a
50// user-allocated array of Fl_Menu_Item.  These methods are quite
51// depreciated and should not be used.  These old methods use the
52// above pointers to detect if the array belongs to an Fl_Menu_
53// widget, and if so it reallocates as necessary.
54
55// Insert a single Fl_Menu_Item into an array of size at offset n,
56// if this is local_array it will be reallocated if needed.
57static Fl_Menu_Item* insert(
58  Fl_Menu_Item* array, int size,
59  int n,
60  const char *text,
61  int flags
62) {
63  if (array == local_array && size >= local_array_alloc) {
64    local_array_alloc = 2*size;
65    Fl_Menu_Item* newarray = new Fl_Menu_Item[local_array_alloc];
66    memmove(newarray, array, size*sizeof(Fl_Menu_Item));
67    delete[] local_array;
68    local_array = array = newarray;
69  }
70  // move all the later items:
71  memmove(array+n+1, array+n, sizeof(Fl_Menu_Item)*(size-n));
72  // create the new item:
73  Fl_Menu_Item* m = array+n;
74  m->text = text ? strdup(text) : 0;
75  m->shortcut_ = 0;
76  m->callback_ = 0;
77  m->user_data_ = 0;
78  m->flags = flags;
79  m->labeltype_ = m->labelfont_ = m->labelsize_ = m->labelcolor_ = 0;
80  return array;
81}
82
83// Comparison that does not care about deleted '&' signs:
84static int compare(const char* a, const char* b) {
85  for (;;) {
86    int n = *a-*b;
87    if (n) {
88      if (*a == '&') a++;
89      else if (*b == '&') b++;
90      else return n;
91    } else if (*a) {
92      a++; b++;
93    } else {
94      return 0;
95    }
96  }
97}
98
99// Add an item.  The text is split at '/' characters to automatically
100// produce submenus (actually a totally unnecessary feature as you can
101// now add submenu titles directly by setting SUBMENU in the flags):
102int Fl_Menu_Item::add(
103  const char *mytext,
104  int sc,
105  Fl_Callback *cb,     
106  void *data,
107  int myflags
108) {
109  Fl_Menu_Item *array = this;
110  Fl_Menu_Item *m = this;
111  const char *p;
112  char *q;
113  char buf[1024];
114
115  int msize = array==local_array ? local_array_size : array->size();
116  int flags1 = 0;
117  const char* item;
118
119  // split at slashes to make submenus:
120  for (;;) {
121
122    // leading slash makes us assumme it is a filename:
123    if (*mytext == '/') {item = mytext; break;}
124
125    // leading underscore causes divider line:
126    if (*mytext == '_') {mytext++; flags1 = FL_MENU_DIVIDER;}
127
128    // copy to buf, changing \x to x:
129    q = buf;
130    for (p=mytext; *p && *p != '/'; *q++ = *p++) if (*p=='\\' && p[1]) p++;
131    *q = 0;
132
133    item = buf;
134    if (*p != '/') break; /* not a menu title */
135    mytext = p+1;       /* point at item title */
136
137    /* find a matching menu title: */
138    for (; m->text; m = m->next())
139      if (m->flags&FL_SUBMENU && !compare(item, m->text)) break;
140
141    if (!m->text) { /* create a new menu */
142      int n = m-array;
143      array = insert(array, msize, n, item, FL_SUBMENU|flags1);
144      msize++;
145      array = insert(array, msize, n+1, 0, 0);
146      msize++;
147      m = array+n;
148    }
149    m++;        /* go into the submenu */
150    flags1 = 0;
151  }
152
153  /* find a matching menu item: */
154  for (; m->text; m = m->next())
155    if (!(m->flags&FL_SUBMENU) && !compare(m->text,item)) break;
156
157  if (!m->text) {       /* add a new menu item */
158    int n = m-array;
159    array = insert(array, msize, n, item, myflags|flags1);
160    msize++;
161    if (myflags & FL_SUBMENU) { // add submenu delimiter
162      array = insert(array, msize, n+1, 0, 0);
163      msize++;
164    }
165    m = array+n;
166  }
167
168  /* fill it in */
169  m->shortcut_ = sc;
170  m->callback_ = cb;
171  m->user_data_ = data;
172  m->flags = myflags|flags1;
173
174  if (array == local_array) local_array_size = msize;
175  return m-array;
176}
177
178int Fl_Menu_::add(const char *t, int s, Fl_Callback *c,void *v,int f) {
179  // make this widget own the local array:
180  if (this != fl_menu_array_owner) {
181    if (fl_menu_array_owner) {
182      Fl_Menu_* o = fl_menu_array_owner;
183      // the previous owner get's its own correctly-sized array:
184      int value_offset = o->value_-local_array;
185      int n = local_array_size;
186      Fl_Menu_Item* newMenu = o->menu_ = new Fl_Menu_Item[n];
187      memcpy(newMenu, local_array, n*sizeof(Fl_Menu_Item));
188      if (o->value_) o->value_ = newMenu+value_offset;
189    }
190    if (menu_) {
191      // this already has a menu array, use it as the local one:
192      delete[] local_array;
193      if (!alloc) copy(menu_); // duplicate a user-provided static array
194      // add to the menu's current array:
195      local_array_alloc = local_array_size = size();
196      local_array = menu_;
197    } else {
198      // start with a blank array:
199      alloc = 2; // indicates that the strings can be freed
200      if (local_array) {
201        menu_ = local_array;
202      } else {
203        local_array_alloc = 15;
204        local_array = menu_ = new Fl_Menu_Item[local_array_alloc];
205        memset(local_array, 0, sizeof(Fl_Menu_Item) * local_array_alloc);
206      }
207      memset(menu_, 0, sizeof(Fl_Menu_Item));
208      local_array_size = 1;
209    }
210    fl_menu_array_owner = this;
211  }
212  int r = menu_->add(t,s,c,v,f);
213  // if it rellocated array we must fix the pointer:
214  int value_offset = value_-menu_;
215  menu_ = local_array; // in case it reallocated it
216  if (value_) value_ = menu_+value_offset;
217  return r;
218}
219
220// This is a Forms (and SGI GL library) compatable add function, it
221// adds many menu items, with '|' seperating the menu items, and tab
222// seperating the menu item names from an optional shortcut string.
223int Fl_Menu_::add(const char *str) {
224  char buf[1024];
225  int r = 0;
226  while (*str) {
227    int sc = 0;
228    char *c;
229    for (c = buf; c < (buf + sizeof(buf) - 2) && *str && *str != '|'; str++) {
230      if (*str == '\t') {*c++ = 0; sc = fl_old_shortcut(str);}
231      else *c++ = *str;
232    }
233    *c = 0;
234    r = add(buf, sc, 0, 0, 0);
235    if (*str) str++;
236  }
237  return r;
238}
239
240void Fl_Menu_::replace(int i, const char *str) {
241  if (i<0 || i>=size()) return;
242  if (!alloc) copy(menu_);
243  if (alloc > 1) {
244    free((void *)menu_[i].text);
245    str = strdup(str);
246  }
247  menu_[i].text = str;
248}
249
250void Fl_Menu_::remove(int i) {
251  int n = size();
252  if (i<0 || i>=n) return;
253  if (!alloc) copy(menu_);
254  // find the next item, skipping submenus:
255  Fl_Menu_Item* item = menu_+i;
256  const Fl_Menu_Item* next_item = item->next();
257  // delete the text only if all items were created with add():
258  if (alloc > 1) {
259    for (Fl_Menu_Item* m = item; m < next_item; m++)
260      if (m->text) free((void*)(m->text));
261  }
262  // MRS: "n" is the menu size(), which includes the trailing NULL entry...
263  memmove(item, next_item, (menu_+n-next_item)*sizeof(Fl_Menu_Item));
264}
265
266//
267// End of "$Id$".
268//
Note: See TracBrowser for help on using the repository browser.