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_.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Menu_.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 // Common menu code 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 // This is a base class for all items that have a menu:
00028 //      Fl_Menu_Bar, Fl_Menu_Button, Fl_Choice
00029 // This provides storage for a menu item, functions to add/modify/delete
00030 // items, and a call for when the user picks a menu item.
00031 
00032 // More code in Fl_Menu_add.cxx
00033 
00034 #include <FL/Fl.H>
00035 #include <FL/Fl_Menu_.H>
00036 #include "flstring.h"
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 
00040 #define SAFE_STRCAT(s) { len += strlen(s); if ( len >= namelen ) { *name='\0'; return(-2); } else strcat(name,(s)); }
00041 
00073 int Fl_Menu_::item_pathname(char *name, int namelen, const Fl_Menu_Item *finditem) const {
00074     int len = 0;
00075     finditem = finditem ? finditem : mvalue();    
00076     name[0] = '\0';
00077     for ( int t=0; t<size(); t++ ) {
00078         const Fl_Menu_Item *m = &(menu()[t]);
00079         if ( m->submenu() ) {                           // submenu? descend
00080             if (*name) SAFE_STRCAT("/");
00081             if (m->label()) SAFE_STRCAT(m->label());
00082             if ( m == finditem ) return(0);             // found? done.
00083         } else {
00084             if (m->label()) {                           // menu item?
00085                 if ( m == finditem ) {                  // found? tack on itemname, done.
00086                     SAFE_STRCAT("/");
00087                     SAFE_STRCAT(m->label());
00088                     return(0);
00089                 }
00090             } else {                                    // end of submenu? pop
00091                 char *ss = strrchr(name, '/');
00092                 if ( ss ) { *ss = 0; len = strlen(name); }      // "File/Edit" -> "File"
00093                 else { name[0] = '\0'; len = 0; }               // "File" -> ""
00094                 continue;
00095             }
00096         }
00097     }
00098     *name = '\0';
00099     return(-1);                                         // item not found
00100 }
00101 
00130 const Fl_Menu_Item * Fl_Menu_::find_item(const char *pathname) {
00131   int i = find_index(pathname);
00132   return( (i==-1) ? 0 : (const Fl_Menu_Item*)(menu_+i));
00133 }
00134 
00156 int Fl_Menu_::find_index(const Fl_Menu_Item *item) const {
00157   Fl_Menu_Item *max = menu_+size();
00158   if (item<menu_ || item>=max) return(-1);
00159   return(item-menu_);
00160 }
00161 
00173 int Fl_Menu_::find_index(Fl_Callback *cb) const {
00174   for ( int t=0; t < size(); t++ )
00175     if (menu_[t].callback_==cb)
00176       return(t);
00177   return(-1);
00178 }
00179 
00193 int Fl_Menu_::find_index(const char *pathname) const {
00194   char menupath[1024] = "";     // File/Export
00195   for ( int t=0; t < size(); t++ ) {
00196     Fl_Menu_Item *m = menu_ + t;
00197     if (m->flags&FL_SUBMENU) {
00198       // IT'S A SUBMENU
00199       // we do not support searches through FL_SUBMENU_POINTER links
00200       if (menupath[0]) strlcat(menupath, "/", sizeof(menupath));
00201       strlcat(menupath, m->label(), sizeof(menupath));
00202       if (!strcmp(menupath, pathname)) return(t);
00203     } else {
00204       if (!m->label()) {
00205         // END OF SUBMENU? Pop back one level.
00206         char *ss = strrchr(menupath, '/');
00207         if ( ss ) *ss = 0;
00208         else menupath[0] = '\0';
00209         continue;
00210       }
00211       // IT'S A MENU ITEM
00212       char itempath[1024];      // eg. Edit/Copy
00213       strcpy(itempath, menupath);
00214       if (itempath[0]) strlcat(itempath, "/", sizeof(itempath));
00215       strlcat(itempath, m->label(), sizeof(itempath));
00216       if (!strcmp(itempath, pathname)) return(t);
00217     }
00218   }
00219   return(-1);
00220 }
00221 
00234 const Fl_Menu_Item * Fl_Menu_::find_item(Fl_Callback *cb) {
00235   for ( int t=0; t < size(); t++ ) {
00236     const Fl_Menu_Item *m = menu_ + t;
00237     if (m->callback_==cb) {
00238       return m;
00239     }
00240   }
00241   return (const Fl_Menu_Item *)0;
00242 }
00243 
00250 int Fl_Menu_::value(const Fl_Menu_Item* m) {
00251   clear_changed();
00252   if (value_ != m) {value_ = m; return 1;}
00253   return 0;
00254 }
00255 
00261 const Fl_Menu_Item* Fl_Menu_::picked(const Fl_Menu_Item* v) {
00262   if (v) {
00263     if (v->radio()) {
00264       if (!v->value()) { // they are turning on a radio item
00265         set_changed();
00266         ((Fl_Menu_Item*)v)->setonly();
00267       }
00268       redraw();
00269     } else if (v->flags & FL_MENU_TOGGLE) {
00270       set_changed();
00271       ((Fl_Menu_Item*)v)->flags ^= FL_MENU_VALUE;
00272       redraw();
00273     } else if (v != value_) { // normal item
00274       set_changed();
00275     }
00276     value_ = v;
00277     if (when()&(FL_WHEN_CHANGED|FL_WHEN_RELEASE)) {
00278       if (changed() || when()&FL_WHEN_NOT_CHANGED) {
00279         if (value_ && value_->callback_) value_->do_callback((Fl_Widget*)this);
00280         else do_callback();
00281       }
00282     }
00283   }
00284   return v;
00285 }
00286 
00288 void Fl_Menu_Item::setonly() {
00289   flags |= FL_MENU_RADIO | FL_MENU_VALUE;
00290   Fl_Menu_Item* j;
00291   for (j = this; ; ) {  // go down
00292     if (j->flags & FL_MENU_DIVIDER) break; // stop on divider lines
00293     j++;
00294     if (!j->text || !j->radio()) break; // stop after group
00295     j->clear();
00296   }
00297   for (j = this-1; ; j--) { // go up
00298     if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break;
00299     j->clear();
00300   }
00301 }
00302 
00307 Fl_Menu_::Fl_Menu_(int X,int Y,int W,int H,const char* l)
00308 : Fl_Widget(X,Y,W,H,l) {
00309   set_flag(SHORTCUT_LABEL);
00310   box(FL_UP_BOX);
00311   when(FL_WHEN_RELEASE_ALWAYS);
00312   value_ = menu_ = 0;
00313   alloc = 0;
00314   selection_color(FL_SELECTION_COLOR);
00315   textfont(FL_HELVETICA);
00316   textsize(FL_NORMAL_SIZE);
00317   textcolor(FL_FOREGROUND_COLOR);
00318   down_box(FL_NO_BOX);
00319 }
00320 
00328 int Fl_Menu_::size() const {
00329   if (!menu_) return 0;
00330   return menu_->size();
00331 }
00332 
00339 void Fl_Menu_::menu(const Fl_Menu_Item* m) {
00340   clear();
00341   value_ = menu_ = (Fl_Menu_Item*)m;
00342 }
00343 
00344 // this version is ok with new Fl_Menu_add code with fl_menu_array_owner:
00345 
00351 void Fl_Menu_::copy(const Fl_Menu_Item* m, void* ud) {
00352   int n = m->size();
00353   Fl_Menu_Item* newMenu = new Fl_Menu_Item[n];
00354   memcpy(newMenu, m, n*sizeof(Fl_Menu_Item));
00355   menu(newMenu);
00356   alloc = 1; // make destructor free array, but not strings
00357   // for convenience, provide way to change all the user data pointers:
00358   if (ud) for (; n--;) {
00359     if (newMenu->callback_) newMenu->user_data_ = ud;
00360     newMenu++;
00361   }
00362 }
00363 
00364 Fl_Menu_::~Fl_Menu_() {
00365   clear();
00366 }
00367 
00368 // Fl_Menu::add() uses this to indicate the owner of the dynamically-
00369 // expanding array.  We must not free this array:
00370 Fl_Menu_* fl_menu_array_owner = 0;
00371 
00378 void Fl_Menu_::clear() {
00379   if (alloc) {
00380     if (alloc>1) for (int i = size(); i--;)
00381       if (menu_[i].text) free((void*)menu_[i].text);
00382     if (this == fl_menu_array_owner)
00383       fl_menu_array_owner = 0;
00384     else
00385       delete[] menu_;
00386     menu_ = 0;
00387     value_ = 0;
00388     alloc = 0;
00389   }
00390 }
00391 
00422 int Fl_Menu_::clear_submenu(int index) {
00423   if ( index < 0 || index >= size() ) return(-1);
00424   if ( ! (menu_[index].flags & FL_SUBMENU) ) return(-1);
00425   ++index;                                      // advance to first item in submenu
00426   while ( index < size() ) {                    // keep remove()ing top item until end is reached
00427     if ( menu_[index].text == 0 ) break;        // end of this submenu? done
00428     remove(index);                              // remove items/submenus
00429   }
00430   return(0);
00431 }
00432 
00433 //
00434 // End of "$Id: Fl_Menu_.cxx 7903 2010-11-28 21:06:39Z matt $".
00435 //