diff --git a/FL/Fl_Gl_Window.H b/FL/Fl_Gl_Window.H index c33bed8db..8889a086b 100644 --- a/FL/Fl_Gl_Window.H +++ b/FL/Fl_Gl_Window.H @@ -207,7 +207,8 @@ public: void make_overlay_current(); // Note: Doxygen docs in Fl_Widget.H to avoid redundancy. - Fl_Gl_Window* as_gl_window() FL_OVERRIDE {return this;} + Fl_Gl_Window* as_gl_window() FL_OVERRIDE { return this; } + Fl_Gl_Window const* as_gl_window() const FL_OVERRIDE { return this; } float pixels_per_unit(); /** Gives the window width in OpenGL pixels. diff --git a/FL/Fl_Group.H b/FL/Fl_Group.H index 1e21b20ba..173f8754b 100644 --- a/FL/Fl_Group.H +++ b/FL/Fl_Group.H @@ -228,6 +228,7 @@ public: // Note: Doxygen docs in Fl_Widget.H to avoid redundancy. Fl_Group* as_group() FL_OVERRIDE { return this; } + Fl_Group const* as_group() const FL_OVERRIDE { return this; } // back compatibility functions: diff --git a/FL/Fl_Menu_Item.H b/FL/Fl_Menu_Item.H index 0f1083a9a..4bca0e1ce 100644 --- a/FL/Fl_Menu_Item.H +++ b/FL/Fl_Menu_Item.H @@ -317,6 +317,10 @@ struct FL_EXPORT Fl_Menu_Item { before FLTK 1.4.0. */ int value() const {return (flags & FL_MENU_VALUE) ? 1 : 0;} + + /** Sets the current value of the check or radio item. */ + void value(int v) { v ? set() : clear(); } + /** Turns the check or radio item "on" for the menu item. Note that this does not turn off any adjacent radio items like setonly() does. @@ -326,7 +330,7 @@ struct FL_EXPORT Fl_Menu_Item { /** Turns the check or radio item "off" for the menu item. */ void clear() {flags &= ~FL_MENU_VALUE;} - void setonly(); + void setonly(Fl_Menu_Item const* first = NULL); /** Gets the visibility of an item. */ int visible() const {return !(flags&FL_MENU_INVISIBLE);} diff --git a/FL/Fl_Widget.H b/FL/Fl_Widget.H index b0317dc6e..969aee6fa 100644 --- a/FL/Fl_Widget.H +++ b/FL/Fl_Widget.H @@ -1091,7 +1091,8 @@ public: \note This method is provided to avoid dynamic_cast. \see Fl_Widget::as_window(), Fl_Widget::as_gl_window() */ - virtual Fl_Group* as_group() {return 0;} + virtual Fl_Group* as_group() { return NULL; } + virtual Fl_Group const* as_group() const { return NULL; } /** Returns an Fl_Window pointer if this widget is an Fl_Window. @@ -1105,7 +1106,8 @@ public: \note This method is provided to avoid dynamic_cast. \see Fl_Widget::as_group(), Fl_Widget::as_gl_window() */ - virtual Fl_Window* as_window() {return 0;} + virtual Fl_Window* as_window() { return 0; } + virtual Fl_Window const* as_window() const { return NULL; } /** Returns an Fl_Gl_Window pointer if this widget is an Fl_Gl_Window. @@ -1117,7 +1119,8 @@ public: \note This method is provided to avoid dynamic_cast. \see Fl_Widget::as_group(), Fl_Widget::as_window() */ - virtual class Fl_Gl_Window* as_gl_window() {return 0;} + virtual class Fl_Gl_Window* as_gl_window() { return NULL; } + virtual class Fl_Gl_Window const* as_gl_window() const { return NULL; } /** Returns non zero if MAC_USE_ACCENTS_MENU flag is set, 0 otherwise. */ diff --git a/FL/Fl_Window.H b/FL/Fl_Window.H index ef4d78007..a6709a216 100644 --- a/FL/Fl_Window.H +++ b/FL/Fl_Window.H @@ -560,6 +560,7 @@ public: // Note: Doxygen docs in Fl_Widget.H to avoid redundancy. Fl_Window* as_window() FL_OVERRIDE { return this; } + Fl_Window const* as_window() const FL_OVERRIDE { return this; } /** Return non-null if this is an Fl_Overlay_Window object. diff --git a/fluid/CMakeLists.txt b/fluid/CMakeLists.txt index ab891a67c..e8b10a1fc 100644 --- a/fluid/CMakeLists.txt +++ b/fluid/CMakeLists.txt @@ -17,6 +17,7 @@ set (CPPFILES CodeEditor.cxx StyleParse.cxx + Fd_Snap_Action.cxx Fl_Function_Type.cxx Fl_Group_Type.cxx Fl_Menu_Type.cxx @@ -45,6 +46,7 @@ set (CPPFILES set (HEADERFILES CodeEditor.h + Fd_Snap_Action.h Fl_Function_Type.h Fl_Group_Type.h Fl_Menu_Type.h diff --git a/fluid/Fd_Snap_Action.cxx b/fluid/Fd_Snap_Action.cxx new file mode 100644 index 000000000..a2b3917b3 --- /dev/null +++ b/fluid/Fd_Snap_Action.cxx @@ -0,0 +1,1565 @@ +// +// Snap action code file for the Fast Light Tool Kit (FLTK). +// +// Copyright 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 +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#include "Fd_Snap_Action.h" + +#include "Fl_Group_Type.h" +#include "alignment_panel.h" +#include "file.h" + +#include +#include +#include +#include +#include +#include + +// TODO: warning if the user wants to change builtin layouts +// TODO: move panel to global settings panel (move load & save to main pulldown, or to toolbox?) +// INFO: how about a small tool box for quick preset selection and diabeling of individual snaps? + +void select_layout_suite_cb(Fl_Widget *, void *user_data); + +int Fd_Snap_Action::eex = 0; +int Fd_Snap_Action::eey = 0; + +static Fd_Layout_Preset fltk_app = { + 15, 15, 15, 15, 0, 0, // window: l, r, t, b, gx, gy + 10, 10, 10, 10, 0, 0, // group: l, r, t, b, gx, gy + 25, 25, // tabs: t, b + 20, 10, 4, // widget_x: min, inc, gap + 20, 4, 8, // widget_y: min, inc, gap + 0, 14, 0, 14 // labelfont/size, textfont/size +}; +static Fd_Layout_Preset fltk_dlg = { + 10, 10, 10, 10, 0, 0, // window: l, r, t, b, gx, gy + 10, 10, 10, 10, 0, 0, // group: l, r, t, b, gx, gy + 20, 20, // tabs: t, b + 20, 10, 5, // widget_x: min, inc, gap + 20, 5, 5, // widget_y: min, inc, gap + 0, 11, 0, 11 // labelfont/size, textfont/size +}; +static Fd_Layout_Preset fltk_tool = { + 10, 10, 10, 10, 0, 0, // window: l, r, t, b, gx, gy + 10, 10, 10, 10, 0, 0, // group: l, r, t, b, gx, gy + 18, 18, // tabs: t, b + 16, 8, 2, // widget_x: min, inc, gap + 16, 4, 2, // widget_y: min, inc, gap + 0, 10, 0, 10 // labelfont/size, textfont/size +}; + +static Fd_Layout_Preset grid_app = { + 12, 12, 12, 12, 12, 12, // window: l, r, t, b, gx, gy + 12, 12, 12, 12, 12, 12, // group: l, r, t, b, gx, gy + 24, 24, // tabs: t, b + 12, 6, 6, // widget_x: min, inc, gap + 12, 6, 6, // widget_y: min, inc, gap + 0, 14, 0, 14 // labelfont/size, textfont/size +}; + +static Fd_Layout_Preset grid_dlg = { + 10, 10, 10, 10, 10, 10, // window: l, r, t, b, gx, gy + 10, 10, 10, 10, 10, 10, // group: l, r, t, b, gx, gy + 20, 20, // tabs: t, b + 10, 5, 5, // widget_x: min, inc, gap + 10, 5, 5, // widget_y: min, inc, gap + 0, 12, 0, 12 // labelfont/size, textfont/size +}; + +static Fd_Layout_Preset grid_tool = { + 8, 8, 8, 8, 8, 8, // window: l, r, t, b, gx, gy + 8, 8, 8, 8, 8, 8, // group: l, r, t, b, gx, gy + 16, 16, // tabs: t, b + 8, 4, 4, // widget_x: min, inc, gap + 8, 4, 4, // widget_y: min, inc, gap + 0, 10, 0, 10 // labelfont/size, textfont/size +}; + +static Fd_Layout_Suite static_suite_list[] = { + { (char*)"FLTK", (char*)"@fd_beaker FLTK", { &fltk_app, &fltk_dlg, &fltk_tool }, FD_STORE_INTERNAL }, + { (char*)"Grid", (char*)"@fd_beaker Grid", { &grid_app, &grid_dlg, &grid_tool }, FD_STORE_INTERNAL } +}; + +static Fl_Menu_Item static_main_menu[] = { + { static_suite_list[0].menu_label, 0, select_layout_suite_cb, (void*)0, FL_MENU_RADIO|FL_MENU_VALUE }, + { static_suite_list[1].menu_label, 0, select_layout_suite_cb, (void*)1, FL_MENU_RADIO }, + { NULL } +}; + +static Fl_Menu_Item static_choice_menu[] = { + { static_suite_list[0].menu_label }, + { static_suite_list[1].menu_label }, + { NULL } +}; + +Fd_Layout_Preset *layout = &fltk_app; +Fd_Layout_List g_layout_list; + +// ---- Callbacks ------------------------------------------------------ MARK: - + +void layout_suite_marker(Fl_Widget *, void *) { + assert(0); + // intentionally left empty +} + +void select_layout_suite_cb(Fl_Widget *, void *user_data) { + int index = (int)(fl_intptr_t)user_data; + assert(index >= 0); + assert(index < g_layout_list.list_size_); + g_layout_list.current_suite(index); + g_layout_list.update_dialogs(); +} + +void select_layout_preset_cb(Fl_Widget *, void *user_data) { + int index = (int)(fl_intptr_t)user_data; + assert(index >= 0); + assert(index < 3); + g_layout_list.current_preset(index); + g_layout_list.update_dialogs(); +} + +void edit_layout_preset_cb(Fl_Button *w, long user_data) { + int index = (int)w->argument(); + assert(index >= 0); + assert(index < 3); + if (user_data == (long)(fl_intptr_t)LOAD) { + w->value(g_layout_list.current_preset() == index); + } else { + g_layout_list.current_preset(index); + g_layout_list.update_dialogs(); + } +} + +// ---- Fd_Layout_Suite ------------------------------------------------ MARK: - + +void Fd_Layout_Preset::write(Fl_Preferences &prefs) { + assert(this); + Fl_Preferences p_win(prefs, "Window"); + p_win.set("left_margin", left_window_margin); + p_win.set("right_margin", right_window_margin); + p_win.set("top_margin", top_window_margin); + p_win.set("bottom_margin", bottom_window_margin); + p_win.set("grid_x", window_grid_x); + p_win.set("grid_y", window_grid_y); + + Fl_Preferences p_grp(prefs, "Group"); + p_grp.set("left_margin", left_group_margin); + p_grp.set("right_margin", right_group_margin); + p_grp.set("top_margin", top_group_margin); + p_grp.set("bottom_margin", bottom_group_margin); + p_grp.set("grid_x", group_grid_x); + p_grp.set("grid_y", group_grid_y); + + Fl_Preferences p_tbs(prefs, "Tabs"); + p_tbs.set("top_margin", top_tabs_margin); + p_tbs.set("bottom_margin", bottom_tabs_margin); + + Fl_Preferences p_wgt(prefs, "Widget"); + p_wgt.set("min_w", widget_min_w); + p_wgt.set("inc_w", widget_inc_w); + p_wgt.set("gap_x", widget_gap_x); + p_wgt.set("min_h", widget_min_h); + p_wgt.set("inc_h", widget_inc_h); + p_wgt.set("gap_y", widget_gap_y); + + Fl_Preferences p_lyt(prefs, "Layout"); + p_lyt.set("labelfont", labelfont); + p_lyt.set("labelsize", labelsize); + p_lyt.set("textfont", textfont); + p_lyt.set("textsize", textsize); +} + +void Fd_Layout_Preset::read(Fl_Preferences &prefs) { + assert(this); + Fl_Preferences p_win(prefs, "Window"); + p_win.get("left_margin", left_window_margin, 15); + p_win.get("right_margin", right_window_margin, 15); + p_win.get("top_margin", top_window_margin, 15); + p_win.get("bottom_margin", bottom_window_margin, 15); + p_win.get("grid_x", window_grid_x, 0); + p_win.get("grid_y", window_grid_y, 0); + + Fl_Preferences p_grp(prefs, "Group"); + p_grp.get("left_margin", left_group_margin, 10); + p_grp.get("right_margin", right_group_margin, 10); + p_grp.get("top_margin", top_group_margin, 10); + p_grp.get("bottom_margin", bottom_group_margin, 10); + p_grp.get("grid_x", group_grid_x, 0); + p_grp.get("grid_y", group_grid_y, 0); + + Fl_Preferences p_tbs(prefs, "Tabs"); + p_tbs.get("top_margin", top_tabs_margin, 25); + p_tbs.get("bottom_margin", bottom_tabs_margin, 25); + + Fl_Preferences p_wgt(prefs, "Widget"); + p_wgt.get("min_w", widget_min_w, 20); + p_wgt.get("inc_w", widget_inc_w, 10); + p_wgt.get("gap_x", widget_gap_x, 4); + p_wgt.get("min_h", widget_min_h, 20); + p_wgt.get("inc_h", widget_inc_h, 4); + p_wgt.get("gap_y", widget_gap_y, 8); + + Fl_Preferences p_lyt(prefs, "Layout"); + p_lyt.get("labelfont", labelfont, 0); + p_lyt.get("labelsize", labelsize, 14); + p_lyt.get("textfont", textfont, 0); + p_lyt.get("textsize", textsize, 14); +} + +void Fd_Layout_Preset::write(Fd_Project_Writer *out) { + out->write_string(" preset { 1\n"); // preset format version + out->write_string(" %d %d %d %d %d %d\n", + left_window_margin, right_window_margin, + top_window_margin, bottom_window_margin, + window_grid_x, window_grid_y); + out->write_string(" %d %d %d %d %d %d\n", + left_group_margin, right_group_margin, + top_group_margin, bottom_group_margin, + group_grid_x, group_grid_y); + out->write_string(" %d %d\n", top_tabs_margin, bottom_tabs_margin); + out->write_string(" %d %d %d %d %d %d\n", + widget_min_w, widget_inc_w, widget_gap_x, + widget_min_h, widget_inc_h, widget_gap_y); + out->write_string(" %d %d %d %d\n", + labelfont, labelsize, textfont, textsize); + out->write_string(" }\n"); // preset format version +} + +void Fd_Layout_Preset::read(Fd_Project_Reader *in) { + const char *key; + key = in->read_word(1); + if (key && !strcmp(key, "{")) { + for (;;) { + key = in->read_word(); + if (!key) return; + if (key[0] == '}') break; + int ver = atoi(key); + if (ver == 0) { + continue; + } else if (ver == 1) { + left_window_margin = in->read_int(); + right_window_margin = in->read_int(); + top_window_margin = in->read_int(); + bottom_window_margin = in->read_int(); + window_grid_x = in->read_int(); + window_grid_y = in->read_int(); + + left_group_margin = in->read_int(); + right_group_margin = in->read_int(); + top_group_margin = in->read_int(); + bottom_group_margin = in->read_int(); + group_grid_x = in->read_int(); + group_grid_y = in->read_int(); + + top_tabs_margin = in->read_int(); + bottom_tabs_margin = in->read_int(); + + widget_min_w = in->read_int(); + widget_inc_w = in->read_int(); + widget_gap_x = in->read_int(); + widget_min_h = in->read_int(); + widget_inc_h = in->read_int(); + widget_gap_y = in->read_int(); + + labelfont = in->read_int(); + labelsize = in->read_int(); + textfont = in->read_int(); + textsize = in->read_int(); + } else { // skip unknown chunks + for (;;) { + key = in->read_word(1); + if (key && (key[0] == '}')) + return; + } + } + } + } else { + // format error + } +} + + +// ---- Fd_Layout_Suite ------------------------------------------------ MARK: - + +void Fd_Layout_Suite::write(Fl_Preferences &prefs) { + assert(this); + assert(name_); + prefs.set("name", name_); + for (int i = 0; i < 3; ++i) { + Fl_Preferences prefs_preset(prefs, Fl_Preferences::Name(i)); + assert(layout[i]); + layout[i]->write(prefs_preset); + } +} + +void Fd_Layout_Suite::read(Fl_Preferences &prefs) { + assert(this); + for (int i = 0; i < 3; ++i) { + Fl_Preferences prefs_preset(prefs, Fl_Preferences::Name(i)); + assert(layout[i]); + layout[i]->read(prefs_preset); + } +} + +void Fd_Layout_Suite::write(Fd_Project_Writer *out) { + out->write_string(" suite {\n"); + out->write_string(" name "); out->write_word(name_); out->write_string("\n"); + for (int i = 0; i < 3; ++i) { + layout[i]->write(out); + } + out->write_string(" }\n"); +} + +void Fd_Layout_Suite::read(Fd_Project_Reader *in) { + const char *key; + key = in->read_word(1); + if (key && !strcmp(key, "{")) { + int ix = 0; + for (;;) { + key = in->read_word(); + if (!key) return; + if (!strcmp(key, "name")) { + name(in->read_word()); + } else if (!strcmp(key, "preset")) { + if (ix >= 3) return; // file format error + layout[ix++]->read(in); + } else if (!strcmp(key, "}")) { + break; + } else { + in->read_word(); // unknown key, ignore, hopefully a key-value pair + } + } + } else { + // file format error + } +} + +void Fd_Layout_Suite::update_label() { + Fl_String sym; + switch (storage_) { + case FD_STORE_INTERNAL: sym.assign("@fd_beaker "); break; + case FD_STORE_USER: sym.assign("@fd_user "); break; + case FD_STORE_PROJECT: sym.assign("@fd_project "); break; + case FD_STORE_FILE: sym.assign("@fd_file "); break; + } + sym.append(name_); + if (menu_label) + ::free(menu_label); + menu_label = fl_strdup(sym.c_str()); + g_layout_list.update_menu_labels(); +} + +void Fd_Layout_Suite::name(const char *n) { + if (name_) + ::free(name_); + if (n) + name_ = fl_strdup(n); + else + name_ = NULL; + update_label(); +} + +void Fd_Layout_Suite::init() { + name_ = NULL; + menu_label = NULL; + layout[0] = layout[1] = layout[2] = NULL; + storage_ = 0; +} + +Fd_Layout_Suite::~Fd_Layout_Suite() { + if (storage_ == FD_STORE_INTERNAL) return; + if (name_) ::free(name_); + for (int i = 0; i < 3; ++i) { + delete layout[i]; + } +} + +// ---- Fd_Layout_List ------------------------------------------------- MARK: - + +static void fd_beaker(Fl_Color c) { + fl_color(221); + fl_begin_polygon(); + fl_vertex(-0.6, 0.2); + fl_vertex(-0.9, 0.8); + fl_vertex(-0.8, 0.9); + fl_vertex( 0.8, 0.9); + fl_vertex( 0.9, 0.8); + fl_vertex( 0.6, 0.2); + fl_end_polygon(); + fl_color(c); + fl_begin_line(); + fl_vertex(-0.3, -0.9); + fl_vertex(-0.2, -0.8); + fl_vertex(-0.2, -0.2); + fl_vertex(-0.9, 0.8); + fl_vertex(-0.8, 0.9); + fl_vertex( 0.8, 0.9); + fl_vertex( 0.9, 0.8); + fl_vertex( 0.2, -0.2); + fl_vertex( 0.2, -0.8); + fl_vertex( 0.3, -0.9); + fl_end_line(); +} + +static void fd_user(Fl_Color c) { + fl_color(245); + fl_begin_complex_polygon(); + fl_arc( 0.1, 0.9, 0.8, 0.0, 80.0); + fl_arc( 0.0, -0.5, 0.4, -65.0, 245.0); + fl_arc(-0.1, 0.9, 0.8, 100.0, 180.0); + fl_end_complex_polygon(); + fl_color(c); + fl_begin_line(); + fl_arc( 0.1, 0.9, 0.8, 0.0, 80.0); + fl_arc( 0.0, -0.5, 0.4, -65.0, 245.0); + fl_arc(-0.1, 0.9, 0.8, 100.0, 180.0); + fl_end_line(); +} + +static void fd_project(Fl_Color c) { + Fl_Color fc = FL_LIGHT2; + fl_color(fc); + fl_begin_complex_polygon(); + fl_vertex(-0.7, -1.0); + fl_vertex(0.1, -1.0); + fl_vertex(0.1, -0.4); + fl_vertex(0.7, -0.4); + fl_vertex(0.7, 1.0); + fl_vertex(-0.7, 1.0); + fl_end_complex_polygon(); + + fl_color(fl_lighter(fc)); + fl_begin_polygon(); + fl_vertex(0.1, -1.0); + fl_vertex(0.1, -0.4); + fl_vertex(0.7, -0.4); + fl_end_polygon(); + + fl_color(fl_darker(c)); + fl_begin_loop(); + fl_vertex(-0.7, -1.0); + fl_vertex(0.1, -1.0); + fl_vertex(0.1, -0.4); + fl_vertex(0.7, -0.4); + fl_vertex(0.7, 1.0); + fl_vertex(-0.7, 1.0); + fl_end_loop(); + + fl_begin_line(); + fl_vertex(0.1, -1.0); + fl_vertex(0.7, -0.4); + fl_end_line(); +} + +void fd_file(Fl_Color c) { + Fl_Color fl = FL_LIGHT2; + Fl_Color fc = FL_DARK3; + fl_color(fc); + fl_begin_polygon(); // case + fl_vertex(-0.9, -1.0); + fl_vertex(0.9, -1.0); + fl_vertex(1.0, -0.9); + fl_vertex(1.0, 0.9); + fl_vertex(0.9, 1.0); + fl_vertex(-0.9, 1.0); + fl_vertex(-1.0, 0.9); + fl_vertex(-1.0, -0.9); + fl_end_polygon(); + + fl_color(fl_lighter(fl)); + fl_begin_polygon(); + fl_vertex(-0.7, -1.0); // slider + fl_vertex(0.7, -1.0); + fl_vertex(0.7, -0.4); + fl_vertex(-0.7, -0.4); + fl_end_polygon(); + + fl_begin_polygon(); // label + fl_vertex(-0.7, 0.0); + fl_vertex(0.7, 0.0); + fl_vertex(0.7, 1.0); + fl_vertex(-0.7, 1.0); + fl_end_polygon(); + + fl_color(fc); + fl_begin_polygon(); + fl_vertex(-0.5, -0.9); // slot + fl_vertex(-0.3, -0.9); + fl_vertex(-0.3, -0.5); + fl_vertex(-0.5, -0.5); + fl_end_polygon(); + + fl_color(fl_darker(c)); + fl_begin_loop(); + fl_vertex(-0.9, -1.0); + fl_vertex(0.9, -1.0); + fl_vertex(1.0, -0.9); + fl_vertex(1.0, 0.9); + fl_vertex(0.9, 1.0); + fl_vertex(-0.9, 1.0); + fl_vertex(-1.0, 0.9); + fl_vertex(-1.0, -0.9); + fl_end_loop(); +} + + +Fd_Layout_List::Fd_Layout_List() +: main_menu_(static_main_menu), + choice_menu_(static_choice_menu), + list_(static_suite_list), + list_size_(2), + list_capacity_(2), + list_is_static_(true), + current_suite_(0), + current_preset_(0), + filename_(NULL) +{ + fl_add_symbol("fd_beaker", fd_beaker, 1); + fl_add_symbol("fd_user", fd_user, 1); + fl_add_symbol("fd_project", fd_project, 1); + fl_add_symbol("fd_file", fd_file, 1); +} + +Fd_Layout_List::~Fd_Layout_List() { + assert(this); + if (!list_is_static_) { + ::free(main_menu_); + ::free(choice_menu_); + for (int i = 0; i < list_size_; i++) { + Fd_Layout_Suite &suite = list_[i]; + if (suite.storage_ != FD_STORE_INTERNAL) + suite.~Fd_Layout_Suite(); + } + ::free(list_); + } + if (filename_) ::free(filename_); +} + +void Fd_Layout_List::update_dialogs() { + static Fl_Menu_Item *preset_menu = NULL; + if (!preset_menu) { + preset_menu = (Fl_Menu_Item*)main_menubar->find_item(select_layout_preset_cb); + assert(preset_menu); + } + assert(this); + assert(current_suite_ >= 0 ); + assert(current_suite_ < list_size_); + assert(current_preset_ >= 0 ); + assert(current_preset_ < 3); + layout = list_[current_suite_].layout[current_preset_]; + assert(layout); + if (grid_window) { + grid_window->do_callback(grid_window, LOAD); + layout_choice->redraw(); + } + preset_menu[current_preset_].setonly(preset_menu); + main_menu_[current_suite_].setonly(main_menu_); +} + +void Fd_Layout_List::update_menu_labels() { + for (int i=0; iwrite_string("\nsnap {\n ver 1\n"); + out->write_string(" current_suite "); out->write_word(list_[current_suite()].name_); out->write_string("\n"); + out->write_string(" current_preset %d\n", current_preset()); + for (int i=0; iwrite_string("}"); +} + +void Fd_Layout_List::read(Fd_Project_Reader *in) { + const char *key; + key = in->read_word(1); + if (key && !strcmp(key, "{")) { + Fl_String cs; + int cp = 0; + for (;;) { + key = in->read_word(); + if (!key) return; + if (!strcmp(key, "ver")) { + in->read_int(); + } else if (!strcmp(key, "current_suite")) { + cs = in->read_word(); + } else if (!strcmp(key, "current_preset")) { + cp = in->read_int(); + } else if (!strcmp(key, "suite")) { + int n = add(in->filename_name()); + list_[n].read(in); + list_[n].storage(FD_STORE_PROJECT); + } else if (!strcmp(key, "}")) { + break; + } else { + in->read_word(); // unknown key, ignore, hopefully a key-value pair + } + } + current_suite(cs); + current_preset(cp); + update_dialogs(); + } else { + // old style "snap" is followed by an integer. Ignore. + } +} + +void Fd_Layout_List::current_suite(int ix) { + assert(ix >= 0); + assert(ix < list_size_); + current_suite_ = ix; + layout = list_[current_suite_].layout[current_preset_]; +} + +void Fd_Layout_List::current_suite(Fl_String arg_name) { + if (arg_name.empty()) return; + for (int i = 0; i < list_size_; ++i) { + Fd_Layout_Suite &suite = list_[i]; + if (suite.name_ && (strcmp(suite.name_, arg_name.c_str()) == 0)) { + current_suite(i); + break; + } + } +} + +void Fd_Layout_List::current_preset(int ix) { + assert(ix >= 0); + assert(ix < 3); + current_preset_ = ix; + layout = list_[current_suite_].layout[current_preset_]; +} + +/** + Allocate enough space for n entries in the list. + */ +void Fd_Layout_List::capacity(int n) { + static Fl_Menu_Item *suite_menu = NULL; + if (!suite_menu) + suite_menu = (Fl_Menu_Item*)main_menubar->find_item(layout_suite_marker); + + int old_n = list_size_; + int i; + + Fd_Layout_Suite *new_list = (Fd_Layout_Suite*)::calloc(n, sizeof(Fd_Layout_Suite)); + for (i = 0; i < old_n; i++) + new_list[i] = list_[i]; + if (!list_is_static_) ::free(list_); + list_ = new_list; + + Fl_Menu_Item *new_main_menu = (Fl_Menu_Item*)::calloc(n+1, sizeof(Fl_Menu_Item)); + for (i = 0; i < old_n; i++) + new_main_menu[i] = main_menu_[i]; + if (!list_is_static_) ::free(main_menu_); + main_menu_ = new_main_menu; + suite_menu->user_data(main_menu_); + + Fl_Menu_Item *new_choice_menu = (Fl_Menu_Item*)::calloc(n+1, sizeof(Fl_Menu_Item)); + for (i = 0; i < old_n; i++) + new_choice_menu[i] = choice_menu_[i]; + if (!list_is_static_) ::free(choice_menu_); + choice_menu_ = new_choice_menu; + layout_choice->menu(choice_menu_); + + list_capacity_ = n; + list_is_static_ = false; +} + +/** + Clone the currently selected suite and append it to the list. + Selectes the new layout and updates the UI. + */ +int Fd_Layout_List::add(const char *name) { + if (list_size_ == list_capacity_) { + capacity(list_capacity_ * 2); + } + int n = list_size_; + Fd_Layout_Suite &old_suite = list_[current_suite_]; + Fd_Layout_Suite &new_suite = list_[n]; + new_suite.init(); + new_suite.name(name); + for (int i=0; i<3; ++i) { + 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_; + if (new_storage == FD_STORE_INTERNAL) + new_storage = FD_STORE_USER; + new_suite.storage(new_storage); + main_menu_[n].label(new_suite.menu_label); + main_menu_[n].callback(main_menu_[0].callback()); + main_menu_[n].argument(n); + main_menu_[n].flags = main_menu_[0].flags; + choice_menu_[n].label(new_suite.menu_label); + list_size_++; + current_suite(n); + return n; +} + +void Fd_Layout_List::rename(const char *name) { + int n = current_suite(); + list_[n].name(name); + main_menu_[n].label(list_[n].menu_label); + choice_menu_[n].label(list_[n].menu_label); +} + +void Fd_Layout_List::remove(int ix) { + int tail = list_size_-ix-1; + if (tail) { + for (int i = ix; i < list_size_-1; i++) + list_[i] = list_[i+1]; + } + ::memmove(main_menu_+ix, main_menu_+ix+1, (tail+1) * sizeof(Fl_Menu_Item)); + ::memmove(choice_menu_+ix, choice_menu_+ix+1, (tail+1) * sizeof(Fl_Menu_Item)); + list_size_--; + if (current_suite() >= list_size_) + current_suite(list_size_ - 1); +} + +void Fd_Layout_List::remove_all(int storage) { + for (int i=list_size_-1; i>=0; --i) { + if (list_[i].storage_ == storage) + remove(i); + } +} + +// ---- Helper --------------------------------------------------------- MARK: - + +static void draw_h_arrow(int, int, int); +static void draw_v_arrow(int x, int y1, int y2); +static void draw_left_brace(const Fl_Widget *w); +static void draw_right_brace(const Fl_Widget *w); +static void draw_top_brace(const Fl_Widget *w); +static void draw_bottom_brace(const Fl_Widget *w); +static void draw_grid(int x, int y, int dx, int dy); +static void draw_width(int x, int y, int r, Fl_Align a); +static void draw_height(int x, int y, int b, Fl_Align a); + +static int nearest(int x, int left, int grid, int right=0x7fff) { + int grid_x = ((x-left+grid/2)/grid)*grid+left; + if (grid_x < left+grid/2) return left; // left+grid/2; + if (grid_x > right-grid/2) return right; // right-grid/2; + return grid_x; +} + +static bool in_window(Fd_Snap_Data &d) { + return (d.wgt && d.wgt->parent == d.win); +} + +static bool in_group(Fd_Snap_Data &d) { + return (d.wgt && d.wgt->parent && d.wgt->parent->is_group() && d.wgt->parent != d.win); +} + +static bool in_tabs(Fd_Snap_Data &d) { + return (d.wgt && d.wgt->parent && d.wgt->parent->is_tabs()); +} + +static Fl_Group *parent(Fd_Snap_Data &d) { + return (d.wgt->o->parent()); +} + +// ---- Fd_Snap_Action ------------------------------------------------- MARK: - + +/** \class Fd_Snap_Action + */ + +int Fd_Snap_Action::check_x_(Fd_Snap_Data &d, int x_ref, int x_snap) { + int dd = x_ref + d.dx - x_snap; + int d2 = abs(dd); + if (d2 > d.x_dist) return 1; + dx = d.dx_out = d.dx - dd; + ex = d.ex_out = x_snap; + if (d2 == d.x_dist) return 0; + d.x_dist = d2; + return -1; +} + +int Fd_Snap_Action::check_y_(Fd_Snap_Data &d, int y_ref, int y_snap) { + int dd = y_ref + d.dy - y_snap; + int d2 = abs(dd); + if (d2 > d.y_dist) return 1; + dy = d.dy_out = d.dy - dd; + ey = d.ey_out = y_snap; + if (d2 == d.y_dist) return 0; + d.y_dist = d2; + return -1; +} + +void Fd_Snap_Action::check_x_y_(Fd_Snap_Data &d, int x_ref, int x_snap, int y_ref, int y_snap) { + int ddx = x_ref + d.dx - x_snap; + int d2x = abs(ddx); + int ddy = y_ref + d.dy - y_snap; + int d2y = abs(ddy); + if ((d2x <= d.x_dist) && (d2y <= d.y_dist)) { + dx = d.dx_out = d.dx - ddx; + ex = d.ex_out = x_snap; + d.x_dist = d2x; + dy = d.dy_out = d.dy - ddy; + ey = d.ey_out = y_snap; + d.y_dist = d2y; + } +} + +bool Fd_Snap_Action::matches(Fd_Snap_Data &d) { + switch (type) { + case 1: return (d.drag & mask) && (eex == ex) && (d.dx == dx); + case 2: return (d.drag & mask) && (eey == ey) && (d.dy == dy); + case 3: return (d.drag & mask) && (eex == ex) && (d.dx == dx) && (eey == ey) && (d.dy == dy); + } + return false; +} + +void Fd_Snap_Action::check_all(Fd_Snap_Data &data) { + for (int i=0; list[i]; i++) { + if (list[i]->mask & data.drag) + list[i]->check(data); + } + eex = data.ex_out; + eey = data.ey_out; +} + +void Fd_Snap_Action::draw_all(Fd_Snap_Data &data) { + for (int i=0; list[i]; i++) { + if (list[i]->matches(data)) + list[i]->draw(data); + } +} + +/** Return a sensible step size for resizing a widget. */ +void Fd_Snap_Action::get_resize_stepsize(int &x_step, int &y_step) { + if ((layout->widget_inc_w > 1) && (layout->widget_inc_h > 1)) { + x_step = layout->widget_inc_w; + y_step = layout->widget_inc_h; + } else if ((layout->group_grid_x > 1) && (layout->group_grid_y > 1)) { + x_step = layout->group_grid_x; + y_step = layout->group_grid_y; + } else { + x_step = layout->window_grid_x; + y_step = layout->window_grid_y; + } +} + +/** Return a sensible step size for moving a widget. */ +void Fd_Snap_Action::get_move_stepsize(int &x_step, int &y_step) { + if ((layout->group_grid_x > 1) && (layout->group_grid_y > 1)) { + x_step = layout->group_grid_x; + y_step = layout->group_grid_y; + } else if ((layout->window_grid_x > 1) && (layout->window_grid_y > 1)) { + x_step = layout->window_grid_x; + y_step = layout->window_grid_y; + } else { + x_step = layout->widget_gap_x; + y_step = layout->widget_gap_y; + } +} + +// ---- snapping prototypes -------------------------------------------- MARK: - + +class Fd_Snap_Left : public Fd_Snap_Action { +public: + Fd_Snap_Left() { type = 1; mask = FD_LEFT|FD_DRAG; } +}; + +class Fd_Snap_Right : public Fd_Snap_Action { +public: + Fd_Snap_Right() { type = 1; mask = FD_RIGHT|FD_DRAG; } +}; + +class Fd_Snap_Top : public Fd_Snap_Action { +public: + Fd_Snap_Top() { type = 2; mask = FD_TOP|FD_DRAG; } +}; + +class Fd_Snap_Bottom : public Fd_Snap_Action { +public: + Fd_Snap_Bottom() { type = 2; mask = FD_BOTTOM|FD_DRAG; } +}; + +// ---- window snapping ------------------------------------------------ MARK: - + +class Fd_Snap_Left_Window_Edge : public Fd_Snap_Left { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { clr(); check_x_(d, d.bx, 0); } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { draw_left_brace(d.win->o); }; +}; +Fd_Snap_Left_Window_Edge snap_left_window_edge; + +class Fd_Snap_Right_Window_Edge : public Fd_Snap_Right { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { clr(); check_x_(d, d.br, d.win->o->w()); } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { draw_right_brace(d.win->o); }; +}; +Fd_Snap_Right_Window_Edge snap_right_window_edge; + +class Fd_Snap_Top_Window_Edge : public Fd_Snap_Top { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { clr(); check_y_(d, d.by, 0); } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { draw_top_brace(d.win->o); }; +}; +Fd_Snap_Top_Window_Edge snap_top_window_edge; + +class Fd_Snap_Bottom_Window_Edge : public Fd_Snap_Bottom { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { clr(); check_y_(d, d.bt, d.win->o->h()); } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { draw_bottom_brace(d.win->o); }; +}; +Fd_Snap_Bottom_Window_Edge snap_bottom_window_edge; + +class Fd_Snap_Left_Window_Margin : public Fd_Snap_Left { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_window(d)) check_x_(d, d.bx, layout->left_window_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_h_arrow(d.bx, (d.by+d.bt)/2, 0); + }; +}; +Fd_Snap_Left_Window_Margin snap_left_window_margin; + +class Fd_Snap_Right_Window_Margin : public Fd_Snap_Right { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_window(d)) check_x_(d, d.br, d.win->o->w()-layout->right_window_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_h_arrow(d.br, (d.by+d.bt)/2, d.win->o->w()-1); + }; +}; +Fd_Snap_Right_Window_Margin snap_right_window_margin; + +class Fd_Snap_Top_Window_Margin : public Fd_Snap_Top { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_window(d)) check_y_(d, d.by, layout->top_window_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_v_arrow((d.bx+d.br)/2, d.by, 0); + }; +}; +Fd_Snap_Top_Window_Margin snap_top_window_margin; + +class Fd_Snap_Bottom_Window_Margin : public Fd_Snap_Bottom { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_window(d)) check_y_(d, d.bt, d.win->o->h()-layout->bottom_window_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_v_arrow((d.bx+d.br)/2, d.bt, d.win->o->h()-1); + }; +}; +Fd_Snap_Bottom_Window_Margin snap_bottom_window_margin; + +// ---- group snapping ------------------------------------------------- MARK: - + +class Fd_Snap_Left_Group_Edge : public Fd_Snap_Left { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d)) check_x_(d, d.bx, parent(d)->x()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_left_brace(parent(d)); + }; +}; +Fd_Snap_Left_Group_Edge snap_left_group_edge; + +class Fd_Snap_Right_Group_Edge : public Fd_Snap_Right { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d)) check_x_(d, d.br, parent(d)->x() + parent(d)->w()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_right_brace(parent(d)); + }; +}; +Fd_Snap_Right_Group_Edge snap_right_group_edge; + +class Fd_Snap_Top_Group_Edge : public Fd_Snap_Top { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d)) check_y_(d, d.by, parent(d)->y()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_top_brace(parent(d)); + }; +}; +Fd_Snap_Top_Group_Edge snap_top_group_edge; + +class Fd_Snap_Bottom_Group_Edge : public Fd_Snap_Bottom { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d)) check_y_(d, d.bt, parent(d)->y() + parent(d)->h()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_bottom_brace(parent(d)); + }; +}; +Fd_Snap_Bottom_Group_Edge snap_bottom_group_edge; + + +class Fd_Snap_Left_Group_Margin : public Fd_Snap_Left { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d)) check_x_(d, d.bx, parent(d)->x() + layout->left_group_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_left_brace(parent(d)); + draw_h_arrow(d.bx, (d.by+d.bt)/2, parent(d)->x()); + }; +}; +Fd_Snap_Left_Group_Margin snap_left_group_margin; + +class Fd_Snap_Right_Group_Margin : public Fd_Snap_Right { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d)) check_x_(d, d.br, parent(d)->x()+parent(d)->w()-layout->right_group_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_right_brace(parent(d)); + draw_h_arrow(d.br, (d.by+d.bt)/2, parent(d)->x()+parent(d)->w()-1); + }; +}; +Fd_Snap_Right_Group_Margin snap_right_group_margin; + +class Fd_Snap_Top_Group_Margin : public Fd_Snap_Top { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d) && !in_tabs(d)) check_y_(d, d.by, parent(d)->y()+layout->top_group_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_top_brace(parent(d)); + draw_v_arrow((d.bx+d.br)/2, d.by, parent(d)->y()); + }; +}; +Fd_Snap_Top_Group_Margin snap_top_group_margin; + +class Fd_Snap_Bottom_Group_Margin : public Fd_Snap_Bottom { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_group(d) && !in_tabs(d)) check_y_(d, d.bt, parent(d)->y()+parent(d)->h()-layout->bottom_group_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_bottom_brace(parent(d)); + draw_v_arrow((d.bx+d.br)/2, d.bt, parent(d)->y()+parent(d)->h()-1); + }; +}; +Fd_Snap_Bottom_Group_Margin snap_bottom_group_margin; + +// ----- tabs snapping ------------------------------------------------- MARK: - + +class Fd_Snap_Top_Tabs_Margin : public Fd_Snap_Top_Group_Margin { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_tabs(d)) check_y_(d, d.by, parent(d)->y()+layout->top_tabs_margin); + } +}; +Fd_Snap_Top_Tabs_Margin snap_top_tabs_margin; + +class Fd_Snap_Bottom_Tabs_Margin : public Fd_Snap_Bottom_Group_Margin { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_tabs(d)) check_y_(d, d.bt, parent(d)->y()+parent(d)->h()-layout->bottom_tabs_margin); + } +}; +Fd_Snap_Bottom_Tabs_Margin snap_bottom_tabs_margin; + +// ----- grid snapping ------------------------------------------------- MARK: - + +class Fd_Snap_Grid : public Fd_Snap_Action { +protected: + int nearest_x, nearest_y; +public: + Fd_Snap_Grid() { type = 3; mask = FD_LEFT|FD_TOP|FD_DRAG; } + void check_grid(Fd_Snap_Data &d, int left, int grid_x, int right, int top, int grid_y, int bottom) { + if ((grid_x <= 1) || (grid_y <= 1)) return; + int suggested_x = d.bx + d.dx; + nearest_x = nearest(suggested_x, left, grid_x, right); + int suggested_y = d.by + d.dy; + nearest_y = nearest(suggested_y, top, grid_y, bottom); + if (d.drag == FD_LEFT) + check_x_(d, d.bx, nearest_x); + else if (d.drag == FD_TOP) + check_y_(d, d.by, nearest_y); + else + check_x_y_(d, d.bx, nearest_x, d.by, nearest_y); + } + bool matches(Fd_Snap_Data &d) FL_OVERRIDE { + if (d.drag == FD_LEFT) return (eex == ex); + if (d.drag == FD_TOP) return (eey == ey) && (d.dx == dx); + return (d.drag & mask) && (eex == ex) && (d.dx == dx) && (eey == ey) && (d.dy == dy); + } +}; + +class Fd_Snap_Window_Grid : public Fd_Snap_Grid { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (in_window(d)) check_grid(d, layout->left_window_margin, layout->window_grid_x, d.win->o->w()-layout->right_window_margin, + layout->top_window_margin, layout->window_grid_y, d.win->o->h()-layout->bottom_window_margin); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_grid(nearest_x, nearest_y, layout->window_grid_x, layout->window_grid_y); + }; +}; +Fd_Snap_Window_Grid snap_window_grid; + +class Fd_Snap_Group_Grid : public Fd_Snap_Grid { +public: + void check(Fd_Snap_Data &d) FL_OVERRIDE { + if (in_group(d)) { + clr(); + Fl_Widget *g = parent(d); + check_grid(d, g->x()+layout->left_group_margin, layout->group_grid_x, g->x()+g->w()-layout->right_group_margin, + g->y()+layout->top_group_margin, layout->group_grid_y, g->y()+g->h()-layout->bottom_group_margin); + } + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_grid(nearest_x, nearest_y, layout->group_grid_x, layout->group_grid_y); + }; +}; +Fd_Snap_Group_Grid snap_group_grid; + +// ----- sibling snapping ---------------------------------------------- MARK: - + +class Fd_Snap_Sibling : public Fd_Snap_Action { +protected: + Fl_Widget *best_match; +public: + Fd_Snap_Sibling() : best_match(NULL) { } + virtual int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) = 0; + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + best_match = NULL; + if (!d.wgt) return; + if (!d.wgt->parent->is_group()) return; + int dsib_min = 1024; + Fl_Group_Type *gt = (Fl_Group_Type*)d.wgt->parent; + Fl_Group *g = (Fl_Group*)gt->o; + Fl_Widget *w = d.wgt->o; + for (int i=0; ichildren(); i++) { + Fl_Widget *c = g->child(i); + if (c == w) continue; + int sret = sibling_check(d, c); + if (sret < 1) { + int dsib; + if (type==1) + dsib = abs( ((d.by+d.bt)/2+d.dy) - (c->y()+c->h()/2) ); + else + dsib = abs( ((d.bx+d.br)/2+d.dx) - (c->x()+c->w()/2) ); + if (sret == -1 || (dsib < dsib_min)) { + dsib_min = dsib; + best_match = c; + } + } + } + } +}; + +class Fd_Snap_Siblings_Left_Same : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Left_Same() { type = 1; mask = FD_LEFT|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return check_x_(d, d.bx, s->x()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_left_brace(best_match); + }; +}; +Fd_Snap_Siblings_Left_Same snap_siblings_left_same; + +class Fd_Snap_Siblings_Left : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Left() { type = 1; mask = FD_LEFT|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return fd_min(check_x_(d, d.bx, s->x()+s->w()), + check_x_(d, d.bx, s->x()+s->w()+layout->widget_gap_x) ); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_right_brace(best_match); + }; +}; +Fd_Snap_Siblings_Left snap_siblings_left; + +class Fd_Snap_Siblings_Right_Same : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Right_Same() { type = 1; mask = FD_RIGHT|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return check_x_(d, d.br, s->x()+s->w()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_right_brace(best_match); + }; +}; +Fd_Snap_Siblings_Right_Same snap_siblings_right_same; + +class Fd_Snap_Siblings_Right : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Right() { type = 1; mask = FD_RIGHT|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return fd_min(check_x_(d, d.br, s->x()), + check_x_(d, d.br, s->x()-layout->widget_gap_x)); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_left_brace(best_match); + }; +}; +Fd_Snap_Siblings_Right snap_siblings_right; + +class Fd_Snap_Siblings_Top_Same : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Top_Same() { type = 2; mask = FD_TOP|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return check_y_(d, d.by, s->y()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_top_brace(best_match); + }; +}; +Fd_Snap_Siblings_Top_Same snap_siblings_top_same; + +class Fd_Snap_Siblings_Top : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Top() { type = 2; mask = FD_TOP|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return fd_min(check_y_(d, d.by, s->y()+s->h()), + check_y_(d, d.by, s->y()+s->h()+layout->widget_gap_y)); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_bottom_brace(best_match); + }; +}; +Fd_Snap_Siblings_Top snap_siblings_top; + +class Fd_Snap_Siblings_Bottom_Same : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Bottom_Same() { type = 2; mask = FD_BOTTOM|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return check_y_(d, d.bt, s->y()+s->h()); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_bottom_brace(best_match); + }; +}; +Fd_Snap_Siblings_Bottom_Same snap_siblings_bottom_same; + +class Fd_Snap_Siblings_Bottom : public Fd_Snap_Sibling { +public: + Fd_Snap_Siblings_Bottom() { type = 2; mask = FD_BOTTOM|FD_DRAG; } + int sibling_check(Fd_Snap_Data &d, Fl_Widget *s) FL_OVERRIDE { + return fd_min(check_y_(d, d.bt, s->y()), + check_y_(d, d.bt, s->y()-layout->widget_gap_y)); + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + if (best_match) draw_top_brace(best_match); + }; +}; +Fd_Snap_Siblings_Bottom snap_siblings_bottom; + + +// ------ widget snapping ---------------------------------------------- MARK: - + +class Fd_Snap_Widget_Ideal_Width : public Fd_Snap_Action { +public: + Fd_Snap_Widget_Ideal_Width() { type = 1; mask = FD_LEFT|FD_RIGHT; } + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (!d.wgt) return; + int iw = 15, ih = 15; + d.wgt->ideal_size(iw, ih); + if (d.drag == FD_RIGHT) { + check_x_(d, d.br, d.bx+iw); + iw = layout->widget_min_w; + if (iw > 0) iw = nearest(d.br-d.bx+d.dx, layout->widget_min_w, layout->widget_inc_w); + check_x_(d, d.br, d.bx+iw); + } else { + check_x_(d, d.bx, d.br-iw); + iw = layout->widget_min_w; + if (iw > 0) iw = nearest(d.br-d.bx-d.dx, layout->widget_min_w, layout->widget_inc_w); + check_x_(d, d.bx, d.br-iw); + } + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_width(d.bx, d.bt+7, d.br, 0); + }; +}; +Fd_Snap_Widget_Ideal_Width snap_widget_ideal_width; + +class Fd_Snap_Widget_Ideal_Height : public Fd_Snap_Action { +public: + Fd_Snap_Widget_Ideal_Height() { type = 2; mask = FD_TOP|FD_BOTTOM; } + void check(Fd_Snap_Data &d) FL_OVERRIDE { + clr(); + if (!d.wgt) return; + int iw, ih; + d.wgt->ideal_size(iw, ih); + if (d.drag == FD_BOTTOM) { + check_y_(d, d.bt, d.by+ih); + ih = layout->widget_min_h; + if (ih > 0) ih = nearest(d.bt-d.by+d.dy, layout->widget_min_h, layout->widget_inc_h); + check_y_(d, d.bt, d.by+ih); + } else { + check_y_(d, d.by, d.bt-ih); + ih = layout->widget_min_h; + if (ih > 0) ih = nearest(d.bt-d.by-d.dy, layout->widget_min_h, layout->widget_inc_h); + check_y_(d, d.by, d.bt-ih); + } + } + void draw(Fd_Snap_Data &d) FL_OVERRIDE { + draw_height(d.br+7, d.by, d.bt, 0); + }; +}; +Fd_Snap_Widget_Ideal_Height snap_widget_ideal_height; + +// ---- snap actions list ---------------------------------------------- MARK: - + +Fd_Snap_Action *Fd_Snap_Action::list[] = { + &snap_left_window_edge, + &snap_right_window_edge, + &snap_top_window_edge, + &snap_bottom_window_edge, + + &snap_left_window_margin, + &snap_right_window_margin, + &snap_top_window_margin, + &snap_bottom_window_margin, + + &snap_window_grid, + &snap_group_grid, + + &snap_left_group_edge, + &snap_right_group_edge, + &snap_top_group_edge, + &snap_bottom_group_edge, + + &snap_left_group_margin, + &snap_right_group_margin, + &snap_top_group_margin, + &snap_bottom_group_margin, + + &snap_top_tabs_margin, + &snap_bottom_tabs_margin, + + &snap_siblings_left_same, &snap_siblings_left, + &snap_siblings_right_same, &snap_siblings_right, + &snap_siblings_top_same, &snap_siblings_top, + &snap_siblings_bottom_same, &snap_siblings_bottom, + + &snap_widget_ideal_width, + &snap_widget_ideal_height, + + NULL +}; + +// ---- draw alignment marks ------------------------------------------- MARK: - + +static void draw_v_arrow(int x, int y1, int y2) { + int dy = (y1>y2) ? -1 : 1 ; + fl_yxline(x, y1, y2); + fl_xyline(x-4, y2, x+4); + fl_line(x-2, y2-dy*5, x, y2-dy); + fl_line(x+2, y2-dy*5, x, y2-dy); +} + +static void draw_h_arrow(int x1, int y, int x2) { + int dx = (x1>x2) ? -1 : 1 ; + fl_xyline(x1, y, x2); + fl_yxline(x2, y-4, y+4); + fl_line(x2-dx*5, y-2, x2-dx, y); + fl_line(x2-dx*5, y+2, x2-dx, y); +} + +static void draw_top_brace(const Fl_Widget *w) { + int x = w->as_window() ? 0 : w->x(); + int y = w->as_window() ? 0 : w->y(); + fl_yxline(x, y-2, y+6); + fl_yxline(x+w->w()-1, y-2, y+6); + fl_xyline(x-2, y, x+w->w()+1); +} + +static void draw_left_brace(const Fl_Widget *w) { + int x = w->as_window() ? 0 : w->x(); + int y = w->as_window() ? 0 : w->y(); + fl_xyline(x-2, y, x+6); + fl_xyline(x-2, y+w->h()-1, x+6); + fl_yxline(x, y-2, y+w->h()+1); +} + +static void draw_right_brace(const Fl_Widget *w) { + int x = w->as_window() ? w->w() - 1 : w->x() + w->w() - 1; + int y = w->as_window() ? 0 : w->y(); + fl_xyline(x-6, y, x+2); + fl_xyline(x-6, y+w->h()-1, x+2); + fl_yxline(x, y-2, y+w->h()+1); +} + +static void draw_bottom_brace(const Fl_Widget *w) { + int x = w->as_window() ? 0 : w->x(); + int y = w->as_window() ? w->h() - 1 : w->y() + w->h() - 1; + fl_yxline(x, y-6, y+2); + fl_yxline(x+w->w()-1, y-6, y+2); + fl_xyline(x-2, y, x+w->w()+1); +} + +static void draw_height(int x, int y, int b, Fl_Align a) { + char buf[16]; + int h = b - y; + sprintf(buf, "%d", h); + fl_font(FL_HELVETICA, 9); + int lw = (int)fl_width(buf); + int lx; + + b --; + if (h < 30) { + // Move height to the side... + if (a == FL_ALIGN_LEFT) lx = x - lw - 2; + else lx = x + 2; + fl_yxline(x, y, b); + } else { + // Put height inside the arrows... + if (a == FL_ALIGN_LEFT) lx = x - lw + 2; + else lx = x - lw / 2; + fl_yxline(x, y, y + (h - 11) / 2); + fl_yxline(x, y + (h + 11) / 2, b); + } + + // Draw the height... + fl_draw(buf, lx, y + (h + 7) / 2); + + // Draw the arrowheads... + fl_line(x-2, y+5, x, y+1, x+2, y+5); + fl_line(x-2, b-5, x, b-1, x+2, b-5); + + // Draw the end lines... + fl_xyline(x - 4, y, x + 4); + fl_xyline(x - 4, b, x + 4); +} + +static void draw_width(int x, int y, int r, Fl_Align a) { + char buf[16]; + int w = r-x; + sprintf(buf, "%d", w); + fl_font(FL_HELVETICA, 9); + int lw = (int)fl_width(buf); + int ly = y + 4; + + r--; + + if (lw > (w - 20)) { + // Move width above/below the arrows... + if (a == FL_ALIGN_TOP) ly -= 10; + else ly += 10; + + fl_xyline(x, y, r); + } else { + // Put width inside the arrows... + fl_xyline(x, y, x + (w - lw - 2) / 2); + fl_xyline(x + (w + lw + 2) / 2, y, r); + } + + // Draw the width... + fl_draw(buf, x + (w - lw) / 2, ly-2); + + // Draw the arrowheads... + fl_line(x+5, y-2, x+1, y, x+5, y+2); + fl_line(r-5, y-2, r-1, y, r-5, y+2); + + // Draw the end lines... + fl_yxline(x, y - 4, y + 4); + fl_yxline(r, y - 4, y + 4); +} + +static void draw_grid(int x, int y, int dx, int dy) { + int dx2 = 1, dy2 = 1; + const int n = 2; + for (int i=-n; i<=n; i++) { + for (int j=-n; j<=n; j++) { + if (abs(i)+abs(j) < 4) { + int xx = x + i*dx , yy = y + j*dy; + fl_xyline(xx-dx2, yy, xx+dx2); + fl_yxline(xx, yy-dy2, yy+dy2); + } + } + } +} diff --git a/fluid/Fd_Snap_Action.h b/fluid/Fd_Snap_Action.h new file mode 100644 index 000000000..d107e957a --- /dev/null +++ b/fluid/Fd_Snap_Action.h @@ -0,0 +1,168 @@ +// +// Snap action header file for the Fast Light Tool Kit (FLTK). +// +// Copyright 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 +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#ifndef _FLUID_FD_SNAP_ACTION_H +#define _FLUID_FD_SNAP_ACTION_H + +#include "Fl_Window_Type.h" + +struct Fl_Menu_Item; + +enum { + FD_STORE_INTERNAL, + FD_STORE_USER, + FD_STORE_PROJECT, + FD_STORE_FILE, +}; + +class Fd_Layout_Preset { +public: + int left_window_margin; + int right_window_margin; + int top_window_margin; + int bottom_window_margin; + int window_grid_x; + int window_grid_y; + + int left_group_margin; + int right_group_margin; + int top_group_margin; + int bottom_group_margin; + int group_grid_x; + int group_grid_y; + + int top_tabs_margin; + int bottom_tabs_margin; + + int widget_min_w; + int widget_inc_w; + int widget_gap_x; + int widget_min_h; + int widget_inc_h; + int widget_gap_y; + + int labelfont; + int labelsize; + int textfont; + int textsize; + + void write(Fl_Preferences &prefs); + void read(Fl_Preferences &prefs); + void write(Fd_Project_Writer*); + void read(Fd_Project_Reader*); +}; + +extern Fd_Layout_Preset *layout; + +class Fd_Layout_Suite { +public: + char *name_; + char *menu_label; + Fd_Layout_Preset *layout[3]; // application, dialog, toolbox; + int storage_; + 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 name(const char *n); + void init(); + ~Fd_Layout_Suite(); +public: + +}; + +class Fd_Layout_List { +public: + Fl_Menu_Item *main_menu_; + Fl_Menu_Item *choice_menu_; + Fd_Layout_Suite *list_; + int list_size_; + int list_capacity_; + bool list_is_static_; + int current_suite_; + int current_preset_; + char *filename_; +public: + Fd_Layout_List(); + ~Fd_Layout_List(); + void update_dialogs(); + void update_menu_labels(); + int current_suite() const { return current_suite_; } + void current_suite(int ix); + void current_suite(Fl_String); + int current_preset() const { return current_preset_; } + void current_preset(int ix); + Fd_Layout_Suite &operator[](int ix) { return list_[ix]; } + int add(const char *name); + void rename(const char *name); + void capacity(int); + + int load(const char *filename); + int save(const char *filename); + void write(Fl_Preferences &prefs, int storage); + void read(Fl_Preferences &prefs, int 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); + Fd_Layout_Preset *at(int); + int size(); +}; + +extern Fd_Layout_List g_layout_list; + +/** + \brief Structure holding all the data to perform interactive alignment operations. + */ +typedef struct Fd_Snap_Data { + int dx, dy; ///< distance of the mouse from its initial PUSH event + int bx, by, br, bt; ///< bounding box of the original push event or current bounding box when drawing + int drag; ///< drag event mask + int x_dist, y_dist; ///< current closest snapping distance in x and y + int dx_out, dy_out; ///< current closest snapping point as a delta + Fl_Widget_Type *wgt; ///< first selected widget + Fl_Window_Type *win; ///< window that handles the drag action + int ex_out, ey_out; ///< chosen snap position +} Fd_Snap_Data; + +/** + \brief Find points of interest when moving the bounding box of all selected widgets. + */ +class Fd_Snap_Action { +protected: + int check_x_(Fd_Snap_Data &d, int x_ref, int x_snap); + int check_y_(Fd_Snap_Data &d, int y_ref, int y_snap); + void check_x_y_(Fd_Snap_Data &d, int x_ref, int x_snap, int y_ref, int y_snap); + void clr() { ex = dx = 0x7fff; } +public: + int ex, ey, dx, dy, type, mask; + Fd_Snap_Action() : ex(0x7fff), ey(0x7fff), dx(128), dy(128), type(0), mask(0) { } + virtual void check(Fd_Snap_Data &d) = 0; + virtual void draw(Fd_Snap_Data &d) { } + virtual bool matches(Fd_Snap_Data &d); +public: + static int eex, eey; + static Fd_Snap_Action *list[]; + static void check_all(Fd_Snap_Data &d); + static void draw_all(Fd_Snap_Data &d); + static void get_resize_stepsize(int &x_step, int &y_step); + static void get_move_stepsize(int &x_step, int &y_step); +}; + +#endif // _FLUID_FD_SNAP_ACTION_H diff --git a/fluid/Fl_Group_Type.h b/fluid/Fl_Group_Type.h index e8c879141..e0c52b5c9 100644 --- a/fluid/Fl_Group_Type.h +++ b/fluid/Fl_Group_Type.h @@ -137,11 +137,6 @@ public: class Fl_Tabs_Type : public Fl_Group_Type { public: - void ideal_spacing(int &x, int &y) FL_OVERRIDE { - x = 10; - fl_font(o->labelfont(), o->labelsize()); - y = fl_height() + o->labelsize() - 6; - } const char *type_name() FL_OVERRIDE {return tabs_type_name;} const char *alt_type_name() FL_OVERRIDE {return "fltk::TabGroup";} Fl_Widget *widget(int X,int Y,int W,int H) FL_OVERRIDE { @@ -152,6 +147,7 @@ public: void remove_child(Fl_Type*) FL_OVERRIDE; int pixmapID() FL_OVERRIDE { return 13; } Fl_Widget *enter_live_mode(int top=0) FL_OVERRIDE; + int is_tabs() const FL_OVERRIDE {return 1;} }; // ---- Fl_Scroll_Type ------------------------------------------------- MARK: - diff --git a/fluid/Fl_Menu_Type.cxx b/fluid/Fl_Menu_Type.cxx index 2f89c9572..604b9f9fd 100644 --- a/fluid/Fl_Menu_Type.cxx +++ b/fluid/Fl_Menu_Type.cxx @@ -164,7 +164,8 @@ Fl_Type *Fl_Menu_Item_Type::make(Strategy strategy) { } if (!o) { o = new Fl_Button(0,0,100,20); // create template widget - o->labelsize(Fl_Widget_Type::default_size); + o->labelsize(layout->labelsize); + o->labelfont(layout->labelfont); } Fl_Menu_Item_Type* t = submenuflag ? new Fl_Submenu_Type() : new Fl_Menu_Item_Type(); diff --git a/fluid/Fl_Type.cxx b/fluid/Fl_Type.cxx index c3b1cbbf4..9ca23a7af 100644 --- a/fluid/Fl_Type.cxx +++ b/fluid/Fl_Type.cxx @@ -34,6 +34,7 @@ copied or otherwise examined. #include "Fl_Type.h" #include "fluid.h" +#include "Fd_Snap_Action.h" #include "Fl_Function_Type.h" #include "Fl_Widget_Type.h" #include "Fl_Window_Type.h" @@ -193,6 +194,8 @@ void delete_all(int selected_only) { shell_settings_write(); widget_browser->hposition(0); widget_browser->vposition(0); + g_layout_list.remove_all(FD_STORE_PROJECT); + g_layout_list.update_dialogs(); } selection_changed(0); widget_browser->redraw(); diff --git a/fluid/Fl_Type.h b/fluid/Fl_Type.h index d52ffa5f7..763a29d26 100644 --- a/fluid/Fl_Type.h +++ b/fluid/Fl_Type.h @@ -160,6 +160,7 @@ public: virtual int is_menu_item() const {return 0;} virtual int is_menu_button() const {return 0;} virtual int is_group() const {return 0;} + virtual int is_tabs() const {return 0;} virtual int is_flex() const {return 0;} virtual int is_window() const {return 0;} virtual int is_code() const {return 0;} diff --git a/fluid/Fl_Widget_Type.cxx b/fluid/Fl_Widget_Type.cxx index 3fb265975..dad196b4f 100644 --- a/fluid/Fl_Widget_Type.cxx +++ b/fluid/Fl_Widget_Type.cxx @@ -1,7 +1,7 @@ // // Widget type code 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 @@ -49,8 +49,6 @@ // instance, sets the widget pointers, and makes all the display // update correctly... -int Fl_Widget_Type::default_size = FL_NORMAL_SIZE; - int Fl_Widget_Type::is_widget() const {return 1;} int Fl_Widget_Type::is_public() const {return public_;} @@ -82,17 +80,6 @@ Fl_Widget_Type::ideal_size(int &w, int &h) { if (h < 15) h = 15; } -// Return the ideal widget spacing... -void -Fl_Widget_Type::ideal_spacing(int &x, int &y) { - if (o->labelsize() < 10) - x = y = 0; - else if (o->labelsize() < 14) - x = y = 5; - else - x = y = 10; -} - /** Make a new Widget node. \param[in] strategy is kAddAsLastChild or kAddAfterCurrent @@ -146,16 +133,6 @@ Fl_Type *Fl_Widget_Type::make(Strategy strategy) { W = H = B; } - // satisfy the grid requirements (otherwise it edits really strangely): - if (gridx>1) { - X = (X/gridx)*gridx; - W = ((W-1)/gridx+1)*gridx; - } - if (gridy>1) { - Y = (Y/gridy)*gridy; - H = ((H-1)/gridy+1)*gridy; - } - // Construct the Fl_Type: Fl_Widget_Type *t = _make(); if (!o) o = widget(0,0,100,100); // create template widget @@ -1366,6 +1343,7 @@ void labelfont_cb(Fl_Choice* i, void *v) { } else { int mod = 0; int n = i->value(); + if (n <= 0) n = layout->labelfont; for (Fl_Type *o = Fl_Type::first; o; o = o->next) { if (o->selected && o->is_widget()) { Fl_Widget_Type* q = (Fl_Widget_Type*)o; @@ -1385,7 +1363,7 @@ void labelsize_cb(Fl_Value_Input* i, void *v) { } else { int mod = 0; n = int(i->value()); - if (n <= 0) n = Fl_Widget_Type::default_size; + if (n <= 0) n = layout->labelsize; for (Fl_Type *o = Fl_Type::first; o; o = o->next) { if (o->selected && o->is_widget()) { Fl_Widget_Type* q = (Fl_Widget_Type*)o; @@ -1842,6 +1820,7 @@ void textfont_cb(Fl_Choice* i, void* v) { } else { int mod = 0; n = (Fl_Font)i->value(); + if (n <= 0) n = layout->textfont; for (Fl_Type *o = Fl_Type::first; o; o = o->next) { if (o->selected && o->is_widget()) { Fl_Widget_Type* q = (Fl_Widget_Type*)o; @@ -1862,7 +1841,7 @@ void textsize_cb(Fl_Value_Input* i, void* v) { } else { int mod = 0; s = int(i->value()); - if (s <= 0) s = Fl_Widget_Type::default_size; + if (s <= 0) s = layout->textsize; for (Fl_Type *o = Fl_Type::first; o; o = o->next) { if (o->selected && o->is_widget()) { Fl_Widget_Type* q = (Fl_Widget_Type*)o; @@ -2635,11 +2614,33 @@ static void load_panel() { the_panel->hide(); } +extern Fl_Window *widgetbin_panel; + // This is called when user double-clicks an item, open or update the panel: void Fl_Widget_Type::open() { - if (!the_panel) the_panel = make_widget_panel(); + bool adjust_position = false; + if (!the_panel) { + the_panel = make_widget_panel(); + adjust_position = true; + } load_panel(); - if (numselected) the_panel->show(); + if (numselected) { + the_panel->show(); + if (adjust_position) { + if (widgetbin_panel && widgetbin_panel->visible()) { + if ( (the_panel->x()+the_panel->w() > widgetbin_panel->x()) + && (the_panel->x() < widgetbin_panel->x()+widgetbin_panel->w()) + && (the_panel->y()+the_panel->h() > widgetbin_panel->y()) + && (the_panel->y() < widgetbin_panel->y()+widgetbin_panel->h()) ) + { + if (widgetbin_panel->y()+widgetbin_panel->h()+the_panel->h() > Fl::h()) + the_panel->position(the_panel->x(), widgetbin_panel->y()-the_panel->h()-30); + else + the_panel->position(the_panel->x(), widgetbin_panel->y()+widgetbin_panel->h()+30); + } + } + } + } } extern void redraw_overlays(); diff --git a/fluid/Fl_Widget_Type.h b/fluid/Fl_Widget_Type.h index a7bc0f798..b41ba0e53 100644 --- a/fluid/Fl_Widget_Type.h +++ b/fluid/Fl_Widget_Type.h @@ -61,8 +61,6 @@ protected: Fl_Widget *live_widget; public: - static int default_size; - const char *xclass; // junk string, used for shortcut Fl_Widget *o; int public_; @@ -111,7 +109,6 @@ public: void copy_properties() FL_OVERRIDE; virtual void ideal_size(int &w, int &h); - virtual void ideal_spacing(int &x, int &y); ~Fl_Widget_Type(); void redraw(); diff --git a/fluid/Fl_Window_Type.cxx b/fluid/Fl_Window_Type.cxx index 78c66cbde..570af58e2 100644 --- a/fluid/Fl_Window_Type.cxx +++ b/fluid/Fl_Window_Type.cxx @@ -1,11 +1,11 @@ // -// Window type code for the Fast Light Tool Kit (FLTK). +// Window type code file for the Fast Light Tool Kit (FLTK). // // The widget describing an Fl_Window. This is also all the code // for interacting with the overlay, which allows the user to // select, move, and resize the children widgets. // -// Copyright 1998-2018 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 @@ -29,6 +29,7 @@ #include "code.h" #include "widget_panel.h" #include "factory.h" +#include "Fd_Snap_Action.h" #include #include @@ -46,8 +47,6 @@ extern Fl_Preferences fluid_prefs; -inline int fl_min(int a, int b) { return (a < b ? a : b); } - // Update the XYWH values in the widget panel... static void update_xywh() { if (current_widget && current_widget->is_widget()) { @@ -63,58 +62,6 @@ static void update_xywh() { } } -void guides_cb(Fl_Check_Button *i, long) { - show_guides = i->value(); - fluid_prefs.set("show_guides", show_guides); - - for (Fl_Type *p = Fl_Type::first; p; p = p->next) { - if (p->is_window()) { - Fl_Window_Type *w = (Fl_Window_Type *)p; - ((Fl_Overlay_Window *)(w->o))->redraw_overlay(); - } - } -} - -void grid_cb(Fl_Int_Input *i, long v) { - int n = atoi(i->value()); - if (n < 0) n = 0; - switch (v) { - case 1: - gridx = n; - fluid_prefs.set("gridx", n); - break; - case 2: - gridy = n; - fluid_prefs.set("gridy", n); - break; - case 3: - snap = n; - fluid_prefs.set("snap", n); - break; - } - - // Next go through all of the windows in the project and set the - // stepping for resizes... - Fl_Type *p; - Fl_Window_Type *w; - - for (p = Fl_Type::first; p; p = p->next) { - if (p->is_window()) { - w = (Fl_Window_Type *)p; - ((Fl_Window *)(w->o))->size_range(gridx, gridy, Fl::w(), Fl::h()); - } - } -} - -// Set default widget sizes... -void default_widget_size_cb(Fl_Round_Button *b, long size) { - // Update the "normal" text size of new widgets... - b->setonly(); - Fl_Widget_Type::default_size = (int)size; - fluid_prefs.set("widget_size", Fl_Widget_Type::default_size); -} - - void i18n_type_cb(Fl_Choice *c, void *) { undo_checkpoint(); @@ -236,18 +183,6 @@ void show_project_cb(Fl_Widget *, void *) { } void show_grid_cb(Fl_Widget *, void *) { - char buf[128]; - sprintf(buf,"%d",gridx); horizontal_input->value(buf); - sprintf(buf,"%d",gridy); vertical_input->value(buf); - sprintf(buf,"%d",snap); snap_input->value(buf); - guides_toggle->value(show_guides); - int s = Fl_Widget_Type::default_size; - if (s<=8) def_widget_size[0]->setonly(); - else if (s<=11) def_widget_size[1]->setonly(); - else if (s<=14) def_widget_size[2]->setonly(); - else if (s<=18) def_widget_size[3]->setonly(); - else if (s<=24) def_widget_size[4]->setonly(); - else if (s<=32) def_widget_size[5]->setonly(); grid_window->hotspot(grid_window); grid_window->show(); } @@ -262,6 +197,7 @@ void header_input_cb(Fl_Input* i, void*) { set_modflag(1); g_project.header_file_name = i->value(); } + void code_input_cb(Fl_Input* i, void*) { if (strcmp(g_project.code_file_name.c_str(), i->value())) set_modflag(1); @@ -370,6 +306,7 @@ uchar *Overlay_Window::read_image(int &ww, int &hh) { void Overlay_Window::draw_overlay() { window->draw_overlay(); } + int Overlay_Window::handle(int e) { int ret = window->handle(e); if (ret==0) { @@ -383,7 +320,7 @@ int Overlay_Window::handle(int e) { } /** - Make and add a new WIndow node. + Make and add a new Window node. \param[in] strategy is kAddAsLastChild or kAddAfterCurrent \return new node */ @@ -399,9 +336,6 @@ Fl_Type *Fl_Window_Type::make(Strategy strategy) { this->o = new Fl_Window(100,100); Fl_Group::current(0); } - // Set the size ranges for this window; in order to avoid opening the - // X display we use an arbitrary maximum size... - ((Fl_Window *)(this->o))->size_range(gridx, gridy, 6144, 4096); myo->factory = this; myo->drag = 0; myo->numselected = 0; @@ -451,9 +385,7 @@ void Fl_Window_Type::open() { w->show(); w->resizable(p); } - w->image(Fl::scheme_bg_); - w->size_range(gridx, gridy, Fl::w(), Fl::h()); } // Read an image of the window @@ -564,42 +496,33 @@ void Overlay_Window::resize(int X,int Y,int W,int H) { // nearest multiple of gridsize, and snap to original position void Fl_Window_Type::newdx() { int mydx, mydy; - if (Fl::event_state(FL_ALT) || !snap) { - mydx = mx-x1; - mydy = my-y1; + mydx = mx-x1; + mydy = my-y1; - if (abs(mydx) < 2 && abs(mydy) < 2) mydx = mydy = 0; - } else { - int dx0 = mx-x1; - int ix = (drag&RIGHT) ? br : bx; - mydx = gridx ? ((ix+dx0+gridx/2)/gridx)*gridx - ix : dx0; - if (dx0 > snap) { - if (mydx < 0) mydx = 0; - } else if (dx0 < -snap) { - if (mydx > 0) mydx = 0; - } else - mydx = 0; - int dy0 = my-y1; - int iy = (drag&BOTTOM) ? by : bt; - mydy = gridy ? ((iy+dy0+gridy/2)/gridy)*gridy - iy : dy0; - if (dy0 > snap) { - if (mydy < 0) mydy = 0; - } else if (dy0 < -snap) { - if (mydy > 0) mydy = 0; - } else - mydy = 0; - } - - if (!(drag & (DRAG | BOX | LEFT | RIGHT))) { + if (!(drag & (FD_DRAG | FD_BOX | FD_LEFT | FD_RIGHT))) { mydx = 0; dx = 0; } - if (!(drag & (DRAG | BOX | TOP | BOTTOM))) { + if (!(drag & (FD_DRAG | FD_BOX | FD_TOP | FD_BOTTOM))) { mydy = 0; dy = 0; } + if (show_guides && (drag & (FD_DRAG|FD_TOP|FD_LEFT|FD_BOTTOM|FD_RIGHT))) { + Fl_Type *selection = 0L; // special power for the first selected widget + for (Fl_Type *q=next; q && q->level>level; q = q->next) { + if (q->selected && q->is_widget() && !q->is_menu_item()) { + selection = q; + break; + } + } + Fd_Snap_Data data = { mydx, mydy, bx, by, br, bt, drag, 4, 4, mydx, mydy, (Fl_Widget_Type*)selection, this }; + Fd_Snap_Action::check_all(data); + if (data.x_dist < 4) mydx = data.dx_out; + if (data.y_dist < 4) mydy = data.dy_out; + } + if (dx != mydx || dy != mydy) { dx = mydx; dy = mydy; ((Overlay_Window *)o)->redraw_overlay(); @@ -613,34 +536,34 @@ void Fl_Window_Type::newposition(Fl_Widget_Type *myo,int &X,int &Y,int &R,int &T R = X+myo->o->w(); T = Y+myo->o->h(); if (!drag) return; - if (drag&DRAG) { + if (drag&FD_DRAG) { X += dx; Y += dy; R += dx; T += dy; } else { - if (drag&LEFT) { + if (drag&FD_LEFT) { if (X==bx) { X += dx; } else { if (Xbr+dx) R = br+dx; } } - if (drag&BOTTOM) { + if (drag&FD_BOTTOM) { if (T==bt) { T += dy; } else { @@ -652,118 +575,6 @@ void Fl_Window_Type::newposition(Fl_Widget_Type *myo,int &X,int &Y,int &R,int &T if (Ty2) ? -1 : 1 ; - fl_yxline(x, y1, y2); - fl_xyline(x-4, y2, x+4); - fl_line(x-2, y2-dy*5, x, y2-dy); - fl_line(x+2, y2-dy*5, x, y2-dy); -} - -static void draw_h_arrow(int x1, int y, int x2) { - int dx = (x1>x2) ? -1 : 1 ; - fl_xyline(x1, y, x2); - fl_yxline(x2, y-4, y+4); - fl_line(x2-dx*5, y-2, x2-dx, y); - fl_line(x2-dx*5, y+2, x2-dx, y); -} - -static void draw_top_brace(const Fl_Widget *w) { - fl_yxline(w->x(), w->y()-2, w->y()+6); - fl_yxline(w->x()+w->w()-1, w->y()-2, w->y()+6); - fl_xyline(w->x()-2, w->y(), w->x()+w->w()+1); -} - -static void draw_left_brace(const Fl_Widget *w) { - fl_xyline(w->x()-2, w->y(), w->x()+6); - fl_xyline(w->x()-2, w->y()+w->h()-1, w->x()+6); - fl_yxline(w->x(), w->y()-2, w->y()+w->h()+1); -} - -static void draw_right_brace(const Fl_Widget *w) { - int xx = w->x() + w->w() - 1; - fl_xyline(xx-6, w->y(), xx+2); - fl_xyline(xx-6, w->y()+w->h()-1, xx+2); - fl_yxline(xx, w->y()-2, w->y()+w->h()+1); -} - -static void draw_bottom_brace(const Fl_Widget *w) { - int yy = w->y() + w->h() - 1; - fl_yxline(w->x(), yy-6, yy+2); - fl_yxline(w->x()+w->w()-1, yy-6, yy+2); - fl_xyline(w->x()-2, yy, w->x()+w->w()+1); -} - -static void draw_height(int x, int y, int b, Fl_Align a) { - char buf[16]; - int h = b - y; - sprintf(buf, "%d", h); - fl_font(FL_HELVETICA, 9); - int lw = (int)fl_width(buf); - int lx; - - b --; - if (h < 30) { - // Move height to the side... - if (a == FL_ALIGN_LEFT) lx = x - lw - 2; - else lx = x + 2; - - fl_yxline(x, y, b); - } else { - // Put height inside the arrows... - lx = x - lw / 2; - - fl_yxline(x, y, y + (h - 11) / 2); - fl_yxline(x, y + (h + 11) / 2, b); - } - - // Draw the height... - fl_draw(buf, lx, y + (h + 9) / 2); - - // Draw the arrowheads... - fl_line(x-2, y+5, x, y+1, x+2, y+5); - fl_line(x-2, b-5, x, b-1, x+2, b-5); - - // Draw the end lines... - fl_xyline(x - 4, y, x + 4); - fl_xyline(x - 4, b, x + 4); -} - -static void draw_width(int x, int y, int r, Fl_Align a) { - char buf[16]; - int w = r-x; - sprintf(buf, "%d", w); - fl_font(FL_HELVETICA, 9); - int lw = (int)fl_width(buf); - int ly = y + 4; - - r --; - - if (lw > (w - 20)) { - // Move width above/below the arrows... - if (a == FL_ALIGN_TOP) ly -= 10; - else ly += 10; - - fl_xyline(x, y, r); - } else { - // Put width inside the arrows... - fl_xyline(x, y, x + (w - lw - 2) / 2); - fl_xyline(x + (w + lw + 2) / 2, y, r); - } - - // Draw the width... - fl_draw(buf, x + (w - lw) / 2, ly); - - // Draw the arrowheads... - fl_line(x+5, y-2, x+1, y, x+5, y+2); - fl_line(r-5, y-2, r-1, y, r-5, y+2); - - // Draw the end lines... - fl_yxline(x, y - 4, y + 4); - fl_yxline(r, y - 4, y + 4); -} - void Fl_Window_Type::draw_overlay() { if (recalc) { bx = o->w(); by = o->h(); br = 0; bt = 0; @@ -781,7 +592,7 @@ void Fl_Window_Type::draw_overlay() { sx = bx; sy = by; sr = br; st = bt; } fl_color(FL_RED); - if (drag==BOX && (x1 != mx || y1 != my)) { + if (drag==FD_BOX && (x1 != mx || y1 != my)) { int x = x1; int r = mx; if (x > r) {x = mx; r = x1;} int y = y1; int b = my; if (y > b) {y = my; b = y1;} fl_rect(x,y,r-x,b-y); @@ -792,10 +603,10 @@ void Fl_Window_Type::draw_overlay() { int mybx,myby,mybr,mybt; int mysx,mysy,mysr,myst; mybx = mysx = o->w(); myby = mysy = o->h(); mybr = mysr = 0; mybt = myst = 0; - Fl_Type *selection = 0L; // used to store the one selected widget (if n==1) + Fl_Type *selection = 0L; // special power for the first selected widget for (Fl_Type *q=next; q && q->level>level; q = q->next) if (q->selected && q->is_widget() && !q->is_menu_item()) { - selection = q; + if (!selection) selection = q; Fl_Widget_Type* myo = (Fl_Widget_Type*)q; int x,y,r,t; newposition(myo,x,y,r,t); @@ -843,293 +654,6 @@ void Fl_Window_Type::draw_overlay() { } if (selected) return; - if (show_guides && drag) { - // draw overlays for UI Guideline distances - // - check for distance to the window edge - // * FLTK suggests 10 pixels from the edge - int d; - int xsp, ysp; - int mybx_bak = mybx, myby_bak = myby, mybr_bak = mybr, mybt_bak = mybt; - Fl_Widget_Type *mysel = (Fl_Widget_Type *)selection; - - - ideal_spacing(xsp, ysp); - - if (drag) { - // Check top spacing... - if (abs(d = myby - ysp) < 3) { - dy -= d; - if (drag & DRAG) mybt -= d; - myby -= d; - draw_v_arrow(mybx+5, myby, 0); - } - - // Check bottom spacing... - if (abs(d = o->h() - mybt - ysp) < 3) { - dy += d; - if (drag & DRAG) myby += d; - mybt += d; - draw_v_arrow(mybx+5, mybt, o->h()); - } - - // Check left spacing... - if (abs(d = mybx - xsp) < 3) { - dx -= d; - if (drag & DRAG) mybr -= d; - mybx -= d; - draw_h_arrow(mybx, myby+5, 0); - } - - // Check right spacing... - if (abs(d = o->w() - mybr - xsp) < 3) { - dx += d; - if (drag & DRAG) mybx += d; - mybr += d; - draw_h_arrow(mybr, myby+5, o->w()); - } - } - - if (numselected==1 && selection && !(drag & DRAG)) { - // Check ideal sizes - int x,y,r,t; - newposition(mysel,x,y,r,t); - int w = r-x; - int h = t-y; - int iw = w, ih = h; - - mysel->ideal_size(iw, ih); - - if (drag & (TOP | BOTTOM)) { - // Check height - if (abs(d = ih - h) < 5) { - // Resize height - if (drag & TOP) { - myby -= d; - y -= d; - dy -= d; - } else { - mybt += d; - t += d; - dy += d; - } - } - - // Draw height guide - draw_height(x < 50 ? x+10 : x-10, y, t, - x < 50 ? FL_ALIGN_RIGHT : FL_ALIGN_LEFT); - } - - if (drag & (LEFT | RIGHT)) { - // Check width - if (abs(d = iw - w) < 5) { - // Resize width - if (drag & LEFT) { - mybx -= d; - x -= d; - dx -= d; - } else { - mybr += d; - r += d; - dx += d; - } - } - - // Draw width guide - draw_width(x, y < 50 ? y+10 : y-10, r, - y < 50 ? FL_ALIGN_BOTTOM : FL_ALIGN_TOP); - } - } - - // Check spacing and alignment between individual widgets - if (drag && selection && selection->is_widget()) { - for (Fl_Type *q=next; q && q->level>level; q = q->next) - if (q != selection && q->is_widget()) { - Fl_Widget_Type *qw = (Fl_Widget_Type*)q; - // Only check visible widgets... - if (!qw->o->visible_r()) continue; - - // Get bounding box of widget... - int qx = qw->o->x(); - int qr = qw->o->x() + qw->o->w(); - int qy = qw->o->y(); - int qt = qw->o->y() + qw->o->h(); - - if (!(qw->o->align() & FL_ALIGN_INSIDE)) { - // Adjust top/bottom for top/bottom labels... - int ww, hh; - ww = qw->o->w(); - hh = qw->o->labelsize(); - qw->o->measure_label(ww, hh); - if (qw->o->align() & FL_ALIGN_TOP) qy -= hh; - if (qw->o->align() & FL_ALIGN_BOTTOM) qt += hh; - } - - // Do horizontal alignment when the widget is within 25 - // pixels vertically... - if (fl_min(abs(qy - mysel->o->y() - mysel->o->h()), - abs(mysel->o->y() - qt)) < 25) { - // Align to left of other widget... - if ((drag & (LEFT | DRAG)) && abs(d = mybx - qx) < 3) { - dx += d; - mybx += d; - if (drag & DRAG) mybr += d; - - draw_left_brace(qw->o); - } - - // Align to right of other widget... - if ((drag & (RIGHT | DRAG)) && - abs(d = qr - mybr) < 3) { - dx += d; - if (drag & DRAG) mybx += d; - mybr += d; - - draw_right_brace(qw->o); - } - } - - // Align to top of other widget... - if ((drag & (TOP | DRAG)) && abs(d = myby - qy) < 3) { - dy += d; - myby += d; - if (drag & DRAG) mybt += d; - - draw_top_brace(qw->o); - } - - // Align to bottom of other widget... - if ((drag & (BOTTOM | DRAG)) && abs(d = qt - mybt) < 3) { - dy += d; - if (drag & DRAG) myby += d; - mybt += d; - - draw_bottom_brace(qw->o); - } - - // Check spacing between widgets - if (mysel->is_group()) mysel->ideal_spacing(xsp, ysp); - else qw->ideal_spacing(xsp, ysp); - - if ((qt)>=myby && qy<=mybt) { - if (drag & (LEFT | DRAG)) { - // Compare left of selected to left of current - if (abs(d = qx - mybx - xsp) >= 3) - d = qx - mybx + xsp; - - if (abs(d) < 3) { - dx += d; - mybx += d; - if (drag & DRAG) mybr += d; - - // Draw left arrow - draw_h_arrow(mybx, (myby+mybt)/2, qx); - } - - // Compare left of selected to right of current - if (abs(d = qr - mybx - xsp) >= 3) - d = qr - mybx + xsp; - - if (abs(d) < 3) { - dx += d; - mybx += d; - if (drag & DRAG) mybr += d; - - // Draw left arrow - draw_h_arrow(mybx, (myby+mybt)/2, qr); - } - } - - if (drag & (RIGHT | DRAG)) { - // Compare right of selected to left of current - if (abs(d = qx - mybr - xsp) >= 3) - d = qx - mybr + xsp; - - if (abs(d) < 3) { - dx += d; - if (drag & DRAG) mybx += d; - mybr += d; - - // Draw right arrow - draw_h_arrow(mybr, (myby+mybt)/2, qx); - } - - // Compare right of selected to right of current - if (abs(d = qr - mybr + xsp) >= 3) - d = qr - mybr - xsp; - - if (abs(d) < 3) { - dx += d; - if (drag & DRAG) mybx += d; - mybr += d; - - // Draw right arrow - draw_h_arrow(mybr, (myby+mybt)/2, qr); - } - } - } - - if (qr>=mybx && qx<=mybr) { - // Compare top of selected to top of current - if (drag & (TOP | DRAG)) { - if (abs(d = qy - myby - ysp) >= 3) - d = qy - myby + ysp; - - if (abs(d) < 3) { - dy += d; - myby += d; - if (drag & DRAG) mybt += d; - - // Draw up arrow... - draw_v_arrow((mybx+mybr)/2, myby, qy); - } - - // Compare top of selected to bottom of current - if (abs(d = qt - myby - ysp) >= 3) - d = qt - myby + ysp; - - if (abs(d) < 3) { - dy += d; - myby += d; - if (drag & DRAG) mybt += d; - - // Draw up arrow... - draw_v_arrow((mybx+mybr)/2, myby, qt); - } - } - - // Compare bottom of selected to top of current - if (drag & (BOTTOM | DRAG)) { - if (abs(d = qy - mybt - ysp) >= 3) - d = qy - mybt + ysp; - - if (abs(d) < 3) { - dy += d; - if (drag & DRAG) myby += d; - mybt += d; - - // Draw down arrow... - draw_v_arrow((mybx+mybr)/2, mybt, qy); - } - - // Compare bottom of selected to bottom of current - if (abs(d = qt - mybt - ysp) >= 3) - d = qt - mybt + ysp; - - if (abs(d) < 3) { - dy += d; - if (drag & DRAG) myby += d; - mybt += d; - - // Draw down arrow... - draw_v_arrow((mybx+mybr)/2, mybt, qt); - } - } - } - } - } - mysx += mybx-mybx_bak; mysr += mybr-mybr_bak; - mysy += myby-myby_bak; myst += mybt-mybt_bak; - } // align the snapping selection box with the box we draw. sx = mysx; sy = mysy; sr = mysr; st = myst; @@ -1144,6 +668,11 @@ void Fl_Window_Type::draw_overlay() { fl_rectf(mysr-5,mysy,5,5); fl_rectf(mysr-5,myst-5,5,5); fl_rectf(mysx,myst-5,5,5); + + if (show_guides && (drag & (FD_DRAG|FD_TOP|FD_LEFT|FD_BOTTOM|FD_RIGHT))) { + Fd_Snap_Data data = { dx, dy, sx, sy, sr, st, drag, 4, 4, dx, dy, (Fl_Widget_Type*)selection, this}; + Fd_Snap_Action::draw_all(data); + } } extern Fl_Menu_Item Main_Menu[]; @@ -1151,6 +680,7 @@ extern Fl_Menu_Item Main_Menu[]; // Calculate new bounding box of selected widgets: void Fl_Window_Type::fix_overlay() { overlay_item->label("Hide O&verlays"); + if (overlay_button) overlay_button->label("Hide &Overlays"); overlays_invisible = 0; recalc = 1; ((Overlay_Window *)(this->o))->redraw_overlay(); @@ -1181,10 +711,13 @@ void redraw_overlays() { void toggle_overlays(Fl_Widget *,void *) { overlays_invisible = !overlays_invisible; - if (overlays_invisible) + if (overlays_invisible) { overlay_item->label("Show O&verlays"); - else + if (overlay_button) overlay_button->label("Show &Overlays"); + } else { overlay_item->label("Hide O&verlays"); + if (overlay_button) overlay_button->label("Hide &Overlays"); + } for (Fl_Type *o=Fl_Type::first; o; o=o->next) if (o->is_window()) { @@ -1193,6 +726,30 @@ void toggle_overlays(Fl_Widget *,void *) { } } +void toggle_guides(Fl_Widget *,void *) { + show_guides = !show_guides; + fluid_prefs.set("show_guides", show_guides); + + if (show_guides) { + guides_item->label("Hide Guides"); + if (guides_button) guides_button->label("Hide &Guides"); + } else { + guides_item->label("Show Guides"); + if (guides_button) guides_button->label("Show &Guides"); + } + + for (Fl_Type *o=Fl_Type::first; o; o=o->next) { + if (o->is_window()) { + Fl_Widget_Type* w = (Fl_Widget_Type*)o; + ((Overlay_Window*)(w->o))->redraw_overlay(); + } + } +} + +void guides_cb(Fl_Button *o, void *v) { + toggle_guides(NULL, NULL); +} + extern void select(Fl_Type *,int); extern void select_only(Fl_Type *); extern void deselect(); @@ -1402,15 +959,12 @@ int Fl_Window_Type::handle(int event) { }} // see if user grabs edges of selected region: if (numselected && !(Fl::event_state(FL_SHIFT)) && - mx<=br+snap && mx>=bx-snap && my<=bt+snap && my>=by-snap) { - int snap1 = snap>5 ? snap : 5; - int w1 = (br-bx)/4; if (w1 > snap1) w1 = snap1; - if (mx>=br-w1) drag |= RIGHT; - else if (mx snap1) w1 = snap1; - if (my<=by+w1) drag |= TOP; - else if (my>bt-w1) drag |= BOTTOM; - if (!drag) drag = DRAG; + mx<=br+2 && mx>=bx-2 && my<=bt+2 && my>=by-2) { + if (mx >= br-5) drag |= FD_RIGHT; + else if (mx <= bx+5) drag |= FD_LEFT; + if (my >= bt-5) drag |= FD_BOTTOM; + else if (my <= by+5) drag |= FD_TOP; + if (!drag) drag = FD_DRAG; } // do object-specific selection of other objects: {Fl_Type* t = selection->click_test(mx, my); @@ -1427,7 +981,7 @@ int Fl_Window_Type::handle(int event) { selection = t; drag = 0; } else { - if (!drag) drag = BOX; // if all else fails, start a new selection region + if (!drag) drag = FD_BOX; // if all else fails, start a new selection region }} return 1; @@ -1442,7 +996,7 @@ int Fl_Window_Type::handle(int event) { if (!drag) return 0; mx = Fl::event_x(); my = Fl::event_y(); - if (drag != BOX && (dx || dy || !Fl::event_is_click())) { + if (drag != FD_BOX && (dx || dy || !Fl::event_is_click())) { if (dx || dy) moveallchildren(); } else if ((Fl::event_clicks() || Fl::event_state(FL_CTRL))) { Fl_Widget_Type::open(); @@ -1510,8 +1064,16 @@ int Fl_Window_Type::handle(int event) { case FL_Up: dx = 0; dy = -1; goto ARROW; case FL_Down: dx = 0; dy = +1; goto ARROW; ARROW: - drag = (Fl::event_state(FL_SHIFT)) ? (RIGHT|BOTTOM) : DRAG; - if (Fl::event_state(FL_COMMAND)) {dx *= gridx; dy *= gridy;} + drag = (Fl::event_state(FL_SHIFT)) ? (FD_RIGHT|FD_BOTTOM) : FD_DRAG; + if (Fl::event_state(FL_COMMAND)) { + int x_step, y_step; + if (drag & (FD_RIGHT|FD_BOTTOM)) + Fd_Snap_Action::get_resize_stepsize(x_step, y_step); + else + Fd_Snap_Action::get_move_stepsize(x_step, y_step); + dx *= x_step; + dy *= y_step; + } moveallchildren(); drag = 0; return 1; @@ -1642,9 +1204,6 @@ Fl_Type *Fl_Widget_Class_Type::make(Strategy strategy) { this->o = new Fl_Window(100,100); Fl_Group::current(0); } - // Set the size ranges for this window; in order to avoid opening the - // X display we use an arbitrary maximum size... - ((Fl_Window *)(this->o))->size_range(gridx, gridy, 6144, 4096); myo->factory = this; myo->drag = 0; myo->numselected = 0; diff --git a/fluid/Fl_Window_Type.h b/fluid/Fl_Window_Type.h index 519af347b..8b6693245 100644 --- a/fluid/Fl_Window_Type.h +++ b/fluid/Fl_Window_Type.h @@ -5,7 +5,7 @@ // This should have the widget pointer in it, but it is still in the // Fl_Type base class. // -// Copyright 1998-2010 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 @@ -28,10 +28,20 @@ class Fl_Widget_Class_Type; extern Fl_Menu_Item window_type_menu[]; extern Fl_Widget_Class_Type *current_widget_class; void toggle_overlays(Fl_Widget *,void *); +void toggle_guides(Fl_Widget *,void *); void show_project_cb(Fl_Widget *, void *); void show_grid_cb(Fl_Widget *, void *); void show_settings_cb(Fl_Widget *, void *); +enum { + FD_LEFT = 1, // user drags the left side of the selection box + FD_RIGHT = 2, + FD_BOTTOM = 4, + FD_TOP = 8, + FD_DRAG = 16, // user drags the entire selection + FD_BOX = 32 // user creates a new selection box +}; + class Fl_Window_Type : public Fl_Widget_Type { protected: @@ -45,7 +55,6 @@ protected: int dx,dy; int drag; // which parts of bbox are being moved int numselected; // number of children selected - enum {LEFT=1,RIGHT=2,BOTTOM=4,TOP=8,DRAG=16,BOX=32}; void draw_overlay(); void newdx(); void newposition(Fl_Widget_Type *,int &x,int &y,int &w,int &h); diff --git a/fluid/Makefile b/fluid/Makefile index 3511b683e..a5569b70f 100644 --- a/fluid/Makefile +++ b/fluid/Makefile @@ -19,6 +19,7 @@ include ../makeinclude CPPFILES = \ CodeEditor.cxx \ StyleParse.cxx \ + Fd_Snap_Action.cxx \ Fl_Function_Type.cxx \ Fl_Group_Type.cxx \ Fl_Menu_Type.cxx \ diff --git a/fluid/align_widget.cxx b/fluid/align_widget.cxx index d66a0cc70..20a85a394 100644 --- a/fluid/align_widget.cxx +++ b/fluid/align_widget.cxx @@ -477,31 +477,3 @@ void align_widget_cb(Fl_Widget*, long how) if (changed) set_modflag(1); } - - -// Set sizes of selected widgets... -void widget_size_cb(Fl_Widget *, long size) { - // Update any selected widgets... - int changed = 0; - for (Fl_Type *o = Fl_Type::first; o; o = o->next) { - if (o->selected && o->is_widget()) { - if (!changed) { - changed = 1; - undo_checkpoint(); - } - - Fl_Widget *w = ((Fl_Widget_Type *)o)->o; - w->labelsize((Fl_Font)size); - Fl_Font f; - int s = (int)size; - Fl_Color c; - ((Fl_Widget_Type *)o)->textstuff(2, f, s, c); - - w->redraw(); - // since this may be a major change, the whole window should be redrawn - if (w->window()) w->window()->redraw(); - } - } - if (changed) - set_modflag(1); -} diff --git a/fluid/align_widget.h b/fluid/align_widget.h index 541894e94..f04372215 100644 --- a/fluid/align_widget.h +++ b/fluid/align_widget.h @@ -20,6 +20,5 @@ class Fl_Widget; void align_widget_cb(Fl_Widget *, long); -void widget_size_cb(Fl_Widget *, long); #endif // _FLUID_ALIGN_WIDGET_H diff --git a/fluid/alignment_panel.cxx b/fluid/alignment_panel.cxx index c264dd035..edc2c3cc2 100644 --- a/fluid/alignment_panel.cxx +++ b/fluid/alignment_panel.cxx @@ -1,7 +1,7 @@ // // Setting and shell dialogs for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2020 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 @@ -497,124 +497,681 @@ ings"); } // Fl_Double_Window* shell_run_window return shell_run_window; } +Fl_Menu_Item *w_layout_menu_storage[4]; Fl_Double_Window *grid_window=(Fl_Double_Window *)0; -Fl_Int_Input *horizontal_input=(Fl_Int_Input *)0; - -Fl_Int_Input *vertical_input=(Fl_Int_Input *)0; - -Fl_Int_Input *snap_input=(Fl_Int_Input *)0; - -Fl_Check_Button *guides_toggle=(Fl_Check_Button *)0; - -static void cb_Close2(Fl_Button*, void*) { - grid_window->hide(); +static void cb_grid_window(Fl_Double_Window* o, void* v) { + propagate_load(o, v); } -Fl_Round_Button *def_widget_size[6]={(Fl_Round_Button *)0}; +Fl_Choice *layout_choice=(Fl_Choice *)0; + +static void cb_layout_choice(Fl_Choice* o, void* v) { + if (v == LOAD) { + o->value(g_layout_list.current_suite()); + } else { + int index = o->value(); + g_layout_list.current_suite(index); + g_layout_list.update_dialogs(); + } +} + +Fl_Menu_Item menu_layout_choice[] = { + {"FLTK", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"Grid", 0, 0, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {0,0,0,0,0,0,0,0,0} +}; + +static void cb_(Fl_Button*, void* v) { + // Clone the current layout suite + + if (v == LOAD) return; + + Fl_String old_name = "Copy of "; + old_name.append(g_layout_list[g_layout_list.current_suite()].name_); + const char *new_name = fl_input("Enter a name for the new layout:", old_name.c_str()); + if (new_name == NULL) + return; + + g_layout_list.add(new_name); + g_layout_list.update_dialogs(); +} + +Fl_Menu_Button *w_layout_menu=(Fl_Menu_Button *)0; + +static void cb_w_layout_menu(Fl_Menu_Button*, void* v) { + if (v == LOAD) { + Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; + if (suite.storage_ == FD_STORE_INTERNAL) { + w_layout_menu_rename->deactivate(); + for (int i=1; i<4; i++) w_layout_menu_storage[i]->deactivate(); + w_layout_menu_delete->deactivate(); + } else { + w_layout_menu_rename->activate(); + for (int i=1; i<4; i++) w_layout_menu_storage[i]->activate(); + w_layout_menu_delete->activate(); + } + w_layout_menu_storage[suite.storage_]->setonly(); + } +} + +static void cb_w_layout_menu_rename(Fl_Menu_*, void*) { + // Rename the current layout suite + + Fl_String old_name = g_layout_list[g_layout_list.current_suite()].name_; + const char *new_name = fl_input("Enter a new name for the layout:", old_name.c_str()); + if (new_name == NULL) + return; + + g_layout_list.rename(new_name); + g_layout_list.update_dialogs(); +} + +static void cb_w_layout_menu_storage(Fl_Menu_*, void*) { + Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; + suite.storage(FD_STORE_INTERNAL); + g_layout_list.update_dialogs(); +} + +static void cb_w_layout_menu_storage1(Fl_Menu_*, void*) { + Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; + suite.storage(FD_STORE_USER); + g_layout_list.update_dialogs(); +} + +static void cb_w_layout_menu_storage2(Fl_Menu_*, void*) { + Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; + suite.storage(FD_STORE_PROJECT); + g_layout_list.update_dialogs(); +} + +static void cb_w_layout_menu_storage3(Fl_Menu_*, void*) { + Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; + suite.storage(FD_STORE_FILE); + g_layout_list.update_dialogs(); +} + +static void cb_w_layout_menu_load(Fl_Menu_*, void*) { + // Give the user a file chooser and load that file + Fl_Native_File_Chooser fnfc; + fnfc.title("Load Layout Settings:"); + fnfc.type(Fl_Native_File_Chooser::BROWSE_FILE); + fnfc.options(Fl_Native_File_Chooser::USE_FILTER_EXT); + fnfc.filter("FLUID Layouts\t*.fll\n"); + if (fnfc.show() != 0) return; + const char *new_filename = fnfc.filename(); + if (!new_filename) return; + g_layout_list.load(new_filename); + //g_layout_list.current_suite(n); + g_layout_list.update_dialogs(); +} + +static void cb_w_layout_menu_save(Fl_Menu_*, void*) { + // Give the user a file chooser with a suggested name + Fl_Native_File_Chooser fnfc; + fnfc.title("Save Layout Settings:"); + fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); + fnfc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); + fnfc.filter("FLUID Layouts\t*.fll\n"); + if (g_layout_list.filename_) { + char *fn = fl_strdup(g_layout_list.filename_); + char *name = (char*)fl_filename_name(g_layout_list.filename_); + if (name > fn) { + name[-1] = 0; + fnfc.directory(fn); + fnfc.preset_file(name); + ::free(fn); + } else if (name) { + fnfc.preset_file(name); + ::free(fn); + } + } + if (fnfc.show() != 0) return; + const char *new_filename = fnfc.filename(); + if (!new_filename) return; + if (g_layout_list.filename_) + ::free(g_layout_list.filename_); + g_layout_list.filename_ = fl_strdup(new_filename); + g_layout_list.save(new_filename); +} + +static void cb_w_layout_menu_delete(Fl_Menu_*, void*) { + // remove the current suite + + g_layout_list.remove(g_layout_list.current_suite()); + g_layout_list.update_dialogs(); +} + +Fl_Menu_Item menu_w_layout_menu[] = { + {"Rename...", 0, (Fl_Callback*)cb_w_layout_menu_rename, 0, 128, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"@fd_beaker FLUID Built-In", 0, (Fl_Callback*)cb_w_layout_menu_storage, 0, 9, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"@fd_user User Preference", 0, (Fl_Callback*)cb_w_layout_menu_storage1, 0, 8, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"@fd_project Store in .fl Project File", 0, (Fl_Callback*)cb_w_layout_menu_storage2, 0, 8, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"@fd_file Store in External File", 0, (Fl_Callback*)cb_w_layout_menu_storage3, 0, 136, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"Load...", 0, (Fl_Callback*)cb_w_layout_menu_load, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"Save...", 0, (Fl_Callback*)cb_w_layout_menu_save, 0, 128, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {"Delete", 0, (Fl_Callback*)cb_w_layout_menu_delete, 0, 0, (uchar)FL_NORMAL_LABEL, 0, 14, 0}, + {0,0,0,0,0,0,0,0,0} +}; + +Fl_Button *preset_choice[3]={(Fl_Button *)0}; + +static void cb_Left(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->left_window_margin); + } else { + layout->left_window_margin = (int)o->value(); + } +} + +static void cb_Top(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->top_window_margin); + } else { + layout->top_window_margin = (int)o->value(); + } +} + +static void cb_Right(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->right_window_margin); + } else { + layout->right_window_margin = (int)o->value(); + } +} + +static void cb_Bottom(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->bottom_window_margin); + } else { + layout->bottom_window_margin = (int)o->value(); + } +} + +static void cb_Horizontal(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->window_grid_x); + } else { + layout->window_grid_x = (int)o->value(); + } +} + +static void cb_Vertical(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->window_grid_y); + } else { + layout->window_grid_y = (int)o->value(); + } +} + +static void cb_Left1(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->left_group_margin); + } else { + layout->left_group_margin = (int)o->value(); + } +} + +static void cb_Top1(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->top_group_margin); + } else { + layout->top_group_margin = (int)o->value(); + } +} + +static void cb_Right1(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->right_group_margin); + } else { + layout->right_group_margin = (int)o->value(); + } +} + +static void cb_Bottom1(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->bottom_group_margin); + } else { + layout->bottom_group_margin = (int)o->value(); + } +} + +static void cb_Horizontal1(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->group_grid_x); + } else { + layout->group_grid_x = (int)o->value(); + } +} + +static void cb_Vertical1(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->group_grid_y); + } else { + layout->group_grid_y = (int)o->value(); + } +} + +static void cb_Top2(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->top_tabs_margin); + } else { + layout->top_tabs_margin = (int)o->value(); + } +} + +static void cb_Bottom2(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->bottom_tabs_margin); + } else { + layout->bottom_tabs_margin = (int)o->value(); + } +} + +static void cb_Minimum(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->widget_min_w); + } else { + layout->widget_min_w = (int)o->value(); + } +} + +static void cb_Increment(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->widget_inc_w); + } else { + layout->widget_inc_w = (int)o->value(); + } +} + +static void cb_Gap(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->widget_gap_x); + } else { + layout->widget_gap_x = (int)o->value(); + } +} + +static void cb_1(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->widget_min_h); + } else { + layout->widget_min_h = (int)o->value(); + } +} + +static void cb_2(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->widget_inc_h); + } else { + layout->widget_inc_h = (int)o->value(); + } +} + +static void cb_3(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value((double)layout->widget_gap_y); + } else { + layout->widget_gap_y = (int)o->value(); + } +} + +static void cb_4(Fl_Choice* o, void* v) { + if (v == LOAD) { + o->value(layout->labelfont); + } else { + layout->labelfont = (int)o->value(); + } +} + +static void cb_5(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value(layout->labelsize); + } else { + layout->labelsize = (int)o->value(); + } +} + +static void cb_6(Fl_Choice* o, void* v) { + if (v == LOAD) { + o->value(layout->textfont); + } else { + layout->textfont = (int)o->value(); + } +} + +static void cb_7(Fl_Value_Input* o, void* v) { + if (v == LOAD) { + o->value(layout->textsize); + } else { + layout->textsize = (int)o->value(); + } +} + +static void cb_Close2(Fl_Button*, void* v) { + if (v != LOAD) grid_window->hide(); +} Fl_Double_Window* make_layout_window() { - { grid_window = new Fl_Double_Window(310, 245, "Layout Settings"); - { Fl_Int_Input* o = horizontal_input = new Fl_Int_Input(116, 10, 50, 25, "x"); - horizontal_input->tooltip("Horizontal grid spacing."); - horizontal_input->type(2); - horizontal_input->box(FL_THIN_DOWN_BOX); - horizontal_input->callback((Fl_Callback*)grid_cb, (void*)(1)); - horizontal_input->align(Fl_Align(FL_ALIGN_RIGHT)); - o->when(FL_WHEN_RELEASE|FL_WHEN_ENTER_KEY); - } // Fl_Int_Input* horizontal_input - { Fl_Int_Input* o = vertical_input = new Fl_Int_Input(179, 10, 50, 25, "pixels"); - vertical_input->tooltip("Vertical grid spacing."); - vertical_input->type(2); - vertical_input->box(FL_THIN_DOWN_BOX); - vertical_input->callback((Fl_Callback*)grid_cb, (void*)(2)); - vertical_input->align(Fl_Align(FL_ALIGN_RIGHT)); - o->when(FL_WHEN_RELEASE|FL_WHEN_ENTER_KEY); - } // Fl_Int_Input* vertical_input - { Fl_Int_Input* o = snap_input = new Fl_Int_Input(116, 45, 50, 25, "pixel snap"); - snap_input->tooltip("Snap to grid within this many pixels."); - snap_input->type(2); - snap_input->box(FL_THIN_DOWN_BOX); - snap_input->callback((Fl_Callback*)grid_cb, (void*)(3)); - snap_input->align(Fl_Align(FL_ALIGN_RIGHT)); - o->when(FL_WHEN_RELEASE|FL_WHEN_ENTER_KEY); - } // Fl_Int_Input* snap_input - { guides_toggle = new Fl_Check_Button(116, 80, 110, 25, "Show Guides"); - guides_toggle->tooltip("Show distance and alignment guides in overlay"); - guides_toggle->down_box(FL_DOWN_BOX); - guides_toggle->callback((Fl_Callback*)guides_cb, (void*)(4)); - } // Fl_Check_Button* guides_toggle - { Fl_Button* o = new Fl_Button(240, 210, 60, 25, "Close"); + { grid_window = new Fl_Double_Window(320, 491, "Layout Settings"); + grid_window->callback((Fl_Callback*)cb_grid_window); + { Fl_Box* o = new Fl_Box(10, 10, 60, 24, "Layout:"); + o->labelfont(1); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { layout_choice = new Fl_Choice(70, 10, 187, 24); + layout_choice->down_box(FL_BORDER_BOX); + layout_choice->callback((Fl_Callback*)cb_layout_choice); + layout_choice->menu(menu_layout_choice); + } // Fl_Choice* layout_choice + { Fl_Button* o = new Fl_Button(257, 10, 24, 24, "+"); + o->callback((Fl_Callback*)cb_); + } // Fl_Button* o + { w_layout_menu = new Fl_Menu_Button(281, 10, 24, 24); + w_layout_menu->callback((Fl_Callback*)cb_w_layout_menu); + w_layout_menu_storage[0] = &menu_w_layout_menu[1]; + w_layout_menu_storage[1] = &menu_w_layout_menu[2]; + w_layout_menu_storage[2] = &menu_w_layout_menu[3]; + w_layout_menu_storage[3] = &menu_w_layout_menu[4]; + w_layout_menu->menu(menu_w_layout_menu); + } // Fl_Menu_Button* w_layout_menu + { Fl_Box* o = new Fl_Box(10, 39, 60, 20, "Preset:"); + o->labelfont(1); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Group* o = new Fl_Group(70, 39, 235, 20); + o->labelsize(11); + o->callback((Fl_Callback*)propagate_load); + { preset_choice[0] = new Fl_Button(70, 39, 78, 20, "Application"); + preset_choice[0]->type(102); + preset_choice[0]->value(1); + preset_choice[0]->selection_color(FL_DARK2); + preset_choice[0]->labelsize(11); + preset_choice[0]->callback((Fl_Callback*)edit_layout_preset_cb, (void*)(0)); + } // Fl_Button* preset_choice[0] + { preset_choice[1] = new Fl_Button(148, 39, 79, 20, "Dialog"); + preset_choice[1]->type(102); + preset_choice[1]->selection_color(FL_DARK2); + preset_choice[1]->labelsize(11); + preset_choice[1]->callback((Fl_Callback*)edit_layout_preset_cb, (void*)(1)); + } // Fl_Button* preset_choice[1] + { preset_choice[2] = new Fl_Button(227, 39, 78, 20, "Toolbox"); + preset_choice[2]->type(102); + preset_choice[2]->selection_color(FL_DARK2); + preset_choice[2]->labelsize(11); + preset_choice[2]->callback((Fl_Callback*)edit_layout_preset_cb, (void*)(2)); + } // Fl_Button* preset_choice[2] + o->end(); + } // Fl_Group* o + { Fl_Box* o = new Fl_Box(70, 64, 235, 20, "---- Window ----"); + o->labelfont(1); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Box* o = new Fl_Box(10, 99, 60, 20, "Margin:"); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Value_Input* o = new Fl_Value_Input(70, 99, 55, 20, "Left:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Left); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(130, 99, 55, 20, "Top:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Top); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(190, 99, 55, 20, "Right:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Right); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(250, 99, 55, 20, "Bottom:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Bottom); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(17, 133, 53, 20, "Grid:"); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Value_Input* o = new Fl_Value_Input(70, 133, 55, 20, "Horizontal:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Horizontal); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(130, 133, 55, 20, "Vertical:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Vertical); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(70, 158, 235, 20, "---- Group ----"); + o->labelfont(1); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Box* o = new Fl_Box(10, 193, 60, 20, "Margin:"); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Value_Input* o = new Fl_Value_Input(70, 193, 55, 20, "Left:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Left1); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(130, 193, 55, 20, "Top:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Top1); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(190, 193, 55, 20, "Right:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Right1); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(250, 193, 55, 20, "Bottom:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Bottom1); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(17, 227, 53, 20, "Grid:"); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Value_Input* o = new Fl_Value_Input(70, 227, 55, 20, "Horizontal:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Horizontal1); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(130, 227, 55, 20, "Vertical:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Vertical1); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(70, 252, 235, 20, "---- Tabs ----"); + o->labelfont(1); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Box* o = new Fl_Box(10, 287, 60, 20, "Margin:"); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Value_Input* o = new Fl_Value_Input(70, 287, 55, 20, "Top:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Top2); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(130, 287, 55, 20, "Bottom:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Bottom2); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(70, 312, 235, 20, "---- Widget ----"); + o->labelfont(1); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Box* o = new Fl_Box(10, 347, 60, 20, "Horizontal:"); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Value_Input* o = new Fl_Value_Input(70, 346, 55, 20, "Minimum:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Minimum); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(130, 346, 55, 20, "Increment:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Increment); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(190, 346, 55, 20, "Gap:"); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_Gap); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(17, 372, 53, 20, "Vertical:"); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); + } // Fl_Box* o + { Fl_Value_Input* o = new Fl_Value_Input(70, 372, 55, 20); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_1); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(130, 372, 55, 20); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_2); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(190, 372, 55, 20); + o->labelsize(11); + o->maximum(32767); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)cb_3); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Group* o = new Fl_Group(70, 397, 200, 20, "Label Font:"); + o->labelsize(11); + o->callback((Fl_Callback*)propagate_load); + o->align(Fl_Align(FL_ALIGN_LEFT)); + { Fl_Choice* o = new Fl_Choice(70, 397, 152, 20); + o->tooltip("The style of the label text."); + o->box(FL_THIN_UP_BOX); + o->down_box(FL_BORDER_BOX); + o->labelfont(1); + o->labelsize(11); + o->textsize(11); + o->callback((Fl_Callback*)cb_4); + Fl_Group::current()->resizable(o); + o->menu(fontmenu); + } // Fl_Choice* o + { Fl_Value_Input* o = new Fl_Value_Input(221, 397, 49, 20); + o->tooltip("The size of the label text."); + o->labelsize(11); + o->maximum(100); + o->step(1); + o->value(14); + o->textsize(11); + o->callback((Fl_Callback*)cb_5); + } // Fl_Value_Input* o + o->end(); + } // Fl_Group* o + { Fl_Group* o = new Fl_Group(70, 422, 200, 20, "Text Font:"); + o->labelsize(11); + o->callback((Fl_Callback*)propagate_load); + o->align(Fl_Align(FL_ALIGN_LEFT)); + { Fl_Choice* o = new Fl_Choice(70, 422, 152, 20); + o->tooltip("The value text style."); + o->box(FL_DOWN_BOX); + o->down_box(FL_BORDER_BOX); + o->labelfont(1); + o->labelsize(11); + o->textsize(11); + o->callback((Fl_Callback*)cb_6); + Fl_Group::current()->resizable(o); + o->menu(fontmenu); + } // Fl_Choice* o + { Fl_Value_Input* o = new Fl_Value_Input(221, 422, 49, 20); + o->tooltip("The value text size."); + o->labelsize(11); + o->maximum(100); + o->step(1); + o->value(14); + o->textsize(11); + o->callback((Fl_Callback*)cb_7); + } // Fl_Value_Input* o + o->end(); + } // Fl_Group* o + { Fl_Button* o = new Fl_Button(245, 456, 60, 25, "Close"); o->tooltip("Close this dialog."); o->callback((Fl_Callback*)cb_Close2); } // Fl_Button* o - { Fl_Box* o = new Fl_Box(47, 10, 70, 25, "Grid:"); - o->labelfont(1); - o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - { Fl_Box* o = new Fl_Box(10, 115, 107, 25, "Widget Size:"); - o->labelfont(1); - o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - { Fl_Group* o = new Fl_Group(105, 115, 192, 75); - { def_widget_size[0] = new Fl_Round_Button(115, 115, 70, 25); - def_widget_size[0]->type(102); - def_widget_size[0]->down_box(FL_ROUND_DOWN_BOX); - def_widget_size[0]->callback((Fl_Callback*)default_widget_size_cb, (void*)(8)); - } // Fl_Round_Button* def_widget_size[0] - { Fl_Box* o = new Fl_Box(130, 115, 50, 25, "tiny"); - o->labelsize(8); - o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - { def_widget_size[1] = new Fl_Round_Button(202, 115, 70, 25); - def_widget_size[1]->type(102); - def_widget_size[1]->down_box(FL_ROUND_DOWN_BOX); - def_widget_size[1]->callback((Fl_Callback*)default_widget_size_cb, (void*)(11)); - } // Fl_Round_Button* def_widget_size[1] - { Fl_Box* o = new Fl_Box(218, 115, 50, 25, "small"); - o->labelsize(11); - o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - { def_widget_size[2] = new Fl_Round_Button(115, 140, 70, 25); - def_widget_size[2]->type(102); - def_widget_size[2]->down_box(FL_ROUND_DOWN_BOX); - def_widget_size[2]->callback((Fl_Callback*)default_widget_size_cb, (void*)(14)); - } // Fl_Round_Button* def_widget_size[2] - { Fl_Box* o = new Fl_Box(130, 140, 50, 25, "normal"); - o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - { def_widget_size[3] = new Fl_Round_Button(202, 140, 90, 25); - def_widget_size[3]->type(102); - def_widget_size[3]->down_box(FL_ROUND_DOWN_BOX); - def_widget_size[3]->callback((Fl_Callback*)default_widget_size_cb, (void*)(18)); - } // Fl_Round_Button* def_widget_size[3] - { Fl_Box* o = new Fl_Box(218, 140, 68, 25, "medium"); - o->labelsize(18); - o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - { def_widget_size[4] = new Fl_Round_Button(115, 165, 75, 25); - def_widget_size[4]->type(102); - def_widget_size[4]->down_box(FL_ROUND_DOWN_BOX); - def_widget_size[4]->callback((Fl_Callback*)default_widget_size_cb, (void*)(24)); - } // Fl_Round_Button* def_widget_size[4] - { Fl_Box* o = new Fl_Box(130, 165, 64, 25, "large"); - o->labelsize(24); - o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - { def_widget_size[5] = new Fl_Round_Button(202, 165, 95, 25); - def_widget_size[5]->type(102); - def_widget_size[5]->down_box(FL_ROUND_DOWN_BOX); - def_widget_size[5]->callback((Fl_Callback*)default_widget_size_cb, (void*)(32)); - } // Fl_Round_Button* def_widget_size[5] - { Fl_Box* o = new Fl_Box(218, 165, 76, 25, "huge"); - o->labelsize(32); - o->align(Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE)); - } // Fl_Box* o - o->end(); - } // Fl_Group* o grid_window->set_non_modal(); grid_window->end(); } // Fl_Double_Window* grid_window + grid_window->do_callback(grid_window, LOAD); return grid_window; } diff --git a/fluid/alignment_panel.fl b/fluid/alignment_panel.fl index c1f0305da..3f3abb04d 100644 --- a/fluid/alignment_panel.fl +++ b/fluid/alignment_panel.fl @@ -2,10 +2,39 @@ version 1.0400 header_name {.h} code_name {.cxx} +snap { + ver 1 + current_suite {FLUID (based on FLTK)} + current_preset 1 + suite { + name {FLUID (based on FLTK)} + preset { 1 + 15 15 15 15 0 0 + 10 10 10 10 0 0 + 25 25 + 20 10 4 20 4 8 + 0 14 0 14 + } + preset { 1 + 10 10 10 10 0 0 + 10 10 10 10 0 0 + 20 20 + 20 10 5 20 5 5 + 0 11 0 11 + } + preset { 1 + 10 10 10 10 0 0 + 10 10 10 10 0 0 + 18 18 + 16 8 2 16 4 2 + 0 10 0 10 + } + } +} comment {// // Setting and shell dialogs for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2020 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 @@ -26,18 +55,24 @@ decl {\#include "fluid.h"} {public global decl {\#include "widget_browser.h"} {public global } +decl {\#include "Fd_Snap_Action.h"} {public global +} + decl {\#include "shell_command.h"} {public global } decl {\#include } {public local } -decl {\#include } {public local +decl {\#include } {selected public local } decl {\#include } {public local } +decl {\#include } {public local +} + decl {\#include } {public local } @@ -60,8 +95,8 @@ decl {extern struct Fl_Menu_Item *dbmanager_item;} {public local Function {make_project_window()} {open } { Fl_Window project_window { - label {Project Settings} - xywh {472 246 399 298} type Double + label {Project Settings} open + xywh {739 251 399 298} type Double code0 {\#include } code1 {\#include } modal visible } { @@ -126,15 +161,15 @@ set_modflag(-1, -1);} } { MenuItem {} { label None - xywh {0 0 100 20} + xywh {0 0 100 20} labelsize 14 } MenuItem {} { label {GNU gettext} - xywh {0 0 100 20} + xywh {0 0 100 20} labelsize 14 } MenuItem {} { label {POSIX catgets} - xywh {0 0 100 20} + xywh {0 0 100 20} labelsize 14 } } Fl_Input i18n_include_input { @@ -182,7 +217,7 @@ Function {make_settings_window()} {open } { Fl_Window settings_window { label {GUI Settings} open - xywh {701 666 360 355} type Double resizable + xywh {722 580 360 355} type Double resizable code0 {o->size_range(o->w(), o->h());} non_modal visible } { Fl_Choice scheme_choice { @@ -293,7 +328,7 @@ Function {make_shell_window()} {open } { Fl_Window shell_window { label {Shell Command} open - xywh {502 196 375 208} type Double resizable modal size_range {375 208 1024 208} visible + xywh {390 202 375 208} type Double resizable modal size_range {375 208 1024 208} visible } { Fl_Group {} {open xywh {0 0 375 165} resizable @@ -323,7 +358,7 @@ if (g_shell_use_fl_settings) { } else { shell_prefs_get(); } -update_shell_window();} selected +update_shell_window();} tooltip {check to read and write shell command from and to .fl files} xywh {82 110 180 19} down_box DOWN_BOX labelsize 12 } Fl_Box {} { @@ -390,109 +425,469 @@ shell_run_window->hide();} } } +decl {Fl_Menu_Item *w_layout_menu_storage[4];} {private global +} + Function {make_layout_window()} {open } { Fl_Window grid_window { label {Layout Settings} - xywh {745 303 310 245} type Double non_modal visible + callback {propagate_load(o, v);} open + xywh {392 444 320 491} type Double non_modal visible } { - Fl_Input horizontal_input { - label x - user_data 1 user_data_type long - callback grid_cb - tooltip {Horizontal grid spacing.} xywh {116 10 50 25} type Int box THIN_DOWN_BOX align 8 - code0 {o->when(FL_WHEN_RELEASE|FL_WHEN_ENTER_KEY);} + Fl_Box {} { + label {Layout:} + xywh {10 10 60 24} labelfont 1 labelsize 11 align 24 } - Fl_Input vertical_input { - label pixels - user_data 2 user_data_type long - callback grid_cb - tooltip {Vertical grid spacing.} xywh {179 10 50 25} type Int box THIN_DOWN_BOX align 8 - code0 {o->when(FL_WHEN_RELEASE|FL_WHEN_ENTER_KEY);} - } - Fl_Input snap_input { - label {pixel snap} - user_data 3 user_data_type long - callback grid_cb - tooltip {Snap to grid within this many pixels.} xywh {116 45 50 25} type Int box THIN_DOWN_BOX align 8 - code0 {o->when(FL_WHEN_RELEASE|FL_WHEN_ENTER_KEY);} - } - Fl_Check_Button guides_toggle { - label {Show Guides} - user_data 4 user_data_type long - callback guides_cb - tooltip {Show distance and alignment guides in overlay} xywh {116 80 110 25} down_box DOWN_BOX + Fl_Choice layout_choice { + callback {if (v == LOAD) { + o->value(g_layout_list.current_suite()); + } else { + int index = o->value(); + g_layout_list.current_suite(index); + g_layout_list.update_dialogs(); + }} + xywh {70 10 187 24} down_box BORDER_BOX + } { + MenuItem {} { + label FLTK + xywh {0 0 31 20} labelsize 14 + } + MenuItem {} { + label Grid + xywh {0 0 31 20} labelsize 14 + } } Fl_Button {} { - label Close - callback {grid_window->hide();} - tooltip {Close this dialog.} xywh {240 210 60 25} + label {+} + callback {// Clone the current layout suite + +if (v == LOAD) return; + +Fl_String old_name = "Copy of "; +old_name.append(g_layout_list[g_layout_list.current_suite()].name_); +const char *new_name = fl_input("Enter a name for the new layout:", old_name.c_str()); +if (new_name == NULL) + return; + +g_layout_list.add(new_name); +g_layout_list.update_dialogs();} + xywh {257 10 24 24} + } + Fl_Menu_Button w_layout_menu { + callback {if (v == LOAD) { + Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; + if (suite.storage_ == FD_STORE_INTERNAL) { + w_layout_menu_rename->deactivate(); + for (int i=1; i<4; i++) w_layout_menu_storage[i]->deactivate(); + w_layout_menu_delete->deactivate(); + } else { + w_layout_menu_rename->activate(); + for (int i=1; i<4; i++) w_layout_menu_storage[i]->activate(); + w_layout_menu_delete->activate(); + } + w_layout_menu_storage[suite.storage_]->setonly(); +}} + xywh {281 10 24 24} + } { + MenuItem w_layout_menu_rename { + label {Rename...} + callback {// Rename the current layout suite + +Fl_String old_name = g_layout_list[g_layout_list.current_suite()].name_; +const char *new_name = fl_input("Enter a new name for the layout:", old_name.c_str()); +if (new_name == NULL) + return; + +g_layout_list.rename(new_name); +g_layout_list.update_dialogs();} + xywh {0 0 31 20} labelsize 14 divider + } + MenuItem {w_layout_menu_storage[0]} { + label {@fd_beaker FLUID Built-In} + callback {Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; +suite.storage(FD_STORE_INTERNAL); +g_layout_list.update_dialogs();} + xywh {0 0 31 20} type Radio labelsize 14 deactivate + } + MenuItem {w_layout_menu_storage[1]} { + label {@fd_user User Preference} + callback {Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; +suite.storage(FD_STORE_USER); +g_layout_list.update_dialogs();} + xywh {0 0 31 20} type Radio labelsize 14 + } + MenuItem {w_layout_menu_storage[2]} { + label {@fd_project Store in .fl Project File} + callback {Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; +suite.storage(FD_STORE_PROJECT); +g_layout_list.update_dialogs();} + xywh {0 0 31 20} type Radio labelsize 14 + } + MenuItem {w_layout_menu_storage[3]} { + label {@fd_file Store in External File} + callback {Fd_Layout_Suite &suite = g_layout_list[g_layout_list.current_suite()]; +suite.storage(FD_STORE_FILE); +g_layout_list.update_dialogs();} + xywh {0 0 31 20} type Radio labelsize 14 divider + } + MenuItem w_layout_menu_load { + label {Load...} + callback {// Give the user a file chooser and load that file +Fl_Native_File_Chooser fnfc; +fnfc.title("Load Layout Settings:"); +fnfc.type(Fl_Native_File_Chooser::BROWSE_FILE); +fnfc.options(Fl_Native_File_Chooser::USE_FILTER_EXT); +fnfc.filter("FLUID Layouts\\t*.fll\\n"); +if (fnfc.show() != 0) return; +const char *new_filename = fnfc.filename(); +if (!new_filename) return; +g_layout_list.load(new_filename); +//g_layout_list.current_suite(n); +g_layout_list.update_dialogs();} + xywh {0 0 31 20} labelsize 14 + } + MenuItem w_layout_menu_save { + label {Save...} + callback {// Give the user a file chooser with a suggested name + Fl_Native_File_Chooser fnfc; + fnfc.title("Save Layout Settings:"); + fnfc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); + fnfc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); + fnfc.filter("FLUID Layouts\\t*.fll\\n"); + if (g_layout_list.filename_) { + char *fn = fl_strdup(g_layout_list.filename_); + char *name = (char*)fl_filename_name(g_layout_list.filename_); + if (name > fn) { + name[-1] = 0; + fnfc.directory(fn); + fnfc.preset_file(name); + ::free(fn); + } else if (name) { + fnfc.preset_file(name); + ::free(fn); + } + } + if (fnfc.show() != 0) return; + const char *new_filename = fnfc.filename(); + if (!new_filename) return; + if (g_layout_list.filename_) + ::free(g_layout_list.filename_); + g_layout_list.filename_ = fl_strdup(new_filename); + g_layout_list.save(new_filename);} + xywh {0 0 31 20} labelsize 14 divider + code0 {\#include } + } + MenuItem w_layout_menu_delete { + label Delete + callback {// remove the current suite + +g_layout_list.remove(g_layout_list.current_suite()); +g_layout_list.update_dialogs();} + xywh {0 0 31 20} labelsize 14 + } + } + Fl_Box {} { + label {Preset:} + xywh {10 39 60 20} labelfont 1 labelsize 11 align 24 + } + Fl_Group {} { + callback propagate_load open + xywh {70 39 235 20} labelsize 11 + } { + Fl_Button {preset_choice[0]} { + label Application + user_data 0 user_data_type long + callback edit_layout_preset_cb + xywh {70 39 78 20} type Radio value 1 selection_color 45 labelsize 11 + } + Fl_Button {preset_choice[1]} { + label Dialog + user_data 1 user_data_type long + callback edit_layout_preset_cb + xywh {148 39 79 20} type Radio selection_color 45 labelsize 11 + } + Fl_Button {preset_choice[2]} { + label Toolbox + user_data 2 user_data_type long + callback edit_layout_preset_cb + xywh {227 39 78 20} type Radio selection_color 45 labelsize 11 + } + } + Fl_Box {} { + label {---- Window ----} + xywh {70 64 235 20} labelfont 1 labelsize 11 align 20 + } + Fl_Box {} { + label {Margin:} + xywh {10 99 60 20} labelsize 11 align 24 + } + Fl_Value_Input {} { + label {Left:} + callback {if (v == LOAD) { + o->value((double)layout->left_window_margin); +} else { + layout->left_window_margin = (int)o->value(); +}} + xywh {70 99 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Top:} + callback {if (v == LOAD) { + o->value((double)layout->top_window_margin); +} else { + layout->top_window_margin = (int)o->value(); +}} + xywh {130 99 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Right:} + callback {if (v == LOAD) { + o->value((double)layout->right_window_margin); +} else { + layout->right_window_margin = (int)o->value(); +}} + xywh {190 99 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Bottom:} + callback {if (v == LOAD) { + o->value((double)layout->bottom_window_margin); +} else { + layout->bottom_window_margin = (int)o->value(); +}} + xywh {250 99 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 } Fl_Box {} { label {Grid:} - xywh {47 10 70 25} labelfont 1 align 24 + xywh {17 133 53 20} labelsize 11 align 24 + } + Fl_Value_Input {} { + label {Horizontal:} + callback {if (v == LOAD) { + o->value((double)layout->window_grid_x); +} else { + layout->window_grid_x = (int)o->value(); +}} + xywh {70 133 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Vertical:} + callback {if (v == LOAD) { + o->value((double)layout->window_grid_y); +} else { + layout->window_grid_y = (int)o->value(); +}} + xywh {130 133 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 } Fl_Box {} { - label {Widget Size:} - xywh {10 115 107 25} labelfont 1 align 24 + label {---- Group ----} + xywh {70 158 235 20} labelfont 1 labelsize 11 align 20 } - Fl_Group {} {open - xywh {105 115 192 75} + Fl_Box {} { + label {Margin:} + xywh {10 193 60 20} labelsize 11 align 24 + } + Fl_Value_Input {} { + label {Left:} + callback {if (v == LOAD) { + o->value((double)layout->left_group_margin); +} else { + layout->left_group_margin = (int)o->value(); +}} + xywh {70 193 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Top:} + callback {if (v == LOAD) { + o->value((double)layout->top_group_margin); +} else { + layout->top_group_margin = (int)o->value(); +}} + xywh {130 193 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Right:} + callback {if (v == LOAD) { + o->value((double)layout->right_group_margin); +} else { + layout->right_group_margin = (int)o->value(); +}} + xywh {190 193 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Bottom:} + callback {if (v == LOAD) { + o->value((double)layout->bottom_group_margin); +} else { + layout->bottom_group_margin = (int)o->value(); +}} + xywh {250 193 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Box {} { + label {Grid:} + xywh {17 227 53 20} labelsize 11 align 24 + } + Fl_Value_Input {} { + label {Horizontal:} + callback {if (v == LOAD) { + o->value((double)layout->group_grid_x); +} else { + layout->group_grid_x = (int)o->value(); +}} + xywh {70 227 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Vertical:} + callback {if (v == LOAD) { + o->value((double)layout->group_grid_y); +} else { + layout->group_grid_y = (int)o->value(); +}} + xywh {130 227 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Box {} { + label {---- Tabs ----} + xywh {70 252 235 20} labelfont 1 labelsize 11 align 20 + } + Fl_Box {} { + label {Margin:} + xywh {10 287 60 20} labelsize 11 align 24 + } + Fl_Value_Input {} { + label {Top:} + callback {if (v == LOAD) { + o->value((double)layout->top_tabs_margin); +} else { + layout->top_tabs_margin = (int)o->value(); +}} + xywh {70 287 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Bottom:} + callback {if (v == LOAD) { + o->value((double)layout->bottom_tabs_margin); +} else { + layout->bottom_tabs_margin = (int)o->value(); +}} + xywh {130 287 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Box {} { + label {---- Widget ----} + xywh {70 312 235 20} labelfont 1 labelsize 11 align 20 + } + Fl_Box {} { + label {Horizontal:} + xywh {10 347 60 20} labelsize 11 align 24 + } + Fl_Value_Input {} { + label {Minimum:} + callback {if (v == LOAD) { + o->value((double)layout->widget_min_w); +} else { + layout->widget_min_w = (int)o->value(); +}} + xywh {70 346 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Increment:} + callback {if (v == LOAD) { + o->value((double)layout->widget_inc_w); +} else { + layout->widget_inc_w = (int)o->value(); +}} + xywh {130 346 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Gap:} + callback {if (v == LOAD) { + o->value((double)layout->widget_gap_x); +} else { + layout->widget_gap_x = (int)o->value(); +}} + xywh {190 346 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Box {} { + label {Vertical:} + xywh {17 372 53 20} labelsize 11 align 24 + } + Fl_Value_Input {} { + callback {if (v == LOAD) { + o->value((double)layout->widget_min_h); +} else { + layout->widget_min_h = (int)o->value(); +}} + xywh {70 372 55 20} labelsize 11 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + callback {if (v == LOAD) { + o->value((double)layout->widget_inc_h); +} else { + layout->widget_inc_h = (int)o->value(); +}} + xywh {130 372 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Value_Input {} { + callback {if (v == LOAD) { + o->value((double)layout->widget_gap_y); +} else { + layout->widget_gap_y = (int)o->value(); +}} + xywh {190 372 55 20} labelsize 11 align 5 maximum 32767 step 1 textsize 11 + } + Fl_Group {} { + label {Label Font:} + callback propagate_load open + xywh {70 397 200 20} labelsize 11 align 4 } { - Fl_Round_Button {def_widget_size[0]} { - user_data 8 user_data_type long - callback default_widget_size_cb - xywh {115 115 70 25} type Radio down_box ROUND_DOWN_BOX + Fl_Choice {} { + callback {if (v == LOAD) { + o->value(layout->labelfont); +} else { + layout->labelfont = (int)o->value(); +}} open + tooltip {The style of the label text.} xywh {70 397 152 20} box THIN_UP_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable + code0 {extern Fl_Menu_Item fontmenu[];} + code1 {o->menu(fontmenu);} + } {} + Fl_Value_Input {} { + callback {if (v == LOAD) { + o->value(layout->labelsize); +} else { + layout->labelsize = (int)o->value(); +}} + tooltip {The size of the label text.} xywh {221 397 49 20} labelsize 11 maximum 100 step 1 value 14 textsize 11 } - Fl_Box {} { - label tiny - xywh {130 115 50 25} labelsize 8 align 20 - } - Fl_Round_Button {def_widget_size[1]} { - user_data 11 user_data_type long - callback default_widget_size_cb - xywh {202 115 70 25} type Radio down_box ROUND_DOWN_BOX - } - Fl_Box {} { - label small - xywh {218 115 50 25} labelsize 11 align 20 - } - Fl_Round_Button {def_widget_size[2]} { - user_data 14 user_data_type long - callback default_widget_size_cb - xywh {115 140 70 25} type Radio down_box ROUND_DOWN_BOX - } - Fl_Box {} { - label normal - xywh {130 140 50 25} align 20 - } - Fl_Round_Button {def_widget_size[3]} { - user_data 18 user_data_type long - callback default_widget_size_cb - xywh {202 140 90 25} type Radio down_box ROUND_DOWN_BOX - } - Fl_Box {} { - label medium - xywh {218 140 68 25} labelsize 18 align 20 - } - Fl_Round_Button {def_widget_size[4]} { - user_data 24 user_data_type long - callback default_widget_size_cb - xywh {115 165 75 25} type Radio down_box ROUND_DOWN_BOX - } - Fl_Box {} { - label large - xywh {130 165 64 25} labelsize 24 align 20 - } - Fl_Round_Button {def_widget_size[5]} { - user_data 32 user_data_type long - callback default_widget_size_cb - xywh {202 165 95 25} type Radio down_box ROUND_DOWN_BOX - } - Fl_Box {} { - label huge - xywh {218 165 76 25} labelsize 32 align 20 + } + Fl_Group {} { + label {Text Font:} + callback propagate_load open + xywh {70 422 200 20} labelsize 11 align 4 + } { + Fl_Choice {} { + callback {if (v == LOAD) { + o->value(layout->textfont); +} else { + layout->textfont = (int)o->value(); +}} open + tooltip {The value text style.} xywh {70 422 152 20} box DOWN_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable + code0 {extern Fl_Menu_Item fontmenu[];} + code1 {o->menu(fontmenu);} + } {} + Fl_Value_Input {} { + callback {if (v == LOAD) { + o->value(layout->textsize); +} else { + layout->textsize = (int)o->value(); +}} + tooltip {The value text size.} xywh {221 422 49 20} labelsize 11 maximum 100 step 1 value 14 textsize 11 } } + Fl_Button {} { + label Close + callback {if (v != LOAD) grid_window->hide();} + tooltip {Close this dialog.} xywh {245 456 60 25} + } } + code {grid_window->do_callback(grid_window, LOAD);} {} } diff --git a/fluid/alignment_panel.h b/fluid/alignment_panel.h index 577648a94..b0e7b3ffc 100644 --- a/fluid/alignment_panel.h +++ b/fluid/alignment_panel.h @@ -1,7 +1,7 @@ // // Setting and shell dialogs for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2020 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 @@ -21,10 +21,12 @@ #include #include "fluid.h" #include "widget_browser.h" +#include "Fd_Snap_Action.h" #include "shell_command.h" #include #include #include +#include #include /** // initialize the scheme from preferences @@ -95,14 +97,21 @@ extern Fl_Simple_Terminal *shell_run_terminal; extern Fl_Return_Button *shell_run_button; Fl_Double_Window* make_shell_window(); extern Fl_Double_Window *grid_window; -extern void grid_cb(Fl_Int_Input*, long); -extern Fl_Int_Input *horizontal_input; -extern Fl_Int_Input *vertical_input; -extern Fl_Int_Input *snap_input; -extern void guides_cb(Fl_Check_Button*, long); -extern Fl_Check_Button *guides_toggle; -#include -extern void default_widget_size_cb(Fl_Round_Button*, long); -extern Fl_Round_Button *def_widget_size[6]; +extern Fl_Choice *layout_choice; +#include +extern Fl_Menu_Button *w_layout_menu; +#include +extern void propagate_load(Fl_Group*, void*); +extern void edit_layout_preset_cb(Fl_Button*, long); +extern Fl_Button *preset_choice[3]; +#include +extern Fl_Menu_Item fontmenu[]; Fl_Double_Window* make_layout_window(); +extern Fl_Menu_Item menu_layout_choice[]; +extern Fl_Menu_Item menu_w_layout_menu[]; +#define w_layout_menu_rename (menu_w_layout_menu+0) +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) #endif diff --git a/fluid/factory.cxx b/fluid/factory.cxx index 551d2b11e..a58648261 100644 --- a/fluid/factory.cxx +++ b/fluid/factory.cxx @@ -27,6 +27,7 @@ #include "fluid.h" #include "Fl_Window_Type.h" #include "Fl_Group_Type.h" +#include "Fd_Snap_Action.h" #include "pixmaps.h" #include "undo.h" @@ -1064,12 +1065,14 @@ Fl_Type *add_new_widget_from_user(Fl_Type *inPrototype, Strategy strategy) { Fl_Widget_Type *wt = (Fl_Widget_Type *)t; // Set font sizes... - wt->o->labelsize(Fl_Widget_Type::default_size); + wt->o->labelsize(layout->labelsize); + wt->o->labelfont(layout->labelfont); - Fl_Font f; - int s = Fl_Widget_Type::default_size; + Fl_Font f = layout->textfont; + int s = layout->textsize; Fl_Color c; + wt->textstuff(1, f, s, c); wt->textstuff(2, f, s, c); // Resize and/or reposition new widget... diff --git a/fluid/file.cxx b/fluid/file.cxx index db59a2733..2da570f3a 100644 --- a/fluid/file.cxx +++ b/fluid/file.cxx @@ -159,6 +159,10 @@ int Fd_Project_Reader::close_read() { return 1; } +const char *Fd_Project_Reader::filename_name() { + return fl_filename_name(fname); +} + /** Convert an ASCII sequence form the \.fl file that starts with a \\ into a single character. Conversion includes the common C style \\ characters like \\n, \\x## hex @@ -309,7 +313,12 @@ void Fd_Project_Reader::read_children(Fl_Type *p, int paste, Strategy strategy, goto CONTINUE; } - if (!strcmp(c, "snap") || !strcmp(c, "gridx") || !strcmp(c, "gridy")) { + if (!strcmp(c, "snap")) { + g_layout_list.read(this); + goto CONTINUE; + } + + if (!strcmp(c, "gridx") || !strcmp(c, "gridy")) { // grid settings are now global read_word(); goto CONTINUE; @@ -523,6 +532,15 @@ const char *Fd_Project_Reader::read_word(int wantbrace) { } } +int Fd_Project_Reader::read_int() { + const char *word = read_word(); + if (word) { + return atoi(word); + } else { + return 0; + } +} + int Fd_Project_Reader::read_fdesign_line(const char*& name, const char*& value) { int length = 0; int x; @@ -791,7 +809,7 @@ int Fd_Project_Writer::write_project(const char *filename, int selected_only) { if (!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. diff --git a/fluid/file.h b/fluid/file.h index 457d14e49..e45bd4256 100644 --- a/fluid/file.h +++ b/fluid/file.h @@ -46,11 +46,13 @@ public: ~Fd_Project_Reader(); int open_read(const char *s); int close_read(); + const char *filename_name(); int read_quoted(); void read_children(Fl_Type *p, int paste, Strategy strategy, char skip_options=0); int read_project(const char *, int merge, Strategy strategy=kAddAsLastChild); void read_error(const char *format, ...); const char *read_word(int wantbrace = 0); + int read_int(); int read_fdesign_line(const char*& name, const char*& value); void read_fdesign(); }; diff --git a/fluid/fluid.cxx b/fluid/fluid.cxx index 7512e7bc8..bb98006bc 100644 --- a/fluid/fluid.cxx +++ b/fluid/fluid.cxx @@ -1,7 +1,7 @@ // // FLUID main entry for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2022 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 @@ -72,16 +72,7 @@ Fl_Menu_Bar *main_menubar = NULL; Fl_Window *main_window; /// Fluid application preferences, allways accessible, will be flushed when app closes. -Fl_Preferences fluid_prefs(Fl_Preferences::USER_L, "fltk.org", "fluid"); - -/// Align widget position and size when designing, saved in app preferences and project file. -int gridx = 5; - -/// Align widget position and size when designing, saved in app preferences and project file. -int gridy = 5; - -/// Activate snapping to grid, saved in app preferences and project file. -int snap = 1; +Fl_Preferences fluid_prefs(Fl_Preferences::USER_L, "fltk.org", "fluid"); /// Show guides in the design window when positioning widgets, saved in app preferences. int show_guides = 1; @@ -132,6 +123,9 @@ Fl_Menu_Item *sourceview_item = NULL; /// Menuitem to show or hide the editing overlay, label will change if overlay visibility changes. Fl_Menu_Item *overlay_item = NULL; +/// Menuitem to show or hide the editing guides, label will change if overlay visibility changes. +Fl_Menu_Item *guides_item = NULL; + //////////////////////////////////////////////////////////////// /// Filename of the current .fl design file @@ -285,7 +279,6 @@ void Fluid_Project::reset() { code_file_set = 0; header_file_name = ".h"; code_file_name = ".cxx"; - } // ---- Sourceview definition @@ -693,6 +686,8 @@ void exit_cb(Fl_Widget *,void *) { if (help_dialog) delete help_dialog; + g_layout_list.write(fluid_prefs, FD_STORE_USER); + undo_clear(); // Destroy tree @@ -1144,10 +1139,6 @@ void delete_cb(Fl_Widget *, void *) { void paste_cb(Fl_Widget*, void*) { //if (ipasteoffset) force_parent = 1; pasteoffset = ipasteoffset; - // TODO: make the paste offset more predictable, if any at all. - // TODO: Don't use the grid if the user switched it off. - if (gridx>1) pasteoffset = ((pasteoffset-1)/gridx+1)*gridx; - if (gridy>1) pasteoffset = ((pasteoffset-1)/gridy+1)*gridy; undo_checkpoint(); undo_suspend(); Strategy strategy = kAddAfterCurrent; @@ -1370,6 +1361,9 @@ void print_menu_cb(Fl_Widget *, void *) { // ---- Main menu bar +extern void select_layout_preset_cb(Fl_Widget *, void *user_data); +extern void layout_suite_marker(Fl_Widget *, void *user_data); + /** This is the main Fluid menu. @@ -1428,6 +1422,7 @@ Fl_Menu_Item Main_Menu[] = { {"&Group", FL_F+7, group_cb}, {"Ung&roup", FL_F+8, ungroup_cb,0, FL_MENU_DIVIDER}, {"Hide O&verlays",FL_COMMAND+FL_SHIFT+'o',toggle_overlays}, + {"Hide Guides",FL_COMMAND+FL_SHIFT+'g',toggle_guides}, {"Show Widget &Bin...",FL_ALT+'b',toggle_widgetbin_cb}, {"Show Source Code...",FL_ALT+FL_SHIFT+'s', (Fl_Callback*)toggle_sourceview_cb, 0, FL_MENU_DIVIDER}, {"Pro&ject Settings...",FL_ALT+'p',show_project_cb}, @@ -1452,19 +1447,15 @@ Fl_Menu_Item Main_Menu[] = { {"&Height",0,(Fl_Callback *)align_widget_cb,(void*)31}, {"&Both",0,(Fl_Callback *)align_widget_cb,(void*)32}, {0}, - {"&Center In Group",0,0,0,FL_SUBMENU}, + {"&Center In Group",0,0,0,FL_SUBMENU|FL_MENU_DIVIDER}, {"&Horizontal",0,(Fl_Callback *)align_widget_cb,(void*)40}, {"&Vertical",0,(Fl_Callback *)align_widget_cb,(void*)41}, {0}, - {"Set &Widget Size",0,0,0,FL_SUBMENU|FL_MENU_DIVIDER}, - {"&Tiny",FL_ALT+'1',(Fl_Callback *)widget_size_cb,(void*)8,0,FL_NORMAL_LABEL,FL_HELVETICA,8}, - {"&Small",FL_ALT+'2',(Fl_Callback *)widget_size_cb,(void*)11,0,FL_NORMAL_LABEL,FL_HELVETICA,11}, - {"&Normal",FL_ALT+'3',(Fl_Callback *)widget_size_cb,(void*)14,0,FL_NORMAL_LABEL,FL_HELVETICA,14}, - {"&Medium",FL_ALT+'4',(Fl_Callback *)widget_size_cb,(void*)18,0,FL_NORMAL_LABEL,FL_HELVETICA,18}, - {"&Large",FL_ALT+'5',(Fl_Callback *)widget_size_cb,(void*)24,0,FL_NORMAL_LABEL,FL_HELVETICA,24}, - {"&Huge",FL_ALT+'6',(Fl_Callback *)widget_size_cb,(void*)32,0,FL_NORMAL_LABEL,FL_HELVETICA,32}, - {0}, - {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb}, + {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb, NULL, FL_MENU_DIVIDER}, + {"Presets", 0, layout_suite_marker, (void*)g_layout_list.main_menu_, FL_SUBMENU_POINTER }, + {"Application", 0, select_layout_preset_cb, (void*)0, FL_MENU_RADIO|FL_MENU_VALUE }, + {"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}, @@ -1618,11 +1609,7 @@ void toggle_sourceview_b_cb(Fl_Button*, void *) { */ void make_main_window() { if (!batch_mode) { - fluid_prefs.get("snap", snap, 1); - fluid_prefs.get("gridx", gridx, 5); - fluid_prefs.get("gridy", gridy, 5); fluid_prefs.get("show_guides", show_guides, 0); - fluid_prefs.get("widget_size", Fl_Widget_Type::default_size, 14); fluid_prefs.get("show_comments", show_comments, 1); shell_prefs_get(); make_layout_window(); @@ -1646,6 +1633,7 @@ void make_main_window() { widgetbin_item = (Fl_Menu_Item*)main_menubar->find_item(toggle_widgetbin_cb); sourceview_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_sourceview_cb); overlay_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_overlays); + guides_item = (Fl_Menu_Item*)main_menubar->find_item((Fl_Callback*)toggle_guides); main_menubar->global(); fill_in_New_Menu(); main_window->end(); @@ -2091,6 +2079,7 @@ int main(int argc,char **argv) { main_window->show(argc,argv); toggle_widgetbin_cb(0,0); toggle_sourceview_cb(0,0); + 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... open_history_cb(0, absolute_history[0]); @@ -2137,13 +2126,10 @@ int main(int argc,char **argv) { // Set (but do not start) timer callback for external editor updates ExternalCodeEditor::set_update_timer_callback(external_editor_timer); - grid_cb(horizontal_input, 0); // Makes sure that windows get snap params... - #ifdef _WIN32 Fl::run(); #else while (!quit_flag) Fl::wait(); - if (quit_flag) exit_cb(0,0); #endif // _WIN32 diff --git a/fluid/fluid.h b/fluid/fluid.h index 7d2a3ade2..c952558df 100644 --- a/fluid/fluid.h +++ b/fluid/fluid.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 @@ -42,9 +42,6 @@ extern Fl_Menu_Item Main_Menu[]; extern Fl_Menu_Bar *main_menubar; extern Fl_Window *main_window; -extern int gridx; -extern int gridy; -extern int snap; extern int show_guides; extern int show_comments; @@ -65,6 +62,9 @@ extern Fl_Menu_Item *history_item; extern Fl_Menu_Item *widgetbin_item; extern Fl_Menu_Item *sourceview_item; extern Fl_Menu_Item *overlay_item; +extern Fl_Button *overlay_button; +extern Fl_Menu_Item *guides_item; +extern Fl_Button *guides_button; extern int modflag; @@ -76,6 +76,7 @@ extern int compile_file; // fluid -c extern int compile_strings; // fluic -cs extern int batch_mode; +extern int pasteoffset; extern int pasteoffset; // ---- project settings @@ -133,7 +134,9 @@ extern void new_from_template_cb(Fl_Widget *w, void *v); extern int write_code_files(); extern void write_strings_cb(Fl_Widget *, void *); extern void align_widget_cb(Fl_Widget *, long); -extern void widget_size_cb(Fl_Widget *, long); extern void toggle_widgetbin_cb(Fl_Widget *, void *); +inline int fd_min(int a, int b) { return (a < b ? a : b); } +inline int fd_min(int a, int b, int c) { return fd_min(a, fd_min(b, c)); } + #endif // _FLUID_FLUID_H diff --git a/fluid/widget_browser.cxx b/fluid/widget_browser.cxx index 089184511..8354df0b9 100644 --- a/fluid/widget_browser.cxx +++ b/fluid/widget_browser.cxx @@ -1,7 +1,7 @@ // // Widget Browser code 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 diff --git a/fluid/widget_panel.cxx b/fluid/widget_panel.cxx index adbff5671..a88028237 100644 --- a/fluid/widget_panel.cxx +++ b/fluid/widget_panel.cxx @@ -113,6 +113,10 @@ Fl_Box *w_when_box=(Fl_Box *)0; Fl_Button *wLiveMode=(Fl_Button *)0; +Fl_Button *overlay_button=(Fl_Button *)0; + +Fl_Button *guides_button=(Fl_Button *)0; + /** Create a panel that can be used with all known widgets */ @@ -969,7 +973,7 @@ access the Widget pointer and \'v\' to access the user value."); } // Fl_Menu_Button* o o->end(); } // Fl_Group* o - { Fl_Group* o = new Fl_Group(95, 335, 310, 20, "Type:"); + { Fl_Group* o = new Fl_Group(95, 332, 310, 26, "Type:"); o->labelfont(1); o->labelsize(11); o->callback((Fl_Callback*)propagate_load); @@ -999,26 +1003,30 @@ access the Widget pointer and \'v\' to access the user value."); } // Fl_Tabs* o { Fl_Group* o = new Fl_Group(10, 370, 400, 20); o->labelsize(11); - { // Hidden resizable box - Fl_Box* o = new Fl_Box(10, 370, 75, 20); - o->labelsize(11); - o->hide(); - Fl_Group::current()->resizable(o); - } // Fl_Box* o - { wLiveMode = new Fl_Button(155, 370, 80, 20, "Live &Resize"); + { wLiveMode = new Fl_Button(10, 370, 80, 20, "Live &Resize"); wLiveMode->tooltip("Create a live duplicate of the selected widgets to test resizing and menu beh\ avior."); wLiveMode->type(1); wLiveMode->labelsize(11); wLiveMode->callback((Fl_Callback*)live_mode_cb); } // Fl_Button* wLiveMode - { Fl_Button* o = new Fl_Button(240, 370, 100, 20, "Hide &Overlays"); - o->tooltip("Hide the widget overlay box."); + { overlay_button = new Fl_Button(94, 370, 80, 20, "Hide &Overlays"); + overlay_button->tooltip("Hide the widget overlay box."); + overlay_button->labelsize(11); + overlay_button->callback((Fl_Callback*)overlay_cb); + } // Fl_Button* overlay_button + { guides_button = new Fl_Button(178, 370, 80, 20, "Hide &Guides"); + guides_button->tooltip("Hide alignment guides."); + guides_button->labelsize(11); + guides_button->callback((Fl_Callback*)guides_cb); + } // Fl_Button* guides_button + { // Hidden resizable box + Fl_Box* o = new Fl_Box(258, 370, 72, 20); o->labelsize(11); - o->labelcolor((Fl_Color)1); - o->callback((Fl_Callback*)overlay_cb); - } // Fl_Button* o - { Fl_Return_Button* o = new Fl_Return_Button(345, 370, 65, 20, "Close"); + o->hide(); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + { Fl_Return_Button* o = new Fl_Return_Button(330, 370, 80, 20, "Close"); o->labelsize(11); o->callback((Fl_Callback*)ok_cb); } // Fl_Return_Button* o diff --git a/fluid/widget_panel.fl b/fluid/widget_panel.fl index ea4c1ad24..afed58034 100644 --- a/fluid/widget_panel.fl +++ b/fluid/widget_panel.fl @@ -30,7 +30,7 @@ Function {make_widget_panel()} { comment {Create a panel that can be used with all known widgets} open } { Fl_Window {} { - comment {Use a Double Window to avoid flickering.} open + comment {Use a Double Window to avoid flickering.} open selected xywh {566 244 420 400} type Double labelsize 11 align 80 resizable hotspot code0 {o->size_range(o->w(), o->h());} size_range {420 400 0 0} visible } { @@ -40,7 +40,7 @@ Function {make_widget_panel()} { } { Fl_Group {} { label GUI - callback propagate_load open selected + callback propagate_load open xywh {10 30 400 330} labelsize 11 when 0 resizable } { Fl_Group {} { @@ -784,7 +784,7 @@ wCallback->do_callback(wCallback, v);} open Fl_Group {} { label {Type:} callback propagate_load open - xywh {95 335 310 20} labelfont 1 labelsize 11 align 4 + xywh {95 332 310 26} labelfont 1 labelsize 11 align 4 } { Fl_Input_Choice {} { callback user_data_type_cb open @@ -809,24 +809,29 @@ wCallback->do_callback(wCallback, v);} open Fl_Group {} {open xywh {10 370 400 20} labelsize 11 } { - Fl_Box {} { - comment {Hidden resizable box} - xywh {10 370 75 20} labelsize 11 hide resizable - } Fl_Button wLiveMode { label {Live &Resize} callback live_mode_cb - tooltip {Create a live duplicate of the selected widgets to test resizing and menu behavior.} xywh {155 370 80 20} type Toggle labelsize 11 + tooltip {Create a live duplicate of the selected widgets to test resizing and menu behavior.} xywh {10 370 80 20} type Toggle labelsize 11 } - Fl_Button {} { + Fl_Button overlay_button { label {Hide &Overlays} callback overlay_cb - tooltip {Hide the widget overlay box.} xywh {240 370 100 20} labelsize 11 labelcolor 1 + tooltip {Hide the widget overlay box.} xywh {94 370 80 20} labelsize 11 + } + Fl_Button guides_button { + label {Hide &Guides} + callback guides_cb + tooltip {Hide alignment guides.} xywh {178 370 80 20} labelsize 11 + } + Fl_Box {} { + comment {Hidden resizable box} + xywh {258 370 72 20} labelsize 11 hide resizable } Fl_Return_Button {} { label Close callback ok_cb - xywh {345 370 65 20} labelsize 11 + xywh {330 370 80 20} labelsize 11 } } } diff --git a/fluid/widget_panel.h b/fluid/widget_panel.h index ddeed0b79..261656317 100644 --- a/fluid/widget_panel.h +++ b/fluid/widget_panel.h @@ -135,6 +135,9 @@ extern Fl_Box *w_when_box; extern void live_mode_cb(Fl_Button*, void*); extern Fl_Button *wLiveMode; extern void overlay_cb(Fl_Button*, void*); +extern Fl_Button *overlay_button; +extern void guides_cb(Fl_Button*, void*); +extern Fl_Button *guides_button; #include extern void ok_cb(Fl_Return_Button*, void*); Fl_Double_Window* make_widget_panel(); diff --git a/src/Fl_Menu_.cxx b/src/Fl_Menu_.cxx index 60712a9ef..28a476e02 100644 --- a/src/Fl_Menu_.cxx +++ b/src/Fl_Menu_.cxx @@ -359,10 +359,11 @@ void Fl_Menu_::setonly(Fl_Menu_Item* item) { } /** Turns the radio item "on" for the menu item and turns "off" adjacent radio items set. - \deprecated This method is dangerous if radio items are first in the menu. - Use Fl_Menu_::setonly(Fl_Menu_Item*) instead. + \note This method is dangerous if radio items are first in the menu. + Make sure that \p first is set ciorrectly or use Fl_Menu_::setonly(Fl_Menu_Item*) instead. + \param[in] first start of menu array or NULL (default) if the radio group is not the first item */ -void Fl_Menu_Item::setonly() { +void Fl_Menu_Item::setonly(Fl_Menu_Item const* first) { flags |= FL_MENU_RADIO | FL_MENU_VALUE; Fl_Menu_Item* j; for (j = this; ; ) { // go down @@ -371,9 +372,10 @@ void Fl_Menu_Item::setonly() { if (!j->text || !j->radio()) break; // stop after group j->clear(); } - for (j = this-1; ; j--) { // go up + if (this != first) for (j = this-1; ; j--) { // go up if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break; j->clear(); + if (j == first) break; } } diff --git a/src/fl_draw.cxx b/src/fl_draw.cxx index 04ebbc6e0..5073d4ee4 100644 --- a/src/fl_draw.cxx +++ b/src/fl_draw.cxx @@ -43,15 +43,17 @@ static char* underline_at; */ static const char* expand_text_(const char* from, char*& buf, int maxbuf, double maxw, int& n, double &width, int wrap, int draw_symbols) { - char* e = buf+(maxbuf-4); underline_at = 0; double w = 0; static int l_local_buff = 500; static char *local_buf = (char*)malloc(l_local_buff); // initial buffer allocation + char* e; if (maxbuf == 0) { buf = local_buf; e = buf + l_local_buff - 4; - } + } else { + e = buf+(maxbuf-4); + } char* o = buf; char* word_end = o; const char* word_start = from; diff --git a/src/fl_symbols.cxx b/src/fl_symbols.cxx index e6ebb4199..2cb586ccb 100644 --- a/src/fl_symbols.cxx +++ b/src/fl_symbols.cxx @@ -655,6 +655,43 @@ static void draw_redo(Fl_Color c) { fl_scale(-1.0, 1.0); } +static void draw_open_box(Fl_Color col) { + fl_color(col); + BCP; + vv(-1.0, -1.0); vv(-0.4, -1.0); vv(-0.4, -0.75); vv(-0.75, -0.75); + vv(-0.75, 0.75); vv(0.75, 0.75); vv(0.75, 0.4); vv(1.0, 0.4); vv(1.0, 1.0); + vv(-1.0, 1.0); + ECP; + set_outline_color(col); + BC; + vv(-1.0, -1.0); vv(-0.4, -1.0); vv(-0.4, -0.75); vv(-0.75, -0.75); + vv(-0.75, 0.75); vv(0.75, 0.75); vv(0.75, 0.4); vv(1.0, 0.4); vv(1.0, 1.0); + vv(-1.0, 1.0); + EC; +} + +static void draw_import(Fl_Color col) +{ + fl_push_matrix(); + fl_scale(-1.0, 1.0); + draw_open_box(col); + fl_scale(-1.0, 1.0); + fl_translate(-0.8, -0.3); + fl_rotate(45.0+90); + draw_round_arrow(col, 3); + fl_pop_matrix(); +} + +static void draw_export(Fl_Color col) +{ + draw_open_box(col); + fl_push_matrix(); + fl_translate(0.7, 0.1); + fl_rotate(225.0); + draw_round_arrow(col, 3); + fl_pop_matrix(); +} + static void fl_init_symbols(void) { static char beenhere; if (beenhere) return; @@ -702,5 +739,8 @@ static void fl_init_symbols(void) { fl_add_symbol("undo", draw_undo, 1); fl_add_symbol("redo", draw_redo, 1); + fl_add_symbol("import", draw_import, 1); + fl_add_symbol("export", draw_export, 1); + // fl_add_symbol("file", draw_file, 1); } diff --git a/test/symbols.cxx b/test/symbols.cxx index d97dfa834..9c51e0fb4 100644 --- a/test/symbols.cxx +++ b/test/symbols.cxx @@ -28,7 +28,7 @@ int N = 0; #define W 70 #define H 70 #define ROWS 6 -#define COLS 6 +#define COLS 7 Fl_Double_Window *window; Fl_Value_Slider *orientation; @@ -119,6 +119,8 @@ bt("@refresh"); bt("@reload"); bt("@undo"); bt("@redo"); +bt("@import"); +bt("@export"); orientation = new Fl_Value_Slider( (int)(window->w()*.05+.5), window->h()-40,