fltk  1.3.5-source
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X.
  Fossies Dox: fltk-1.3.5-source.tar.bz2  ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Menu_.cxx
Go to the documentation of this file.
1 //
2 // "$Id$"
3 //
4 // Common menu code for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2016 by Bill Spitzak and others.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file. If this
10 // file is missing or damaged, see the license at:
11 //
12 // http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems on the following page:
15 //
16 // http://www.fltk.org/str.php
17 //
18 
19 // This is a base class for all items that have a menu:
20 // Fl_Menu_Bar, Fl_Menu_Button, Fl_Choice
21 // This provides storage for a menu item, functions to add/modify/delete
22 // items, and a call for when the user picks a menu item.
23 
24 // More code in Fl_Menu_add.cxx
25 
26 #include <FL/Fl.H>
27 #include <FL/Fl_Menu_.H>
28 #include "flstring.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 #define SAFE_STRCAT(s) { len += (int) strlen(s); if ( len >= namelen ) { *name='\0'; return(-2); } else strcat(name,(s)); }
33 
65 int Fl_Menu_::item_pathname(char *name, int namelen, const Fl_Menu_Item *finditem) const {
66  name[0] = '\0';
67  return item_pathname_(name, namelen, finditem, menu_);
68 }
69 
70 // INTERNAL: Descend into a specific menu hierarchy
72  int namelen,
73  const Fl_Menu_Item *finditem,
74  const Fl_Menu_Item *menu) const {
75  int len = 0;
76  int level = 0;
77  finditem = finditem ? finditem : mvalue();
78  menu = menu ? menu : this->menu();
79  for ( int t=0; t<size(); t++ ) {
80  const Fl_Menu_Item *m = menu + t;
81  if (m->submenu()) { // submenu? descend
82  if (m->flags & FL_SUBMENU_POINTER) {
83  // SUBMENU POINTER? Recurse to descend
84  int slen = strlen(name);
85  const Fl_Menu_Item *submenu = (const Fl_Menu_Item*)m->user_data();
86  if (m->label()) {
87  if (*name) SAFE_STRCAT("/");
88  SAFE_STRCAT(m->label());
89  }
90  if (item_pathname_(name, len, finditem, submenu) == 0)
91  return 0;
92  name[slen] = 0; // continue from where we were
93  } else {
94  // REGULAR SUBMENU? DESCEND
95  ++level;
96  if (*name) SAFE_STRCAT("/");
97  if (m->label()) SAFE_STRCAT(m->label());
98  if (m == finditem) return(0); // found? done.
99  }
100  } else {
101  if (m->label()) { // menu item?
102  if ( m == finditem ) { // found? tack on itemname, done.
103  SAFE_STRCAT("/");
104  SAFE_STRCAT(m->label());
105  return(0);
106  }
107  } else { // end of submenu? pop
108  if ( --level < 0 ) {
109  *name = '\0';
110  return -1;
111  }
112  char *ss = strrchr(name, '/');
113  if ( ss ) { *ss = 0; len = (int) strlen(name); } // "File/Edit" -> "File"
114  else { name[0] = '\0'; len = 0; } // "File" -> ""
115  continue;
116  }
117  }
118  }
119  *name = '\0';
120  return(-1); // item not found
121 }
122 
151 const Fl_Menu_Item * Fl_Menu_::find_item(const char *pathname) {
152  int i = find_index(pathname);
153  return( (i==-1) ? 0 : (const Fl_Menu_Item*)(menu_+i));
154 }
155 
182 int Fl_Menu_::find_index(const Fl_Menu_Item *item) const {
183  Fl_Menu_Item *max = menu_+size();
184  if (item<menu_ || item>=max) return(-1);
185  return (int) (item-menu_);
186 }
187 
201  for ( int t=0; t < size(); t++ )
202  if (menu_[t].callback_==cb)
203  return(t);
204  return(-1);
205 }
206 
220 int Fl_Menu_::find_index(const char *pathname) const {
221  char menupath[1024] = ""; // File/Export
222  for ( int t=0; t < size(); t++ ) {
223  Fl_Menu_Item *m = menu_ + t;
224  if (m->flags&FL_SUBMENU) {
225  // IT'S A SUBMENU
226  // we do not support searches through FL_SUBMENU_POINTER links
227  if (menupath[0]) strlcat(menupath, "/", sizeof(menupath));
228  strlcat(menupath, m->label(), sizeof(menupath));
229  if (!strcmp(menupath, pathname)) return(t);
230  } else {
231  if (!m->label()) {
232  // END OF SUBMENU? Pop back one level.
233  char *ss = strrchr(menupath, '/');
234  if ( ss ) *ss = 0;
235  else menupath[0] = '\0';
236  continue;
237  }
238  // IT'S A MENU ITEM
239  char itempath[1024]; // eg. Edit/Copy
240  strcpy(itempath, menupath);
241  if (itempath[0]) strlcat(itempath, "/", sizeof(itempath));
242  strlcat(itempath, m->label(), sizeof(itempath));
243  if (!strcmp(itempath, pathname)) return(t);
244  }
245  }
246  return(-1);
247 }
248 
262  for ( int t=0; t < size(); t++ ) {
263  const Fl_Menu_Item *m = menu_ + t;
264  if (m->callback_==cb) {
265  return m;
266  }
267  }
268  return (const Fl_Menu_Item *)0;
269 }
270 
278  clear_changed();
279  if (value_ != m) {value_ = m; return 1;}
280  return 0;
281 }
282 
289  if (v) {
290  if (v->radio()) {
291  if (!v->value()) { // they are turning on a radio item
292  set_changed();
293  setonly((Fl_Menu_Item*)v);
294  }
295  redraw();
296  } else if (v->flags & FL_MENU_TOGGLE) {
297  set_changed();
298  ((Fl_Menu_Item*)v)->flags ^= FL_MENU_VALUE;
299  redraw();
300  } else if (v != value_) { // normal item
301  set_changed();
302  }
303  value_ = v;
305  if (changed() || when()&FL_WHEN_NOT_CHANGED) {
307  else do_callback();
308  }
309  }
310  }
311  return v;
312 }
313 
314 /* Scans an array of Fl_Menu_Item's that begins at start, searching for item.
315  Returns NULL if item is not found.
316  If item is present, returns start, unless item belongs to an
317  FL_SUBMENU_POINTER-adressed array of items, in which case the first item of this array is returned.
318  */
320 {
321  Fl_Menu_Item* m = start;
322  int nest = 0; // will indicate submenu nesting depth
323  while (1) { // loop over all menu items
324  if (!m->text) { // m is a null item
325  if (!nest) return NULL; // item was not found
326  nest--; // m marks the end of a submenu -> decrement submenu nesting depth
327  } else { // a true item
328  if (m == item) return start; // item is found, return menu start item
329  if (m->flags & FL_SUBMENU_POINTER) {
330  // scan the detached submenu which begins at m->user_data()
332  if (first) return first; // if item was found in the submenu, return
333  }
334  else if (m->flags & FL_SUBMENU) { // a direct submenu
335  nest++; // increment submenu nesting depth
336  }
337  }
338  m++; // step to next menu item
339  }
340 }
341 
342 
345  // find the first item of the (sub)menu containing item
347  if (!first) return; // item does not belong to our menu
348  item->flags |= FL_MENU_RADIO | FL_MENU_VALUE;
349  Fl_Menu_Item* j;
350  for (j = item; ; ) { // go down
351  if (j->flags & FL_MENU_DIVIDER) break; // stop on divider lines
352  j++;
353  if (!j->text || !j->radio()) break; // stop after group
354  j->clear();
355  }
356  for (j = item-1; j>=first; j--) { // go up
357  //DEBUG printf("GO UP: WORKING ON: item='%s', flags=%x\n", j->text, j->flags);
358  if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break;
359  j->clear();
360  }
361 }
362 
369  Fl_Menu_Item* j;
370  for (j = this; ; ) { // go down
371  if (j->flags & FL_MENU_DIVIDER) break; // stop on divider lines
372  j++;
373  if (!j->text || !j->radio()) break; // stop after group
374  j->clear();
375  }
376  for (j = this-1; ; j--) { // go up
377  if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break;
378  j->clear();
379  }
380 }
381 
386 Fl_Menu_::Fl_Menu_(int X,int Y,int W,int H,const char* l)
387 : Fl_Widget(X,Y,W,H,l) {
389  box(FL_UP_BOX);
391  value_ = menu_ = 0;
392  alloc = 0;
398 }
399 
407 int Fl_Menu_::size() const {
408  if (!menu_) return 0;
409  return menu_->size();
410 }
411 
418 void Fl_Menu_::menu(const Fl_Menu_Item* m) {
419  clear();
420  value_ = menu_ = (Fl_Menu_Item*)m;
421 }
422 
423 // this version is ok with new Fl_Menu_add code with fl_menu_array_owner:
424 
430 void Fl_Menu_::copy(const Fl_Menu_Item* m, void* ud) {
431  int n = m->size();
432  Fl_Menu_Item* newMenu = new Fl_Menu_Item[n];
433  memcpy(newMenu, m, n*sizeof(Fl_Menu_Item));
434  menu(newMenu);
435  alloc = 1; // make destructor free array, but not strings
436  // for convenience, provide way to change all the user data pointers:
437  if (ud) for (; n--;) {
438  if (newMenu->callback_) newMenu->user_data_ = ud;
439  newMenu++;
440  }
441 }
442 
444  clear();
445 }
446 
447 // Fl_Menu::add() uses this to indicate the owner of the dynamically-
448 // expanding array. We must not free this array:
450 
458  if (alloc) {
459  if (alloc>1) for (int i = size(); i--;)
460  if (menu_[i].text) free((void*)menu_[i].text);
461  if (this == fl_menu_array_owner)
463  else
464  delete[] menu_;
465  menu_ = 0;
466  value_ = 0;
467  alloc = 0;
468  }
469 }
470 
501 int Fl_Menu_::clear_submenu(int index) {
502  if ( index < 0 || index >= size() ) return(-1);
503  if ( ! (menu_[index].flags & FL_SUBMENU) ) return(-1);
504  ++index; // advance to first item in submenu
505  while ( index < size() ) { // keep remove()ing top item until end is reached
506  if ( menu_[index].text == 0 ) break; // end of this submenu? done
507  remove(index); // remove items/submenus
508  }
509  return(0);
510 }
511 
512 //
513 // End of "$Id$".
514 //
FL_MENU_RADIO
Item is a radio button (one checkbox of many can be on)
Definition: Fl_Menu_Item.H:36
Fl.H
Fl_Menu_::item_pathname
int item_pathname(char *name, int namelen, const Fl_Menu_Item *finditem=0) const
Definition: Fl_Menu_.cxx:65
Fl_Menu_Item::flags
int flags
menu item flags like FL_MENU_TOGGLE, FL_MENU_RADIO
Definition: Fl_Menu_Item.H:117
Fl_Menu_::menu
const Fl_Menu_Item * menu() const
Definition: Fl_Menu_.H:110
Fl_Menu_Item::value
int value() const
Definition: Fl_Menu_Item.H:318
FL_SUBMENU_POINTER
Indicates user_data() is a pointer to another menu array.
Definition: Fl_Menu_Item.H:38
Fl_Menu_::clear_submenu
int clear_submenu(int index)
Definition: Fl_Menu_.cxx:501
Fl_Menu_::setonly
void setonly(Fl_Menu_Item *item)
Definition: Fl_Menu_.cxx:344
FL_WHEN_NOT_CHANGED
Do the callback whenever the user interacts with the widget.
Definition: Enumerations.H:442
Fl_Menu_Item::radio
int radio() const
Definition: Fl_Menu_Item.H:310
Fl_Widget::clear_changed
void clear_changed()
Definition: Fl_Widget.H:791
FL_WHEN_RELEASE
Do the callback when the button or key is released and the value changes.
Definition: Enumerations.H:443
Fl_Menu_Item::label
const char * label() const
Definition: Fl_Menu_Item.H:148
fl_menu_array_owner
Fl_Menu_ * fl_menu_array_owner
Definition: Fl_Menu_.cxx:449
Fl_Widget::changed
unsigned int changed() const
Definition: Fl_Widget.H:781
free
void free()
H
static int H
Definition: Fl_Tooltip.cxx:76
FL_SUBMENU
This item is a submenu to other items.
Definition: Fl_Menu_Item.H:39
Fl_Widget::callback_
Fl_Callback * callback_
Definition: Fl_Widget.H:105
Fl_Widget::set_flag
void set_flag(unsigned int c)
Definition: Fl_Widget.H:149
NULL
#define NULL
Definition: forms.H:34
Fl_Menu_::alloc
uchar alloc
Definition: Fl_Menu_.H:58
Fl_Widget::when
Fl_When when() const
Definition: Fl_Widget.H:621
Fl_Widget::do_callback
void do_callback()
Definition: Fl_Widget.H:861
Fl_Menu_Item::size
int size() const
Definition: Fl_Menu.cxx:58
Fl_Callback
void() Fl_Callback(Fl_Widget *, void *)
Definition: Fl_Widget.H:49
FL_MENU_TOGGLE
Item is a checkbox toggle (shows checkbox for on/off state)
Definition: Fl_Menu_Item.H:34
FL_FOREGROUND_COLOR
const Fl_Color FL_FOREGROUND_COLOR
the default foreground color (0) used for labels and text
Definition: Enumerations.H:937
Fl_Menu_Item::submenu
int submenu() const
Definition: Fl_Menu_Item.H:298
Fl_Menu_::item_pathname_
int item_pathname_(char *name, int namelen, const Fl_Menu_Item *finditem, const Fl_Menu_Item *menu=0) const
Definition: Fl_Menu_.cxx:71
Fl_Menu_::picked
const Fl_Menu_Item * picked(const Fl_Menu_Item *)
Definition: Fl_Menu_.cxx:288
FL_WHEN_CHANGED
Do the callback only when the widget value changes.
Definition: Enumerations.H:441
Fl_Menu_Item::user_data
void * user_data() const
Definition: Fl_Menu_Item.H:251
Fl_Menu_::textfont
Fl_Font textfont() const
Definition: Fl_Menu_.H:155
Fl_Widget::selection_color
Fl_Color selection_color() const
Definition: Fl_Widget.H:396
FL_UP_BOX
see figure 1
Definition: Enumerations.H:607
Fl_Widget::flags
unsigned int flags() const
Definition: Fl_Widget.H:147
FL_HELVETICA
const Fl_Font FL_HELVETICA
Helvetica (or Arial) normal (0)
Definition: Enumerations.H:879
Fl_Menu_::value_
const Fl_Menu_Item * value_
Definition: Fl_Menu_.H:54
FL_WHEN_RELEASE_ALWAYS
Do the callback when the button or key is released, even if the value doesn't change.
Definition: Enumerations.H:444
Fl_Menu_Item::clear
void clear()
Definition: Fl_Menu_Item.H:326
max
static int max(int i1, int i2)
Definition: Fl_Text_Buffer.cxx:58
first_submenu_item
static Fl_Menu_Item * first_submenu_item(Fl_Menu_Item *item, Fl_Menu_Item *start)
Definition: Fl_Menu_.cxx:319
FL_MENU_VALUE
The on/off state for checkbox/radio buttons (if set, state is 'on')
Definition: Fl_Menu_Item.H:35
Fl_Menu_::remove
void remove(int)
Definition: Fl_Menu_add.cxx:482
Fl_Menu_Item::user_data_
void * user_data_
menu item user_data for the menu's callback
Definition: Fl_Menu_Item.H:116
Fl_Menu_::down_box
Fl_Boxtype down_box() const
Definition: Fl_Menu_.H:173
Fl_Menu_Item::callback_
Fl_Callback * callback_
menu item callback
Definition: Fl_Menu_Item.H:115
Fl_Menu_::textcolor
Fl_Color textcolor() const
Definition: Fl_Menu_.H:163
cb
static void cb(Fl_Widget *, void *v)
Definition: factory.cxx:937
Fl_Menu_::textsize
Fl_Fontsize textsize() const
Definition: Fl_Menu_.H:159
Fl_Menu_.H
Fl_Widget::redraw
void redraw()
Definition: Fl.cxx:1782
FL_NORMAL_SIZE
Fl_Fontsize FL_NORMAL_SIZE
normal font size
Definition: Fl_Widget.cxx:117
SAFE_STRCAT
#define SAFE_STRCAT(s)
Definition: Fl_Menu_.cxx:32
first
static idle_cb * first
Definition: Fl_add_idle.cxx:33
Fl_Widget
Definition: Fl_Widget.H:101
Fl_Menu_
Definition: Fl_Menu_.H:51
FL_NO_BOX
nothing is drawn at all, this box is invisible
Definition: Enumerations.H:605
Fl_Widget::box
Fl_Boxtype box() const
Definition: Fl_Widget.H:363
Fl_Menu_::text
const char * text() const
Definition: Fl_Menu_.H:150
Fl_Menu_::value
int value() const
Definition: Fl_Menu_.H:140
Fl_Menu_::mvalue
const Fl_Menu_Item * mvalue() const
Definition: Fl_Menu_.H:138
FL_SELECTION_COLOR
const Fl_Color FL_SELECTION_COLOR
the default selection/highlight color
Definition: Enumerations.H:940
FL_MENU_DIVIDER
Creates divider line below this item. Also ends a group of radio buttons.
Definition: Fl_Menu_Item.H:40
Fl_Widget::set_changed
void set_changed()
Definition: Fl_Widget.H:786
Fl_Menu_Item::setonly
void setonly()
Definition: Fl_Menu_.cxx:367
Fl_Menu_::find_item
const Fl_Menu_Item * find_item(const char *name)
Definition: Fl_Menu_.cxx:151
Fl_Menu_Item
Definition: Fl_Menu_Item.H:112
Fl_Menu_::Fl_Menu_
Fl_Menu_(int, int, int, int, const char *=0)
Definition: Fl_Menu_.cxx:386
Y
static int Y
Definition: Fl_Tooltip.cxx:76
Fl_Menu_Item::text
const char * text
menu item text, returned by label()
Definition: Fl_Menu_Item.H:113
flstring.h
Fl_Widget::SHORTCUT_LABEL
the label contains a shortcut we need to draw
Definition: Fl_Widget.H:162
strlcat
#define strlcat
Definition: flstring.h:79
Fl_Menu_Item::do_callback
void do_callback(Fl_Widget *o) const
Definition: Fl_Menu_Item.H:384
Fl_Menu_::copy
void copy(const Fl_Menu_Item *m, void *user_data=0)
Definition: Fl_Menu_.cxx:430
Fl_Menu_::menu_
Fl_Menu_Item * menu_
Definition: Fl_Menu_.H:53
start
static int start(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, int &X, int &Y, int &W, int &H)
Definition: Fl_Image.cxx:655
Fl_Menu_::clear
void clear()
Definition: Fl_Menu_.cxx:457
name
static const char * name
Definition: Fl_arg.cxx:53
Fl_Menu_::~Fl_Menu_
~Fl_Menu_()
Definition: Fl_Menu_.cxx:443
Fl_Menu_::find_index
int find_index(const char *name) const
Definition: Fl_Menu_.cxx:220
Fl_Menu_::size
int size() const
Definition: Fl_Menu_.cxx:407