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