|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_Menu_add.cxx 8110 2010-12-23 08:02:52Z manolo $" 00003 // 00004 // Menu utilities for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 // Methods to alter the menu in an Fl_Menu_ widget. 00028 00029 // These are for Forms emulation and for dynamically changing the 00030 // menus. They are in this source file so they are not linked in if 00031 // not used, which is what will happen if the program only uses 00032 // constant menu tables. 00033 00034 // Not at all guaranteed to be Forms compatible, especially with any 00035 // string with a % sign in it! 00036 00037 #include <FL/Fl_Menu_.H> 00038 #include "flstring.h" 00039 #include <stdio.h> 00040 #include <stdlib.h> 00041 00042 // If the array is this, we will double-reallocate as necessary: 00043 static Fl_Menu_Item* local_array = 0; 00044 static int local_array_alloc = 0; // number allocated 00045 static int local_array_size = 0; // == size(local_array) 00046 extern Fl_Menu_* fl_menu_array_owner; // in Fl_Menu_.cxx 00047 00048 // For historical reasons there are matching methods that work on a 00049 // user-allocated array of Fl_Menu_Item. These methods are quite 00050 // depreciated and should not be used. These old methods use the 00051 // above pointers to detect if the array belongs to an Fl_Menu_ 00052 // widget, and if so it reallocates as necessary. 00053 00054 00055 00056 // Insert a single Fl_Menu_Item into an array of size at offset n, 00057 // if this is local_array it will be reallocated if needed. 00058 static Fl_Menu_Item* array_insert( 00059 Fl_Menu_Item* array, // array to modify 00060 int size, // size of array 00061 int n, // index of new insert position 00062 const char *text, // text of new item (copy is made) 00063 int flags // flags for new item 00064 ) { 00065 if (array == local_array && size >= local_array_alloc) { 00066 local_array_alloc = 2*size; 00067 Fl_Menu_Item* newarray = new Fl_Menu_Item[local_array_alloc]; 00068 memmove(newarray, array, size*sizeof(Fl_Menu_Item)); 00069 delete[] local_array; 00070 local_array = array = newarray; 00071 } 00072 // move all the later items: 00073 memmove(array+n+1, array+n, sizeof(Fl_Menu_Item)*(size-n)); 00074 // create the new item: 00075 Fl_Menu_Item* m = array+n; 00076 m->text = text ? strdup(text) : 0; 00077 m->shortcut_ = 0; 00078 m->callback_ = 0; 00079 m->user_data_ = 0; 00080 m->flags = flags; 00081 m->labeltype_ = m->labelsize_ = m->labelcolor_ = 0; 00082 m->labelfont_ = FL_HELVETICA; 00083 return array; 00084 } 00085 00086 00087 00088 // Comparison that does not care about deleted '&' signs: 00089 static int compare(const char* a, const char* b) { 00090 for (;;) { 00091 int n = *a-*b; 00092 if (n) { 00093 if (*a == '&') a++; 00094 else if (*b == '&') b++; 00095 else return n; 00096 } else if (*a) { 00097 a++; b++; 00098 } else { 00099 return 0; 00100 } 00101 } 00102 } 00103 00104 00105 00110 int Fl_Menu_Item::add( 00111 const char *mytext, 00112 int sc, 00113 Fl_Callback *cb, 00114 void *data, 00115 int myflags 00116 ) { 00117 return(insert(-1,mytext,sc,cb,data,myflags)); // -1: append 00118 } 00119 00120 00121 00141 int Fl_Menu_Item::insert( 00142 int index, 00143 const char *mytext, 00144 int sc, 00145 Fl_Callback *cb, 00146 void *data, 00147 int myflags 00148 ) { 00149 Fl_Menu_Item *array = this; 00150 Fl_Menu_Item *m = this; 00151 const char *p; 00152 char *q; 00153 char buf[1024]; 00154 00155 int msize = array==local_array ? local_array_size : array->size(); 00156 int flags1 = 0; 00157 const char* item; 00158 00159 // split at slashes to make submenus: 00160 for (;;) { 00161 00162 // leading slash makes us assume it is a filename: 00163 if (*mytext == '/') {item = mytext; break;} 00164 00165 // leading underscore causes divider line: 00166 if (*mytext == '_') {mytext++; flags1 = FL_MENU_DIVIDER;} 00167 00168 // copy to buf, changing \x to x: 00169 q = buf; 00170 for (p=mytext; *p && *p != '/'; *q++ = *p++) if (*p=='\\' && p[1]) p++; 00171 *q = 0; 00172 00173 item = buf; 00174 if (*p != '/') break; /* not a menu title */ 00175 index = -1; /* any submenu specified overrides insert position */ 00176 mytext = p+1; /* point at item title */ 00177 00178 /* find a matching menu title: */ 00179 for (; m->text; m = m->next()) 00180 if (m->flags&FL_SUBMENU && !compare(item, m->text)) break; 00181 00182 if (!m->text) { /* create a new menu */ 00183 int n = (index==-1) ? m-array : index; 00184 array = array_insert(array, msize, n, item, FL_SUBMENU|flags1); 00185 msize++; 00186 array = array_insert(array, msize, n+1, 0, 0); 00187 msize++; 00188 m = array+n; 00189 } 00190 m++; /* go into the submenu */ 00191 flags1 = 0; 00192 } 00193 00194 /* find a matching menu item: */ 00195 for (; m->text; m = m->next()) 00196 if (!(m->flags&FL_SUBMENU) && !compare(m->text,item)) break; 00197 00198 if (!m->text) { /* add a new menu item */ 00199 int n = (index==-1) ? m-array : index; 00200 array = array_insert(array, msize, n, item, myflags|flags1); 00201 msize++; 00202 if (myflags & FL_SUBMENU) { // add submenu delimiter 00203 array = array_insert(array, msize, n+1, 0, 0); 00204 msize++; 00205 } 00206 m = array+n; 00207 } 00208 00209 /* fill it in */ 00210 m->shortcut_ = sc; 00211 m->callback_ = cb; 00212 m->user_data_ = data; 00213 m->flags = myflags|flags1; 00214 00215 if (array == local_array) local_array_size = msize; 00216 return m-array; 00217 } 00218 00219 00220 00327 int Fl_Menu_::add(const char *label,int shortcut,Fl_Callback *callback,void *userdata,int flags) { 00328 return(insert(-1,label,shortcut,callback,userdata,flags)); // -1: append 00329 } 00330 00331 00332 00364 int Fl_Menu_::insert( 00365 int index, 00366 const char *label, 00367 int shortcut, 00368 Fl_Callback *callback, 00369 void *userdata, 00370 int flags 00371 ) { 00372 // make this widget own the local array: 00373 if (this != fl_menu_array_owner) { 00374 if (fl_menu_array_owner) { 00375 Fl_Menu_* o = fl_menu_array_owner; 00376 // the previous owner get's its own correctly-sized array: 00377 int value_offset = o->value_-local_array; 00378 int n = local_array_size; 00379 Fl_Menu_Item* newMenu = o->menu_ = new Fl_Menu_Item[n]; 00380 memcpy(newMenu, local_array, n*sizeof(Fl_Menu_Item)); 00381 if (o->value_) o->value_ = newMenu+value_offset; 00382 } 00383 if (menu_) { 00384 // this already has a menu array, use it as the local one: 00385 delete[] local_array; 00386 if (!alloc) copy(menu_); // duplicate a user-provided static array 00387 // add to the menu's current array: 00388 local_array_alloc = local_array_size = size(); 00389 local_array = menu_; 00390 } else { 00391 // start with a blank array: 00392 alloc = 2; // indicates that the strings can be freed 00393 if (local_array) { 00394 menu_ = local_array; 00395 } else { 00396 local_array_alloc = 15; 00397 local_array = menu_ = new Fl_Menu_Item[local_array_alloc]; 00398 memset(local_array, 0, sizeof(Fl_Menu_Item) * local_array_alloc); 00399 } 00400 memset(menu_, 0, sizeof(Fl_Menu_Item)); 00401 local_array_size = 1; 00402 } 00403 fl_menu_array_owner = this; 00404 } 00405 int r = menu_->insert(index,label,shortcut,callback,userdata,flags); 00406 // if it rellocated array we must fix the pointer: 00407 int value_offset = value_-menu_; 00408 menu_ = local_array; // in case it reallocated it 00409 if (value_) value_ = menu_+value_offset; 00410 return r; 00411 } 00412 00413 00414 00431 int Fl_Menu_::add(const char *str) { 00432 char buf[1024]; 00433 int r = 0; 00434 while (*str) { 00435 int sc = 0; 00436 char *c; 00437 for (c = buf; c < (buf + sizeof(buf) - 2) && *str && *str != '|'; str++) { 00438 if (*str == '\t') {*c++ = 0; sc = fl_old_shortcut(str);} 00439 else *c++ = *str; 00440 } 00441 *c = 0; 00442 r = add(buf, sc, 0, 0, 0); 00443 if (*str) str++; 00444 } 00445 return r; 00446 } 00447 00448 00449 00458 void Fl_Menu_::replace(int i, const char *str) { 00459 if (i<0 || i>=size()) return; 00460 if (!alloc) copy(menu_); 00461 if (alloc > 1) { 00462 free((void *)menu_[i].text); 00463 str = strdup(str); 00464 } 00465 menu_[i].text = str; 00466 } 00467 00468 00469 00478 void Fl_Menu_::remove(int i) { 00479 int n = size(); 00480 if (i<0 || i>=n) return; 00481 if (!alloc) copy(menu_); 00482 // find the next item, skipping submenus: 00483 Fl_Menu_Item* item = menu_+i; 00484 const Fl_Menu_Item* next_item = item->next(); 00485 // delete the text only if all items were created with add(): 00486 if (alloc > 1) { 00487 for (Fl_Menu_Item* m = item; m < next_item; m++) 00488 if (m->text) free((void*)(m->text)); 00489 } 00490 // MRS: "n" is the menu size(), which includes the trailing NULL entry... 00491 memmove(item, next_item, (menu_+n-next_item)*sizeof(Fl_Menu_Item)); 00492 } 00493 00494 // 00495 // End of "$Id: Fl_Menu_add.cxx 8110 2010-12-23 08:02:52Z manolo $". 00496 //