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)  

Fl_Menu_add.cxx

Go to the documentation of this file.
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 //