diff options
| author | Michael R Sweet <michael.r.sweet@gmail.com> | 1998-10-06 18:21:25 +0000 |
|---|---|---|
| committer | Michael R Sweet <michael.r.sweet@gmail.com> | 1998-10-06 18:21:25 +0000 |
| commit | f9039b2ae21988783feae9b362818e7923e82d14 (patch) | |
| tree | 6d6fe3679d73448758f9794e7d4d4f6b22a4adad /fluid/Fl_Menu_Type.cxx | |
| parent | 67e89232f9ba067825a158734a09e0fa21aacbe3 (diff) | |
Initial revision
git-svn-id: file:///fltk/svn/fltk/trunk@2 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'fluid/Fl_Menu_Type.cxx')
| -rw-r--r-- | fluid/Fl_Menu_Type.cxx | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/fluid/Fl_Menu_Type.cxx b/fluid/Fl_Menu_Type.cxx new file mode 100644 index 000000000..02318602c --- /dev/null +++ b/fluid/Fl_Menu_Type.cxx @@ -0,0 +1,487 @@ +// Fl_Menu_Type.C + +// Menu items are kludged by making a phony Fl_Box widget so the normal +// widget panel can be used to control them. + +// This file also contains code to make Fl_Menu_Button, Fl_Menu_Bar, +// etc widgets. + +#include <FL/Fl.H> +#include "Fl_Widget_Type.H" +#include <FL/fl_message.H> +#include <FL/Fl_Menu_.H> +#include <FL/Fl_Button.H> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +static Fl_Menu_Item menu_item_type_menu[] = { + {"Normal",0,0,(void*)0}, + {"Toggle",0,0,(void*)FL_MENU_BOX}, + {"Radio",0,0,(void*)FL_MENU_RADIO}, + {0}}; + +class Fl_Menu_Item_Type : public Fl_Widget_Type { +public: + Fl_Menu_Item* subtypes() {return menu_item_type_menu;} + const char* type_name() {return "menuitem";} + Fl_Type* make(); + int is_menu_item() const {return 1;} + int is_button() const {return 1;} // this gets shortcut to work + Fl_Widget* widget(int,int,int,int) {return 0;} + Fl_Widget_Type* _make() {return 0;} + void write_declare(); + const char* menu_name(int& i); + int flags(); + void write_static(); + void write_item(); + void write_code1(); + void write_code2(); +}; + +class Fl_Submenu_Type : public Fl_Menu_Item_Type { +public: + Fl_Menu_Item* subtypes() {return 0;} + const char* type_name() {return "submenu";} + int is_parent() const {return 1;} + int is_button() const {return 0;} // disable shortcut + Fl_Type* make(); + // changes to submenu must propagate up so build_menu is called + // on the parent Fl_Menu_Type: + void add_child(Fl_Type*a, Fl_Type*b) {parent->add_child(a,b);} + void move_child(Fl_Type*a, Fl_Type*b) {parent->move_child(a,b);} + void remove_child(Fl_Type*a) {parent->remove_child(a);} +}; + +extern int reading_file; +extern int force_parent; + +static char submenuflag; + +Fl_Type *Fl_Menu_Item_Type::make() { + // Find the current menu item: + Fl_Type* q = Fl_Type::current; + Fl_Type* p = q; + if (p) { + if (force_parent && q->is_menu_item() || !q->is_parent()) p = p->parent; + } + force_parent = 0; + if (!p || !(p->is_menu_button() || p->is_menu_item() && p->is_parent())) { + fl_message("Please select a menu to add to"); + return 0; + } + if (!o) { + o = new Fl_Button(0,0,100,20); // create template widget + } + + Fl_Menu_Item_Type* t = submenuflag ? new Fl_Submenu_Type() : new Fl_Menu_Item_Type(); + t->o = new Fl_Button(0,0,100,20); + t->factory = this; + t->add(p); + if (!reading_file) t->label(submenuflag ? "submenu" : "item"); + return t; +} + +Fl_Type *Fl_Submenu_Type::make() { + submenuflag = 1; + Fl_Type* t = Fl_Menu_Item_Type::make(); + submenuflag = 0; + return t; +} + +Fl_Menu_Item_Type Fl_Menu_Item_type; +Fl_Submenu_Type Fl_Submenu_type; + +//////////////////////////////////////////////////////////////// +// Writing the C code: + +#include <ctype.h> + +// test functions in Fl_Widget_Type.C: +int is_name(const char *c); +const char *array_name(Fl_Widget_Type *o); +int isdeclare(const char *c); + +void Fl_Menu_Item_Type::write_declare() { + if (callback() && is_name(callback())) + ::write_declare("extern void %s(Fl_Menu_*, %s);", callback(), + user_data_type() ? user_data_type() : "void*"); + for (int n=0; n < NUM_EXTRA_CODE; n++) { + if (extra_code(n) && isdeclare(extra_code(n))) + ::write_declare("%s", extra_code(n)); + } +} + +const char* Fl_Menu_Item_Type::menu_name(int& i) { + i = 0; + Fl_Type* t = prev; + while (t && t->is_menu_item()) { + // be sure to count the {0} that ends a submenu: + if (t->level > t->next->level || + // detect empty submenu: + t->level==t->next->level &&t->is_parent()) + i++; + t = t->prev; i++; + } + return unique_id(t, "menu", t->name(), t->label()); +} + +#include "Fluid_Image.H" + +void Fl_Menu_Item_Type::write_static() { + if (callback() && !is_name(callback())) { + // see if 'o' or 'v' used, to prevent unused argument warnings: + int use_o = 0; + int use_v = 0; + const char *d; + for (d = callback(); *d;) { + if (*d == 'o' && !is_id(d[1])) use_o = 1; + if (*d == 'v' && !is_id(d[1])) use_v = 1; + do d++; while (is_id(*d)); + while (*d && !is_id(*d)) d++; + } + const char* cn = callback_name(); + const char* k = class_name(); + if (k) { + write_c("\ninline void %s::%s_i(Fl_Menu_*", k, cn); + } else { + write_c("\nstatic void %s(Fl_Menu_*", cn); + } + if (use_o) write_c(" o"); + const char* ut = user_data_type() ? user_data_type() : "void*"; + write_c(", %s", ut); + if (use_v) write_c(" v"); + write_c(") {\n %s", callback()); + if (*(d-1) != ';') write_c(";"); + write_c("\n}\n"); + if (k) { + write_c("void %s::%s(Fl_Menu_* o, %s v) {\n", k, cn, ut); + write_c(" ((%s*)(o->", k); + Fl_Type* t = parent; while (t->is_menu_item()) t = t->parent; + for (t = t->parent; t->is_widget(); t = t->parent) write_c("parent()->"); + write_c("user_data()))->%s_i(o,v);\n}\n", cn); + } + } + if (image) { + if (image->written != write_number) { + image->write_static(); + image->written = write_number; + } + } + if (next && next->is_menu_item()) return; + // okay, when we hit last item in the menu we have to write the + // entire array out: + int level; + const char* k = class_name(); + if (k) { + write_c("\nFl_Menu_Item %s::%s[] = {\n", k, menu_name(level)); + } else + write_c("\nFl_Menu_Item %s[] = {\n", menu_name(level)); + Fl_Type* t = prev; while (t && t->is_menu_item()) t = t->prev; + level = t->level+1; + for (Fl_Type* q = t->next; q && q->is_menu_item(); q = q->next) { + ((Fl_Menu_Item_Type*)q)->write_item(); + if (q->is_parent()) level++; + int l1 = + (q->next && q->next->is_menu_item()) ? q->next->level : t->next->level; + while (level > l1) {write_c(" {0},\n"); level--;} + level = l1; + } + write_c(" {0}\n};\n"); +} + +int Fl_Menu_Item_Type::flags() { + int i = o->type(); + if (((Fl_Button*)o)->value()) i |= FL_MENU_VALUE; + if (!o->active()) i |= FL_MENU_INACTIVE; + if (!o->visible()) i |= FL_MENU_INVISIBLE; + if (is_parent()) i |= FL_SUBMENU; + if (hotspot()) i |= FL_MENU_DIVIDER; + return i; +} + +void Fl_Menu_Item_Type::write_item() { + write_c(" {"); + if (image) write_c("0"); + else if (label()) write_cstring(label()); + else write_c("\"\""); + if (((Fl_Button*)o)->shortcut()) + write_c(", 0x%x, ", ((Fl_Button*)o)->shortcut()); + else + write_c(", 0, "); + if (callback()) { + const char* k = class_name(); + if (k) { + write_c(" (Fl_Callback*)%s::%s,", k, callback_name()); + } else { + write_c(" (Fl_Callback*)%s,", callback_name()); + } + } else + write_c(" 0,"); + if (user_data()) + write_c(" (void*)(%s),", user_data()); + else + write_c(" 0,"); + write_c(" %d, %d, %d, %d, %d", flags(), + o->labeltype(), o->labelfont(), o->labelsize(), o->labelcolor()); + write_c("},\n"); +} + +void Fl_Menu_Item_Type::write_code1() { + if (!prev->is_menu_item()) { + // for first menu item, declare the array + int i; const char* n = menu_name(i); + if (class_name()) + write_h(" static Fl_Menu_Item %s[];\n", n); + else + write_h("extern Fl_Menu_Item %s[];\n", n); + } + + const char *c = array_name(this); + if (c) { + int i; const char* n = menu_name(i); + write_h("#define %s (%s+%d)\n", c, n, i); + } + + if (callback()) { + if (!is_name(callback()) && class_name()) { + const char* cn = callback_name(); + const char* ut = user_data_type() ? user_data_type() : "void*"; + write_public(0); + write_h(" inline void %s_i(Fl_Menu_*, %s);\n", cn, ut); + write_h(" static void %s(Fl_Menu_*, %s);\n", cn, ut); + } + } + + int init = 0; + if (image) { + int i; const char* n = menu_name(i); + write_c(" {Fl_Menu_Item* o = &%s[%d];\n", n, i); + init = 1; + image->write_code(); + } + for (int n=0; n < NUM_EXTRA_CODE; n++) + if (extra_code(n) && !isdeclare(extra_code(n))) { + if (!init) { + init = 1; + int i; const char* n = menu_name(i); + write_c("%s{ Fl_Menu_Item* o = &%s[%d];\n", indent(), n, i); + } + write_c("%s %s\n", indent(), extra_code(n)); + } + if (init) write_c("%s}\n",indent()); +} + +void Fl_Menu_Item_Type::write_code2() {} + +//////////////////////////////////////////////////////////////// +// This is the base class for widgets that contain a menu (ie +// subclasses of Fl_Menu_. +// This is a parent widget and menu items can be added as +// children. An actual array of Fl_Menu_Items is kept parallel +// with the child objects and updated as they change. + +class Fl_Menu_Type : public Fl_Widget_Type { + int textstuff(int w, Fl_Font& f, int& s, Fl_Color& c) { + Fl_Menu_ *o = (Fl_Menu_*)(w==4 ? ((Fl_Widget_Type*)this->factory)->o : this->o); + switch (w) { + case 4: + case 0: f = o->textfont(); s = o->textsize(); c = o->textcolor(); break; + case 1: o->textfont(f); break; + case 2: o->textsize(s); break; + case 3: o->textcolor(c); break; + } + return 1; + } +public: + int is_menu_button() const {return 1;} + int is_parent() const {return 1;} + int menusize; + void build_menu(); + Fl_Menu_Type() : Fl_Widget_Type() {menusize = 0;} + ~Fl_Menu_Type() { + if (menusize) delete[] (Fl_Menu_Item*)(((Fl_Menu_*)o)->menu()); + } + void add_child(Fl_Type*, Fl_Type*) {build_menu();} + void move_child(Fl_Type*, Fl_Type*) {build_menu();} + void remove_child(Fl_Type*) {build_menu();} + Fl_Type* click_test(int x, int y); + void write_code2(); +}; + +void Fl_Menu_Type::build_menu() { + Fl_Menu_* w = (Fl_Menu_*)o; + // count how many Fl_Menu_Item structures needed: + int n = 0; + Fl_Type* q; + for (q = next; q && q->level > level; q = q->next) { + if (q->is_parent()) n++; // space for null at end of submenu + n++; + } + if (!n) { + if (menusize) delete[] (Fl_Menu_Item*)(w->menu()); + w->menu(0); + menusize = 0; + } else { + n++; // space for null at end of menu + if (menusize<n) { + if (menusize) delete[] (Fl_Menu_Item*)(w->menu()); + menusize = n+10; + w->menu(new Fl_Menu_Item[menusize]); + } + // fill them all in: + Fl_Menu_Item* m = (Fl_Menu_Item*)(w->menu()); + int lvl = level+1; + for (q = next; q && q->level > level; q = q->next) { + Fl_Menu_Item_Type* i = (Fl_Menu_Item_Type*)q; + m->label(i->o->label()); + m->shortcut(((Fl_Button*)(i->o))->shortcut()); + m->callback(0,(void*)i); + m->flags = i->flags(); + m->labeltype(i->o->labeltype()); + m->labelfont(i->o->labelfont()); + m->labelsize(i->o->labelsize()); + m->labelcolor(i->o->labelcolor()); + m++; + if (q->is_parent()) lvl++; + int l1 = + (q->next && q->next->is_menu_item()) ? q->next->level : level; + while (lvl > l1) {m->label(0); m++; lvl--;} + lvl = l1; + } + } + o->redraw(); +} + +Fl_Type* Fl_Menu_Type::click_test(int, int) { + if (selected) return 0; // let user move the widget + Fl_Menu_* w = (Fl_Menu_*)o; + if (!menusize) return 0; + const Fl_Menu_Item* save = w->mvalue(); + w->value((Fl_Menu_Item*)0); + Fl::pushed(w); + w->handle(FL_PUSH); + const Fl_Menu_Item* m = w->mvalue(); + if (m) { + // restore the settings of toggles & radio items: + if (m->flags & (FL_MENU_RADIO | FL_MENU_TOGGLE)) build_menu(); + return (Fl_Type*)(m->user_data()); + } + w->value(save); + return this; +} + +void Fl_Menu_Type::write_code2() { + if (next && next->is_menu_item()) + write_c("%so->menu(%s);\n", indent(), + unique_id(this, "menu", name(), label())); + Fl_Widget_Type::write_code2(); +} + +//////////////////////////////////////////////////////////////// + +#include <FL/Fl_Menu_Button.H> +static Fl_Menu_Item button_type_menu[] = { + {"normal",0,0,(void*)0}, + {"popup1",0,0,(void*)Fl_Menu_Button::POPUP1}, + {"popup2",0,0,(void*)Fl_Menu_Button::POPUP2}, + {"popup3",0,0,(void*)Fl_Menu_Button::POPUP3}, + {"popup12",0,0,(void*)Fl_Menu_Button::POPUP12}, + {"popup23",0,0,(void*)Fl_Menu_Button::POPUP23}, + {"popup13",0,0,(void*)Fl_Menu_Button::POPUP13}, + {"popup123",0,0,(void*)Fl_Menu_Button::POPUP123}, + {0}}; +class Fl_Menu_Button_Type : public Fl_Menu_Type { + Fl_Menu_Item *subtypes() {return button_type_menu;} +public: + virtual const char *type_name() {return "Fl_Menu_Button";} + Fl_Widget *widget(int x,int y,int w,int h) { + return new Fl_Menu_Button(x,y,w,h,"menu");} + Fl_Widget_Type *_make() {return new Fl_Menu_Button_Type();} +}; +Fl_Menu_Button_Type Fl_Menu_Button_type; + +//////////////////////////////////////////////////////////////// + +#include <FL/Fl_Choice.H> + +static Fl_Menu_Item dummymenu[] = {{"CHOICE"},{0}}; + +class Fl_Choice_Type : public Fl_Menu_Type { +public: + virtual const char *type_name() {return "Fl_Choice";} + Fl_Widget *widget(int x,int y,int w,int h) { + Fl_Choice *o = new Fl_Choice(x,y,w,h,"choice:"); + o->menu(dummymenu); + return o; + } + Fl_Widget_Type *_make() {return new Fl_Choice_Type();} +}; +Fl_Choice_Type Fl_Choice_type; + +//////////////////////////////////////////////////////////////// + +#include <FL/Fl_Menu_Bar.H> +class Fl_Menu_Bar_Type : public Fl_Menu_Type { +public: + virtual const char *type_name() {return "Fl_Menu_Bar";} + Fl_Widget *widget(int x,int y,int w,int h) { + return new Fl_Menu_Bar(x,y,w,h);} + Fl_Widget_Type *_make() {return new Fl_Menu_Bar_Type();} +}; +Fl_Menu_Bar_Type Fl_Menu_Bar_type; + +//////////////////////////////////////////////////////////////// +// Shortcut entry item in panel: + +#include <FL/Fl_Output.H> +#include "Shortcut_Button.H" +#include <FL/fl_draw.H> + +void Shortcut_Button::draw() { + if (value()) draw_box(FL_THIN_DOWN_BOX, (Fl_Color)9); + else draw_box(FL_THIN_UP_BOX, FL_WHITE); + fl_font(FL_HELVETICA,14); fl_color(FL_BLACK); + fl_draw(fl_shortcut_label(svalue),x()+6,y(),w(),h(),FL_ALIGN_LEFT); +} + +int Shortcut_Button::handle(int e) { + when(0); type(FL_TOGGLE_BUTTON); + if (e == FL_KEYBOARD) { + if (!value()) return 0; + int v = Fl::event_text()[0]; + if (v > 32 && v < 0x7f || v > 0xa0 && v <= 0xff) { + v = v | Fl::event_state()&(FL_META|FL_ALT|FL_CTRL); + } else { + v = Fl::event_state()&(FL_META|FL_ALT|FL_CTRL|FL_SHIFT) | Fl::event_key(); + if (v == FL_BackSpace && svalue) v = 0; + } + if (v != svalue) {svalue = v; set_changed(); redraw();} + return 1; + } else if (e == FL_UNFOCUS) { + int c = changed(); value(0); if (c) set_changed(); + return 1; + } else if (e == FL_FOCUS) { + return value(); + } else { + int r = Fl_Button::handle(e); + if (e == FL_RELEASE && value() && Fl::focus() != this) take_focus(); + return r; + } +} + +void shortcut_in_cb(Shortcut_Button* i, void* v) { + if (v == LOAD) { + if (!current_widget->is_button()) {i->hide(); return;} + i->show(); + i->svalue = ((Fl_Button*)(current_widget->o))->shortcut(); + i->redraw(); + } else { + for (Fl_Type *o = Fl_Type::first; o; o = o->next) + if (o->selected && o->is_button()) { + Fl_Button* b = (Fl_Button*)(((Fl_Widget_Type*)o)->o); + b->shortcut(i->svalue); + if (o->is_menu_item()) ((Fl_Widget_Type*)o)->redraw(); + } + } +} |
