From 71b8e77935bc9b0a3afc97d322037f2549165d2f Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Tue, 26 Sep 2023 15:01:03 +0100 Subject: [PATCH] FLUID: adds greatly enhanced Shell Commands (#774) The user can add an arbitrary number of highly configurable shell commands through the setting panel. The commands can be saved as user preferences, inside the .fl file, or exported to an external file. Shell scripts can be limited to individual platforms, can have shortcut keys, etc. . * documentation will follow * support to call `fltk-config` will follow --- FL/Fl_Preferences.H | 9 +- fluid/Fd_Snap_Action.cxx | 14 +- fluid/Fd_Snap_Action.h | 21 +- fluid/Fl_Type.cxx | 9 +- fluid/README_fl.txt | 4 + fluid/alignment_panel.cxx | 1341 ++++++++++++++++++++++++++++++++-- fluid/alignment_panel.fl | 623 ++++++++++++++-- fluid/alignment_panel.h | 33 +- fluid/file.cxx | 55 +- fluid/fluid.cxx | 140 +++- fluid/fluid.h | 33 +- fluid/pixmaps/fd_project.png | Bin 0 -> 6950 bytes fluid/pixmaps/fd_user.png | Bin 0 -> 8612 bytes fluid/shell_command.cxx | 848 +++++++++++++++++---- fluid/shell_command.h | 100 ++- fluid/sourceview_panel.cxx | 11 +- fluid/sourceview_panel.fl | 11 +- src/Fl_Preferences.cxx | 54 +- src/filename_absolute.cxx | 1 + test/tree.fl | 6 +- test/unittest_core.cxx | 3 +- 21 files changed, 2891 insertions(+), 425 deletions(-) create mode 100644 fluid/pixmaps/fd_project.png create mode 100644 fluid/pixmaps/fd_user.png diff --git a/FL/Fl_Preferences.H b/FL/Fl_Preferences.H index 5f988a344..6aee47878 100644 --- a/FL/Fl_Preferences.H +++ b/FL/Fl_Preferences.H @@ -22,6 +22,7 @@ # include # include "Fl_Export.H" +# include "fl_attr.h" class Fl_String; @@ -131,6 +132,7 @@ public: ROOT_MASK = 0x00FF, ///< Mask for the values above CORE = 0x0100, ///< OR'd by FLTK to read and write core library preferences and options C_LOCALE = 0x1000, ///< This flag should always be set, it makes sure that floating point + CLEAR = 0x2000, ///< Don't read a possibly existing database. Instead, start with an empty set of preferences. ///< values are written correctly independently of the current locale SYSTEM_L = SYSTEM | C_LOCALE, ///< Preferences are used system-wide, locale independent USER_L = USER | C_LOCALE, ///< Preferences apply only to the current user, locale independent @@ -188,7 +190,7 @@ public: static Root filename( char *buffer, size_t buffer_size, Root root, const char *vendor, const char *application ); Fl_Preferences( Root root, const char *vendor, const char *application ); - Fl_Preferences( const char *path, const char *vendor, const char *application ); + Fl_Preferences( const char *path, const char *vendor, const char *application, Root flags ); Fl_Preferences( Fl_Preferences &parent, const char *group ); Fl_Preferences( Fl_Preferences *parent, const char *group ); Fl_Preferences( Fl_Preferences &parent, int groupIndex ); @@ -197,6 +199,9 @@ public: Fl_Preferences( ID id ); virtual ~Fl_Preferences(); + FL_DEPRECATED("in 1.4.0 - use Fl_Preferences(path, vendor, application, flags) instead", + Fl_Preferences( const char *path, const char *vendor, const char *application ) ); + Root filename( char *buffer, size_t buffer_size); /** Return an ID that can later be reused to open more references to this dataset. @@ -374,7 +379,7 @@ public: // older Sun compilers need this (public definition of the following cl Root root_type_; public: RootNode( Fl_Preferences *, Root root, const char *vendor, const char *application ); - RootNode( Fl_Preferences *, const char *path, const char *vendor, const char *application ); + RootNode( Fl_Preferences *, const char *path, const char *vendor, const char *application, Root flags ); RootNode( Fl_Preferences * ); ~RootNode(); int read(); diff --git a/fluid/Fd_Snap_Action.cxx b/fluid/Fd_Snap_Action.cxx index 3f52907ad..3602256f8 100644 --- a/fluid/Fd_Snap_Action.cxx +++ b/fluid/Fd_Snap_Action.cxx @@ -422,7 +422,7 @@ void Fd_Layout_Suite::init() { name_ = NULL; menu_label = NULL; layout[0] = layout[1] = layout[2] = NULL; - storage_ = 0; + storage_ = FD_STORE_INTERNAL; } /** @@ -651,7 +651,7 @@ void Fd_Layout_List::update_menu_labels() { */ int Fd_Layout_List::load(const Fl_String &filename) { remove_all(FD_STORE_FILE); - Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", NULL); + Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", NULL, Fl_Preferences::C_LOCALE); read(prefs, FD_STORE_FILE); return 0; } @@ -661,7 +661,7 @@ int Fd_Layout_List::load(const Fl_String &filename) { */ int Fd_Layout_List::save(const Fl_String &filename) { assert(this); - Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", NULL); + Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", NULL, (Fl_Preferences::Root)(Fl_Preferences::C_LOCALE|Fl_Preferences::CLEAR)); prefs.clear(); write(prefs, FD_STORE_FILE); return 0; @@ -670,7 +670,7 @@ int Fd_Layout_List::save(const Fl_String &filename) { /** Write Suite and Layout selection and selected layout data to Preferences database. */ -void Fd_Layout_List::write(Fl_Preferences &prefs, int storage) { +void Fd_Layout_List::write(Fl_Preferences &prefs, Fd_Tool_Store storage) { Fl_Preferences prefs_list(prefs, "Layouts"); prefs_list.clear(); prefs_list.set("current_suite", list_[current_suite()].name_); @@ -688,7 +688,7 @@ void Fd_Layout_List::write(Fl_Preferences &prefs, int storage) { /** Read Suite and Layout selection and selected layout data to Preferences database. */ -void Fd_Layout_List::read(Fl_Preferences &prefs, int storage) { +void Fd_Layout_List::read(Fl_Preferences &prefs, Fd_Tool_Store storage) { Fl_Preferences prefs_list(prefs, "Layouts"); Fl_String cs; int cp = 0; @@ -859,7 +859,7 @@ int Fd_Layout_List::add(const char *name) { new_suite.layout[i] = new Fd_Layout_Preset; ::memcpy(new_suite.layout[i], old_suite.layout[i], sizeof(Fd_Layout_Preset)); } - int new_storage = old_suite.storage_; + Fd_Tool_Store new_storage = old_suite.storage_; if (new_storage == FD_STORE_INTERNAL) new_storage = FD_STORE_USER; new_suite.storage(new_storage); @@ -904,7 +904,7 @@ void Fd_Layout_List::remove(int ix) { Remove all Suites that use the given storage attribute. \param[in] storage storage attribute, see FD_STORE_INTERNAL, etc. */ -void Fd_Layout_List::remove_all(int storage) { +void Fd_Layout_List::remove_all(Fd_Tool_Store storage) { for (int i=list_size_-1; i>=0; --i) { if (list_[i].storage_ == storage) remove(i); diff --git a/fluid/Fd_Snap_Action.h b/fluid/Fd_Snap_Action.h index 1355332a9..fefb4618f 100644 --- a/fluid/Fd_Snap_Action.h +++ b/fluid/Fd_Snap_Action.h @@ -17,6 +17,7 @@ #ifndef _FLUID_FD_SNAP_ACTION_H #define _FLUID_FD_SNAP_ACTION_H +#include "fluid.h" #include "Fl_Window_Type.h" #include @@ -25,16 +26,6 @@ struct Fl_Menu_Item; extern Fl_Menu_Item main_layout_submenu_[]; -/** - Indicate the storage location for a layout suite. - */ -enum { - FD_STORE_INTERNAL, ///< stored inside FLUID app - FD_STORE_USER, ///< suite is stored in the user wide FLUID settings - FD_STORE_PROJECT, ///< suite is stored within the current .fl project file - FD_STORE_FILE ///< store suite in external file -}; - /** \brief Collection of layout settings. @@ -97,13 +88,13 @@ public: char *name_; ///< name of the suite char *menu_label; ///< label text used in pulldown menu Fd_Layout_Preset *layout[3]; ///< presets for application, dialog, and toolbox windows - int storage_; ///< storage location (see FD_STORE_INTERNAL, etc.) + Fd_Tool_Store storage_; ///< storage location (see FD_STORE_INTERNAL, etc.) void write(Fl_Preferences &prefs); void read(Fl_Preferences &prefs); void write(Fd_Project_Writer*); void read(Fd_Project_Reader*); void update_label(); - void storage(int s) { storage_ = s; update_label(); } + void storage(Fd_Tool_Store s) { storage_ = s; update_label(); } void name(const char *n); void init(); ~Fd_Layout_Suite(); @@ -146,13 +137,13 @@ public: int load(const Fl_String &filename); int save(const Fl_String &filename); - void write(Fl_Preferences &prefs, int storage); - void read(Fl_Preferences &prefs, int storage); + void write(Fl_Preferences &prefs, Fd_Tool_Store storage); + void read(Fl_Preferences &prefs, Fd_Tool_Store storage); void write(Fd_Project_Writer*); void read(Fd_Project_Reader*); int add(Fd_Layout_Suite*); void remove(int index); - void remove_all(int storage); + void remove_all(Fd_Tool_Store storage); Fd_Layout_Preset *at(int); int size(); }; diff --git a/fluid/Fl_Type.cxx b/fluid/Fl_Type.cxx index d98db5883..379c4cb90 100644 --- a/fluid/Fl_Type.cxx +++ b/fluid/Fl_Type.cxx @@ -252,11 +252,16 @@ void delete_all(int selected_only) { } if(!selected_only) { // reset the setting for the external shell command - shell_prefs_get(); - shell_settings_write(); + if (g_shell_config) { + g_shell_config->clear(FD_STORE_PROJECT); + g_shell_config->rebuild_shell_menu(); + g_shell_config->update_settings_dialog(); + } widget_browser->hposition(0); widget_browser->vposition(0); g_layout_list.remove_all(FD_STORE_PROJECT); + g_layout_list.current_suite(0); + g_layout_list.current_preset(0); g_layout_list.update_dialogs(); } selection_changed(0); diff --git a/fluid/README_fl.txt b/fluid/README_fl.txt index 6cd14fe08..1845a1f12 100644 --- a/fluid/README_fl.txt +++ b/fluid/README_fl.txt @@ -444,6 +444,10 @@ Type "Fl_Widget" : C++ variable name "extra_code" : C++ extra code lines ... : inherits more from Fl_Type +Type "Fl_Button" : C++ variable name + + "compact" : integer, set the flag for compact buttons, defaults to 0 + Type "Fl_Flex" : C++ variable name "margins" : this Word is written with printf as "{%d %d %d %d}", diff --git a/fluid/alignment_panel.cxx b/fluid/alignment_panel.cxx index 29f21fd4c..49348eb24 100644 --- a/fluid/alignment_panel.cxx +++ b/fluid/alignment_panel.cxx @@ -22,7 +22,61 @@ #include #include #include +#include "../src/flstring.h" void scheme_cb(Fl_Scheme_Choice *, void *); +int w_settings_shell_list_selected; + +Fl_Double_Window *script_panel=(Fl_Double_Window *)0; + +static void cb_script_panel(Fl_Double_Window*, void*) { + if (Fl::event()==FL_SHORTCUT && Fl::event_key()==FL_Escape) + return; // ignore Escape + script_panel->hide(); // otherwise hide..; +} + +Fl_Text_Editor *script_input=(Fl_Text_Editor *)0; + +Fl_Return_Button *script_panel_ok=(Fl_Return_Button *)0; + +Fl_Button *script_panel_cancel=(Fl_Button *)0; + +Fl_Double_Window* make_script_panel() { + { Fl_Double_Window* o = script_panel = new Fl_Double_Window(540, 180, "Shell Script Editor"); + script_panel->labelsize(11); + script_panel->callback((Fl_Callback*)cb_script_panel); + { script_input = new Fl_Text_Editor(10, 10, 520, 130); + script_input->box(FL_DOWN_BOX); + script_input->labelsize(11); + script_input->textfont(4); + script_input->textsize(11); + script_input->when(FL_WHEN_RELEASE | FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY); + Fl_Group::current()->resizable(script_input); + script_input->buffer(new Fl_Text_Buffer); + } // Fl_Text_Editor* script_input + { Fl_Group* o = new Fl_Group(10, 150, 520, 20); + o->labelsize(11); + { script_panel_ok = new Fl_Return_Button(400, 150, 60, 20, "OK"); + script_panel_ok->labelsize(11); + script_panel_ok->window()->hotspot(script_panel_ok); + } // Fl_Return_Button* script_panel_ok + { script_panel_cancel = new Fl_Button(470, 150, 60, 20, "Cancel"); + script_panel_cancel->labelsize(11); + } // Fl_Button* script_panel_cancel + { Fl_Box* o = new Fl_Box(10, 150, 380, 20); + o->labelsize(11); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + o->end(); + } // Fl_Group* o + script_panel->set_modal(); + o->size_range(200, 150); + script_panel->end(); + } // Fl_Double_Window* script_panel + // Enable line numbers + script_input->linenumber_width(60); + script_input->linenumber_size(script_input->Fl_Text_Display::textsize()); + return script_panel; +} Fl_Double_Window *settings_window=(Fl_Double_Window *)0; @@ -755,63 +809,1089 @@ static Fl_Image *image_shell_64() { return image; } -static void cb_Command(Fl_Input* o, void* v) { +Fl_Browser *w_settings_shell_list=(Fl_Browser *)0; + +static void cb_w_settings_shell_list(Fl_Browser* o, void* v) { if (v == LOAD) { - o->value(g_shell_command.c_str()); + // load from g_shell_config + if (g_shell_config) { + o->clear(); + w_settings_shell_list_selected = 0; + for (int i=0; ilist_size; i++) { + Fd_Shell_Command *cmd = g_shell_config->list[i]; + o->add(cmd->name.c_str()); + if (cmd->storage == FD_STORE_USER) + o->icon(i+1, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + o->icon(i+1, w_settings_shell_fd_project->image()); + } + } } else { - g_shell_command = o->value(); + // int prev_selected = w_settings_shell_list_selected; + w_settings_shell_list_selected = 0; + int selected = w_settings_shell_list->value(); + if (selected) { + if (w_settings_shell_list->selected(selected)) + w_settings_shell_list_selected = selected; + } + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); } } -static void cb_save(Fl_Check_Button* o, void* v) { - if (v == LOAD) { - o->value(g_shell_save_fl); +Fl_Group *w_settings_shell_toolbox=(Fl_Group *)0; + +static void cb_w_settings_shell_toolbox(Fl_Group* o, void* v) { + if (v==LOAD) { + propagate_load(o, v); + } +} + +static void cb_8(Fl_Button*, void* v) { + if (v != LOAD) { + int selected = w_settings_shell_list_selected; + Fd_Shell_Command *cmd = new Fd_Shell_Command("new shell command"); + g_shell_config->insert(selected, cmd); + w_settings_shell_list->insert(selected+1, cmd->name.c_str()); + w_settings_shell_list->deselect(); + w_settings_shell_list->value(selected+1); + if (cmd->storage == FD_STORE_USER) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_project->image()); + w_settings_shell_list->do_callback(); + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); + g_shell_config->rebuild_shell_menu(); + } +} + +Fl_Button *w_settings_shell_dup=(Fl_Button *)0; + +static void cb_w_settings_shell_dup(Fl_Button* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v==LOAD) { + if (selected) { + o->activate(); + } else { + o->deactivate(); + } } else { - g_shell_save_fl = o->value(); + if (!selected) return; + Fd_Shell_Command *cmd = new Fd_Shell_Command(g_shell_config->list[selected-1]); + g_shell_config->insert(selected, cmd); + w_settings_shell_list->insert(selected+1, cmd->name.c_str()); + w_settings_shell_list->deselect(); + w_settings_shell_list->deselect(); + w_settings_shell_list->value(selected+1); + if (cmd->storage == FD_STORE_USER) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_project->image()); + w_settings_shell_list->do_callback(); + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); + g_shell_config->rebuild_shell_menu(); + } +} + +Fl_Button *w_settings_shell_remove=(Fl_Button *)0; + +static void cb_w_settings_shell_remove(Fl_Button* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v==LOAD) { + if (selected) { + o->activate(); + } else { + o->deactivate(); + } + } else { + if (!selected) return; + g_shell_config->remove(selected-1); + w_settings_shell_list->remove(selected); + if (selected <= w_settings_shell_list->size()) + w_settings_shell_list->value(selected); + else + w_settings_shell_list->value(0); + w_settings_shell_list->do_callback(); + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); + g_shell_config->rebuild_shell_menu(); + } +} + +Fl_Menu_Button *w_settings_shell_menu=(Fl_Menu_Button *)0; + +static void cb_Import(Fl_Menu_*, void* v) { + if (v != LOAD) + Fd_Shell_Command_List::import_from_file(); +} + +static void cb_Export(Fl_Menu_*, void* v) { + if (v != LOAD) + Fd_Shell_Command_List::export_selected(); +} + +Fl_Menu_Item menu_w_settings_shell_menu[] = { + {"Import...", 0, (Fl_Callback*)cb_Import, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"Export selected...", 0, (Fl_Callback*)cb_Export, 0, 128, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"Import Example Scripts:", 0, 0, 0, 1, (uchar)FL_NORMAL_LABEL, 1, 10, 0}, + {"Compile with fltk-config", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"Build and run", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"Build with Xcode on macOS", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"Build with CMake", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {0,0,0,0,0,0,0,0,0} +}; + +Fl_Button *w_settings_shell_play=(Fl_Button *)0; + +static void cb_w_settings_shell_play(Fl_Button* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v==LOAD) { + if (selected) { + o->activate(); + } else { + o->deactivate(); + } + } else { + if (!selected) return; + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->run(); + } +} + +Fl_Group *w_settings_shell_cmd=(Fl_Group *)0; + +static void cb_w_settings_shell_cmd(Fl_Group* o, void* v) { + if (v==LOAD) { + int selected = w_settings_shell_list_selected; + if (selected) { + o->activate(); + } else { + o->deactivate(); + } + propagate_load(o, v); + } +} + +static void cb_Name(Fl_Input* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->name.c_str()); + } else { + o->value(""); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->name = o->value(); + w_settings_shell_list->text(selected, o->value()); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } + } +} + +static void cb_Label(Fl_Input* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->label.c_str()); + } else { + o->value(""); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->label = o->value(); + cmd->update_shell_menu(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } + } +} + +static void cb_Shortcut(Fl_Shortcut_Button* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->shortcut); + o->default_value(o->value()); + } else { + o->value(0); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->shortcut = o->value(); + cmd->update_shell_menu(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } + } +} + +static void cb_Store(Fl_Choice* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v == LOAD) { + if (selected) { + Fd_Tool_Store ts = g_shell_config->list[selected-1]->storage; + o->value(o->find_item_with_argument((long)ts)); + } else { + o->value(o->find_item_with_argument((long)FD_STORE_USER)); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + Fd_Tool_Store ts = (Fd_Tool_Store)(o->mvalue()->argument()); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + cmd->storage = ts; + //w_settings_shell_list->text(selected, cmd->name.c_str()); + if (cmd->storage == FD_STORE_USER) + w_settings_shell_list->icon(selected, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + w_settings_shell_list->icon(selected, w_settings_shell_fd_project->image()); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } + } +} + +Fl_Menu_Item menu_Store[] = { + {"@fd_user User Setting", 0, 0, (void*)(FD_STORE_USER), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"@fd_project Project File", 0, 0, (void*)(FD_STORE_PROJECT), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {0,0,0,0,0,0,0,0,0} +}; + +static void cb_Condition(Fl_Choice* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v == LOAD) { + if (selected) { + int cond = g_shell_config->list[selected-1]->condition; + o->value(o->find_item_with_argument(cond)); + } else { + o->value(o->find_item_with_argument(0)); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int cond = (int)(o->mvalue()->argument()); + cmd->condition = cond; + g_shell_config->rebuild_shell_menu(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } + } +} + +Fl_Menu_Item menu_Condition[] = { + {"all platforms", 0, 0, (void*)(Fd_Shell_Command::ALWAYS), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"MS Windows only", 0, 0, (void*)(Fd_Shell_Command::WIN_ONLY), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"Linux only", 0, 0, (void*)(Fd_Shell_Command::UX_ONLY), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"macOS only", 0, 0, (void*)(Fd_Shell_Command::MAC_ONLY), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"Linux and macOS", 0, 0, (void*)(Fd_Shell_Command::MAC_AND_UX_ONLY), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"don\'t use", 0, 0, (void*)(Fd_Shell_Command::NEVER), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {0,0,0,0,0,0,0,0,0} +}; + +static void cb_Label1(Fl_Input* o, void* v) { + if (v == LOAD) { + // o->value(g_shell_command.c_str()); + } else { + // g_shell_command = o->value(); + } +} + +Fl_Text_Editor *w_settings_shell_command=(Fl_Text_Editor *)0; + +static void cb_w_settings_shell_command(Fl_Text_Editor* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v == LOAD) { + if (selected) { + o->buffer()->text(g_shell_config->list[selected-1]->command.c_str()); + } else { + o->buffer()->text(""); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->command = o->buffer()->text(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } + } +} + +Fl_Menu_Button *w_settings_shell_text_macros=(Fl_Menu_Button *)0; + +static void cb_w_settings_shell_text_macros(Fl_Menu_Button* o, void*) { + const Fl_Menu_Item *mi = o->mvalue(); + if (mi) { + char buffer[256]; + fl_strlcpy(buffer, mi->label(), 255); + int n = (int)strlen(buffer)-1; + if (buffer[n]=='@') buffer[n] = 0; + char *word = buffer; + if (word[0]=='@') word++; + if (w_settings_shell_command->buffer()->selected()) { + int start = 0, end = 0; + w_settings_shell_command->buffer()->selection_position(&start, &end); + w_settings_shell_command->buffer()->replace(start, end, word); + } else { + int pos = w_settings_shell_command->insert_position(); + w_settings_shell_command->buffer()->insert(pos, word); + } + w_settings_shell_command->do_callback(w_settings_shell_command, (void*)NULL); + } +} + +Fl_Menu_Item menu_w_settings_shell_text_macros[] = { + {"@@BASENAME@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@PROJECTFILE_PATH@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@PROJECTFILE_NAME@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@CODEFILE_PATH@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@CODEFILE_NAME@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@HEADERFILE_PATH@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@HEADERFILE_NAME@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@TEXTFILE_PATH@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@TEXTFILE_NAME@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + // Not yet implemented + {"@@FLTK_CONFIG@@", 0, 0, 0, 16, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {"@@TMPDIR@@", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 4, 11, 0}, + {0,0,0,0,0,0,0,0,0} +}; + +static void cb_square(Fl_Button*, void*) { + if (!script_panel) make_script_panel(); + script_input->buffer()->text(w_settings_shell_command->buffer()->text()); + script_panel->show(); + + for (;;) { + Fl_Widget* w = Fl::readqueue(); + if (w == script_panel_cancel) goto BREAK2; + else if (w == script_panel_ok) break; + else if (!w) Fl::wait(); + } + + w_settings_shell_command->buffer()->text(script_input->buffer()->text()); + w_settings_shell_command->do_callback(); + BREAK2: + script_panel->hide(); +} + +static void cb_save(Fl_Check_Button* o, void* v) { + int selected = w_settings_shell_list_selected; + if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->flags & Fd_Shell_Command::SAVE_PROJECT); + } else { + o->value(0); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int v = o->value(); + if (v) { + cmd->flags |= Fd_Shell_Command::SAVE_PROJECT; + } else { + cmd->flags &= ~Fd_Shell_Command::SAVE_PROJECT; + } + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } } } static void cb_save1(Fl_Check_Button* o, void* v) { + int selected = w_settings_shell_list_selected; if (v == LOAD) { - o->value(g_shell_save_code); + if (selected) { + o->value(g_shell_config->list[selected-1]->flags & Fd_Shell_Command::SAVE_SOURCECODE); + } else { + o->value(0); + } } else { - g_shell_save_code = o->value(); + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int v = o->value(); + if (v) { + cmd->flags |= Fd_Shell_Command::SAVE_SOURCECODE; + } else { + cmd->flags &= ~Fd_Shell_Command::SAVE_SOURCECODE; + } + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } } } static void cb_save2(Fl_Check_Button* o, void* v) { + int selected = w_settings_shell_list_selected; if (v == LOAD) { - o->value(g_shell_save_strings); - } else { - g_shell_save_strings = o->value(); - } -} - -Fl_Check_Button *shell_use_fl_button=(Fl_Check_Button *)0; - -static void cb_shell_use_fl_button(Fl_Check_Button* o, void* v) { - if (v == LOAD) { - o->value(g_shell_use_fl_settings); - } else { - g_shell_use_fl_settings = o->value(); - fluid_prefs.set("shell_use_fl", g_shell_use_fl_settings); - if (g_shell_use_fl_settings) { - shell_settings_read(); + if (selected) { + o->value(g_shell_config->list[selected-1]->flags & Fd_Shell_Command::SAVE_STRINGS); } else { - shell_prefs_get(); + o->value(0); + } + } else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int v = o->value(); + if (v) { + cmd->flags |= Fd_Shell_Command::SAVE_STRINGS; + } else { + cmd->flags &= ~Fd_Shell_Command::SAVE_STRINGS; + } + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); } - w_settings_shell_tab->do_callback(w_settings_shell_tab, LOAD); } } -static void cb_save3(Fl_Button*, void* v) { - if (v != LOAD) - shell_prefs_set(); +Fl_Box *w_settings_shell_fd_project=(Fl_Box *)0; + +static const unsigned char idata_fd_project[] = +{137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0, +115,122,122,244,0,0,1,110,105,67,67,80,105,99,99,0,0,40,145,117,145,187,75,195, +80,20,198,127,173,239,23,14,58,136,116,200,80,197,65,65,20,196,81,235,208,165, +72,169,21,172,186,180,49,109,133,164,13,73,139,136,171,224,226,80,112,16,93, +124,13,254,7,186,10,174,10,130,160,8,34,110,238,190,22,145,120,174,45,180,136, +189,225,230,252,248,238,253,14,39,95,192,31,49,117,203,109,156,2,43,87,112,98, +225,144,182,144,88,212,90,94,104,163,153,46,2,244,39,117,215,158,142,70,35,212, +93,159,119,248,84,189,29,81,189,234,223,251,119,117,172,24,174,14,190,86,225,9, +221,118,10,194,50,13,145,181,130,173,120,91,184,87,207,38,87,132,15,133,135,29, +25,80,248,74,233,169,50,63,43,206,148,249,93,177,19,143,205,128,95,245,212,50, +53,156,170,97,61,235,88,194,67,194,65,203,44,234,149,121,212,151,116,26,185, +249,57,169,253,178,3,184,196,8,19,66,35,69,145,85,76,10,140,72,205,73,102,255, +251,70,127,125,179,228,197,163,203,219,102,29,71,28,25,178,226,29,22,181,40,93, +13,169,105,209,13,121,76,214,85,238,127,243,116,211,227,99,229,238,157,33,104, +122,242,188,183,1,104,217,129,239,146,231,125,29,121,222,247,49,52,60,194,69, +174,234,207,75,78,147,31,162,151,170,90,240,0,186,55,225,236,178,170,165,118, +225,124,11,250,30,236,164,147,252,149,26,100,251,211,105,120,61,133,174,4,244, +220,64,251,82,57,171,202,57,39,247,16,223,144,95,116,13,123,251,48,40,247,187, +151,127,0,229,44,103,253,189,250,32,75,0,0,0,9,112,72,89,115,0,0,22,37,0,0,22, +37,1,73,82,36,240,0,0,1,13,116,69,88,116,82,97,119,32,112,114,111,102,105,108, +101,32,116,121,112,101,32,101,120,105,102,0,10,101,120,105,102,10,32,32,32,32, +32,49,49,52,10,52,53,55,56,54,57,54,54,48,48,48,48,52,57,52,57,50,97,48,48,48, +56,48,48,48,48,48,48,48,52,48,48,49,97,48,49,48,53,48,48,48,49,48,48,48,48,48, +48,51,101,48,48,48,48,48,48,49,98,48,49,48,53,48,48,48,49,48,48,48,48,48,48,10, +52,54,48,48,48,48,48,48,50,56,48,49,48,51,48,48,48,49,48,48,48,48,48,48,48,50, +48,48,48,48,48,48,54,57,56,55,48,52,48,48,48,49,48,48,48,48,48,48,52,101,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,57,48,48,48,48,48,48,48,10,48,49,48,48,48, +48,48,48,57,48,48,48,48,48,48,48,48,49,48,48,48,48,48,48,48,50,48,48,48,50,97, +48,48,52,48,48,48,49,48,48,48,48,48,48,53,50,48,48,48,48,48,48,48,51,97,48,48, +52,48,48,48,49,48,48,48,48,48,48,56,48,48,48,10,48,48,48,48,48,48,48,48,48,48, +48,48,10,190,225,144,105,0,0,0,90,116,69,88,116,82,97,119,32,112,114,111,102, +105,108,101,32,116,121,112,101,32,105,112,116,99,0,10,105,112,116,99,10,32,32, +32,32,32,32,50,54,10,53,48,54,56,54,102,55,52,54,102,55,51,54,56,54,102,55,48, +50,48,51,51,50,101,51,48,48,48,51,56,52,50,52,57,52,100,48,52,48,52,48,48,48, +48,48,48,48,48,48,48,48,48,10,199,209,105,220,0,0,20,96,116,69,88,116,82,97, +119,32,112,114,111,102,105,108,101,32,116,121,112,101,32,120,109,112,0,10,120, +109,112,10,32,32,32,32,50,53,53,53,10,51,99,51,102,55,56,55,48,54,49,54,51,54, +98,54,53,55,52,50,48,54,50,54,53,54,55,54,57,54,101,51,100,50,50,101,102,98,98, +98,102,50,50,50,48,54,57,54,52,51,100,50,50,53,55,51,53,52,100,51,48,52,100,55, +48,52,51,54,53,54,56,54,57,10,52,56,55,97,55,50,54,53,53,51,55,97,52,101,53,52, +54,51,55,97,54,98,54,51,51,57,54,52,50,50,51,102,51,101,48,97,51,99,55,56,51, +97,55,56,54,100,55,48,54,100,54,53,55,52,54,49,50,48,55,56,54,100,54,99,54,101, +55,51,51,97,55,56,10,51,100,50,50,54,49,54,52,54,102,54,50,54,53,51,97,54,101, +55,51,51,97,54,100,54,53,55,52,54,49,50,102,50,50,50,48,55,56,51,97,55,56,54, +100,55,48,55,52,54,98,51,100,50,50,53,56,52,100,53,48,50,48,52,51,54,102,55,50, +54,53,50,48,10,51,52,50,101,51,52,50,101,51,48,50,100,52,53,55,56,54,57,55,54, +51,50,50,50,51,101,48,97,50,48,51,99,55,50,54,52,54,54,51,97,53,50,52,52,52,54, +50,48,55,56,54,100,54,99,54,101,55,51,51,97,55,50,54,52,54,54,51,100,50,50,54, +56,10,55,52,55,52,55,48,51,97,50,102,50,102,55,55,55,55,55,55,50,101,55,55,51, +51,50,101,54,102,55,50,54,55,50,102,51,49,51,57,51,57,51,57,50,102,51,48,51,50, +50,102,51,50,51,50,50,100,55,50,54,52,54,54,50,100,55,51,55,57,54,101,55,52,10, +54,49,55,56,50,100,54,101,55,51,50,51,50,50,51,101,48,97,50,48,50,48,51,99,55, +50,54,52,54,54,51,97,52,52,54,53,55,51,54,51,55,50,54,57,55,48,55,52,54,57,54, +102,54,101,50,48,55,50,54,52,54,54,51,97,54,49,54,50,54,102,55,53,10,55,52,51, +100,50,50,50,50,48,97,50,48,50,48,50,48,50,48,55,56,54,100,54,99,54,101,55,51, +51,97,54,53,55,56,54,57,54,54,51,100,50,50,54,56,55,52,55,52,55,48,51,97,50, +102,50,102,54,101,55,51,50,101,54,49,54,52,54,102,54,50,54,53,10,50,101,54,51, +54,102,54,100,50,102,54,53,55,56,54,57,54,54,50,102,51,49,50,101,51,48,50,102, +50,50,48,97,50,48,50,48,50,48,50,48,55,56,54,100,54,99,54,101,55,51,51,97,55, +52,54,57,54,54,54,54,51,100,50,50,54,56,55,52,55,52,55,48,10,51,97,50,102,50, +102,54,101,55,51,50,101,54,49,54,52,54,102,54,50,54,53,50,101,54,51,54,102,54, +100,50,102,55,52,54,57,54,54,54,54,50,102,51,49,50,101,51,48,50,102,50,50,48,97, +50,48,50,48,50,48,54,53,55,56,54,57,54,54,51,97,53,48,10,54,57,55,56,54,53,54, +99,53,56,52,52,54,57,54,100,54,53,54,101,55,51,54,57,54,102,54,101,51,100,50, +50,51,56,51,50,50,50,48,97,50,48,50,48,50,48,54,53,55,56,54,57,54,54,51,97,53, +48,54,57,55,56,54,53,54,99,53,57,52,52,54,57,10,54,100,54,53,54,101,55,51,54, +57,54,102,54,101,51,100,50,50,51,49,51,50,51,56,50,50,48,97,50,48,50,48,50,48, +55,52,54,57,54,54,54,54,51,97,53,50,54,53,55,51,54,102,54,99,55,53,55,52,54,57, +54,102,54,101,53,53,54,101,54,57,55,52,10,51,100,50,50,51,50,50,50,48,97,50,48, +50,48,50,48,55,52,54,57,54,54,54,54,51,97,53,57,53,50,54,53,55,51,54,102,54,99, +55,53,55,52,54,57,54,102,54,101,51,100,50,50,51,49,51,52,51,52,50,48,50,102,50, +48,51,49,50,50,48,97,50,48,10,50,48,50,48,55,52,54,57,54,54,54,54,51,97,53,56, +53,50,54,53,55,51,54,102,54,99,55,53,55,52,54,57,54,102,54,101,51,100,50,50,51, +49,51,52,51,52,50,48,50,102,50,48,51,49,50,50,50,102,51,101,48,97,50,48,51,99, +50,102,55,50,54,52,10,54,54,51,97,53,50,52,52,52,54,51,101,48,97,51,99,50,102, +55,56,51,97,55,56,54,100,55,48,54,100,54,53,55,52,54,49,51,101,48,97,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,10,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,48, +97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,10,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,10,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48, +97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,48,97,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,10,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,51,99,51,102,55,56,55,48,54,49, +54,51,54,98,54,53,55,52,50,48,54,53,54,101,54,52,51,100,50,50,55,55,50,50,51, +102,51,101,10,87,123,188,247,0,0,3,115,73,68,65,84,88,71,189,151,75,75,91,65,20, +199,79,110,222,169,52,180,203,22,186,239,210,47,80,236,206,126,5,177,17,151,46, +68,23,82,220,138,90,84,116,163,184,80,81,132,98,93,234,42,203,210,79,209,149, +32,213,68,164,165,165,129,230,97,94,246,252,166,157,246,246,102,154,132,230, +226,31,134,59,247,204,153,243,158,123,207,68,206,206,206,164,86,171,73,52,26, +149,68,34,17,175,84,42,215,123,123,123,15,119,118,118,164,23,26,141,134,164,211, +105,243,28,29,29,149,229,229,229,183,177,88,236,101,171,213,106,235,83,154,205, +166,120,158,39,145,72,196,12,23,188,106,181,42,201,100,82,110,111,111,69,149,55, +246,247,247,139,187,187,187,102,209,110,252,215,200,100,50,162,202,12,111,62, +159,151,211,211,211,49,85,252,70,135,231,212,230,64,44,149,74,201,205,205,141, +196,227,113,97,174,222,84,48,102,102,102,70,230,230,230,186,110,110,183,219,178, +177,177,33,219,219,219,198,129,133,133,5,188,30,27,31,31,71,78,78,89,90,93,5,40, +60,60,32,92,8,168,215,235,120,86,96,129,148,244,138,0,70,219,208,142,140,140, +144,66,89,89,89,145,163,163,163,49,221,255,90,195,31,65,62,60,200,7,240,48,39, +53,198,0,187,96,94,126,230,43,195,28,239,122,129,189,150,111,120,120,88,22,23, +23,13,109,105,105,73,142,143,143,95,169,242,247,42,51,107,249,144,79,202,49, +136,186,1,198,0,191,17,186,88,177,194,123,1,239,134,134,134,76,228,152,79,78,78, +202,250,250,186,137,232,218,218,154,156,156,156,60,211,72,92,43,235,115,60,247, +43,166,238,128,137,67,192,136,102,183,170,245,3,30,45,92,227,25,74,121,78,76, +76,152,72,112,2,168,137,195,195,195,148,210,223,169,226,23,208,40,92,210,203, +201,3,158,205,15,33,98,232,60,101,22,188,222,133,108,235,135,90,64,40,239,200, +154,154,154,50,17,96,190,185,185,73,77,80,224,121,93,127,130,62,12,97,15,48,6, +88,101,254,72,244,19,1,194,138,48,242,74,26,108,152,145,145,203,229,76,65,226, +212,234,234,170,28,28,28,96,228,71,235,168,69,44,24,110,221,156,237,39,255,22, +40,197,155,173,173,45,115,36,153,147,22,66,205,241,198,57,140,164,54,74,165,82, +99,122,122,250,47,71,141,235,129,40,164,131,133,249,47,16,242,96,85,227,29,133, +201,187,149,107,63,116,58,10,24,131,209,22,158,221,4,51,2,117,67,201,127,110, +187,1,190,249,249,121,185,188,188,148,98,177,40,87,87,87,102,126,126,126,110, +230,133,66,65,46,46,46,100,118,118,214,242,127,192,32,127,10,92,149,246,217,65, +11,11,159,130,4,151,1,53,7,45,44,60,8,18,92,6,60,114,208,194,66,35,72,112,25, +80,113,208,194,66,50,72,112,25,240,205,65,11,11,55,65,194,93,167,160,175,8,68, +29,180,176,224,142,0,103,211,254,163,245,140,86,59,247,253,31,252,95,216,95, +243,108,144,199,21,129,14,166,16,113,63,72,112,25,80,119,208,194,194,215,32,193, +101,64,104,41,112,160,28,36,220,117,10,238,5,9,119,157,130,14,125,46,3,254,252, +43,195,71,51,72,112,25,240,197,65,11,11,29,245,229,217,179,106,155,10,237,104, +154,253,180,228,253,2,153,246,142,161,207,36,223,26,123,155,2,30,139,86,33,237, +148,246,118,41,255,197,97,16,160,148,238,135,214,140,161,198,52,81,110,47,39, +224,119,71,196,176,157,45,253,28,173,211,160,176,109,25,45,25,50,213,193,199, +190,27,152,225,137,209,159,99,17,30,151,203,101,218,236,44,52,154,76,90,234,65, +128,34,228,250,90,246,136,255,29,196,176,206,118,175,58,79,232,226,83,24,236, +213,122,16,176,223,94,207,73,175,70,249,59,81,177,117,128,158,31,49,127,246,30, +207,181,170,20,0,0,0,0,73,69,78,68,174,66,96,130}; +static Fl_Image *image_fd_project() { + static Fl_Image *image = NULL; + if (!image) + image = new Fl_PNG_Image("fd_project.png", idata_fd_project, 6950); + return image; } -static void cb_Run(Fl_Return_Button*, void* v) { - if (v != LOAD) - do_shell_command(NULL, NULL); +Fl_Box *w_settings_shell_fd_user=(Fl_Box *)0; + +static const unsigned char idata_fd_user[] = +{137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0, +115,122,122,244,0,0,1,110,105,67,67,80,105,99,99,0,0,40,145,117,145,187,75,195, +80,20,198,127,173,239,23,14,58,136,116,200,80,197,65,65,20,196,81,235,208,165, +72,169,21,172,186,180,49,109,133,164,13,73,139,136,171,224,226,80,112,16,93, +124,13,254,7,186,10,174,10,130,160,8,34,110,238,190,22,145,120,174,45,180,136, +189,225,230,252,248,238,253,14,39,95,192,31,49,117,203,109,156,2,43,87,112,98, +225,144,182,144,88,212,90,94,104,163,153,46,2,244,39,117,215,158,142,70,35,212, +93,159,119,248,84,189,29,81,189,234,223,251,119,117,172,24,174,14,190,86,225,9, +221,118,10,194,50,13,145,181,130,173,120,91,184,87,207,38,87,132,15,133,135,29, +25,80,248,74,233,169,50,63,43,206,148,249,93,177,19,143,205,128,95,245,212,50, +53,156,170,97,61,235,88,194,67,194,65,203,44,234,149,121,212,151,116,26,185, +249,57,169,253,178,3,184,196,8,19,66,35,69,145,85,76,10,140,72,205,73,102,255, +251,70,127,125,179,228,197,163,203,219,102,29,71,28,25,178,226,29,22,181,40,93, +13,169,105,209,13,121,76,214,85,238,127,243,116,211,227,99,229,238,157,33,104, +122,242,188,183,1,104,217,129,239,146,231,125,29,121,222,247,49,52,60,194,69, +174,234,207,75,78,147,31,162,151,170,90,240,0,186,55,225,236,178,170,165,118, +225,124,11,250,30,236,164,147,252,149,26,100,251,211,105,120,61,133,174,4,244, +220,64,251,82,57,171,202,57,39,247,16,223,144,95,116,13,123,251,48,40,247,187, +151,127,0,229,44,103,253,189,250,32,75,0,0,0,9,112,72,89,115,0,0,22,37,0,0,22, +37,1,73,82,36,240,0,0,1,13,116,69,88,116,82,97,119,32,112,114,111,102,105,108, +101,32,116,121,112,101,32,101,120,105,102,0,10,101,120,105,102,10,32,32,32,32, +32,49,49,52,10,52,53,55,56,54,57,54,54,48,48,48,48,52,57,52,57,50,97,48,48,48, +56,48,48,48,48,48,48,48,52,48,48,49,97,48,49,48,53,48,48,48,49,48,48,48,48,48, +48,51,101,48,48,48,48,48,48,49,98,48,49,48,53,48,48,48,49,48,48,48,48,48,48,10, +52,54,48,48,48,48,48,48,50,56,48,49,48,51,48,48,48,49,48,48,48,48,48,48,48,50, +48,48,48,48,48,48,54,57,56,55,48,52,48,48,48,49,48,48,48,48,48,48,52,101,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,57,48,48,48,48,48,48,48,10,48,49,48,48,48, +48,48,48,57,48,48,48,48,48,48,48,48,49,48,48,48,48,48,48,48,50,48,48,48,50,97, +48,48,52,48,48,48,49,48,48,48,48,48,48,53,50,48,48,48,48,48,48,48,51,97,48,48, +52,48,48,48,49,48,48,48,48,48,48,56,48,48,48,10,48,48,48,48,48,48,48,48,48,48, +48,48,10,190,225,144,105,0,0,0,90,116,69,88,116,82,97,119,32,112,114,111,102, +105,108,101,32,116,121,112,101,32,105,112,116,99,0,10,105,112,116,99,10,32,32, +32,32,32,32,50,54,10,53,48,54,56,54,102,55,52,54,102,55,51,54,56,54,102,55,48, +50,48,51,51,50,101,51,48,48,48,51,56,52,50,52,57,52,100,48,52,48,52,48,48,48, +48,48,48,48,48,48,48,48,48,10,199,209,105,220,0,0,20,96,116,69,88,116,82,97, +119,32,112,114,111,102,105,108,101,32,116,121,112,101,32,120,109,112,0,10,120, +109,112,10,32,32,32,32,50,53,53,53,10,51,99,51,102,55,56,55,48,54,49,54,51,54, +98,54,53,55,52,50,48,54,50,54,53,54,55,54,57,54,101,51,100,50,50,101,102,98,98, +98,102,50,50,50,48,54,57,54,52,51,100,50,50,53,55,51,53,52,100,51,48,52,100,55, +48,52,51,54,53,54,56,54,57,10,52,56,55,97,55,50,54,53,53,51,55,97,52,101,53,52, +54,51,55,97,54,98,54,51,51,57,54,52,50,50,51,102,51,101,48,97,51,99,55,56,51, +97,55,56,54,100,55,48,54,100,54,53,55,52,54,49,50,48,55,56,54,100,54,99,54,101, +55,51,51,97,55,56,10,51,100,50,50,54,49,54,52,54,102,54,50,54,53,51,97,54,101, +55,51,51,97,54,100,54,53,55,52,54,49,50,102,50,50,50,48,55,56,51,97,55,56,54, +100,55,48,55,52,54,98,51,100,50,50,53,56,52,100,53,48,50,48,52,51,54,102,55,50, +54,53,50,48,10,51,52,50,101,51,52,50,101,51,48,50,100,52,53,55,56,54,57,55,54, +51,50,50,50,51,101,48,97,50,48,51,99,55,50,54,52,54,54,51,97,53,50,52,52,52,54, +50,48,55,56,54,100,54,99,54,101,55,51,51,97,55,50,54,52,54,54,51,100,50,50,54, +56,10,55,52,55,52,55,48,51,97,50,102,50,102,55,55,55,55,55,55,50,101,55,55,51, +51,50,101,54,102,55,50,54,55,50,102,51,49,51,57,51,57,51,57,50,102,51,48,51,50, +50,102,51,50,51,50,50,100,55,50,54,52,54,54,50,100,55,51,55,57,54,101,55,52,10, +54,49,55,56,50,100,54,101,55,51,50,51,50,50,51,101,48,97,50,48,50,48,51,99,55, +50,54,52,54,54,51,97,52,52,54,53,55,51,54,51,55,50,54,57,55,48,55,52,54,57,54, +102,54,101,50,48,55,50,54,52,54,54,51,97,54,49,54,50,54,102,55,53,10,55,52,51, +100,50,50,50,50,48,97,50,48,50,48,50,48,50,48,55,56,54,100,54,99,54,101,55,51, +51,97,54,53,55,56,54,57,54,54,51,100,50,50,54,56,55,52,55,52,55,48,51,97,50, +102,50,102,54,101,55,51,50,101,54,49,54,52,54,102,54,50,54,53,10,50,101,54,51, +54,102,54,100,50,102,54,53,55,56,54,57,54,54,50,102,51,49,50,101,51,48,50,102, +50,50,48,97,50,48,50,48,50,48,50,48,55,56,54,100,54,99,54,101,55,51,51,97,55, +52,54,57,54,54,54,54,51,100,50,50,54,56,55,52,55,52,55,48,10,51,97,50,102,50, +102,54,101,55,51,50,101,54,49,54,52,54,102,54,50,54,53,50,101,54,51,54,102,54, +100,50,102,55,52,54,57,54,54,54,54,50,102,51,49,50,101,51,48,50,102,50,50,48,97, +50,48,50,48,50,48,54,53,55,56,54,57,54,54,51,97,53,48,10,54,57,55,56,54,53,54, +99,53,56,52,52,54,57,54,100,54,53,54,101,55,51,54,57,54,102,54,101,51,100,50, +50,51,56,51,50,50,50,48,97,50,48,50,48,50,48,54,53,55,56,54,57,54,54,51,97,53, +48,54,57,55,56,54,53,54,99,53,57,52,52,54,57,10,54,100,54,53,54,101,55,51,54, +57,54,102,54,101,51,100,50,50,51,49,51,50,51,56,50,50,48,97,50,48,50,48,50,48, +55,52,54,57,54,54,54,54,51,97,53,50,54,53,55,51,54,102,54,99,55,53,55,52,54,57, +54,102,54,101,53,53,54,101,54,57,55,52,10,51,100,50,50,51,50,50,50,48,97,50,48, +50,48,50,48,55,52,54,57,54,54,54,54,51,97,53,57,53,50,54,53,55,51,54,102,54,99, +55,53,55,52,54,57,54,102,54,101,51,100,50,50,51,49,51,52,51,52,50,48,50,102,50, +48,51,49,50,50,48,97,50,48,10,50,48,50,48,55,52,54,57,54,54,54,54,51,97,53,56, +53,50,54,53,55,51,54,102,54,99,55,53,55,52,54,57,54,102,54,101,51,100,50,50,51, +49,51,52,51,52,50,48,50,102,50,48,51,49,50,50,50,102,51,101,48,97,50,48,51,99, +50,102,55,50,54,52,10,54,54,51,97,53,50,52,52,52,54,51,101,48,97,51,99,50,102, +55,56,51,97,55,56,54,100,55,48,54,100,54,53,55,52,54,49,51,101,48,97,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,10,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,48, +97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,10,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,10,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48, +97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,48,97,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,10,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,48,97,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50, +48,50,48,50,48,50,48,50,48,10,50,48,50,48,50,48,50,48,50,48,50,48,50,48,50,48, +50,48,50,48,50,48,50,48,50,48,50,48,50,48,48,97,51,99,51,102,55,56,55,48,54,49, +54,51,54,98,54,53,55,52,50,48,54,53,54,101,54,52,51,100,50,50,55,55,50,50,51, +102,51,101,10,87,123,188,247,0,0,9,241,73,68,65,84,88,71,109,87,105,144,85,197, +21,254,186,239,242,222,155,25,102,88,12,14,46,227,16,96,12,26,80,118,103,16, +113,3,5,89,203,10,70,75,42,106,170,48,196,16,141,154,20,18,177,8,41,21,149,82, +81,244,71,48,166,42,75,37,96,22,29,5,9,155,131,37,139,16,65,113,153,25,71,8,66, +153,165,148,137,226,204,91,238,210,55,223,233,251,30,49,58,77,53,115,223,237, +190,167,207,249,206,57,223,57,173,218,59,223,128,163,92,104,147,32,138,12,84, +162,225,58,62,100,36,137,66,38,147,65,177,88,4,31,225,186,46,130,56,134,210,9, +188,140,139,158,82,30,78,198,65,20,26,238,5,60,237,91,57,242,157,231,184,8,75,1, +148,82,118,130,223,12,168,27,152,62,127,97,104,3,23,9,52,226,242,76,228,173,50, +118,81,169,4,249,124,15,5,198,86,160,85,138,135,185,78,22,189,61,37,104,30,104, +98,5,87,103,184,158,227,51,191,113,249,206,24,132,97,152,202,41,79,101,13,74, +240,229,225,26,83,131,68,203,193,49,12,2,24,45,31,184,246,35,199,113,64,120,104, +177,139,222,82,137,104,228,16,169,88,187,137,250,238,137,79,62,251,246,238,93, +187,250,83,232,137,113,227,199,71,77,77,77,71,78,22,78,222,149,209,94,41,227, +249,68,165,68,153,148,65,52,42,255,250,26,174,67,200,211,161,211,153,104,139, +136,60,151,104,133,235,106,68,38,132,118,29,132,145,25,250,139,103,158,217,186, +105,227,214,97,199,143,253,131,240,41,56,70,67,211,13,67,134,12,198,236,249,215, +220,178,112,225,245,187,170,171,252,233,132,58,53,216,162,233,244,121,184,12, +213,217,222,97,31,100,183,5,138,10,40,229,88,248,5,21,223,23,69,138,242,46,179, +252,222,159,183,183,190,176,121,104,130,44,178,153,254,152,56,102,10,98,198,196, +161,183,246,163,55,255,31,120,185,24,87,207,188,20,15,220,191,242,128,49,193, +196,40,14,98,71,149,229,81,137,218,218,218,20,213,47,12,87,39,97,89,1,5,35,112, +241,3,109,53,151,169,24,3,69,56,158,118,215,172,121,114,127,235,11,155,134,122, +110,45,150,46,125,16,45,205,151,211,184,156,85,160,95,181,135,109,59,94,194,170, +71,238,69,235,11,127,197,160,1,3,198,222,241,163,239,63,79,9,179,147,10,242, +125,123,128,56,19,70,9,26,9,52,135,24,136,66,137,138,184,196,103,122,194,247, +125,245,234,206,221,109,191,122,246,119,163,20,170,112,255,202,53,184,184,249, +106,6,99,21,181,118,224,185,89,20,243,6,151,77,189,6,203,151,61,4,159,10,62,251, +203,223,98,223,190,191,141,75,143,48,167,142,234,35,6,233,70,30,46,43,137,157, +113,249,131,116,138,117,68,166,186,189,189,115,50,19,18,115,103,45,192,248,177, +23,35,10,178,60,184,14,90,101,9,105,22,97,192,248,40,41,76,110,158,134,185,179, +175,227,59,31,7,14,188,233,126,249,176,190,178,160,18,129,68,168,156,50,246,111, +100,115,93,16,160,207,146,55,15,190,131,160,148,96,204,133,205,40,246,42,248,78, +53,24,151,20,232,160,144,15,80,83,221,143,252,193,12,9,52,206,251,198,88,196, +92,123,243,224,161,56,149,92,65,160,239,161,157,47,40,165,202,81,43,239,44,26, +212,56,8,130,248,224,129,3,240,189,44,134,15,111,66,198,175,161,229,220,39,123, +153,1,53,53,57,20,11,198,198,144,239,229,48,98,68,19,60,47,131,183,223,126,183, +88,62,162,143,99,255,55,180,48,147,107,35,228,203,27,211,223,76,195,184,177, +177,129,86,149,112,244,232,17,166,98,17,145,216,38,228,198,45,226,127,215,35, +123,122,224,90,47,142,29,63,76,18,42,161,190,190,254,36,18,221,135,220,175,156, +162,203,169,167,210,116,41,127,36,40,72,124,184,218,137,167,78,157,130,108,149, +135,182,157,91,200,7,12,80,29,17,58,11,144,245,171,226,239,48,250,156,73,219, +131,215,118,109,227,122,140,25,51,102,100,42,178,83,37,250,118,133,85,47,34,158, +9,179,65,38,148,87,230,1,199,42,101,146,200,204,152,57,237,125,147,228,177, +243,181,205,120,175,99,31,81,233,229,222,34,21,76,200,142,204,29,174,105,175, +136,119,59,247,98,123,91,171,85,104,250,244,43,125,77,6,53,166,98,28,229,39,95, +85,66,71,41,251,83,63,42,65,14,168,40,18,89,10,117,108,38,12,31,209,120,83,115, +203,120,148,130,147,184,231,222,219,177,105,243,6,120,126,36,52,129,124,177,100, +41,124,71,219,75,88,198,181,56,233,193,228,201,147,208,216,216,56,75,228,168, +50,11,138,187,84,31,222,176,172,35,100,33,22,11,92,177,74,103,197,119,36,33,81, +111,207,83,79,175,217,187,224,186,121,40,20,63,197,99,143,63,136,205,91,90,89, +17,149,240,4,182,110,219,132,135,30,89,137,124,161,27,243,230,207,196,186,103, +158,218,67,22,125,79,170,171,84,80,97,191,40,138,208,91,232,65,108,34,235,182, +34,43,101,41,40,165,65,104,161,150,169,211,103,85,174,15,162,152,148,226,32,40, +18,137,112,206,178,101,75,183,141,190,224,124,107,49,139,55,74,20,98,40,208, +247,61,6,102,128,81,163,206,199,138,21,247,173,47,20,10,45,130,105,38,227,217, +170,88,98,33,75,203,112,130,79,79,118,227,147,238,19,164,238,188,157,172,39,14, +9,141,126,42,79,139,136,69,37,101,66,177,192,243,60,233,11,62,102,74,62,76,82, +162,50,9,38,76,152,96,149,148,67,46,188,112,12,171,90,6,29,29,93,193,231,159,23, +158,20,223,107,126,28,70,37,155,214,242,189,252,22,20,4,101,73,83,249,93,118, +129,197,223,22,159,116,166,164,45,127,197,255,217,108,214,30,24,4,17,118,239, +126,61,137,194,4,35,207,29,133,65,3,79,39,180,202,90,87,83,93,135,97,67,207,101, +63,224,153,3,111,28,202,184,174,239,136,229,41,145,41,203,41,34,75,179,204,139, +65,50,108,191,192,227,221,83,197,226,212,72,35,213,214,114,250,174,187,187,155, +188,190,79,255,229,207,47,206,223,183,247,157,135,227,64,161,101,210,101,164,94, +32,173,90,160,146,53,152,48,126,10,142,28,237,204,254,224,182,59,159,187,100, +202,164,127,206,155,63,235,195,150,150,139,158,173,170,170,122,217,36,113,94,24, +95,14,15,67,246,29,236,92,114,185,156,85,66,181,119,118,88,6,252,127,69,82,37, +94,106,221,56,106,245,234,71,175,232,62,209,51,203,113,170,91,76,224,231,38,76, +184,20,75,190,119,23,206,58,123,56,203,116,10,181,75,234,62,246,81,39,158,88, +187,10,239,180,239,71,18,247,218,56,169,98,149,252,241,79,238,196,220,185,179, +47,247,60,231,21,81,34,117,133,177,127,5,25,213,222,222,14,169,136,142,231,218, +128,50,73,32,10,12,88,187,246,233,59,215,173,251,245,45,42,169,61,99,120,227,88, +76,155,190,0,83,155,175,68,255,65,131,105,56,59,7,82,95,28,146,176,24,55,137, +229,112,33,167,8,255,254,248,24,118,182,109,196,43,109,47,163,189,243,32,15,138, +177,232,214,155,112,251,29,183,77,85,137,121,53,45,72,58,45,76,68,80,189,253, +214,33,194,209,207,194,33,41,215,211,243,233,232,229,203,151,255,126,203,150,29, +231,185,172,120,75,22,255,20,211,167,221,72,70,172,163,94,14,164,159,8,36,152,0, +219,204,74,200,136,44,9,48,41,227,174,71,106,87,228,6,213,139,23,95,124,14,79, +174,125,136,27,3,92,50,181,217,172,121,124,245,24,173,205,33,203,158,182,81,165, +225,75,126,184,132,86,211,227,180,202,209,222,153,119,223,125,207,235,219,183, +239,110,168,171,61,3,43,239,123,156,254,190,10,85,85,167,161,80,136,88,130,93, +27,88,68,144,169,71,146,226,193,177,73,27,78,66,12,135,235,113,28,165,5,149, +194,217,39,226,155,163,70,99,207,174,93,248,224,112,151,58,124,164,107,241,244, +171,166,29,103,237,56,40,116,45,25,161,125,95,160,15,108,239,199,96,187,97,103, +219,158,129,190,219,31,171,87,173,195,216,11,46,99,233,29,192,146,27,157,138, +222,82,41,141,232,56,182,201,99,93,32,214,136,95,77,148,240,119,134,41,153,35, +186,213,136,131,12,198,140,190,24,143,174,94,135,154,220,215,176,99,251,107,120, +125,239,254,7,136,182,170,196,154,14,216,239,101,115,210,5,71,151,175,88,249, +179,165,33,133,44,188,97,49,154,190,62,142,66,171,73,48,20,200,86,91,14,9,73,54, +174,207,190,136,133,73,44,141,227,52,88,45,205,10,141,11,125,115,198,180,44,138, +121,71,64,127,148,242,62,70,142,156,136,57,115,174,167,66,46,86,63,242,196,32, +130,214,84,9,119,45,36,81,40,244,158,182,97,195,134,223,124,208,245,193,192,179, +207,26,134,111,93,187,144,13,8,157,29,123,105,59,109,42,221,140,177,129,26,210, +223,18,197,158,167,109,129,137,152,86,202,94,92,202,118,73,185,230,118,135,37, +211,247,170,17,20,20,22,222,120,11,59,231,6,116,117,29,118,159,127,190,117,69, +84,142,35,29,209,145,142,155,61,255,15,235,255,116,70,93,221,233,184,249,59, +139,104,5,153,138,157,175,133,88,167,80,11,2,162,172,237,106,89,5,227,40,96,239, +79,74,54,129,205,0,197,12,136,19,42,39,237,16,247,243,106,192,192,78,121,223, +146,26,207,91,116,235,98,42,31,99,195,31,215,79,114,41,75,134,155,48,178,185, +195,59,114,248,56,130,162,143,230,139,166,216,194,164,43,209,29,167,85,76,243, +191,48,76,155,28,199,241,108,76,164,205,108,74,90,70,114,154,123,36,150,4,21, +113,179,40,171,29,9,204,34,41,187,26,227,199,93,100,255,190,223,113,204,72,44, +249,76,101,22,35,15,135,187,62,26,98,34,31,67,234,207,177,27,148,244,134,210, +116,136,134,101,4,36,215,229,224,180,175,55,246,112,197,158,80,131,190,86,25,72, +95,85,25,210,97,185,90,89,235,131,82,104,175,114,48,164,97,93,139,51,235,155, +104,168,151,251,232,248,103,20,202,119,212,86,31,61,122,108,149,4,80,67,67,131, +189,136,228,195,30,114,127,129,26,74,235,205,128,67,234,83,200,83,249,222,152, +118,58,94,249,89,242,46,172,108,42,95,195,180,101,87,47,35,233,202,106,232,196, +168,98,176,15,30,124,26,254,254,161,170,233,234,234,194,208,198,122,81,52,202, +53,156,51,196,44,186,245,230,127,13,169,111,200,38,186,23,253,6,120,82,231,221, +176,196,226,159,208,145,112,107,172,97,9,97,81,9,159,217,14,33,166,242,18,73, +230,4,103,29,223,243,217,94,114,184,238,68,118,63,97,36,82,174,152,47,212,204, +238,14,243,174,189,2,19,155,135,117,203,225,246,210,218,222,241,22,3,134,23,84, +238,147,74,103,27,19,11,113,26,120,114,249,176,150,90,139,203,237,112,5,133,83, +163,124,159,80,105,166,84,154,25,123,221,51,105,57,150,247,65,216,203,236,81, +116,89,108,93,41,107,255,5,119,155,194,247,64,241,254,70,0,0,0,0,73,69,78,68, +174,66,96,130}; +static Fl_Image *image_fd_user() { + static Fl_Image *image = NULL; + if (!image) + image = new Fl_PNG_Image("fd_user.png", idata_fd_user, 8612); + return image; } Fl_Group *w_settings_i18n_tab=(Fl_Group *)0; @@ -1011,6 +2091,9 @@ static void cb_i18n_pos_set_input(Fl_Int_Input* o, void* v) { } static void cb_Close(Fl_Button*, void*) { + if (g_shell_config) + g_shell_config->write(fluid_prefs, FD_STORE_USER); + g_layout_list.write(fluid_prefs, FD_STORE_USER); settings_window->hide(); } @@ -1527,50 +2610,153 @@ ped using octal notation `\\0123`. If this option is checked, Fluid will write\ w_settings_shell_tab->labelsize(11); w_settings_shell_tab->callback((Fl_Callback*)cb_w_settings_shell_tab); w_settings_shell_tab->hide(); - { Fl_Input* o = new Fl_Input(100, 78, 220, 20, "Command:"); - o->tooltip("external shell command"); - o->labelfont(1); - o->labelsize(11); - o->textfont(4); - o->textsize(11); - o->callback((Fl_Callback*)cb_Command); - } // Fl_Input* o - { Fl_Check_Button* o = new Fl_Check_Button(100, 98, 220, 20, "save .fl project file"); - o->tooltip("save the project to the .fl file before running the command"); - o->down_box(FL_DOWN_BOX); - o->labelsize(11); - o->callback((Fl_Callback*)cb_save); - } // Fl_Check_Button* o - { Fl_Check_Button* o = new Fl_Check_Button(100, 118, 220, 19, "save source code"); - o->tooltip("generate the source code and header file before running the command"); - o->down_box(FL_DOWN_BOX); - o->labelsize(11); - o->callback((Fl_Callback*)cb_save1); - } // Fl_Check_Button* o - { Fl_Check_Button* o = new Fl_Check_Button(100, 137, 220, 20, "save i18n strings"); - o->tooltip("save the internationalisation string before running the command"); - o->down_box(FL_DOWN_BOX); - o->labelsize(11); - o->callback((Fl_Callback*)cb_save2); - } // Fl_Check_Button* o - { shell_use_fl_button = new Fl_Check_Button(100, 194, 220, 19, "save settings in .fl project files"); - shell_use_fl_button->tooltip("check to read and write shell command from and to .fl files"); - shell_use_fl_button->down_box(FL_DOWN_BOX); - shell_use_fl_button->labelsize(11); - shell_use_fl_button->callback((Fl_Callback*)cb_shell_use_fl_button); - shell_use_fl_button->deactivate(); - } // Fl_Check_Button* shell_use_fl_button - { Fl_Button* o = new Fl_Button(100, 218, 115, 20, "save as default"); - o->tooltip("update the Fluid app settings for external shell commands to the current sett\ -ings"); - o->labelsize(11); - o->callback((Fl_Callback*)cb_save3); - } // Fl_Button* o - { Fl_Return_Button* o = new Fl_Return_Button(100, 162, 100, 20, "Run"); - o->tooltip("save selected files and run the command"); - o->labelsize(11); - o->callback((Fl_Callback*)cb_Run); - } // Fl_Return_Button* o + { w_settings_shell_list = new Fl_Browser(100, 90, 220, 110, "Shell \ncommand \nlist:"); + w_settings_shell_list->type(3); + w_settings_shell_list->labelfont(1); + w_settings_shell_list->labelsize(11); + w_settings_shell_list->textsize(13); + w_settings_shell_list->callback((Fl_Callback*)cb_w_settings_shell_list); + w_settings_shell_list->align(Fl_Align(FL_ALIGN_LEFT)); + } // Fl_Browser* w_settings_shell_list + { w_settings_shell_toolbox = new Fl_Group(100, 200, 220, 22); + w_settings_shell_toolbox->callback((Fl_Callback*)cb_w_settings_shell_toolbox); + { Fl_Button* o = new Fl_Button(100, 200, 24, 22, "+"); + o->labelsize(11); + o->callback((Fl_Callback*)cb_8); + } // Fl_Button* o + { w_settings_shell_dup = new Fl_Button(124, 200, 24, 22, "++"); + w_settings_shell_dup->labelsize(11); + w_settings_shell_dup->callback((Fl_Callback*)cb_w_settings_shell_dup); + w_settings_shell_dup->deactivate(); + } // Fl_Button* w_settings_shell_dup + { w_settings_shell_remove = new Fl_Button(148, 200, 24, 22, "-"); + w_settings_shell_remove->labelsize(11); + w_settings_shell_remove->callback((Fl_Callback*)cb_w_settings_shell_remove); + w_settings_shell_remove->deactivate(); + } // Fl_Button* w_settings_shell_remove + { w_settings_shell_menu = new Fl_Menu_Button(172, 200, 24, 22); + w_settings_shell_menu->labelsize(11); + w_settings_shell_menu->textsize(11); + w_settings_shell_menu->menu(menu_w_settings_shell_menu); + } // Fl_Menu_Button* w_settings_shell_menu + { w_settings_shell_play = new Fl_Button(270, 200, 50, 22, "Run"); + w_settings_shell_play->labelsize(11); + w_settings_shell_play->callback((Fl_Callback*)cb_w_settings_shell_play); + w_settings_shell_play->deactivate(); + } // Fl_Button* w_settings_shell_play + w_settings_shell_toolbox->end(); + } // Fl_Group* w_settings_shell_toolbox + { w_settings_shell_cmd = new Fl_Group(10, 235, 320, 291); + w_settings_shell_cmd->callback((Fl_Callback*)cb_w_settings_shell_cmd); + { Fl_Input* o = new Fl_Input(100, 246, 220, 20, "Name:"); + o->labelfont(1); + o->labelsize(11); + o->textfont(4); + o->textsize(11); + o->callback((Fl_Callback*)cb_Name); + o->when(FL_WHEN_RELEASE | FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY); + } // Fl_Input* o + { Fl_Input* o = new Fl_Input(100, 272, 220, 20, "Label:"); + o->labelfont(1); + o->labelsize(11); + o->textfont(4); + o->textsize(11); + o->callback((Fl_Callback*)cb_Label); + } // Fl_Input* o + { Fl_Shortcut_Button* o = new Fl_Shortcut_Button(100, 297, 130, 20, "Shortcut"); + o->box(FL_UP_BOX); + o->color(FL_BACKGROUND_COLOR); + o->selection_color(FL_BACKGROUND_COLOR); + o->labeltype(FL_NORMAL_LABEL); + o->labelfont(0); + o->labelsize(11); + o->labelcolor(FL_FOREGROUND_COLOR); + o->callback((Fl_Callback*)cb_Shortcut); + o->align(Fl_Align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE)); + o->when(FL_WHEN_RELEASE); + } // Fl_Shortcut_Button* o + { Fl_Choice* o = new Fl_Choice(100, 322, 130, 20, "Store:"); + o->down_box(FL_BORDER_BOX); + o->labelfont(1); + o->labelsize(11); + o->textsize(11); + o->callback((Fl_Callback*)cb_Store); + o->menu(menu_Store); + } // Fl_Choice* o + { Fl_Choice* o = new Fl_Choice(100, 348, 130, 20, "Condition:"); + o->down_box(FL_BORDER_BOX); + o->labelfont(1); + o->labelsize(11); + o->textsize(11); + o->callback((Fl_Callback*)cb_Condition); + o->menu(menu_Condition); + } // Fl_Choice* o + { Fl_Input* o = new Fl_Input(230, 348, 90, 20, "Label:"); + o->labelfont(1); + o->labelsize(11); + o->textfont(4); + o->textsize(11); + o->callback((Fl_Callback*)cb_Label1); + o->hide(); + } // Fl_Input* o + { Fl_Text_Editor* o = w_settings_shell_command = new Fl_Text_Editor(100, 373, 196, 80, "Shell script:"); + w_settings_shell_command->labelfont(1); + w_settings_shell_command->labelsize(11); + w_settings_shell_command->textfont(4); + w_settings_shell_command->textsize(12); + w_settings_shell_command->callback((Fl_Callback*)cb_w_settings_shell_command); + w_settings_shell_command->align(Fl_Align(FL_ALIGN_LEFT)); + o->buffer(new Fl_Text_Buffer); + } // Fl_Text_Editor* w_settings_shell_command + { Fl_Group* o = new Fl_Group(296, 373, 24, 44); + { w_settings_shell_text_macros = new Fl_Menu_Button(296, 373, 24, 22); + w_settings_shell_text_macros->labelsize(11); + w_settings_shell_text_macros->textsize(11); + w_settings_shell_text_macros->callback((Fl_Callback*)cb_w_settings_shell_text_macros); + w_settings_shell_text_macros->menu(menu_w_settings_shell_text_macros); + } // Fl_Menu_Button* w_settings_shell_text_macros + { Fl_Button* o = new Fl_Button(296, 395, 24, 22, "@square"); + o->tooltip("open big code editor"); + o->labelsize(11); + o->labelcolor(FL_BACKGROUND_COLOR); + o->callback((Fl_Callback*)cb_square); + } // Fl_Button* o + o->end(); + } // Fl_Group* o + { Fl_Check_Button* o = new Fl_Check_Button(100, 458, 220, 20, "save .fl project file"); + o->tooltip("save the project to the .fl file before running the command"); + o->down_box(FL_DOWN_BOX); + o->labelsize(11); + o->callback((Fl_Callback*)cb_save); + } // Fl_Check_Button* o + { Fl_Check_Button* o = new Fl_Check_Button(100, 478, 220, 19, "save source code"); + o->tooltip("generate the source code and header file before running the command"); + o->down_box(FL_DOWN_BOX); + o->labelsize(11); + o->callback((Fl_Callback*)cb_save1); + } // Fl_Check_Button* o + { Fl_Check_Button* o = new Fl_Check_Button(100, 497, 220, 20, "save i18n strings"); + o->tooltip("save the internationalisation strings before running the command"); + o->down_box(FL_DOWN_BOX); + o->labelsize(11); + o->callback((Fl_Callback*)cb_save2); + } // Fl_Check_Button* o + w_settings_shell_cmd->end(); + } // Fl_Group* w_settings_shell_cmd + { Fl_Box* o = w_settings_shell_fd_project = new Fl_Box(20, 70, 16, 15); + w_settings_shell_fd_project->bind_image( image_fd_project() ); + w_settings_shell_fd_project->labelsize(11); + w_settings_shell_fd_project->hide(); + w_settings_shell_fd_project->deactivate(); + o->image()->scale(16, 16); + } // Fl_Box* w_settings_shell_fd_project + { Fl_Box* o = w_settings_shell_fd_user = new Fl_Box(20, 70, 16, 15); + w_settings_shell_fd_user->bind_image( image_fd_user() ); + w_settings_shell_fd_user->labelsize(11); + w_settings_shell_fd_user->hide(); + w_settings_shell_fd_user->deactivate(); + o->image()->scale(16, 16); + } // Fl_Box* w_settings_shell_fd_user o->image()->scale(36, 24); w_settings_shell_tab->end(); } // Fl_Group* w_settings_shell_tab @@ -1676,7 +2862,6 @@ le FLTK_GETTEXT_FOUND"); o->labelsize(11); o->callback((Fl_Callback*)cb_Close); } // Fl_Button* o - settings_window->set_non_modal(); settings_window->end(); } // Fl_Double_Window* settings_window w_settings_tabs->do_callback(w_settings_tabs, LOAD); diff --git a/fluid/alignment_panel.fl b/fluid/alignment_panel.fl index da80df3a4..ef9d48455 100644 --- a/fluid/alignment_panel.fl +++ b/fluid/alignment_panel.fl @@ -4,7 +4,7 @@ header_name {.h} code_name {.cxx} snap { ver 1 - current_suite FLTK + current_suite {FLUID (based on FLTK)} current_preset 0 suite { name {FLUID (based on FLTK)} @@ -91,6 +91,9 @@ decl {\#include } {private global decl {\#include } {private global } +decl {\#include "../src/flstring.h"} {private global +} + decl {void init_scheme(void);} { comment {// initialize the scheme from preferences} public global } @@ -104,11 +107,49 @@ decl {extern void i18n_cb(Fl_Choice *,void *);} {public local decl {void scheme_cb(Fl_Scheme_Choice *, void *);} {public local } +decl {int w_settings_shell_list_selected;} {public local +} + +Function {make_script_panel()} {open +} { + Fl_Window script_panel { + label {Shell Script Editor} + callback {if (Fl::event()==FL_SHORTCUT && Fl::event_key()==FL_Escape) + return; // ignore Escape +script_panel->hide(); // otherwise hide..} open + xywh {764 319 540 180} type Double labelsize 11 resizable + code0 {o->size_range(200, 150);} modal visible + } { + Fl_Text_Editor script_input { + xywh {10 10 520 130} box DOWN_BOX labelsize 11 when 13 textfont 4 textsize 11 resizable + code0 {script_input->buffer(new Fl_Text_Buffer);} + } + Fl_Group {} {open + xywh {10 150 520 20} labelsize 11 + } { + Fl_Return_Button script_panel_ok { + label OK + xywh {400 150 60 20} labelsize 11 hotspot + } + Fl_Button script_panel_cancel { + label Cancel + xywh {470 150 60 20} labelsize 11 + } + Fl_Box {} { + xywh {10 150 380 20} labelsize 11 resizable + } + } + } + code {// Enable line numbers +script_input->linenumber_width(60); +script_input->linenumber_size(script_input->Fl_Text_Display::textsize());} {} +} + Function {make_settings_window()} {open } { Fl_Window settings_window { label {FLUID Settings} open - xywh {423 204 340 580} type Double align 80 non_modal visible + xywh {392 362 340 580} type Double align 80 visible } { Fl_Tabs w_settings_tabs { callback {propagate_load(o, v);} open @@ -758,73 +799,528 @@ g_layout_list.update_dialogs();} } Fl_Group w_settings_shell_tab { label Shell - callback {propagate_load(o, v);} + callback {propagate_load(o, v);} open image {icons/shell_64.png} compress_image 1 xywh {10 60 320 480} labelsize 11 hide code0 {o->image()->scale(36, 24);} } { - Fl_Input {} { - label {Command:} + Fl_Browser w_settings_shell_list { + label {Shell +command +list:} callback {if (v == LOAD) { - o->value(g_shell_command.c_str()); -} else { - g_shell_command = o->value(); -}} - tooltip {external shell command} xywh {100 78 220 20} labelfont 1 labelsize 11 textfont 4 textsize 11 - } - Fl_Check_Button {} { - label {save .fl project file} - callback {if (v == LOAD) { - o->value(g_shell_save_fl); -} else { - g_shell_save_fl = o->value(); -}} - tooltip {save the project to the .fl file before running the command} xywh {100 98 220 20} down_box DOWN_BOX labelsize 11 - } - Fl_Check_Button {} { - label {save source code} - callback {if (v == LOAD) { - o->value(g_shell_save_code); -} else { - g_shell_save_code = o->value(); -}} - tooltip {generate the source code and header file before running the command} xywh {100 118 220 19} down_box DOWN_BOX labelsize 11 - } - Fl_Check_Button {} { - label {save i18n strings} - callback {if (v == LOAD) { - o->value(g_shell_save_strings); -} else { - g_shell_save_strings = o->value(); -}} - tooltip {save the internationalisation string before running the command} xywh {100 137 220 20} down_box DOWN_BOX labelsize 11 - } - Fl_Check_Button shell_use_fl_button { - label {save settings in .fl project files} - callback {if (v == LOAD) { - o->value(g_shell_use_fl_settings); -} else { - g_shell_use_fl_settings = o->value(); - fluid_prefs.set("shell_use_fl", g_shell_use_fl_settings); - if (g_shell_use_fl_settings) { - shell_settings_read(); - } else { - shell_prefs_get(); + // load from g_shell_config + if (g_shell_config) { + o->clear(); + w_settings_shell_list_selected = 0; + for (int i=0; ilist_size; i++) { + Fd_Shell_Command *cmd = g_shell_config->list[i]; + o->add(cmd->name.c_str()); + if (cmd->storage == FD_STORE_USER) + o->icon(i+1, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + o->icon(i+1, w_settings_shell_fd_project->image()); + } } - w_settings_shell_tab->do_callback(w_settings_shell_tab, LOAD); +} else { +// int prev_selected = w_settings_shell_list_selected; + w_settings_shell_list_selected = 0; + int selected = w_settings_shell_list->value(); + if (selected) { + if (w_settings_shell_list->selected(selected)) + w_settings_shell_list_selected = selected; + } + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); }} - tooltip {check to read and write shell command from and to .fl files} xywh {100 194 220 19} down_box DOWN_BOX labelsize 11 deactivate + xywh {100 90 220 110} type Multi labelfont 1 labelsize 11 align 4 textsize 13 } - Fl_Button {} { - label {save as default} - callback {if (v != LOAD) - shell_prefs_set();} - tooltip {update the Fluid app settings for external shell commands to the current settings} xywh {100 218 115 20} labelsize 11 + Fl_Group w_settings_shell_toolbox { + callback {if (v==LOAD) { + propagate_load(o, v); +}} open + xywh {100 200 220 22} + } { + Fl_Button {} { + label {+} + callback {if (v != LOAD) { + int selected = w_settings_shell_list_selected; + Fd_Shell_Command *cmd = new Fd_Shell_Command("new shell command"); + g_shell_config->insert(selected, cmd); + w_settings_shell_list->insert(selected+1, cmd->name.c_str()); + w_settings_shell_list->deselect(); + w_settings_shell_list->value(selected+1); + if (cmd->storage == FD_STORE_USER) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_project->image()); + w_settings_shell_list->do_callback(); + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); + g_shell_config->rebuild_shell_menu(); +}} + xywh {100 200 24 22} labelsize 11 + } + Fl_Button w_settings_shell_dup { + label {++} + callback {int selected = w_settings_shell_list_selected; +if (v==LOAD) { + if (selected) { + o->activate(); + } else { + o->deactivate(); + } +} else { + if (!selected) return; + Fd_Shell_Command *cmd = new Fd_Shell_Command(g_shell_config->list[selected-1]); + g_shell_config->insert(selected, cmd); + w_settings_shell_list->insert(selected+1, cmd->name.c_str()); + w_settings_shell_list->deselect(); + w_settings_shell_list->deselect(); + w_settings_shell_list->value(selected+1); + if (cmd->storage == FD_STORE_USER) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + w_settings_shell_list->icon(selected+1, w_settings_shell_fd_project->image()); + w_settings_shell_list->do_callback(); + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); + g_shell_config->rebuild_shell_menu(); +}} + xywh {124 200 24 22} labelsize 11 deactivate + } + Fl_Button w_settings_shell_remove { + label {-} + callback {int selected = w_settings_shell_list_selected; +if (v==LOAD) { + if (selected) { + o->activate(); + } else { + o->deactivate(); + } +} else { + if (!selected) return; + g_shell_config->remove(selected-1); + w_settings_shell_list->remove(selected); + if (selected <= w_settings_shell_list->size()) + w_settings_shell_list->value(selected); + else + w_settings_shell_list->value(0); + w_settings_shell_list->do_callback(); + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); + g_shell_config->rebuild_shell_menu(); +}} + xywh {148 200 24 22} labelsize 11 deactivate + } + Fl_Menu_Button w_settings_shell_menu {open + xywh {172 200 24 22} labelsize 11 textsize 11 + } { + MenuItem {} { + label {Import...} + callback {if (v != LOAD) + Fd_Shell_Command_List::import_from_file();} + xywh {90 90 100 20} labelsize 11 + } + MenuItem {} { + label {Export selected...} + callback {if (v != LOAD) + Fd_Shell_Command_List::export_selected();} + xywh {10 10 100 20} labelsize 11 divider + } + MenuItem {} { + label {Import Example Scripts:} + xywh {20 20 100 20} labelfont 1 labelsize 10 deactivate + } + MenuItem {} { + label {Compile with fltk-config} + xywh {30 30 100 20} labelsize 11 + } + MenuItem {} { + label {Build and run} + xywh {40 40 100 20} labelsize 11 + } + MenuItem {} { + label {Build with Xcode on macOS} + xywh {50 50 100 20} labelsize 11 + } + MenuItem {} { + label {Build with CMake} + xywh {60 60 100 20} labelsize 11 + } + } + Fl_Button w_settings_shell_play { + label Run + callback {int selected = w_settings_shell_list_selected; +if (v==LOAD) { + if (selected) { + o->activate(); + } else { + o->deactivate(); + } +} else { + if (!selected) return; + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->run(); +}} + xywh {270 200 50 22} labelsize 11 deactivate + } } - Fl_Return_Button {} { - label Run - callback {if (v != LOAD) - do_shell_command(NULL, NULL);} - tooltip {save selected files and run the command} xywh {100 162 100 20} labelsize 11 + Fl_Group w_settings_shell_cmd { + callback {if (v==LOAD) { + int selected = w_settings_shell_list_selected; + if (selected) { + o->activate(); + } else { + o->deactivate(); + } + propagate_load(o, v); +}} open + xywh {10 235 320 291} + } { + Fl_Input {} { + label {Name:} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->name.c_str()); + } else { + o->value(""); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->name = o->value(); + w_settings_shell_list->text(selected, o->value()); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} + xywh {100 246 220 20} labelfont 1 labelsize 11 when 13 textfont 4 textsize 11 + } + Fl_Input {} { + label {Label:} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->label.c_str()); + } else { + o->value(""); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->label = o->value(); + cmd->update_shell_menu(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} + xywh {100 272 220 20} labelfont 1 labelsize 11 textfont 4 textsize 11 + } + Fl_Button {} { + label Shortcut + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->shortcut); + o->default_value(o->value()); + } else { + o->value(0); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->shortcut = o->value(); + cmd->update_shell_menu(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} + xywh {100 297 130 20} labelsize 11 align 16 + code0 {\#include } + class Fl_Shortcut_Button + } + Fl_Choice {} { + label {Store:} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + Fd_Tool_Store ts = g_shell_config->list[selected-1]->storage; + o->value(o->find_item_with_argument((long)ts)); + } else { + o->value(o->find_item_with_argument((long)FD_STORE_USER)); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + Fd_Tool_Store ts = (Fd_Tool_Store)(o->mvalue()->argument()); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + cmd->storage = ts; + //w_settings_shell_list->text(selected, cmd->name.c_str()); + if (cmd->storage == FD_STORE_USER) + w_settings_shell_list->icon(selected, w_settings_shell_fd_user->image()); + else if (cmd->storage == FD_STORE_PROJECT) + w_settings_shell_list->icon(selected, w_settings_shell_fd_project->image()); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} open + xywh {100 322 130 20} down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 + } { + MenuItem {} { + label {@fd_user User Setting} + user_data FD_STORE_USER user_data_type long + xywh {0 0 100 20} labelsize 11 + } + MenuItem {} { + label {@fd_project Project File} + user_data FD_STORE_PROJECT user_data_type long + xywh {0 0 100 20} labelsize 11 + } + } + Fl_Choice {} { + label {Condition:} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + int cond = g_shell_config->list[selected-1]->condition; + o->value(o->find_item_with_argument(cond)); + } else { + o->value(o->find_item_with_argument(0)); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int cond = (int)(o->mvalue()->argument()); + cmd->condition = cond; + g_shell_config->rebuild_shell_menu(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} open + xywh {100 348 130 20} down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 + } { + MenuItem {} { + label {all platforms} + user_data {Fd_Shell_Command::ALWAYS} user_data_type long + xywh {0 0 100 20} labelsize 11 + } + MenuItem {} { + label {MS Windows only} + user_data {Fd_Shell_Command::WIN_ONLY} user_data_type long + xywh {0 0 100 20} labelsize 11 + } + MenuItem {} { + label {Linux only} + user_data {Fd_Shell_Command::UX_ONLY} user_data_type long + xywh {0 0 100 20} labelsize 11 + } + MenuItem {} { + label {macOS only} + user_data {Fd_Shell_Command::MAC_ONLY} user_data_type long + xywh {0 0 100 20} labelsize 11 + } + MenuItem {} { + label {Linux and macOS} + user_data {Fd_Shell_Command::MAC_AND_UX_ONLY} user_data_type long + xywh {0 0 100 20} labelsize 11 + } + MenuItem {} { + label {don't use} + user_data {Fd_Shell_Command::NEVER} user_data_type long + xywh {0 0 100 20} labelsize 11 + } + } + Fl_Input {} { + label {Label:} + callback {if (v == LOAD) { +// o->value(g_shell_command.c_str()); +} else { +// g_shell_command = o->value(); +}} + xywh {230 348 90 20} labelfont 1 labelsize 11 textfont 4 textsize 11 hide + } + Fl_Text_Editor w_settings_shell_command { + label {Shell script:} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + o->buffer()->text(g_shell_config->list[selected-1]->command.c_str()); + } else { + o->buffer()->text(""); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + cmd->command = o->buffer()->text(); + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} + xywh {100 373 196 80} labelfont 1 labelsize 11 align 4 textfont 4 textsize 12 + code0 {o->buffer(new Fl_Text_Buffer);} + } + Fl_Group {} {open + xywh {296 373 24 44} + } { + Fl_Menu_Button w_settings_shell_text_macros { + callback {const Fl_Menu_Item *mi = o->mvalue(); +if (mi) { + char buffer[256]; + fl_strlcpy(buffer, mi->label(), 255); + int n = (int)strlen(buffer)-1; + if (buffer[n]=='@') buffer[n] = 0; + char *word = buffer; + if (word[0]=='@') word++; + if (w_settings_shell_command->buffer()->selected()) { + int start = 0, end = 0; + w_settings_shell_command->buffer()->selection_position(&start, &end); + w_settings_shell_command->buffer()->replace(start, end, word); + } else { + int pos = w_settings_shell_command->insert_position(); + w_settings_shell_command->buffer()->insert(pos, word); + } + w_settings_shell_command->do_callback(w_settings_shell_command, (void*)NULL); +}} open + xywh {296 373 24 22} labelsize 11 textsize 11 + } { + MenuItem {} { + label {@@BASENAME@@} + xywh {80 80 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@PROJECTFILE_PATH@@} + xywh {0 0 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@PROJECTFILE_NAME@@} + xywh {10 10 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@CODEFILE_PATH@@} + xywh {20 20 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@CODEFILE_NAME@@} + xywh {30 30 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@HEADERFILE_PATH@@} + xywh {40 40 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@HEADERFILE_NAME@@} + xywh {50 50 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@TEXTFILE_PATH@@} + xywh {60 60 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@TEXTFILE_NAME@@} + xywh {70 70 100 20} labelfont 4 labelsize 11 + } + MenuItem {} { + label {@@FLTK_CONFIG@@} + comment {Not yet implemented} + xywh {70 70 100 20} labelfont 4 labelsize 11 hide + } + MenuItem {} { + label {@@TMPDIR@@} + xywh {70 70 100 20} labelfont 4 labelsize 11 + } + } + Fl_Button {} { + label {@square} + callback {if (!script_panel) make_script_panel(); +script_input->buffer()->text(w_settings_shell_command->buffer()->text()); +script_panel->show(); + +for (;;) { + Fl_Widget* w = Fl::readqueue(); + if (w == script_panel_cancel) goto BREAK2; + else if (w == script_panel_ok) break; + else if (!w) Fl::wait(); +} + +w_settings_shell_command->buffer()->text(script_input->buffer()->text()); +w_settings_shell_command->do_callback(); +BREAK2: +script_panel->hide();} + tooltip {open big code editor} xywh {296 395 24 22} labelsize 11 labelcolor 49 + } + } + Fl_Check_Button {} { + label {save .fl project file} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->flags & Fd_Shell_Command::SAVE_PROJECT); + } else { + o->value(0); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int v = o->value(); + if (v) { + cmd->flags |= Fd_Shell_Command::SAVE_PROJECT; + } else { + cmd->flags &= ~Fd_Shell_Command::SAVE_PROJECT; + } + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} + tooltip {save the project to the .fl file before running the command} xywh {100 458 220 20} down_box DOWN_BOX labelsize 11 + } + Fl_Check_Button {} { + label {save source code} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->flags & Fd_Shell_Command::SAVE_SOURCECODE); + } else { + o->value(0); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int v = o->value(); + if (v) { + cmd->flags |= Fd_Shell_Command::SAVE_SOURCECODE; + } else { + cmd->flags &= ~Fd_Shell_Command::SAVE_SOURCECODE; + } + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} + tooltip {generate the source code and header file before running the command} xywh {100 478 220 19} down_box DOWN_BOX labelsize 11 + } + Fl_Check_Button {} { + label {save i18n strings} + callback {int selected = w_settings_shell_list_selected; +if (v == LOAD) { + if (selected) { + o->value(g_shell_config->list[selected-1]->flags & Fd_Shell_Command::SAVE_STRINGS); + } else { + o->value(0); + } +} else { + if (selected) { + Fd_Shell_Command *cmd = g_shell_config->list[selected-1]; + int v = o->value(); + if (v) { + cmd->flags |= Fd_Shell_Command::SAVE_STRINGS; + } else { + cmd->flags &= ~Fd_Shell_Command::SAVE_STRINGS; + } + if (cmd->storage == FD_STORE_PROJECT) set_modflag(1); + } +}} + tooltip {save the internationalisation strings before running the command} xywh {100 497 220 20} down_box DOWN_BOX labelsize 11 + } + } + Fl_Box w_settings_shell_fd_project { + image {pixmaps/fd_project.png} compress_image 1 bind_image 1 bind_deimage 1 xywh {20 70 16 15} labelsize 11 hide deactivate + code0 {o->image()->scale(16, 16);} + } + Fl_Box w_settings_shell_fd_user { + image {pixmaps/fd_user.png} compress_image 1 bind_image 1 bind_deimage 1 xywh {20 70 16 15} labelsize 11 hide deactivate + code0 {o->image()->scale(16, 16);} } } Fl_Group w_settings_i18n_tab { @@ -953,7 +1449,10 @@ g_layout_list.update_dialogs();} } Fl_Button {} { label Close - callback {settings_window->hide();} + callback {if (g_shell_config) + g_shell_config->write(fluid_prefs, FD_STORE_USER); +g_layout_list.write(fluid_prefs, FD_STORE_USER); +settings_window->hide();} tooltip {Close this dialog.} xywh {230 550 100 20} labelsize 11 } } diff --git a/fluid/alignment_panel.h b/fluid/alignment_panel.h index a084917b3..932398ee5 100644 --- a/fluid/alignment_panel.h +++ b/fluid/alignment_panel.h @@ -35,14 +35,23 @@ void init_scheme(void); extern struct Fl_Menu_Item *dbmanager_item; extern void i18n_cb(Fl_Choice *,void *); extern void scheme_cb(Fl_Scheme_Choice *, void *); +extern int w_settings_shell_list_selected; #include +extern Fl_Double_Window *script_panel; +#include +extern Fl_Text_Editor *script_input; +#include +#include +extern Fl_Return_Button *script_panel_ok; +#include +extern Fl_Button *script_panel_cancel; +#include +Fl_Double_Window* make_script_panel(); extern Fl_Double_Window *settings_window; #include extern Fl_Tabs *w_settings_tabs; -#include extern void scheme_cb(Fl_Scheme_Choice*, void*); extern Fl_Scheme_Choice *scheme_choice; -#include #include extern Fl_Check_Button *tooltips_button; extern Fl_Check_Button *completion_button; @@ -68,7 +77,6 @@ extern Fl_Check_Button *avoid_early_includes_button; extern Fl_Group *w_settings_layout_tab; #include extern Fl_Choice *layout_choice; -#include #include extern Fl_Menu_Button *w_layout_menu; #include @@ -78,8 +86,19 @@ extern Fl_Button *preset_choice[3]; #include extern Fl_Menu_Item fontmenu_w_default[]; extern Fl_Group *w_settings_shell_tab; -extern Fl_Check_Button *shell_use_fl_button; -#include +#include +extern Fl_Browser *w_settings_shell_list; +extern Fl_Group *w_settings_shell_toolbox; +extern Fl_Button *w_settings_shell_dup; +extern Fl_Button *w_settings_shell_remove; +extern Fl_Menu_Button *w_settings_shell_menu; +extern Fl_Button *w_settings_shell_play; +extern Fl_Group *w_settings_shell_cmd; +#include +extern Fl_Text_Editor *w_settings_shell_command; +extern Fl_Menu_Button *w_settings_shell_text_macros; +extern Fl_Box *w_settings_shell_fd_project; +extern Fl_Box *w_settings_shell_fd_user; extern Fl_Group *w_settings_i18n_tab; extern void i18n_type_cb(Fl_Choice*, void*); extern Fl_Choice *i18n_type_chooser; @@ -102,6 +121,10 @@ extern Fl_Menu_Item *w_layout_menu_storage[4]; #define w_layout_menu_load (menu_w_layout_menu+5) #define w_layout_menu_save (menu_w_layout_menu+6) #define w_layout_menu_delete (menu_w_layout_menu+7) +extern Fl_Menu_Item menu_w_settings_shell_menu[]; +extern Fl_Menu_Item menu_Store[]; +extern Fl_Menu_Item menu_Condition[]; +extern Fl_Menu_Item menu_w_settings_shell_text_macros[]; extern Fl_Menu_Item menu_i18n_type_chooser[]; extern Fl_Double_Window *shell_run_window; #include diff --git a/fluid/file.cxx b/fluid/file.cxx index 163b41dee..d93a71a1a 100644 --- a/fluid/file.cxx +++ b/fluid/file.cxx @@ -137,7 +137,7 @@ int Fd_Project_Reader::open_read(const char *s) { fin = stdin; fname = "stdin"; } else { - FILE *f = fl_fopen(s,"r"); + FILE *f = fl_fopen(s, "r"); if (!f) return 0; fin = f; @@ -325,29 +325,12 @@ void Fd_Project_Reader::read_children(Fl_Type *p, int paste, Strategy strategy, goto CONTINUE; } - if (strcmp(c, "win_shell_cmd")==0) { - if (shell_settings_windows.command) - free((void*)shell_settings_windows.command); - shell_settings_windows.command = fl_strdup(read_word()); - goto CONTINUE; - } else if (strcmp(c, "win_shell_flags")==0) { - shell_settings_windows.flags = atoi(read_word()); - goto CONTINUE; - } else if (strcmp(c, "linux_shell_cmd")==0) { - if (shell_settings_linux.command) - free((void*)shell_settings_linux.command); - shell_settings_linux.command = fl_strdup(read_word()); - goto CONTINUE; - } else if (strcmp(c, "linux_shell_flags")==0) { - shell_settings_linux.flags = atoi(read_word()); - goto CONTINUE; - } else if (strcmp(c, "mac_shell_cmd")==0) { - if (shell_settings_macos.command) - free((void*)shell_settings_macos.command); - shell_settings_macos.command = fl_strdup(read_word()); - goto CONTINUE; - } else if (strcmp(c, "mac_shell_flags")==0) { - shell_settings_macos.flags = atoi(read_word()); + if (strcmp(c, "shell_commands")==0) { + if (g_shell_config) { + g_shell_config->read(this); + } else { + read_word(); + } goto CONTINUE; } } @@ -431,7 +414,10 @@ int Fd_Project_Reader::read_project(const char *filename, int merge, Strategy st } } selection_changed(Fl_Type::current); - shell_settings_read(); + if (g_shell_config) { + g_shell_config->rebuild_shell_menu(); + g_shell_config->update_settings_dialog(); + } int ret = close_read(); undo_resume(); return ret; @@ -816,23 +802,8 @@ int Fd_Project_Writer::write_project(const char *filename, int selected_only) { write_string("\nheader_name"); write_word(g_project.header_file_name.c_str()); write_string("\ncode_name"); write_word(g_project.code_file_name.c_str()); g_layout_list.write(this); -#if 0 - // https://github.com/fltk/fltk/issues/328 - // Project wide settings require a redesign. - shell_settings_write(); - if (shell_settings_windows.command) { - write_string("\nwin_shell_cmd"); write_word(shell_settings_windows.command); - write_string("\nwin_shell_flags"); write_string("%d", shell_settings_windows.flags); - } - if (shell_settings_linux.command) { - write_string("\nlinux_shell_cmd"); write_word(shell_settings_linux.command); - write_string("\nlinux_shell_flags"); write_string("%d", shell_settings_linux.flags); - } - if (shell_settings_macos.command) { - write_string("\nmac_shell_cmd"); write_word(shell_settings_macos.command); - write_string("\nmac_shell_flags"); write_string("%d", shell_settings_macos.flags); - } -#endif + if (g_shell_config) + g_shell_config->write(this); } for (Fl_Type *p = Fl_Type::first; p;) { diff --git a/fluid/fluid.cxx b/fluid/fluid.cxx index 9533ecc5d..545a691ec 100644 --- a/fluid/fluid.cxx +++ b/fluid/fluid.cxx @@ -172,6 +172,9 @@ Fl_String g_code_filename_arg; Fl_String g_header_filename_arg; Fl_String g_launch_path; +Fl_String tmpdir_path; +bool tmpdir_create_called = false; + /** \var int Fluid_Project::header_file_set If set, command line overrides header file name in .fl file. */ @@ -311,10 +314,6 @@ void Fluid_Project::reset() { code_file_set = 0; header_file_name = ".h"; code_file_name = ".cxx"; - - g_layout_list.remove_all(FD_STORE_PROJECT); - g_layout_list.current_suite(0); - g_layout_list.current_preset(0); } void Fluid_Project::update_settings_dialog() { @@ -324,6 +323,113 @@ void Fluid_Project::update_settings_dialog() { } } +// make sure that a path name ends with a forward slash +static Fl_String end_with_slash(const Fl_String &str) { + char last = str[str.size()-1]; + if (last !='/' && last != '\\') + return str + "/"; + else + return str; +} + +/** Generate a path to a directory for temporary data storage. + The path is stored in g_tmpdir. + */ +static void create_tmpdir() { + if (tmpdir_create_called) + return; + tmpdir_create_called = true; + + char buf[128]; +#if _WIN32 + // The usual temp file locations on Windows are + // %system%\Windows\Temp + // %userprofiles%\AppData\Local + // usually resolving into + // C:/Windows/Temp/ + // C:\Users\\AppData\Local\Temp + fl_snprintf(buf, sizeof(buf)-1, "fluid-%d/", (long)GetCurrentProcessId()); + Fl_String name = buf; + wchar_t tempdirW[FL_PATH_MAX+1]; + char tempdir[FL_PATH_MAX+1]; + unsigned len = GetTempPathW(FL_PATH_MAX, tempdirW); + if (len == 0) { + strcpy(tempdir, "c:/windows/temp/"); + } else { + unsigned wn = fl_utf8fromwc(tempdir, FL_PATH_MAX, tempdirW, len); + tempdir[wn] = 0; + } + Fl_String path = tempdir; + end_with_slash(path); + path += name; + fl_make_path(path.c_str()); + if (fl_access(path.c_str(), 6) == 0) tmpdir_path = path; +#else + fl_snprintf(buf, sizeof(buf)-1, "fluid-%d/", getpid()); + Fl_String name = buf; + Fl_String path = fl_getenv("TMPDIR"); + if (!path.empty()) { + end_with_slash(path); + path += name; + fl_make_path(path.c_str()); + if (fl_access(path.c_str(), 6) == 0) tmpdir_path = path; + } + if (tmpdir_path.empty()) { + path = Fl_String("/tmp/") + name; + fl_make_path(path.c_str()); + if (fl_access(path.c_str(), 6) == 0) tmpdir_path = path; + } +#endif + if (tmpdir_path.empty()) { + char pbuf[FL_PATH_MAX+1]; + fluid_prefs.get_userdata_path(pbuf, FL_PATH_MAX); + path = Fl_String(pbuf); + end_with_slash(path); + path += name; + fl_make_path(path.c_str()); + if (fl_access(path.c_str(), 6) == 0) tmpdir_path = path; + } + if (tmpdir_path.empty()) + fl_alert("Can't create directory for temporary data storage."); +} + +/** Delete the temporary directory that was created in set_tmpdir. */ +static void delete_tmpdir() { + // was a temporary directory created + if (!tmpdir_create_called) + return; + if (tmpdir_path.empty()) + return; + + // first delete all files that may still be left in the temp directory + struct dirent **de; + int n_de = fl_filename_list(tmpdir_path.c_str(), &de); + if (n_de >= 0) { + for (int i=0; id_name; + fl_unlink(path.c_str()); + } + fl_filename_free_list(&de, n_de); + } + + // then delete the directory itself + if (fl_rmdir(tmpdir_path.c_str()) < 0) { + fl_alert("WARNING: Can't delete tmpdir '%s': %s", tmpdir_path.c_str(), strerror(errno)); + } +} + +/** + Return the path to a temporary directory for this instance of FLUID. + Fluid will do its best to clear and delete this directory when exiting. + \return the path to the temporary directory, ending in a '/', or and empty + string is no directory could be created. + */ +const Fl_String &get_tmpdir() { + if (!tmpdir_create_called) + create_tmpdir(); + return tmpdir_path; +} + /** Give the user the opportunity to save a project before clearing it. @@ -397,7 +503,7 @@ void enter_project_dir() { // store the current working directory for later app_work_dir = fl_getcwd(); // set the current directory to the path of our .fl file - Fl_String project_path = fl_filename_path(fl_filename_absolute(Fl_String(filename))); + Fl_String project_path = fl_filename_path(fl_filename_absolute(filename)); if (fl_chdir(project_path.c_str()) == -1) { fprintf(stderr, "** Fluid internal error: enter_project_dir() can't chdir to %s: %s\n", project_path.c_str(), strerror(errno)); @@ -733,6 +839,8 @@ void exit_cb(Fl_Widget *,void *) { if (help_dialog) delete help_dialog; + if (g_shell_config) + g_shell_config->write(fluid_prefs, FD_STORE_USER); g_layout_list.write(fluid_prefs, FD_STORE_USER); undo_clear(); @@ -742,6 +850,7 @@ void exit_cb(Fl_Widget *,void *) { // and cleans up editor tmp files. Then remove fluid tmpdir /last/. g_project.reset(); ExternalCodeEditor::tmpdir_clear(); + delete_tmpdir(); exit(0); } @@ -989,15 +1098,6 @@ void apple_open_cb(const char *c) { } #endif // __APPLE__ -// make sure that a path nae ends with a forward slash -static Fl_String end_with_slash(const Fl_String &str) { - char last = str[str.size()-1]; - if (last !='/' && last != '\\') - return str + "/"; - else - return str; -} - /** Get the absolute path of the project file, for example `/Users/matt/dev/`. */ @@ -1585,10 +1685,7 @@ Fl_Menu_Item Main_Menu[] = { {"Dialog", 0, select_layout_preset_cb, (void*)1, FL_MENU_RADIO }, {"Toolbox", 0, select_layout_preset_cb, (void*)2, FL_MENU_RADIO }, {0}, -{"&Shell",0,0,0,FL_SUBMENU}, - {"Execute &Command...",FL_ALT+'x',(Fl_Callback *)show_shell_window}, - {"Execute &Again...",FL_ALT+'g',(Fl_Callback *)do_shell_command}, - {0}, +{"&Shell", 0, Fd_Shell_Command_List::menu_marker, (void*)Fd_Shell_Command_List::default_menu, FL_SUBMENU_POINTER}, {"&Help",0,0,0,FL_SUBMENU}, {"&Rapid development with FLUID...",0,help_cb}, {"&FLTK Programmers Manual...",0,manual_cb, 0, FL_MENU_DIVIDER}, @@ -1710,7 +1807,6 @@ void make_main_window() { fluid_prefs.get("show_guides", show_guides, 1); fluid_prefs.get("show_restricted", show_restricted, 1); fluid_prefs.get("show_comments", show_comments, 1); - shell_prefs_get(); make_shell_window(); } @@ -1740,6 +1836,9 @@ void make_main_window() { if (!batch_mode) { load_history(); + g_shell_config = new Fd_Shell_Command_List; + // TODO: load example commands if this is the very first time we use this +// g_shell_config->restore_defaults(); make_settings_window(); } } @@ -1851,6 +1950,7 @@ void set_filename(const char *c) { set_modflag(modflag); } + /** Set the "modified" flag and update the title of the main window. @@ -2044,6 +2144,8 @@ int main(int argc,char **argv) { main_window->show(argc,argv); toggle_widgetbin_cb(0,0); toggle_sourceview_cb(0,0); + if (g_shell_config) + g_shell_config->read(fluid_prefs, FD_STORE_USER); g_layout_list.read(fluid_prefs, FD_STORE_USER); if (!c && openlast_button->value() && absolute_history[0][0]) { // Open previous file when no file specified... diff --git a/fluid/fluid.h b/fluid/fluid.h index 024dc61ff..402194edd 100644 --- a/fluid/fluid.h +++ b/fluid/fluid.h @@ -28,6 +28,8 @@ #define MENUHEIGHT 25 #define WINHEIGHT (BROWSERHEIGHT+MENUHEIGHT) +// ---- types + class Fl_Double_Window; class Fl_Window; class Fl_Menu_Bar; @@ -36,6 +38,19 @@ class Fl_Choice; class Fl_Button; class Fl_Check_Button; +/** + Indicate the storage location for tools like layout suites and shell macros. + \see class Fd_Shell_Command, class Fd_Layout_Suite + */ +typedef enum { + FD_STORE_INTERNAL, ///< stored inside FLUID app + FD_STORE_USER, ///< suite is stored in the user wide FLUID settings + FD_STORE_PROJECT, ///< suite is stored within the current .fl project file + FD_STORE_FILE ///< store suite in external file +} Fd_Tool_Store; + +// ---- global variables + extern int force_parent; extern Fl_Preferences fluid_prefs; @@ -71,9 +86,6 @@ extern Fl_Check_Button *guides_button; extern int modflag; -extern void enter_project_dir(); -extern void leave_project_dir(); - extern int update_file; // fluid -u extern int compile_file; // fluid -c extern int compile_strings; // fluic -cs @@ -81,7 +93,11 @@ extern int batch_mode; extern int pasteoffset; -// ---- project settings +extern Fl_String g_code_filename_arg; +extern Fl_String g_header_filename_arg; +extern Fl_String g_launch_path; + +// ---- project class declaration class Fluid_Project { public: @@ -123,16 +139,15 @@ public: extern Fluid_Project g_project; -extern Fl_String g_code_filename_arg; -extern Fl_String g_header_filename_arg; -extern Fl_String g_launch_path; - - // ---- public functions +extern void enter_project_dir(); +extern void leave_project_dir(); extern void set_filename(const char *c); extern void set_modflag(int mf, int mfc=-1); +extern const Fl_String &get_tmpdir(); + // ---- public callback functions extern void save_cb(Fl_Widget *, void *v); diff --git a/fluid/pixmaps/fd_project.png b/fluid/pixmaps/fd_project.png new file mode 100644 index 0000000000000000000000000000000000000000..6288496c0601f64fbf1a0ac43b0c7382dbecf227 GIT binary patch literal 6950 zcmdT}3tUY39zW%kL*%lhwyE*Bw^k2l&U1zqlb&>w7NspU&CFS28CktsQY%8Jt8OH* zTU=#DmWy83R`TdpQn=(*)Vh^&JxVF=|C}+JQJ+=&u}kNC&N=_r@B90HzrX+KGoRBY z7iW8I*Z_tgNZZlD#uYrd%%wFH+*gN&K7}9+xoq}q7nxWLL8fs5aXE7fUB(rMA8yeb zH7(lzyvtdka9q*+#!LGh(m(kz`#5h!RGPNqmgqxwYhCB_gd_K9O_Vq1 z>&69VS{#qgtEumN-rP0H#QTgfFQ8;avZk4vpKndd_gpjI4e}mKQg7mIqgH9D`jkTU+ z8@JF2j&Ue;q+h+T3t#io{j;eh)ilT6Q2$shNB4xOmv*|WLOaCi>cZymC;pZ9#C6Sk zCM*qooO@DZ>Gg<~zx}d?6LPzahg%icW;T@1b>3n8Lt=)B#D3n7vKU^1R8v%2M!!Tcp`*{5TMOtM-WV^c=CMJ$6=g>KoFDhE0LKeoL>_w18#ZrYK+X! zUkt&_U11CtC1C;~`6Nx@;KJAz$d6&Dl#zzOYjOm z2nIJc2TBkGjEOOt0=AGm5+i*{g2GXRL`j0AKuM&S1VyE^udgqSqF`J=;>-v^VFWJ0 z5L^Q6#K2lmJ{adyA_@c&7$w4`1Wtk{0K_m5grXP?swTq36dx0TYJ)&h!XzVkD8lqf zF)5`mW)5aD05(81!vhm3Cf+P(nRLSd2w#>HAD0loAHauZXrKs;;lL{9LQsifk5MEB zbTCYSkz%k6CrM01pg4|`Z}CvfF;w_4g@Y5+7o|~}Vh>bG0k)`=%|)R!#=`{630eq9 zL1QSmOB4yf6Qh8a6b_R-ijPVdLCm~@hbj|519%IZLrDRJ0BHhXf)p@&%@o*zf|LYc z#ApU30YVg~s)+!EeW6$<`Ks*M)Y5KuVITn*MoLgx8N`TTJp)Gf4$tx;fpe@o3V2xI z&fECi@XDax;FYOCDG(Sa=YuUJCiuV&0aJDcRN(}Z5#uv8R5DWyeG@5QBH>;_dBAsm zcd(KZvjqSUV}zJuHYIC20TKg9oZXPBIaR_0y#=x?c^D4%9s;%u0{mq8!c3)9g86+7 z2A;j%vS9y#tpIoLTE$xhhI_nM%H5^hAiX_VM!ik+ckK5EQWm_g%zl4HePyCtr^2Ye zVw4byrwWkzM1Onl1&Gn|UVs?(9~!7M*zJ`j5@17 zf{}X0clFd5^-qjCv>K55RR4PK2?!CrC!i1i_Jd#YZ+=fHyd2Qd-WH?2JqDPxUl%jL zr1eM4M=$NSi~0DZscRWvuZX&xJ^z@g&JQ?g>XlKI@^*UwNb9>8b#Wi1wBIV`W0a<< z<)buP-Lzltsftlw`3`B!hq_+A3NqhA*zZmhrTCx+yM^VpLC~PpjyA#t?)G_!bLW03 z9CvP>{B}BiyhJy<XQrn0p|vc@D@+UU97-0ZQyKlPN${Pn(G4O2=k&#Oq_Ua?8r zzdxd0w4}B3z@FAtI%$1T_Nwhc3y)1aB<|y8G92eD=T>mJMA|9QdK|8JYmj-($cL(_g0BAZ!bV- znzpO2ug{jtPgWnx%9>DJU0oaz6*VN+=u=~3duQjx9$rICt*p47S_iK+1~2l7h<~~n zva7zdEhZ+`dhz1LajB`Pyj!n43XO#`tj-U6gqRS;P>#=%we@C&hAp8Hd4FFS9PF;E zr>DI_CUe}jeY$^VnzMJxn;X4$?OJ(#l(o>((ozx_c=d7k8E!c2 znb3M&IAX-!$iayk#4rnUE3H3y4z>E`Qi1g(2S0t6RiJ@_#-mcOh!Pff{bSz|EgR19 zqj$GKUsb+LeHOE5dRv!qr}uxnpDd3(_esR413If_GLb=-3JR`qf0oW#`kCK8!^t-T z;N~I2gZ4y@T4OorWv5x8J;uPE1+biFb=QAdwi|x9G^y+O{VvU2t=qmYpM1w4Y`3P- zmPHdD#dvp@ff4T66uX5b3Dn(qd~ZC;{6Vf*63H9qN8PjN2bktQ2WLBrYoU3NAD~tcRXU( hK7D>xz`7J;UU;if`H75i;2#Q*qph<|rnOJx{{c#>@wos1 literal 0 HcmV?d00001 diff --git a/fluid/pixmaps/fd_user.png b/fluid/pixmaps/fd_user.png new file mode 100644 index 0000000000000000000000000000000000000000..503cc54a2a157ad2430751b9aa00b126e25ce649 GIT binary patch literal 8612 zcmdT}2{=@38&;M$)-(wYVE=@B5zTe(w8zp5vP9h&0sK;s%5PCMG6s?Vakz z;8m1m(g?A3XdR~4MYGP$**DY>29hAw_F*$#XNBL4hT& z>M|N%kfB=Zgo?YN0@oz1xU(G}aQo^#F&zpT^=R#}?Hx+q;NUlMy=<97Tk!CiH-S*! zjtK?iwi=Csffil;7?BI{ITr7kDluJei*qh|bp>!vuYa2v^C?c)Zl=}IM=7j;W$fjS z8Dm^-15RRsk9Nw&gWG=wCOJ_RAH>uvWB<8&T2vP-0Ef#?b9W{tflc&dnYOX`d$1hb z9vXNLV}iG+i`yZxqZ3Kg!`Fo*O7d|eGXeB7AWGj96p#QCg~6h6XfzDmkT@g`P5^JP z^bxorVK4;(OaX=h?-dv`Fa&A-sz6*i4~PUo5jc3g$V#p zj2v(j3I!l+5o8Q#3t9nbs!pbk0{&`4YGF(ev|AfVt#Boh569`kE-Dp&x61b48$a59{XVQg>` z24o8-F>+zxWP}0&N8iCa7?^^LfP-hd`2^qJ!<~6}VBVcS<9~%;2>KrULTa!SFaT7J1zXA%g$3Qf z(aTN;op*ws5rL)GaDmz4&_5z^^hn@4p$eey*ssA0oaik80@01I#n79QVLJ*;3_>Cq z4Y@eyqA=X|0vRk75J<51U|`F@KtCCL0eYnt1!I3S81(E*%Yyv}wgT|AYv)EIhY}(a(xmfSA870$RH8v!lNSh_2;t z0iv`2r-8mL%s+^S&0cESe;zFs zv-HWokVgMd_nohT^zR{z?@k!Z{0BY2%>ViX`1$vPwz|r0yq2?><0;d+)w7kuBOOUX zWIPv-To2zqE@4A2dp=iYR`W(cQ&)O_4y=~%_&ErF5xdmtIAfzRE!ZV#-A(%hpsXB8 zp_`)lR9q8FUCf8H(3rn#L)U@)+=n?g>t98qh_^C-NVsv`Og(;M>6(0#E3?5 z?Y_{pRoPBFQgw5TN)et#q^nXc1RMU4!^(qkIA=Yj0EO8^rZ_3$qm&F=; zh0wSzuT4-6A~-Ow;Xrne=)KB^dl_Z3Oa<_=*6&F(jf$wy7pPX+$ZBR^p3;N3 z;W~9s@F*dnLCS!{t@FOOOV}h-z44X;*K$Ewk@9h|JFYu?9Ezelj3XUh@nz$yBBzHU z4U}ibhpeimP5L5Td+uoM+OKdO?q#7MhN>Pid=k?0G`CbMkZOdnv4@S}V6&I9L7Ksi!ZCUAjJ2<>Y?q zKe`q5>_Y#TZ#mcFwhn@bT^VZ>AlZwbWL-^LqY*VCSMsSNwXBSK#n&N3rZ{mn0ZRsm z^|k3`;~AJa5uXY{vzF@+-j_ErhBOoCv(j8)9#1G6(K zK3kAk1DoRYG|$&9Xpl20-0z_5S-C(y+2;7x^7E!?HrFDY6|HM>w1zYWIfLrbmND0N ze8?EyZop9z1B?XvAHlBD;4vd2gm3 zU%S_Tv@;zWw^t=?I6YZj@?wM0mSGv;M_Bfd$i2jzjrVi6%TLO2n zp)L{E^-9>7s%lBim~59;;khiyZw`1mZRQer;A7(6=o1?fQ~svoMUmquo6li!WN<){ zom7C<3tfEuHEjQ_SO1E+|Lhr7_tj-MXH?a0k&Y{QVs;w@IQJIm*w=ZBZ!kL4Vq#F( zR@GVQD+$?NXM1uxrP7z2SSv* zKcU1%K4O${?@rX}iF|noARFSixu-1$Pu!r}=n`UJ;MEf|v?_DxdUBow56AJt(gx8K zjZGxgqMM`J`Z<-!I?8&+7vLP5^%C~Q#j43&cj3ylV1q)fZoNrelLDa~IJ{1CQ__=> z>Q4d?7LvBfl$BR-9ZewB<5H$o+dC7P53Oq`FBqouN}ZN!l-j6U(iE)%ce-)2r`@Ek`_WFZ$4}g*3#zJ;u2T)> zdRyf0(aI*0BYJkElOB>Xtwr-K($1g~V26Pd>)tiZc9trpR@pUV2Hi{AK6v}=+31w~ zoE*P4aaU_W8y;S@ap>ERkwgl<3K+gRti?a^9Ggvy`}DzJsP<(=iTuR2H>-^{ zdWIDRu?juz=-|nwoOtv62wYnf;KEmp_bWclpZO>&ovmc+(}UMbqB5Bz6{^pvggRms zR~Xx@J99-46WQysA&Y%(c2dx*)VX$xvwTMNs3>n#QQwm!mlu7&pZ)5!2;l{JjHx+q4x&m{M)~xoOnt2)4JejHN;t5PInsn|` zWH?|_Jq23(&0euRj$UIEz++GlNLkCg7k;fR&o|(sV1Dz4#*|W{i(R^h%a879?YY|U zpd-VCoBz zT(kV!&p735`=K|_tWA#UFqS&rhb{e=t(E8#ip{Rr_uk=BiDH$HDWP2T$EboQ3#=o~ zy?lDbcIJRj;PC7UN@-5*Ii6?3B=?7`TJeSWsgjEu!ep)!6wXnVPpIZqc_KMilI+3#y0uku&;Z%IX=HUtTN)4iVYV1BC27Pe)M3T}R@8Fz=rd4}?`IKU` z18ZVba$y)g%aC*Vg}itB%~^XS_YE89po5#4>bNMYq$S?*O^oipc~jq)c1F0x(qoV) zEn<6HWv28<0%E)oRm#G|jUs9TEk$c%$HE_a zP{K(p;!k@!uNGp)UFuQ{L#ca&cG{Q%keXPllG7X z??-z?l>D6HSPa$FLaQmSZm)L>3KrHGY(AnkU~<=Fsw2T`tM!!mh+LkNw9W0SBr|!j z{)YX1wU>!kc-IFA&(5aj^bZWw+^_dDLN=hzBWh(TKfVs)&OUT^bLE=PY(B +// - options to save project, code, and strings before running +// - test-run button + +// TODO: add @APPDIR@? +// TODO: get a macro to find `fltk-config` @FLTK_CONFIG@ +// TODO: add an input field so the user can insert their preferred file and path for fltk-config (user setting) +// `fltk-config` is actually tricky to find +// for live builds, we could check the program launch directory +// if we know where build/Xcode/bin/Debug/fluid is, we +// may or may not find ./build/Xcode/fltk-config +// on macOS with homebrew, we find /opt/homebrew/bin/fltk-config but the user +// can set their own install path. +// We can query the shell path, but that requires knowing the users shell (echo $SHELL). +// We can run the shell as a login shell with `-l`, so the user $PTH is set: /bin/bash -l -c 'fltk-config' +// The shell should output the path of the fltk-config that it found and why it is using that one. +// This can also output the fltk-config version. +// TODO: add a bunch of sensible sample shell commands +// TODO: when this new feature is used for the very first time, import two or three samples as initial user setting +// TODO: make the settings dialog resizable +// TODO: make g_shell_config static, not a pointer, but don't load anything in batch mode + +// FEATURE: Fd_Tool_Store icons are currently redundant with @file and @save and could be improved +// FEATURE: hostname, username, getenv support? +// FEATURE: ad the files ./fluid.prefs and ./fluid.user.prefs as tool locations + +/* + Some ideas: + + default shell is in $SHELL on linux and macOS + + On macOS, we can write Apple Scripts: + + #!/usr/bin/env osascript + say "@BASENAME@" + + osascript < +#include #include #include #include +static Fl_String fltk_config_cmd; static Fl_Process s_proc; -/// Shell settings in the .fl file -Shell_Settings shell_settings_windows = { }; -Shell_Settings shell_settings_linux = { }; -Shell_Settings shell_settings_macos = { }; - -/// Current shell command, stored in .fl file for each platform, and in app prefs -Fl_String g_shell_command; - -/// Save .fl file before running, stored in .fl file for each platform, and in app prefs -int g_shell_save_fl = 1; - -/// Save code file before running, stored in .fl file for each platform, and in app prefs -int g_shell_save_code = 1; - -/// Save strings file before running, stored in .fl file for each platform, and in app prefs -int g_shell_save_strings = 0; - -/// Use these settings from .fl files, stored in app prefs -int g_shell_use_fl_settings = 1; - -/** - Read the default shell settings from the app preferences. - */ -void shell_prefs_get() -{ - fluid_prefs.get("shell_command", g_shell_command, "echo \"Custom Shell Command\""); - fluid_prefs.get("shell_savefl", g_shell_save_fl, 1); - fluid_prefs.get("shell_writecode", g_shell_save_code, 1); - fluid_prefs.get("shell_writemsgs", g_shell_save_strings, 0); - fluid_prefs.get("shell_use_fl", g_shell_use_fl_settings, 1); -} - -/** - Write the current shell settings to the app preferences. - */ -void shell_prefs_set() -{ - fluid_prefs.set("shell_command", g_shell_command); - fluid_prefs.set("shell_savefl", g_shell_save_fl); - fluid_prefs.set("shell_writecode", g_shell_save_code); - fluid_prefs.set("shell_writemsgs", g_shell_save_strings); - fluid_prefs.set("shell_use_fl", g_shell_use_fl_settings); -} - -/** - Copy shell settings from the .fl buffer if use_fl_settings is set. - */ -void shell_settings_read() -{ - if (g_shell_use_fl_settings==0) - return; -#if defined(_WIN32) - Shell_Settings &shell_settings = shell_settings_windows; -#elif defined(__APPLE__) - Shell_Settings &shell_settings = shell_settings_macos; -#else - Shell_Settings &shell_settings = shell_settings_linux; -#endif - g_shell_command = shell_settings.command; - g_shell_save_fl = ((shell_settings.flags&1)==1); - g_shell_save_code = ((shell_settings.flags&2)==2); - g_shell_save_strings = ((shell_settings.flags&4)==4); -} - -/** - Copy current shell settings to the .fl buffer if use_fl_settings is set. - */ -void shell_settings_write() -{ - if (g_shell_use_fl_settings==0) - return; -#if defined(_WIN32) - Shell_Settings &shell_settings = shell_settings_windows; -#elif defined(__APPLE__) - Shell_Settings &shell_settings = shell_settings_macos; -#else - Shell_Settings &shell_settings = shell_settings_linux; -#endif - if (shell_settings.command) - free((void*)shell_settings.command); - shell_settings.command = NULL; - if (!g_shell_command.empty()) - shell_settings.command = fl_strdup(g_shell_command.c_str()); - shell_settings.flags = 0; - if (g_shell_save_fl) - shell_settings.flags |= 1; - if (g_shell_save_code) - shell_settings.flags |= 2; - if (g_shell_save_strings) - shell_settings.flags |= 4; -} /** \class Fl_Process - \todo Explain. + Launch an external shell command. */ +/** + Create a process manager + */ Fl_Process::Fl_Process() { _fpt= NULL; } +/** + Destroy the project manager. + */ Fl_Process::~Fl_Process() { + // TODO: check what we need to do if a task is still running if (_fpt) close(); } -// FIXME: popen needs the UTF-8 equivalent fl_popen -// portable open process: +/** + Open a process. + + \param[in] cmd the shell command that we want to run + \param[in] mode "r" or "w" for creating a stream that can read or write + \return a stream that is redirected from the shell command stdout + */ FILE * Fl_Process::popen(const char *cmd, const char *mode) { #if defined(_WIN32) && !defined(__CYGWIN__) // PRECONDITIONS @@ -174,6 +171,9 @@ FILE * Fl_Process::popen(const char *cmd, const char *mode) { #endif } +/** + Close the current process. + */ int Fl_Process::close() { #if defined(_WIN32) && !defined(__CYGWIN__) if (_fpt) { @@ -192,11 +192,22 @@ int Fl_Process::close() { #endif } -// non-null if file is open +/** + non-null if file is open. + + \return the current file descriptor of the process' stdout + */ FILE *Fl_Process::desc() const { return _fpt; } +/** + Receive a single line from the current process. + + \param[out] line buffer to receive the line + \param[in] s size of the provided buffer + \return NULL if an error occurred, otherwise a pointer to the string + */ char *Fl_Process::get_line(char * line, size_t s) const { return _fpt ? fgets(line, (int)s, _fpt) : NULL; } @@ -237,31 +248,33 @@ void Fl_Process::clean_close(HANDLE& h) { #endif +/** + Prepare FLUID for running a shell command according to the command flags. -// Shell command support... - -static bool prepare_shell_command() { + \param[in] flags set various flags to save the project, code, and string before running the command + \return false if the previous command is still running + */ +static bool prepare_shell_command(int flags) { // settings_window->hide(); if (s_proc.desc()) { fl_alert("Previous shell command still running!"); return false; } - if (g_shell_command.empty()) { - fl_alert("No shell command entered!"); - return false; - } - if (g_shell_save_fl) { + if (flags & Fd_Shell_Command::SAVE_PROJECT) { save_cb(0, 0); } - if (g_shell_save_code) { + if (flags & Fd_Shell_Command::SAVE_SOURCECODE) { write_code_files(); } - if (g_shell_save_strings) { + if (flags & Fd_Shell_Command::SAVE_STRINGS) { write_strings_cb(0, 0); } return true; } +/** + Called by the file handler when the command is finished. + */ void shell_proc_done() { shell_run_terminal->append("... END SHELL COMMAND ...\n"); shell_run_button->activate(); @@ -293,8 +306,56 @@ void shell_pipe_cb(FL_SOCKET, void*) { } } -void do_shell_command(Fl_Return_Button*, void*) { - if (!prepare_shell_command()) return; +/** Find the script `fltk-config` that most closely relates to this version of FLUID. + This is not implemented yet. + */ +//static void find_fltk_config() { +// +//} + +static void expand_macro(Fl_String &cmd, const Fl_String ¯o, const Fl_String &content) { + for (int i=0;;) { + i = cmd.find(macro, i); + if (i==Fl_String::npos) break; + cmd.replace(i, macro.size(), content); + } +} + +static void expand_macros(Fl_String &cmd) { + expand_macro(cmd, "@BASENAME@", g_project.basename()); + expand_macro(cmd, "@PROJECTFILE_PATH@", g_project.projectfile_path()); + expand_macro(cmd, "@PROJECTFILE_NAME@", g_project.projectfile_name()); + expand_macro(cmd, "@CODEFILE_PATH@", g_project.codefile_path()); + expand_macro(cmd, "@CODEFILE_NAME@", g_project.codefile_name()); + expand_macro(cmd, "@HEADERFILE_PATH@", g_project.headerfile_path()); + expand_macro(cmd, "@HEADERFILE_NAME@", g_project.headerfile_name()); + expand_macro(cmd, "@TEXTFILE_PATH@", g_project.stringsfile_path()); + expand_macro(cmd, "@TEXTFILE_NAME@", g_project.stringsfile_name()); +// TODO: implement finding the script `fltk-config` for all platforms +// if (cmd.find("@FLTK_CONFIG@") != Fl_String::npos) { +// find_fltk_config(); +// expand_macro(cmd, "@FLTK_CONFIG@", fltk_config_cmd.c_str()); +// } + if (cmd.find("@TMPDIR@") != Fl_String::npos) + expand_macro(cmd, "@TMPDIR@", get_tmpdir()); +} + +/** + Prepare for and run a shell command. + + \param[in] cmd the command that is sent to `/bin/sh -c ...` or `cmd.exe` on Windows machines + \param[in] flags various flags in preparation of the command + */ +void run_shell_command(const Fl_String &cmd, int flags) { + if (cmd.empty()) { + fl_alert("No shell command entered!"); + return; + } + + if (!prepare_shell_command(flags)) return; + + Fl_String expanded_cmd = cmd; + expand_macros(expanded_cmd); if (!shell_run_window->visible()) { Fl_Preferences pos(fluid_prefs, "shell_run_Window_pos"); @@ -310,10 +371,10 @@ void do_shell_command(Fl_Return_Button*, void*) { } // Show the output window and clear things... - shell_run_terminal->printf("\033[0;32m%s\033[0m\n", g_shell_command.c_str()); - shell_run_window->label(g_shell_command.c_str()); + shell_run_terminal->printf("\033[0;32m%s\033[0m\n", expanded_cmd.c_str()); + shell_run_window->label(expanded_cmd.c_str()); - if (s_proc.popen((char *)g_shell_command.c_str()) == NULL) { + if (s_proc.popen((char *)expanded_cmd.c_str()) == NULL) { shell_run_terminal->printf("\033[1;31mUnable to run shell command: %s\033[0m\n", strerror(errno)); shell_run_window->label("FLUID Shell"); @@ -329,28 +390,553 @@ void do_shell_command(Fl_Return_Button*, void*) { } /** - Show a dialog box to run an external shell command. - - Copies the current settings into the dialog box. - - This dialog box offers a field for a command line and three check buttons - to generate and save various files before the command is run. - - If the fourth checkbox, "use settings in .fl design files" is checked, - all shell settings will be store in the current .fl file, and they will - be read and restored when the .fl is loaded again. - - Fluid will save different shell settings for different operating system as - it is common that a different OS requires a different shell command. - - Fluid comes with default shell settings. Pressing the "save as default" button - will store the current setting in the Fluid app settings and are used for new - designs, or if the "use settings..." box is not checked. - - Fluid app settings are saved per user and per machine. + Create an empty shell command structure. */ -void show_shell_window() { +Fd_Shell_Command::Fd_Shell_Command() +: shortcut(0), + storage(FD_STORE_USER), + condition(0), + flags(0), + shell_menu_item_(NULL) +{ +} + +/** + Copy the aspects of a shell command dataset into a new shell command. + + \param[in] rhs copy from this prototype + */ +Fd_Shell_Command::Fd_Shell_Command(const Fd_Shell_Command *rhs) +: name(rhs->name), + label(rhs->label), + shortcut(rhs->shortcut), + storage(rhs->storage), + condition(rhs->condition), + condition_data(rhs->condition_data), + command(rhs->command), + flags(rhs->flags), + shell_menu_item_(NULL) +{ +} + +/** + Create a default storage for a shell command and how it is accessible in FLUID. + + \param[in] name is used as a stand-in for the command name and label + */ +Fd_Shell_Command::Fd_Shell_Command(const Fl_String &in_name) +: name(in_name), + label(in_name), + shortcut(0), + storage(FD_STORE_USER), + condition(Fd_Shell_Command::ALWAYS), + command("echo \"Hello, FLUID!\""), + flags(Fd_Shell_Command::SAVE_PROJECT|Fd_Shell_Command::SAVE_SOURCECODE), + shell_menu_item_(NULL) +{ +} + +/** + Create a storage for a shell command and how it is accessible in FLUID. + + \param[in] in_name name of this command in the command list in the settings panel + \param[in] in_label label text in the main pulldown menu + \param[in] in_shortcut a keyboard shortcut that will also appear in the main menu + \param[in] in_storage storage location for this command + \param[in] in_condition commands can be hidden for certain platforms by setting a condition + \param[in] in_condition_data more details for future conditions, i.e. per user, per host, etc. + \param[in] in_command the shell command that we want to run + \param[in] in_flags some flags to tell FLUID to save the project, code, or strings before running the command + */ +Fd_Shell_Command::Fd_Shell_Command(const Fl_String &in_name, + const Fl_String &in_label, + Fl_Shortcut in_shortcut, + Fd_Tool_Store in_storage, + int in_condition, + const Fl_String &in_condition_data, + const Fl_String &in_command, + int in_flags) +: name(in_name), + label(in_label), + shortcut(in_shortcut), + storage(in_storage), + condition(in_condition), + condition_data(in_condition_data), + command(in_command), + flags(in_flags), + shell_menu_item_(NULL) +{ +} + +/** + Run this command now. + + Will open the Shell Panel and execute the command if no other command is + currently running. + */ +void Fd_Shell_Command::run() { + if (!command.empty()) + run_shell_command(command, flags); +} + +/** + Update the shell submenu in main menu with the shortcut and a copy of the label. + */ +void Fd_Shell_Command::update_shell_menu() { + if (shell_menu_item_) { + const char *old_label = shell_menu_item_->label(); // can be NULL + const char *new_label = label.c_str(); // never NULL + if (!old_label || (old_label && strcmp(old_label, new_label))) { + if (old_label) ::free((void*)old_label); + shell_menu_item_->label(fl_strdup(new_label)); + } + shell_menu_item_->shortcut(shortcut); + } +} + +/** + Check if the set condition is met. + + \return true if this command appears in the main menu + */ +bool Fd_Shell_Command::is_active() { + switch (condition) { + case ALWAYS: return true; + case NEVER: return false; +#ifdef _WIN32 + case MAC_ONLY: return false; + case UX_ONLY: return false; + case WIN_ONLY: return true; + case MAC_AND_UX_ONLY: return false; +#elif defined(__APPLE__) + case MAC_ONLY: return true; + case UX_ONLY: return false; + case WIN_ONLY: return false; + case MAC_AND_UX_ONLY: return true; +#else + case MAC_ONLY: return false; + case UX_ONLY: return true; + case WIN_ONLY: return false; + case MAC_AND_UX_ONLY: return true; +#endif + case USER_ONLY: return false; // TODO: get user name + case HOST_ONLY: return false; // TODO: get host name + case ENV_ONLY: { + const char *value = fl_getenv(condition_data.c_str()); + if (value && *value) return true; + return false; + } + } + return false; +} + +void Fd_Shell_Command::read(Fl_Preferences &prefs) { + int tmp; + prefs.get("name", name, ""); + prefs.get("label", label, ""); + prefs.get("shortcut", tmp, 0); + shortcut = (Fl_Shortcut)tmp; + prefs.get("storage", tmp, -1); + if (tmp != -1) storage = (Fd_Tool_Store)tmp; + prefs.get("condition", condition, ALWAYS); + prefs.get("condition_data", condition_data, ""); + prefs.get("command", command, ""); + prefs.get("flags", flags, 0); +} + +void Fd_Shell_Command::write(Fl_Preferences &prefs, bool save_location) { + prefs.set("name", name); + prefs.set("label", label); + if (shortcut != 0) prefs.set("shortcut", (int)shortcut); + if (save_location) prefs.set("storage", (int)storage); + if (condition != ALWAYS) prefs.set("condition", condition); + if (!condition_data.empty()) prefs.set("condition_data", condition_data); + if (!command.empty()) prefs.set("command", command); + if (flags != 0) prefs.set("flags", flags); +} + +void Fd_Shell_Command::read(class Fd_Project_Reader *in) { + const char *c = in->read_word(1); + if (strcmp(c, "{")!=0) return; // expecting start of group + storage = FD_STORE_PROJECT; + for (;;) { + c = in->read_word(1); + if (strcmp(c, "}")==0) break; // end of command list + else if (strcmp(c, "name")==0) + name = in->read_word(); + else if (strcmp(c, "label")==0) + label = in->read_word(); + else if (strcmp(c, "shortcut")==0) + shortcut = in->read_int(); + else if (strcmp(c, "condition")==0) + condition = in->read_int(); + else if (strcmp(c, "condition_data")==0) + condition_data = in->read_word(); + else if (strcmp(c, "command")==0) + command = in->read_word(); + else if (strcmp(c, "flags")==0) + flags = in->read_int(); + else + in->read_word(); // skip an unknown word + } +} + +void Fd_Shell_Command::write(class Fd_Project_Writer *out) { + out->write_string("\n command {"); + out->write_string("\n name "); out->write_word(name.c_str()); + out->write_string("\n label "); out->write_word(label.c_str()); + if (shortcut) out->write_string("\n shortcut %d", shortcut); + if (condition) out->write_string("\n condition %d", condition); + if (!condition_data.empty()) { + out->write_string("\n condition_data "); out->write_word(condition_data.c_str()); + } + if (!command.empty()) { + out->write_string("\n command "); out->write_word(command.c_str()); + } + if (flags) out->write_string("\n flags %d", flags); + out->write_string("\n }"); +} + + +/** + Manage a list of shell commands and their parameters. + */ +Fd_Shell_Command_List::Fd_Shell_Command_List() +: list(NULL), + list_size(0), + list_capacity(0), + shell_menu_(NULL) +{ +} + +/** + Release all shell commands and destroy this class. + */ +Fd_Shell_Command_List::~Fd_Shell_Command_List() { + clear(); +} + +/** + Return the shell command at the given index. + + \param[in] index must be between 0 and list_size-1 + \return a pointer to the shell command data + */ +Fd_Shell_Command *Fd_Shell_Command_List::at(int index) const { + return list[index]; +} + +/** + Clear all shell commands. + */ +void Fd_Shell_Command_List::clear() { + if (list) { + for (int i=0; i=0; i--) { + if (list[i]->storage == storage) { + remove(i); + } + } +} + +/** + Read shell configuration from a preferences group. + */ +void Fd_Shell_Command_List::read(Fl_Preferences &prefs, Fd_Tool_Store storage) { + // import the old shell commands from previous user settings + if (&fluid_prefs == &prefs) { + int version; + prefs.get("shell_commands_version", version, 0); + if (version == 0) { + int save_fl, save_code, save_strings; + Fd_Shell_Command *cmd = new Fd_Shell_Command(); + cmd->storage = FD_STORE_USER; + cmd->name = "Sample Shell Command"; + cmd->label = "Sample Shell Command"; + cmd->shortcut = FL_ALT+'g'; + fluid_prefs.get("shell_command", cmd->command, "echo \"Sample Shell Command\""); + fluid_prefs.get("shell_savefl", save_fl, 1); + fluid_prefs.get("shell_writecode", save_code, 1); + fluid_prefs.get("shell_writemsgs", save_strings, 0); + if (save_fl) cmd->flags |= Fd_Shell_Command::SAVE_PROJECT; + if (save_code) cmd->flags |= Fd_Shell_Command::SAVE_SOURCECODE; + if (save_strings) cmd->flags |= Fd_Shell_Command::SAVE_STRINGS; + add(cmd); + } + version = 1; + prefs.set("shell_commands_version", version); + } + Fl_Preferences shell_commands(prefs, "shell_commands"); + int n = shell_commands.groups(); + for (int i=0; istorage = FD_STORE_USER; + cmd->read(cmd_prefs); + add(cmd); + } +} + +/** + Write shell configuration to a preferences group. + */ +void Fd_Shell_Command_List::write(Fl_Preferences &prefs, Fd_Tool_Store storage) { + Fl_Preferences shell_commands(prefs, "shell_commands"); + shell_commands.delete_all_groups(); + int index = 0; + for (int i=0; istorage == FD_STORE_USER) { + Fl_Preferences cmd(shell_commands, Fl_Preferences::Name(index++)); + list[i]->write(cmd); + } + } +} + +/** + Read shell configuration from a project file. + */ +void Fd_Shell_Command_List::read(Fd_Project_Reader *in) { + const char *c = in->read_word(1); + if (strcmp(c, "{")!=0) return; // expecting start of group + clear(FD_STORE_PROJECT); + for (;;) { + c = in->read_word(1); + if (strcmp(c, "}")==0) break; // end of command list + else if (strcmp(c, "command")==0) { + Fd_Shell_Command *cmd = new Fd_Shell_Command(); + add(cmd); + cmd->read(in); + } else { + in->read_word(); // skip an unknown group + } + } +} + +/** + Write shell configuration to a project file. + */ +void Fd_Shell_Command_List::write(Fd_Project_Writer *out) { + int n_in_project_file = 0; + for (int i=0; istorage == FD_STORE_PROJECT) + n_in_project_file++; + } + if (n_in_project_file > 0) { + out->write_string("\nshell_commands {"); + for (int i=0; istorage == FD_STORE_PROJECT) + list[i]->write(out); + } + out->write_string("\n}"); + } +} + +/** + Add a previously created shell command to the end of the list. + + \param[in] cmd a pointer to the command that we want to add + */ +void Fd_Shell_Command_List::add(Fd_Shell_Command *cmd) { + if (list_size == list_capacity) { + list_capacity += 16; + list = (Fd_Shell_Command**)::realloc(list, list_capacity * sizeof(Fd_Shell_Command**)); + } + list[list_size++] = cmd; +} + +/** + Insert a newly created shell command at the given position in the list. + + \param[in] index must be between 0 and list_size-1 + \param[in] cmd a pointer to the command that we want to add + */ +void Fd_Shell_Command_List::insert(int index, Fd_Shell_Command *cmd) { + if (list_size == list_capacity) { + list_capacity += 16; + list = (Fd_Shell_Command**)::realloc(list, list_capacity * sizeof(Fd_Shell_Command**)); + } + ::memmove(list+index+1, list+index, (list_size-index)*sizeof(Fd_Shell_Command**)); + list_size++; + list[index] = cmd; +} + +/** + Remove and delete the command at the given index. + + \param[in] index must be between 0 and list_size-1 + */ +void Fd_Shell_Command_List::remove(int index) { + delete list[index]; + list_size--; + ::memmove(list+index, list+index+1, (list_size-index)*sizeof(Fd_Shell_Command**)); +} + +/** + This is called whenever the user clicks a shell command menu in the main menu. + + \param[in] u cast tp long to get the index of the shell command + */ +void menu_shell_cmd_cb(Fl_Widget*, void *u) { + long index = (long)(fl_intptr_t)u; + g_shell_config->list[index]->run(); +} + +/** + This is called when the user selects the menu to edit the shell commands. + It pops up the setting panel at the shell settings tab. + */ +void menu_shell_customize_cb(Fl_Widget*, void*) { settings_window->show(); w_settings_tabs->value(w_settings_shell_tab); } +/** + Rebuild the entire shell submenu from scratch and replace the old menu. + */ +void Fd_Shell_Command_List::rebuild_shell_menu() { + static Fl_Menu_Item *shell_submenu = NULL; + if (!shell_submenu) + shell_submenu = (Fl_Menu_Item*)main_menubar->find_item(menu_marker); + + int i, j, num_active_items = 0; + // count the active commands + for (i=0; iis_active()) num_active_items++; + } + // allocate a menu item array + Fl_Menu_Item *mi = (Fl_Menu_Item*)::calloc(num_active_items+2, sizeof(Fl_Menu_Item)); + // set the menu item pointer for all active commands + for (i=j=0; iis_active()) { + cmd->shell_menu_item_ = mi + j; + mi[j].callback(menu_shell_cmd_cb); + mi[j].argument(i); + cmd->update_shell_menu(); + j++; + } + } + if (j>0) mi[j-1].flags |= FL_MENU_DIVIDER; + mi[j].label(fl_strdup("Customize...")); + mi[j].shortcut(FL_ALT+'x'); + mi[j].callback(menu_shell_customize_cb); + // replace the old menu array with the new one + Fl_Menu_Item *mi_old = shell_menu_; + shell_menu_ = mi; + shell_submenu->user_data(shell_menu_); + // free all resources from the old menu + if (mi_old && (mi_old != default_menu)) { + for (i=0; ; i++) { + const char *label = mi_old[i].label(); + if (!label) break; + ::free((void*)label); + } + ::free(mi_old); + } +} + +/** + Tell the settings dialog to query this list and update its GUI elements. + */ +void Fd_Shell_Command_List::update_settings_dialog() { + if (w_settings_shell_tab) + w_settings_shell_tab->do_callback(w_settings_shell_tab, LOAD); +} + +/** + The default shell submenu in batch mode. + */ +Fl_Menu_Item Fd_Shell_Command_List::default_menu[] = { + { "Customize...", FL_ALT+'x', menu_shell_customize_cb }, + { NULL } +}; + +/** + Used to find the shell submenu within the main menu tree. + */ +void Fd_Shell_Command_List::menu_marker(Fl_Widget*, void*) { + // intentionally left empty +} + +/** + Export all selected shell commands to an external file. + + Verify that g_shell_config and w_settings_shell_list are not NULL. Open a + file chooser and export all items that are selected in w_settings_shell_list + into an external file. + */ +void Fd_Shell_Command_List::export_selected() { + if (!g_shell_config || (g_shell_config->list_size == 0)) return; + if (!w_settings_shell_list) return; + + Fl_Native_File_Chooser dialog; + dialog.title("Export selected shell commands:"); + dialog.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); + dialog.filter("FLUID Files\t*.flcmd\n"); + dialog.directory(g_project.projectfile_path().c_str()); + dialog.preset_file((g_project.basename() + ".flcmd").c_str()); + if (dialog.show() != 0) return; + + Fl_Preferences file(dialog.filename(), "flcmd.fluid.fltk.org", NULL, (Fl_Preferences::Root)(Fl_Preferences::C_LOCALE|Fl_Preferences::CLEAR)); + Fl_Preferences shell_commands(file, "shell_commands"); + int i, index = 0, n = w_settings_shell_list->size(); + for (i = 0; i < n; i++) { + if (w_settings_shell_list->selected(i+1)) { + Fl_Preferences cmd(shell_commands, Fl_Preferences::Name(index++)); + g_shell_config->list[i]->write(cmd, true); + } + } +} + +/** + Import shell commands from an external file and add them to the list. + + Verify that g_shell_config and w_settings_shell_list are not NULL. Open a + file chooser and import all items. + */ +void Fd_Shell_Command_List::import_from_file() { + if (!g_shell_config || (g_shell_config->list_size == 0)) return; + if (!w_settings_shell_list) return; + + Fl_Native_File_Chooser dialog; + dialog.title("Import shell commands:"); + dialog.type(Fl_Native_File_Chooser::BROWSE_FILE); + dialog.filter("FLUID Files\t*.flcmd\n"); + dialog.directory(g_project.projectfile_path().c_str()); + dialog.preset_file((g_project.basename() + ".flcmd").c_str()); + if (dialog.show() != 0) return; + + Fl_Preferences file(dialog.filename(), "flcmd.fluid.fltk.org", NULL, Fl_Preferences::C_LOCALE); + Fl_Preferences shell_commands(file, "shell_commands"); + int i, n = shell_commands.groups(); + for (i = 0; i < n; i++) { + Fl_Preferences cmd_prefs(shell_commands, Fl_Preferences::Name(i)); + Fd_Shell_Command *cmd = new Fd_Shell_Command(); + cmd->storage = FD_STORE_USER; + cmd->read(cmd_prefs); + g_shell_config->add(cmd); + } + w_settings_shell_list->do_callback(w_settings_shell_list, LOAD); + w_settings_shell_cmd->do_callback(w_settings_shell_cmd, LOAD); + w_settings_shell_toolbox->do_callback(w_settings_shell_toolbox, LOAD); + g_shell_config->rebuild_shell_menu(); +} + +/** + A pointer to the list of shell commands if we are not in batch mode. + */ +Fd_Shell_Command_List *g_shell_config = NULL; + diff --git a/fluid/shell_command.h b/fluid/shell_command.h index cfd7b6579..ea39375f2 100644 --- a/fluid/shell_command.h +++ b/fluid/shell_command.h @@ -1,7 +1,7 @@ // // FLUID main entry for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2021 by Bill Spitzak and others. +// Copyright 1998-2023 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 @@ -17,11 +17,13 @@ #ifndef _FLUID_SHELL_COMMAND_H #define _FLUID_SHELL_COMMAND_H -#include -#include +#include "fluid.h" #include +#include +#include +#include #if defined(_WIN32) && !defined(__CYGWIN__) # include # include @@ -33,29 +35,10 @@ # include #endif -void show_shell_window(); -void do_shell_command(class Fl_Return_Button*, void*); - -typedef struct { - char *command; - int flags; -} Shell_Settings; - -extern Shell_Settings shell_settings_windows; -extern Shell_Settings shell_settings_linux; -extern Shell_Settings shell_settings_macos; - -extern Fl_String g_shell_command; -extern int g_shell_save_fl; -extern int g_shell_save_code; -extern int g_shell_save_strings; -extern int g_shell_use_fl_settings; - -void shell_prefs_get(); -void shell_prefs_set(); -void shell_settings_read(); -void shell_settings_write(); +struct Fl_Menu_Item; +class Fl_Widget; +void run_shell_command(const Fl_String &cmd, int flags); class Fl_Process { public: @@ -88,4 +71,71 @@ protected: FILE * _fpt; }; +class Fd_Shell_Command { +public: + enum { ALWAYS, NEVER, MAC_ONLY, UX_ONLY, WIN_ONLY, MAC_AND_UX_ONLY, USER_ONLY, HOST_ONLY, ENV_ONLY }; // conditions + enum { SAVE_PROJECT = 1, SAVE_SOURCECODE = 2, SAVE_STRINGS = 4, SAVE_ALL = 7 }; // flags + Fd_Shell_Command(); + Fd_Shell_Command(const Fd_Shell_Command *rhs); + Fd_Shell_Command(const Fl_String &in_name); + Fd_Shell_Command(const Fl_String &in_name, + const Fl_String &in_label, + Fl_Shortcut in_shortcut, + Fd_Tool_Store in_storage, + int in_condition, + const Fl_String &in_condition_data, + const Fl_String &in_command, + int in_flags); + Fl_String name; + Fl_String label; + Fl_Shortcut shortcut; + Fd_Tool_Store storage; + int condition; // always, hide, windows only, linux only, mac only, user, machine + Fl_String condition_data; // user name, machine name + Fl_String command; + int flags; // save_project, save_code, save_string, ... + Fl_Menu_Item *shell_menu_item_; + void run(); + void read(Fl_Preferences &prefs); + void write(Fl_Preferences &prefs, bool save_location = false); + void read(class Fd_Project_Reader*); + void write(class Fd_Project_Writer*); + void update_shell_menu(); + bool is_active(); +}; + +class Fd_Shell_Command_List { +public: + Fd_Shell_Command **list; + int list_size; + int list_capacity; + Fl_Menu_Item *shell_menu_; +public: + Fd_Shell_Command_List(); + ~Fd_Shell_Command_List(); + Fd_Shell_Command *at(int index) const; + void add(Fd_Shell_Command *cmd); + void insert(int index, Fd_Shell_Command *cmd); + void remove(int index); + void clear(); + void clear(Fd_Tool_Store store); +// void move_up(); +// void move_down(); +// int load(const Fl_String &filename); +// int save(const Fl_String &filename); + void read(Fl_Preferences &prefs, Fd_Tool_Store storage); + void write(Fl_Preferences &prefs, Fd_Tool_Store storage); + void read(class Fd_Project_Reader*); + void write(class Fd_Project_Writer*); + void rebuild_shell_menu(); + void update_settings_dialog(); + + static Fl_Menu_Item default_menu[]; + static void menu_marker(Fl_Widget*, void*); + static void export_selected(); + static void import_from_file(); +}; + +extern Fd_Shell_Command_List *g_shell_config; + #endif // _FLUID_SHELL_COMMAND_H diff --git a/fluid/sourceview_panel.cxx b/fluid/sourceview_panel.cxx index 2cd008f85..64d7c6b0d 100644 --- a/fluid/sourceview_panel.cxx +++ b/fluid/sourceview_panel.cxx @@ -87,17 +87,17 @@ void update_sourceview_cb(class Fl_Button*, void*) { if (!sv_source_filename) { sv_source_filename = (char*)malloc(FL_PATH_MAX); - fluid_prefs.getUserdataPath(sv_source_filename, FL_PATH_MAX); + fl_strlcpy(sv_source_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX); } if (!sv_header_filename) { sv_header_filename = (char*)malloc(FL_PATH_MAX); - fluid_prefs.getUserdataPath(sv_header_filename, FL_PATH_MAX); + fl_strlcpy(sv_header_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX); } if (!sv_design_filename) { sv_design_filename = (char*)malloc(FL_PATH_MAX); - fluid_prefs.getUserdataPath(sv_design_filename, FL_PATH_MAX); + fl_strlcpy(sv_design_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcat(sv_design_filename, "source_view_tmp.fl", FL_PATH_MAX); } @@ -108,8 +108,9 @@ void update_sourceview_cb(class Fl_Button*, void*) { sv_project->scroll(top, 0); } else if (sv_strings->visible_r()) { static const char *exts[] = { ".txt", ".po", ".msg" }; - char fn[FL_PATH_MAX]; - fluid_prefs.getUserdataPath(fn, FL_PATH_MAX); + char fn[FL_PATH_MAX+1]; + fl_strlcpy(fn, get_tmpdir().c_str(), FL_PATH_MAX); + fl_strlcat(fn, "strings", FL_PATH_MAX); fl_filename_setext(fn, FL_PATH_MAX, exts[g_project.i18n_type]); write_strings(fn); int top = sv_strings->top_line(); diff --git a/fluid/sourceview_panel.fl b/fluid/sourceview_panel.fl index e78224677..61f6242a9 100644 --- a/fluid/sourceview_panel.fl +++ b/fluid/sourceview_panel.fl @@ -102,17 +102,17 @@ and load those into the Code Viewer widgets.} open return_type void if (!sv_source_filename) { sv_source_filename = (char*)malloc(FL_PATH_MAX); - fluid_prefs.getUserdataPath(sv_source_filename, FL_PATH_MAX); + fl_strlcpy(sv_source_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcat(sv_source_filename, "source_view_tmp.cxx", FL_PATH_MAX); } if (!sv_header_filename) { sv_header_filename = (char*)malloc(FL_PATH_MAX); - fluid_prefs.getUserdataPath(sv_header_filename, FL_PATH_MAX); + fl_strlcpy(sv_header_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcat(sv_header_filename, "source_view_tmp.h", FL_PATH_MAX); } if (!sv_design_filename) { sv_design_filename = (char*)malloc(FL_PATH_MAX); - fluid_prefs.getUserdataPath(sv_design_filename, FL_PATH_MAX); + fl_strlcpy(sv_design_filename, get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcat(sv_design_filename, "source_view_tmp.fl", FL_PATH_MAX); } @@ -123,8 +123,9 @@ and load those into the Code Viewer widgets.} open return_type void sv_project->scroll(top, 0); } else if (sv_strings->visible_r()) { static const char *exts[] = { ".txt", ".po", ".msg" }; - char fn[FL_PATH_MAX]; - fluid_prefs.getUserdataPath(fn, FL_PATH_MAX); + char fn[FL_PATH_MAX+1]; + fl_strlcpy(fn, get_tmpdir().c_str(), FL_PATH_MAX); + fl_strlcat(fn, "strings", FL_PATH_MAX); fl_filename_setext(fn, FL_PATH_MAX, exts[g_project.i18n_type]); write_strings(fn); int top = sv_strings->top_line(); diff --git a/src/Fl_Preferences.cxx b/src/Fl_Preferences.cxx index 93b29db45..c7a47881f 100644 --- a/src/Fl_Preferences.cxx +++ b/src/Fl_Preferences.cxx @@ -233,7 +233,9 @@ Fl_Preferences::Root Fl_Preferences::filename( char *buffer, size_t buffer_size, \/Library/Preferences/\$(vendor)/\$(application).prefs, which would silently fail to create a preference file. - \param[in] root can be \c USER_L or \c SYSTEM_L for user specific or system wide preferences + \param[in] root can be \c USER_L or \c SYSTEM_L for user specific or system + wide preferences, add the CLEAR flag to start with a clean set of + preferences instead of reading them from the database \param[in] vendor unique text describing the company or author of this file, must be a valid filepath segment \param[in] application unique text describing the application, must be a valid filepath segment @@ -246,19 +248,41 @@ Fl_Preferences::Fl_Preferences( Root root, const char *vendor, const char *appli } /** - \brief Use this constructor to create or read a preference file at an - arbitrary position in the file system. + \brief Deprecated: Use this constructor to create or read a preference file at an + arbitrary position in the file system. - The file name is generated in the form \$(path)/\$(application).prefs. - If \p application is \c NULL, \p path is taken literally as the file path and name. + This constructor should no longer be used because the generated database uses + the current locale, making it impossible to exchange floating point settings + between machines with different language settings. - \param[in] path path to the directory that contains the preference file - \param[in] vendor unique text describing the company or author of this file, must be a valid filepath segment - \param[in] application unique text describing the application, must be a valid filepath segment + Use `Fl_Preferences(path, vendor, application, C_LOCALE)` in new projects and + `Fl_Preferences(path, vendor, application, 0)` if you must keep backward + compatibility. + + \see Fl_Preferences( const char *path, const char *vendor, const char *application, Root flags ) */ Fl_Preferences::Fl_Preferences( const char *path, const char *vendor, const char *application ) { node = new Node( "." ); - rootNode = new RootNode( this, path, vendor, application ); + rootNode = new RootNode( this, path, vendor, application, (Root)0 ); + node->setRoot(rootNode); +} + +/** + \brief Use this constructor to create or read a preference file at an + arbitrary position in the file system. + + The file name is generated in the form \$(path)/\$(application).prefs. + If \p application is \c NULL, \p path is taken literally as the file path and name. + + \param[in] path path to the directory that contains the preference file + \param[in] vendor unique text describing the company or author of this file, must be a valid filepath segment + \param[in] application unique text describing the application, must be a valid filename or NULL + \param[in] set C_LOCALE to make the preferences file independent of the current locale, + add the CLEAR flag to start with a clean set of preferences instead of reading from the database + */ +Fl_Preferences::Fl_Preferences( const char *path, const char *vendor, const char *application, Root flags ) { + node = new Node( "." ); + rootNode = new RootNode( this, path, vendor, application, flags ); node->setRoot(rootNode); } @@ -1168,23 +1192,24 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char filename_(0L), vendor_(0L), application_(0L), - root_type_(root) + root_type_((Root)(root & ~CLEAR)) { char *filename = Fl::system_driver()->preference_rootnode(prefs, root, vendor, application); filename_ = filename ? fl_strdup(filename) : 0L; vendor_ = fl_strdup(vendor); application_ = fl_strdup(application); - read(); + if ( (root & CLEAR) == 0 ) + read(); } // create the root node // - construct the name of the file that will hold our preferences -Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, const char *vendor, const char *application ) +Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, const char *vendor, const char *application, Root flags ) : prefs_(prefs), filename_(0L), vendor_(0L), application_(0L), - root_type_(Fl_Preferences::USER) + root_type_( (Root)(USER | (flags & C_LOCALE) )) { if (!vendor) @@ -1199,7 +1224,8 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, con } vendor_ = fl_strdup(vendor); application_ = fl_strdup(application); - read(); + if ( (flags & CLEAR) == 0 ) + read(); } // create a root node that exists only on RAM and can not be read or written to diff --git a/src/filename_absolute.cxx b/src/filename_absolute.cxx index 70b86fcf7..0d0155df1 100644 --- a/src/filename_absolute.cxx +++ b/src/filename_absolute.cxx @@ -367,3 +367,4 @@ Fl_String fl_getcwd() { fl_getcwd(buffer, FL_PATH_MAX); return Fl_String(buffer); } + diff --git a/test/tree.fl b/test/tree.fl index a48be0284..cb2c8803e 100644 --- a/test/tree.fl +++ b/test/tree.fl @@ -392,7 +392,7 @@ tree->clear_changed();} open tooltip {Test tree} xywh {15 22 320 539} box DOWN_BOX color 55 selection_color 15 class Fl_Tree } {} - Fl_Group {} {open selected + Fl_Group {} {open xywh {350 5 681 556} code0 {o->resizable(0);} } { @@ -780,7 +780,7 @@ Fl::visible_focus(onoff);} } } Fl_Group {} { - label {Test Operations} + label {Test Operations} open selected tooltip {These controls only affect the defaults for new items that are created. These test the Fl_Tree_Prefs methods.} xywh {350 435 330 125} box GTK_DOWN_BOX color 47 labelsize 12 } { Fl_Group showitem_box { @@ -847,7 +847,7 @@ tree->redraw();} callback {const char *filename = fl_file_chooser("Select a Preferences style Database", "Preferences(*.prefs)", 0L); if (filename) { tree->clear(); - Fl_Preferences prefs(filename, 0L, 0L); + Fl_Preferences prefs(filename, 0L, 0L, Fl_Preferences::C_LOCALE); tree->load(prefs); tree->redraw(); }} diff --git a/test/unittest_core.cxx b/test/unittest_core.cxx index 6091dd7b4..ad60d172c 100644 --- a/test/unittest_core.cxx +++ b/test/unittest_core.cxx @@ -278,7 +278,7 @@ TEST(fl_filename, relative) { r = fl_filename_relative("../foo.txt", base); EXPECT_STREQ(r.c_str(), "../foo.txt"); return true; - } +} TEST(fl_filename, absolute) { Fl_String base = "/var/tmp/somedir"; @@ -293,6 +293,7 @@ TEST(fl_filename, absolute) { return true; } + bool cb1a_ok = false, cb1b_ok = false, cb1c_ok = false; int cb1_alloc = 0; class MyString : public Fl_String {