// // Menu Node header file for the Fast Light Tool Kit (FLTK). // // Copyright 1998-2025 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this // file is missing or damaged, see the license at: // // https://www.fltk.org/COPYING.php // // Please see the following page on how to report bugs and issues: // // https://www.fltk.org/bugs.php // // Type for creating all subclasses of Fl_Widget // This should have the widget pointer in it, but it is still in the // Node base class. // #ifndef FLUID_NODES_MENU_NODE_H #define FLUID_NODES_MENU_NODE_H #include "nodes/Button_Node.h" #include "Fluid.h" #include "app/Snap_Action.h" #include #include #include #include #include #include extern Fl_Menu_Item dummymenu[]; extern Fl_Menu_Item button_type_menu[]; extern Fl_Menu_Item menu_item_type_menu[]; extern Fl_Menu_Item menu_bar_type_menu[]; /** \brief Manage all types on menu items. Deriving Menu_Item_Node from Button_Node is intentional. For the purpose of editing, a Menu Item is implemented with `o` pointing to an Fl_Button for holding all properties. */ class Menu_Item_Node : public Button_Node { public: typedef Button_Node super; static Menu_Item_Node prototype; public: Fl_Menu_Item* subtypes() {return menu_item_type_menu;} const char* type_name() {return "MenuItem";} const char* alt_type_name() {return "fltk::Item";} Node* make(Strategy strategy); Node* make(int flags, Strategy strategy); int is_button() const {return 1;} // this gets shortcut to work Fl_Widget* widget(int,int,int,int) {return 0;} Widget_Node* _make() {return 0;} virtual const char* menu_name(Code_Writer& f, int& i); int flags(); void write_static(Code_Writer& f); void write_item(Code_Writer& f); void write_code1(Code_Writer& f); void write_code2(Code_Writer& f); int is_true_widget() const { return 0; } Type type() const { return FLD_NODE_TYPE_Menu_Item; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Menu_Item) ? true : super::is_a(inType); } }; /** \brief Manage Radio style Menu Items. */ class Radio_Menu_Item_Node : public Menu_Item_Node { public: typedef Menu_Item_Node super; static Radio_Menu_Item_Node prototype; public: const char* type_name() {return "RadioMenuItem";} Node* make(Strategy strategy); Type type() const { return FLD_NODE_TYPE_Radio_Menu_Item; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Radio_Menu_Item) ? true : super::is_a(inType); } }; /** \brief Manage Checkbox style Menu Items. */ class Checkbox_Menu_Item_Node : public Menu_Item_Node { public: typedef Menu_Item_Node super; static Checkbox_Menu_Item_Node prototype; public: const char* type_name() {return "CheckMenuItem";} Node* make(Strategy strategy); Type type() const { return FLD_NODE_TYPE_Checkbox_Menu_Item; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Checkbox_Menu_Item) ? true : super::is_a(inType); } }; /** \brief Manage Submenu style Menu Items. Submenu Items are simply buttons just like all other menu items, but they can also hold a pointer to a list of submenus, or have a flag set that allows submenus to follow in the current array. As buttons, they can be clicked by the user, and they will call their callback, if one is set. */ class Submenu_Node : public Menu_Item_Node { public: typedef Menu_Item_Node super; static Submenu_Node prototype; public: Fl_Menu_Item* subtypes() {return 0;} const char* type_name() {return "Submenu";} const char* alt_type_name() {return "fltk::ItemGroup";} int can_have_children() const {return 1;} int is_button() const {return 0;} // disable shortcut Node* make(Strategy strategy); // changes to submenu must propagate up so build_menu is called // on the parent Menu_Node: void add_child(Node*a, Node*b) {parent->add_child(a,b);} void move_child(Node*a, Node*b) {parent->move_child(a,b);} void remove_child(Node*a) {parent->remove_child(a);} Type type() const { return FLD_NODE_TYPE_Submenu; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Submenu) ? true : super::is_a(inType); } }; // ----------------------------------------------------------------------------- /** \brief Base class for all widgets that can have a pulldown menu attached. Widgets with this type can be derived from Fl_Menu_ or from Fl_Group (Fl_Input_Choice). */ class Menu_Manager_Node : public Widget_Node { typedef Widget_Node super; public: void ideal_size(int &w, int &h) { Layout_Preset *layout = Fluid.proj.layout; h = layout->textsize_not_null() + 8; w = layout->textsize_not_null() * 6 + 8; Snap_Action::better_size(w, h); } int can_have_children() const {return 1;} int menusize; virtual void build_menu() = 0; Menu_Manager_Node() : Widget_Node() {menusize = 0;} void add_child(Node*, Node*) { build_menu(); } void move_child(Node*, Node*) { build_menu(); } void remove_child(Node*) { build_menu();} Node* click_test(int x, int y) = 0; void write_code2(Code_Writer& f); void copy_properties() = 0; Type type() const { return FLD_NODE_TYPE_Menu_Manager_; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Menu_Manager_) ? true : super::is_a(inType); } }; /** \brief Manage the composite widget Input Choice. \note Input Choice is a composite window, so `o` will be pointing to a widget derived from Fl_Group. All menu related methods from Fl_Menu_Trait_Type must be virtual and must be reimplemented here (click_test, build_menu, textstuff). */ class Input_Choice_Node : public Menu_Manager_Node { public: typedef Menu_Manager_Node super; static Input_Choice_Node prototype; private: int textstuff(int w, Fl_Font& f, int& s, Fl_Color& c) { Fl_Input_Choice *myo = (Fl_Input_Choice*)(w==4 ? ((Widget_Node*)this->factory)->o : this->o); switch (w) { case 4: case 0: f = (Fl_Font)myo->textfont(); s = myo->textsize(); c = myo->textcolor(); break; case 1: myo->textfont(f); break; case 2: myo->textsize(s); break; case 3: myo->textcolor(c); break; } return 1; } public: ~Input_Choice_Node() { if (menusize) delete[] (Fl_Menu_Item*)(((Fl_Input_Choice*)o)->menu()); } const char *type_name() {return "Fl_Input_Choice";} const char *alt_type_name() {return "fltk::ComboBox";} Node* click_test(int,int); Fl_Widget *widget(int X,int Y,int W,int H) { Fl_Input_Choice *myo = new Fl_Input_Choice(X,Y,W,H,"input choice:"); myo->menu(dummymenu); myo->value("input"); return myo; } Widget_Node *_make() {return new Input_Choice_Node();} void build_menu(); Type type() const { return FLD_NODE_TYPE_Input_Choice; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Input_Choice) ? true : super::is_a(inType); } void copy_properties(); }; /** \brief Base class to handle widgets that are derived from Fl_Menu_. */ class Menu_Base_Node : public Menu_Manager_Node { typedef Menu_Manager_Node super; int textstuff(int w, Fl_Font& f, int& s, Fl_Color& c) { Fl_Menu_ *myo = (Fl_Menu_*)(w==4 ? ((Widget_Node*)this->factory)->o : this->o); switch (w) { case 4: case 0: f = myo->textfont(); s = myo->textsize(); c = myo->textcolor(); break; case 1: myo->textfont(f); break; case 2: myo->textsize(s); break; case 3: myo->textcolor(c); break; } return 1; } public: int can_have_children() const {return 1;} void build_menu(); ~Menu_Base_Node() { if (menusize) delete[] (Fl_Menu_Item*)(((Fl_Menu_*)o)->menu()); } Node* click_test(int x, int y); void copy_properties(); Type type() const { return FLD_NODE_TYPE_Menu_; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Menu_) ? true : super::is_a(inType); } }; extern Fl_Menu_Item button_type_menu[]; /** \brief Make Menu Button widgets. */ class Menu_Button_Node : public Menu_Base_Node { public: typedef Menu_Base_Node super; static Menu_Button_Node prototype; private: Fl_Menu_Item *subtypes() {return button_type_menu;} public: const char *type_name() {return "Fl_Menu_Button";} const char *alt_type_name() {return "fltk::MenuButton";} Fl_Widget *widget(int X,int Y,int W,int H) { return new Fl_Menu_Button(X,Y,W,H,"menu");} Widget_Node *_make() {return new Menu_Button_Node();} Type type() const { return FLD_NODE_TYPE_Menu_Button; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Menu_Button) ? true : super::is_a(inType); } }; /** \brief Manage Choice type menu widgets. */ class Choice_Node : public Menu_Base_Node { public: typedef Menu_Base_Node super; static Choice_Node prototype; public: const char *type_name() {return "Fl_Choice";} const char *alt_type_name() {return "fltk::Choice";} Fl_Widget *widget(int X,int Y,int W,int H) { Fl_Choice *myo = new Fl_Choice(X,Y,W,H,"choice:"); myo->menu(dummymenu); return myo; } Widget_Node *_make() {return new Choice_Node();} Type type() const { return FLD_NODE_TYPE_Choice; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Choice) ? true : super::is_a(inType); } }; /** \brief Manage Menubar widgets. */ class Menu_Bar_Node : public Menu_Base_Node { public: typedef Menu_Base_Node super; static Menu_Bar_Node prototype; private: Fl_Menu_Item *subtypes() {return menu_bar_type_menu;} public: Menu_Bar_Node(); ~Menu_Bar_Node(); const char *type_name() {return "Fl_Menu_Bar";} const char *alt_type_name() {return "fltk::MenuBar";} Fl_Widget *widget(int X,int Y,int W,int H) {return new Fl_Menu_Bar(X,Y,W,H);} Widget_Node *_make() {return new Menu_Bar_Node();} void write_static(Code_Writer& f); void write_code1(Code_Writer& f); // void write_code2(Code_Writer& f); Type type() const { return FLD_NODE_TYPE_Menu_Bar; } bool is_a(Type inType) const { return (inType==FLD_NODE_TYPE_Menu_Bar) ? true : super::is_a(inType); } int is_sys_menu_bar(); const char* sys_menubar_name() const; const char *sys_menubar_proxy_name(); protected: char *_proxy_name; }; #endif // FLUID_NODES_MENU_NODE_H