diff options
| author | Matthias Melcher <github@matthiasm.com> | 2025-03-07 16:34:35 +0100 |
|---|---|---|
| committer | Matthias Melcher <github@matthiasm.com> | 2025-03-07 16:34:48 +0100 |
| commit | 1985aefc0e502048f92b91beef87c0dfbe669fed (patch) | |
| tree | af62874def4590e437a47784b4428d975ceb262f /fluid/Fd_Snap_Action.cxx | |
| parent | 42a04c064d4b31c3a85210311f3ada163c406a25 (diff) | |
Restructuring Fluid source files.
Diffstat (limited to 'fluid/Fd_Snap_Action.cxx')
| -rw-r--r-- | fluid/Fd_Snap_Action.cxx | 1816 |
1 files changed, 0 insertions, 1816 deletions
diff --git a/fluid/Fd_Snap_Action.cxx b/fluid/Fd_Snap_Action.cxx deleted file mode 100644 index 1e9fee1a3..000000000 --- a/fluid/Fd_Snap_Action.cxx +++ /dev/null @@ -1,1816 +0,0 @@ -// -// 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 "settings_panel.h" -#include "file.h" - -#include <FL/fl_draw.H> -#include <FL/Fl_Menu_Bar.H> -#include <FL/fl_string_functions.h> -#include <math.h> -#include <string.h> -#include <assert.h> - -// 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 disabling 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, -1, 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, -1, 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, -1, 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, -1, 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, -1, 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, -1, 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 } -}; - -Fl_Menu_Item main_layout_submenu_[] = { - { 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 *) { - // 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: - - -/** - Write presets to a Preferences database. - */ -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); -} - -/** - Read presets from a Preferences database. - */ -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); -} - -/** - Write presets to an .fl project file. - */ -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 -} - -/** - Read presets from an .fl project file. - */ -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 - } -} - -/** - Return the preferred text size, but make sure it's not 0. - */ -int Fd_Layout_Preset::textsize_not_null() { - // try the user selected text size - if (textsize > 0) return textsize; - // if the user did not set one, try the label size - if (labelsize > 0) return labelsize; - // if that doesn;t work, fall back to the default value - return 14; -} - - -// ---- Fd_Layout_Suite ------------------------------------------------ MARK: - - -/** - Write a presets suite to a Preferences database. - */ -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); - } -} - -/** - Read a presets suite from a Preferences database. - */ -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); - } -} - -/** - Write a presets suite to an .fl project file. - */ -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"); -} - -/** - Read a presets suite from an .fl project file. - */ -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 - } -} - -/** - \brief Update the menu_label to show a symbol representing the storage location. - Also updates the FLUID user interface. - */ -void Fd_Layout_Suite::update_label() { - std::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(); -} - -/** - \brief Update the Suite name and the Suite menu_label. - Also updates the FLUID user interface. - */ -void Fd_Layout_Suite::name(const char *n) { - if (name_) - ::free(name_); - if (n) - name_ = fl_strdup(n); - else - name_ = NULL; - update_label(); -} - -/** - Initialize the class for first use. - */ -void Fd_Layout_Suite::init() { - name_ = NULL; - menu_label = NULL; - layout[0] = layout[1] = layout[2] = NULL; - storage_ = FD_STORE_INTERNAL; -} - -/** - Free all allocated resources. - */ -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: - - -/** - Draw a little FLUID beaker symbol. - */ -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(); -} - -/** - Draw a user silhouette symbol - */ -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(); -} - -/** - Draw a document symbol. - */ -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(); -} - -/** - Draw a 3 1/2" floppy symbol. - */ -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(); -} - -/** - Instantiate the class that holds a list of all layouts and manages the UI. - */ -Fd_Layout_List::Fd_Layout_List() -: main_menu_(main_layout_submenu_), - 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) -{ - 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); -} - -/** - Release allocated resources. - */ -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_); - } -} - -/** - Update the Setting dialog and menus to reflect the current Layout selection state. - */ -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 (w_settings_layout_tab) { - w_settings_layout_tab->do_callback(w_settings_layout_tab, LOAD); - layout_choice->redraw(); - } - preset_menu[current_preset_].setonly(preset_menu); - main_menu_[current_suite_].setonly(main_menu_); -} - -/** - Refresh the label pointers for both pulldown menus. - */ -void Fd_Layout_List::update_menu_labels() { - for (int i=0; i<list_size_; i++) { - main_menu_[i].label(list_[i].menu_label); - choice_menu_[i].label(list_[i].menu_label); - } -} - -/** - Load all user layouts from the FLUID user preferences. - */ -int Fd_Layout_List::load(const std::string &filename) { - remove_all(FD_STORE_FILE); - Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", NULL, Fl_Preferences::C_LOCALE); - read(prefs, FD_STORE_FILE); - return 0; -} - -/** - Save all user layouts to the FLUID user preferences. - */ -int Fd_Layout_List::save(const std::string &filename) { - assert(this); - Fl_Preferences prefs(filename.c_str(), "layout.fluid.fltk.org", NULL, (Fl_Preferences::Root)(Fl_Preferences::C_LOCALE|Fl_Preferences::CLEAR)); - prefs.clear(); - write(prefs, FD_STORE_FILE); - return 0; -} - -/** - Write Suite and Layout selection and selected layout data to Preferences database. - */ -void Fd_Layout_List::write(Fl_Preferences &prefs, Fd_Tool_Store storage) { - Fl_Preferences prefs_list(prefs, "Layouts"); - prefs_list.clear(); - prefs_list.set("current_suite", list_[current_suite()].name_); - prefs_list.set("current_preset", current_preset()); - int n = 0; - for (int i = 0; i < list_size_; ++i) { - Fd_Layout_Suite &suite = list_[i]; - if (suite.storage_ == storage) { - Fl_Preferences prefs_suite(prefs_list, Fl_Preferences::Name(n++)); - suite.write(prefs_suite); - } - } -} - -/** - Read Suite and Layout selection and selected layout data to Preferences database. - */ -void Fd_Layout_List::read(Fl_Preferences &prefs, Fd_Tool_Store storage) { - Fl_Preferences prefs_list(prefs, "Layouts"); - std::string cs; - int cp = 0; - preferences_get(prefs_list, "current_suite", cs, ""); - prefs_list.get("current_preset", cp, 0); - for (int i = 0; i < prefs_list.groups(); ++i) { - Fl_Preferences prefs_suite(prefs_list, Fl_Preferences::Name(i)); - char *new_name = NULL; - prefs_suite.get("name", new_name, NULL); - if (new_name) { - int n = add(new_name); - list_[n].read(prefs_suite); - list_[n].storage(storage); - ::free(new_name); - } - } - current_suite(cs); - current_preset(cp); - update_dialogs(); -} - -/** - Write Suite and Layout selection and project layout data to an .fl project file. - */ -void Fd_Layout_List::write(Fd_Project_Writer *out) { - // Don't write the Snap field if no custom layout was used - if ((current_suite()==0) && (current_preset()==0)) { - int nSuite = 0; - for (int i=0; i<list_size_; i++) { - if (list_[i].storage_ == FD_STORE_PROJECT) nSuite++; - } - if (nSuite == 0) return; - } - out->write_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; i<list_size_; i++) { - Fd_Layout_Suite &suite = list_[i]; - if (suite.storage_ == FD_STORE_PROJECT) - suite.write(out); - } - out->write_string("}"); -} - -/** - Read Suite and Layout selection and project layout data from an .fl project file. - */ -void Fd_Layout_List::read(Fd_Project_Reader *in) { - const char *key; - key = in->read_word(1); - if (key && !strcmp(key, "{")) { - std::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. - } -} - -/** - Set the current Suite. - \param[in] ix index into list of suites - */ -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_]; -} - -/** - Set the current Suite. - \param[in] arg_name name of the selected suite - \return if no name is given or the name is not found, keep the current suite selected - */ -void Fd_Layout_List::current_suite(std::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; - } - } -} - -/** - Select a Preset within the current Suite. - \param[in] ix 0 = application, 1 = dialog, 2 = toolbox - */ -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; - if (layout_choice) layout_choice->menu(choice_menu_); - - list_capacity_ = n; - list_is_static_ = false; -} - -/** - \brief Clone the currently selected suite and append it to the list. - Selects 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)); - } - Fd_Tool_Store 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; -} - -/** - Rename the current Suite. - */ -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); -} - -/** - Remove the given suite. - \param[in] ix index into list of suites - */ -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); -} - -/** - Remove all Suites that use the given storage attribute. - \param[in] storage storage attribute, see FD_STORE_INTERNAL, etc. - */ -void Fd_Layout_List::remove_all(Fd_Tool_Store 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); -void draw_width(int x, int y, int r, Fl_Align a); -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_a(ID_Group) && d.wgt->parent != d.win); -} - -static bool in_tabs(Fd_Snap_Data &d) { - return (d.wgt && d.wgt->parent && d.wgt->parent->is_a(ID_Tabs)); -} - -static Fl_Group *parent(Fd_Snap_Data &d) { - return (d.wgt->o->parent()); -} - -// ---- Fd_Snap_Action ------------------------------------------------- MARK: - - -/** \class Fd_Snap_Action - - When a user drags one or more widgets, snap actions can be defined that provide - hints if a preferred widget position or size is nearby. The user's motion is - then directed towards the nearest preferred position, and the widget selection - snaps into place. - - FLUID provides a list of various snap actions. Every snap action uses the data - from the motion event and combines it with the sizes and positions of all other - widgets in the layout. - - Common snap actions include gaps and margins, but also alignments and - simple grid positions. - */ - -/** - \brief Check if a snap action has reached a preferred x position. - \param[inout] d current event data - \param[in] x_ref position of moving point - \param[in] x_snap position of target point - \return 1 if the points are not within range and won;t be considered - \return 0 if the point is as close as another in a previous action - \return -1 if this point is closer than any previous check, and this is the - new distance to beat. - */ -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; -} - -/** - \brief Check if a snap action has reached a preferred y position. - \see Fd_Snap_Action::check_x_(Fd_Snap_Data &d, int x_ref, int x_snap) - */ -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; -} - -/** - \brief Check if a snap action has reached a preferred x and y position. - \see Fd_Snap_Action::check_x_(Fd_Snap_Data &d, int x_ref, int x_snap) - */ -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; - } -} - -/** - \brief Check if a snap action was applied to the current event. - This method is used to determine if a visual indicator for this snap action - should be drawn. - \param[inout] d current event data - */ -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; -} - -/** - \brief Run through all possible snap actions and store the winning coordinates in eex and eey. - \param[inout] d current event data - */ -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; -} - -/** - \brief Draw a visual indicator for all snap actions that were applied during the last check. - Only one snap coordinate can win. FLUID chooses the one that is closest to - the current user event. If two or more snap actions suggest the same - coordinate, all of them will be drawn. - \param[inout] d current event data - */ -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; - } -} - -/** Fix the given size to the same or next bigger snap position. */ -void Fd_Snap_Action::better_size(int &w, int &h) { - int x_min = 1, y_min = 1, x_inc = 1, y_inc = 1; - get_resize_stepsize(x_inc, y_inc); - if (x_inc < 1) x_inc = 1; - if (y_inc < 1) y_inc = 1; - if ((layout->widget_min_w > 1) && (layout->widget_min_h > 1)) { - x_min = layout->widget_min_w; - y_min = layout->widget_min_h; - } else if ((layout->group_grid_x > 1) && (layout->group_grid_y > 1)) { - x_min = layout->group_grid_x; - y_min = layout->group_grid_y; - } else { - x_min = x_inc; - y_min = y_inc; - } - int ww = fd_max(w - x_min, 0); w = (w - ww + x_inc - 1) / x_inc; w = w * x_inc; w = w + ww; - int hh = fd_max(h - y_min, 0); h = (h - hh + y_inc - 1) / y_inc; h = h * y_inc; h = h + hh; -} - - -// ---- snapping prototypes -------------------------------------------- MARK: - - -/** - Base class for all actions that drag the left side or the entire widget. - */ -class Fd_Snap_Left : public Fd_Snap_Action { -public: - Fd_Snap_Left() { type = 1; mask = FD_LEFT|FD_DRAG; } -}; - -/** - Base class for all actions that drag the right side or the entire widget. - */ -class Fd_Snap_Right : public Fd_Snap_Action { -public: - Fd_Snap_Right() { type = 1; mask = FD_RIGHT|FD_DRAG; } -}; - -/** - Base class for all actions that drag the top side or the entire widget. - */ -class Fd_Snap_Top : public Fd_Snap_Action { -public: - Fd_Snap_Top() { type = 2; mask = FD_TOP|FD_DRAG; } -}; - -/** - Base class for all actions that drag the bottom side or the entire widget. - */ -class Fd_Snap_Bottom : public Fd_Snap_Action { -public: - Fd_Snap_Bottom() { type = 2; mask = FD_BOTTOM|FD_DRAG; } -}; - -// ---- window snapping ------------------------------------------------ MARK: - - -/** - Check if the widget hits the left window edge. - */ -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; - -/** - Check if the widget hits the right 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; - -/** - Check if the widget hits the top 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; - -/** - Check if the widget hits the bottom 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; - -/** - Check if the widget hits the left window edge plus a user defined margin. - */ -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: - - -/** - Check if the widget hits the left group edge. - */ -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; - - -/** - Check if the widget hits the left group edge plus a user defined margin. - */ -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: - - -/** - Check if the widget top hits the Fl_Tabs group top edge plus a user defined margin. - */ -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: - - -/** - Base class for grid based snapping. - */ -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); - } -}; - -/** - Check if the widget hits window grid coordinates. - */ -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; - -/** - Check if the widget hits group grid coordinates. - */ -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: - - -/** - Base class the check distance to other widgets in the same group. - */ -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_a(ID_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; i<g->children(); 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; - } - } - } - } -}; - -/** - Check if widgets have the same x coordinate, so they can be vertically aligned. - */ -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; - -/** - Check if widgets touch left to right, or have a user selected gap left to right. - */ -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: - - -/** - Snap horizontal resizing to min_w or min_w and a multiple of inc_w. - */ -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: - - -/** - /brief The list of all snap actions available to FLUID. - New snap actions can be appended to the list. If multiple snap actions - with different coordinates, but the same snap distance are found, the last - action in the list wins. All snap actions with the same distance and same - winning coordinates are drawn in the overlay plane. - */ -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); -} - -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); -} - -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); - } - } - } -} |
