1 // 2 // "$Id$" 3 // 4 // An input/chooser widget. 5 // ______________ ____ 6 // | || __ | 7 // | input area || \/ | 8 // |______________||____| 9 // 10 // Copyright 1998-2010 by Bill Spitzak and others. 11 // Copyright 2004 by Greg Ercolano. 12 // 13 // This library is free software. Distribution and use rights are outlined in 14 // the file "COPYING" which should have been included with this file. If this 15 // file is missing or damaged, see the license at: 16 // 17 // http://www.fltk.org/COPYING.php 18 // 19 // Please report all bugs and problems on the following page: 20 // 21 // http://www.fltk.org/str.php 22 // 23 24 /* \file 25 Fl_Input_Choice widget . */ 26 27 #ifndef Fl_Input_Choice_H 28 #define Fl_Input_Choice_H 29 30 #include <FL/Fl.H> 31 #include <FL/Fl_Group.H> 32 #include <FL/Fl_Input.H> 33 #include <FL/Fl_Menu_Button.H> 34 #include <FL/fl_draw.H> 35 #include <string.h> 36 37 /** 38 A combination of the input widget and a menu button. 39 40 \image html input_choice.jpg 41 \image latex input_choice.jpg "Fl_Input_Choice widget" width=6cm 42 43 The user can either type into the input area, or use the 44 menu button chooser on the right to choose an item which loads 45 the input area with the selected text. 46 47 The application can directly access both the internal Fl_Input 48 and Fl_Menu_Button widgets respectively using the input() and menubutton() 49 accessor methods. 50 51 The default behavior is to invoke the Fl_Input_Choice::callback() 52 if the user changes the input field's contents, either by typing, 53 pasting, or clicking a different item in the choice menu. 54 55 The callback can determine if an item was picked vs. typing 56 into the input field by checking the value of menubutton()->changed(), 57 which will be: 58 59 - 1: the user picked a different item in the choice menu 60 - 0: the user typed or pasted directly into the input field 61 62 Example use: 63 \code 64 #include <stdio.h> 65 #include <FL/Fl.H> 66 #include <FL/Fl_Double_Window.H> 67 #include <FL/Fl_Input_Choice.H> 68 void choice_cb(Fl_Widget *w, void *userdata) { 69 // Show info about the picked item 70 Fl_Input_Choice *choice = (Fl_Input_Choice*)w; 71 const Fl_Menu_Item *item = choice->menubutton()->mvalue(); 72 printf("*** Choice Callback:\n"); 73 printf(" item label()='%s'\n", item ? item->label() : "(No item)"); 74 printf(" item value()=%d\n", choice->menubutton()->value()); 75 printf(" input value()='%s'\n", choice->input()->value()); 76 printf(" The user %s\n", choice->menubutton()->changed() 77 ? "picked a menu item" 78 : "typed text"); 79 } 80 int main() { 81 Fl_Double_Window win(200,100,"Input Choice"); 82 win.begin(); 83 Fl_Input_Choice choice(10,10,100,30); 84 choice.callback(choice_cb, 0); 85 choice.add("Red"); 86 choice.add("Orange"); 87 choice.add("Yellow"); 88 //choice.value("Red"); // uncomment to make "Red" default 89 win.end(); 90 win.show(); 91 return Fl::run(); 92 } 93 \endcode 94 */ 95 class FL_EXPORT Fl_Input_Choice : public Fl_Group { 96 // Private class to handle slightly 'special' behavior of menu button 97 class InputMenuButton : public Fl_Menu_Button { draw()98 void draw() { 99 draw_box(FL_UP_BOX, color()); 100 fl_color(active_r() ? labelcolor() : fl_inactive(labelcolor())); 101 int xc = x()+w()/2, yc=y()+h()/2; 102 fl_polygon(xc-5,yc-3,xc+5,yc-3,xc,yc+3); 103 if (Fl::focus() == this) draw_focus(); 104 } 105 public: 106 InputMenuButton(int X,int Y,int W,int H,const char*L=0) : Fl_Menu_Button(X,Y,W,H,L)107 Fl_Menu_Button(X, Y, W, H, L) { box(FL_UP_BOX); } 108 }; 109 110 Fl_Input *inp_; 111 InputMenuButton *menu_; 112 113 // note: this is used by the Fl_Input_Choice ctor defined in Fl_Group. menu_cb(Fl_Widget *,void * data)114 static void menu_cb(Fl_Widget*, void *data) { 115 Fl_Input_Choice *o=(Fl_Input_Choice *)data; 116 Fl_Widget_Tracker wp(o); 117 const Fl_Menu_Item *item = o->menubutton()->mvalue(); 118 if (item && item->flags & (FL_SUBMENU|FL_SUBMENU_POINTER)) return; // ignore submenus 119 if (!strcmp(o->inp_->value(), o->menu_->text())) 120 { 121 o->Fl_Widget::clear_changed(); 122 if (o->when() & FL_WHEN_NOT_CHANGED) 123 o->do_callback(); 124 } 125 else 126 { 127 o->inp_->value(o->menu_->text()); 128 o->inp_->set_changed(); 129 o->Fl_Widget::set_changed(); 130 if (o->when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE)) 131 o->do_callback(); 132 } 133 134 if (wp.deleted()) return; 135 136 if (o->callback() != default_callback) 137 { 138 o->Fl_Widget::clear_changed(); 139 o->inp_->clear_changed(); 140 } 141 } 142 143 // note: this is used by the Fl_Input_Choice ctor defined in Fl_Group. inp_cb(Fl_Widget *,void * data)144 static void inp_cb(Fl_Widget*, void *data) { 145 Fl_Input_Choice *o=(Fl_Input_Choice *)data; 146 Fl_Widget_Tracker wp(o); 147 if (o->inp_->changed()) { 148 o->Fl_Widget::set_changed(); 149 if (o->when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE)) 150 o->do_callback(); 151 } else { 152 o->Fl_Widget::clear_changed(); 153 if (o->when() & FL_WHEN_NOT_CHANGED) 154 o->do_callback(); 155 } 156 157 if (wp.deleted()) return; 158 159 if (o->callback() != default_callback) 160 o->Fl_Widget::clear_changed(); 161 } 162 163 // Custom resize behavior -- input stretches, menu button doesn't inp_x()164 inline int inp_x() { return(x() + Fl::box_dx(box())); } inp_y()165 inline int inp_y() { return(y() + Fl::box_dy(box())); } inp_w()166 inline int inp_w() { return(w() - Fl::box_dw(box()) - 20); } inp_h()167 inline int inp_h() { return(h() - Fl::box_dh(box())); } 168 menu_x()169 inline int menu_x() { return(x() + w() - 20 - Fl::box_dx(box())); } menu_y()170 inline int menu_y() { return(y() + Fl::box_dy(box())); } menu_w()171 inline int menu_w() { return(20); } menu_h()172 inline int menu_h() { return(h() - Fl::box_dh(box())); } 173 174 public: 175 /** 176 Creates a new Fl_Input_Choice widget using the given position, size, 177 and label string. 178 Inherited destructor destroys the widget and any values associated with it. 179 */ 180 Fl_Input_Choice(int X,int Y,int W,int H,const char*L=0); 181 182 /** Adds an item to the menu. 183 You can access the more complex Fl_Menu_Button::add() methods 184 (setting callbacks, userdata, etc), via menubutton(). Example: 185 \code 186 Fl_Input_Choice *choice = new Fl_Input_Choice(100,10,120,25,"Fonts"); 187 Fl_Menu_Button *mb = choice->menubutton(); // use Fl_Input_Choice's Fl_Menu_Button 188 mb->add("Helvetica", 0, MyFont_CB, (void*)mydata); // use Fl_Menu_Button's add() methods 189 mb->add("Courier", 0, MyFont_CB, (void*)mydata); 190 mb->add("More..", 0, FontDialog_CB, (void*)mydata); 191 \endcode 192 */ add(const char * s)193 void add(const char *s) { menu_->add(s); } 194 /** Returns the combined changed() state of the input and menu button widget. */ changed()195 int changed() const { return inp_->changed() | Fl_Widget::changed(); } 196 /** Clears the changed() state of both input and menu button widgets. */ clear_changed()197 void clear_changed() { 198 inp_->clear_changed(); 199 Fl_Widget::clear_changed(); 200 } 201 /** Sets the changed() state of both input and menu button widgets 202 to the specfied value.*/ set_changed()203 void set_changed() { 204 inp_->set_changed(); 205 // no need to call Fl_Widget::set_changed() 206 } 207 /** Removes all items from the menu. */ clear()208 void clear() { menu_->clear(); } 209 /** Gets the box type of the menu button */ down_box()210 Fl_Boxtype down_box() const { return (menu_->down_box()); } 211 /** Sets the box type of the menu button */ down_box(Fl_Boxtype b)212 void down_box(Fl_Boxtype b) { menu_->down_box(b); } 213 /** Gets the Fl_Menu_Item array used for the menu. */ menu()214 const Fl_Menu_Item *menu() { return (menu_->menu()); } 215 /** Sets the Fl_Menu_Item array used for the menu. */ menu(const Fl_Menu_Item * m)216 void menu(const Fl_Menu_Item *m) { menu_->menu(m); } resize(int X,int Y,int W,int H)217 void resize(int X, int Y, int W, int H) { 218 Fl_Group::resize(X,Y,W,H); 219 inp_->resize(inp_x(), inp_y(), inp_w(), inp_h()); 220 menu_->resize(menu_x(), menu_y(), menu_w(), menu_h()); 221 } 222 /// Gets the Fl_Input text field's text color. textcolor()223 Fl_Color textcolor() const { return (inp_->textcolor());} 224 /// Sets the Fl_Input text field's text color to \p c. textcolor(Fl_Color c)225 void textcolor(Fl_Color c) { inp_->textcolor(c);} 226 /// Gets the Fl_Input text field's font style. textfont()227 Fl_Font textfont() const { return (inp_->textfont());} 228 /// Sets the Fl_Input text field's font style to \p f. textfont(Fl_Font f)229 void textfont(Fl_Font f) { inp_->textfont(f);} 230 /// Gets the Fl_Input text field's font size textsize()231 Fl_Fontsize textsize() const { return (inp_->textsize()); } 232 /// Sets the Fl_Input text field's font size to \p s. textsize(Fl_Fontsize s)233 void textsize(Fl_Fontsize s) { inp_->textsize(s); } 234 /// Returns the Fl_Input text field's current contents. value()235 const char* value() const { return (inp_->value()); } 236 /** Sets the Fl_Input text field's contents to \p val. 237 Does not affect the menu selection.*/ value(const char * val)238 void value(const char *val) { inp_->value(val); } 239 /** Chooses item# \p val in the menu, and sets the Fl_Input text field 240 to that value. Any previous text is cleared.*/ value(int val)241 void value(int val) { 242 menu_->value(val); 243 inp_->value(menu_->text(val)); 244 } 245 /** Returns a pointer to the internal Fl_Menu_Button widget. 246 This can be used to access any of the methods of the menu button, e.g. 247 \code 248 Fl_Input_Choice *choice = new Fl_Input_Choice(100,10,120,25,"Choice:"); 249 [..] 250 // Print all the items in the choice menu 251 for ( int t=0; t<choice->menubutton()->size(); t++ ) { 252 const Fl_Menu_Item &item = choice->menubutton()->menu()[t]; 253 printf("item %d -- label=%s\n", t, item.label() ? item.label() : "(Null)"); 254 } 255 \endcode 256 */ menubutton()257 Fl_Menu_Button *menubutton() { return menu_; } 258 /** Returns a pointer to the internal Fl_Input widget. 259 This can be used to directly access all of the Fl_Input widget's 260 methods.*/ input()261 Fl_Input *input() { return inp_; } 262 }; 263 264 #endif // !Fl_Input_Choice_H 265 266 // 267 // End of "$Id$". 268 // 269