From 6fbfaba19d0a2d2dc7080e450d5055ff19ac89e1 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Wed, 15 Feb 2023 15:24:25 +0100 Subject: Move class Fl_Shortcut_Button from FLUID to core (#677) (#680) --- fluid/CMakeLists.txt | 4 +- fluid/Fl_Menu_Type.cxx | 47 ++++--- fluid/Fl_Widget_Type.cxx | 5 +- fluid/Makefile | 2 +- fluid/Shortcut_Button.cxx | 349 ---------------------------------------------- fluid/Shortcut_Button.h | 99 ------------- fluid/custom_widgets.cxx | 294 ++++++++++++++++++++++++++++++++++++++ fluid/custom_widgets.h | 89 ++++++++++++ fluid/function_panel.cxx | 2 +- fluid/function_panel.fl | 4 +- fluid/widget_panel.cxx | 22 +-- fluid/widget_panel.fl | 23 +-- fluid/widget_panel.h | 6 +- 13 files changed, 449 insertions(+), 497 deletions(-) delete mode 100644 fluid/Shortcut_Button.cxx delete mode 100644 fluid/Shortcut_Button.h create mode 100644 fluid/custom_widgets.cxx create mode 100644 fluid/custom_widgets.h (limited to 'fluid') diff --git a/fluid/CMakeLists.txt b/fluid/CMakeLists.txt index a7a0d08df..a9aac0019 100644 --- a/fluid/CMakeLists.txt +++ b/fluid/CMakeLists.txt @@ -24,11 +24,11 @@ set (CPPFILES Fl_Widget_Type.cxx Fl_Window_Type.cxx Fluid_Image.cxx - Shortcut_Button.cxx about_panel.cxx align_widget.cxx alignment_panel.cxx code.cxx + custom_widgets.cxx factory.cxx file.cxx fluid.cxx @@ -52,13 +52,13 @@ set (HEADERFILES Fl_Widget_Type.h Fl_Window_Type.h Fluid_Image.h - Shortcut_Button.h StyleParse.h about_panel.h align_widget.h alignment_panel.h code.h comments.h + custom_widgets.h factory.h file.h fluid.h diff --git a/fluid/Fl_Menu_Type.cxx b/fluid/Fl_Menu_Type.cxx index 371f7ab29..9d88f56c8 100644 --- a/fluid/Fl_Menu_Type.cxx +++ b/fluid/Fl_Menu_Type.cxx @@ -28,7 +28,7 @@ #include "file.h" #include "code.h" #include "Fluid_Image.h" -#include "Shortcut_Button.h" +#include "custom_widgets.h" #include #include @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -392,14 +393,18 @@ void Fl_Menu_Item_Type::write_item(Fd_Code_Writer& f) { else f.write_c("\"\""); if (((Fl_Button*)o)->shortcut()) { - int s = ((Fl_Button*)o)->shortcut(); - if (g_project.use_FL_COMMAND && (s & (FL_CTRL|FL_META))) { - f.write_c(", FL_COMMAND|0x%x, ", s & ~(FL_CTRL|FL_META)); - } else { - f.write_c(", 0x%x, ", s); - } - } else + int s = ((Fl_Button*)o)->shortcut(); + if (g_project.use_FL_COMMAND && (s & (FL_CTRL|FL_META))) { + f.write_c(", "); + if (s & FL_COMMAND) f.write_c("FL_COMMAND|"); + if (s & FL_CONTROL) f.write_c("FL_CONTROL|"); + f.write_c("0x%x, ", s & ~(FL_CTRL|FL_META)); + } else { + f.write_c(", 0x%x, ", s); + } + } else { f.write_c(", 0, "); + } if (callback()) { const char* k = is_name(callback()) ? 0 : class_name(1); if (k) { @@ -689,16 +694,16 @@ Fl_Menu_Bar_Type Fl_Menu_Bar_type; // Shortcut entry item in panel: -void shortcut_in_cb(Shortcut_Button* i, void* v) { +void shortcut_in_cb(Fl_Shortcut_Button* i, void* v) { if (v == LOAD) { if (current_widget->is_button()) - i->svalue = ((Fl_Button*)(current_widget->o))->shortcut(); + i->value( ((Fl_Button*)(current_widget->o))->shortcut() ); else if (current_widget->is_input()) - i->svalue = ((Fl_Input_*)(current_widget->o))->shortcut(); + i->value( ((Fl_Input_*)(current_widget->o))->shortcut() ); else if (current_widget->is_value_input()) - i->svalue = ((Fl_Value_Input*)(current_widget->o))->shortcut(); + i->value( ((Fl_Value_Input*)(current_widget->o))->shortcut() ); else if (current_widget->is_text_display()) - i->svalue = ((Fl_Text_Display*)(current_widget->o))->shortcut(); + i->value( ((Fl_Text_Display*)(current_widget->o))->shortcut() ); else { i->hide(); return; @@ -710,21 +715,21 @@ void shortcut_in_cb(Shortcut_Button* i, void* v) { for (Fl_Type *o = Fl_Type::first; o; o = o->next) if (o->selected && o->is_button()) { Fl_Button* b = (Fl_Button*)(((Fl_Widget_Type*)o)->o); - if (b->shortcut()!=i->svalue) mod = 1; - b->shortcut(i->svalue); + if (b->shortcut() != (int)i->value()) mod = 1; + b->shortcut(i->value()); if (o->is_menu_item()) ((Fl_Widget_Type*)o)->redraw(); } else if (o->selected && o->is_input()) { Fl_Input_* b = (Fl_Input_*)(((Fl_Widget_Type*)o)->o); - if (b->shortcut()!=i->svalue) mod = 1; - b->shortcut(i->svalue); + if (b->shortcut() != (int)i->value()) mod = 1; + b->shortcut(i->value()); } else if (o->selected && o->is_value_input()) { Fl_Value_Input* b = (Fl_Value_Input*)(((Fl_Widget_Type*)o)->o); - if (b->shortcut()!=i->svalue) mod = 1; - b->shortcut(i->svalue); + if (b->shortcut() != (int)i->value()) mod = 1; + b->shortcut(i->value()); } else if (o->selected && o->is_text_display()) { Fl_Text_Display* b = (Fl_Text_Display*)(((Fl_Widget_Type*)o)->o); - if (b->shortcut()!=i->svalue) mod = 1; - b->shortcut(i->svalue); + if (b->shortcut() != (int)i->value()) mod = 1; + b->shortcut(i->value()); } if (mod) set_modflag(1); } diff --git a/fluid/Fl_Widget_Type.cxx b/fluid/Fl_Widget_Type.cxx index 76cc31b11..afdb61823 100644 --- a/fluid/Fl_Widget_Type.cxx +++ b/fluid/Fl_Widget_Type.cxx @@ -3019,7 +3019,10 @@ void Fl_Widget_Type::write_widget_code(Fd_Code_Writer& f) { else if (is_text_display()) shortcut = ((Fl_Text_Display*)o)->shortcut(); if (shortcut) { if (g_project.use_FL_COMMAND && (shortcut & (FL_CTRL|FL_META))) { - f.write_c("%s%s->shortcut(FL_COMMAND|0x%x);\n", f.indent(), var, shortcut & ~(FL_CTRL|FL_META)); + f.write_c("%s%s->shortcut(", f.indent(), var); + if (shortcut & FL_COMMAND) f.write_c("FL_COMMAND|"); + if (shortcut & FL_CONTROL) f.write_c("FL_CONTROL|"); + f.write_c("0x%x);\n", shortcut & ~(FL_CTRL|FL_META)); } else { f.write_c("%s%s->shortcut(0x%x);\n", f.indent(), var, shortcut); } diff --git a/fluid/Makefile b/fluid/Makefile index aa85f8d14..3511b683e 100644 --- a/fluid/Makefile +++ b/fluid/Makefile @@ -26,11 +26,11 @@ CPPFILES = \ Fl_Widget_Type.cxx \ Fl_Window_Type.cxx \ Fluid_Image.cxx \ - Shortcut_Button.cxx \ about_panel.cxx \ align_widget.cxx \ alignment_panel.cxx \ code.cxx \ + custom_widgets.cxx \ factory.cxx \ file.cxx \ fluid.cxx \ diff --git a/fluid/Shortcut_Button.cxx b/fluid/Shortcut_Button.cxx deleted file mode 100644 index bbeb6305f..000000000 --- a/fluid/Shortcut_Button.cxx +++ /dev/null @@ -1,349 +0,0 @@ -// -// Widget type code for the Fast Light Tool Kit (FLTK). -// -// 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 -// 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 "Shortcut_Button.h" - -#include "fluid.h" -#include "Fl_Window_Type.h" -#include "factory.h" -#include "widget_panel.h" -#include "widget_browser.h" - -#include -#include -#include -#include -#include -#include -#include "../src/flstring.h" - -/** \class Shortcut_Button - A button that allows the user to type a key combination to create shortcuts. - After clicked once, the button catches the following keyboard events and - records the pressed keys and all modifiers. It draws a text representation of - the shortcut. The backspace key deletes the current shortcut. - */ - -/** - Draw the textual representation of the shortcut. - */ -void Shortcut_Button::draw() { - if (value()) draw_box(FL_DOWN_BOX, (Fl_Color)9); - else draw_box(FL_UP_BOX, FL_WHITE); - fl_font(FL_HELVETICA,14); fl_color(FL_FOREGROUND_COLOR); - if (g_project.use_FL_COMMAND && (svalue & (FL_CTRL|FL_META))) { - char buf[1024]; - fl_snprintf(buf, 1023, "Command+%s", fl_shortcut_label(svalue&~(FL_CTRL|FL_META))); - fl_draw(buf,x()+6,y(),w(),h(),FL_ALIGN_LEFT); - } else { - fl_draw(fl_shortcut_label(svalue),x()+6,y(),w(),h(),FL_ALIGN_LEFT); - } -} - -/** - Handle keystrokes to catch the user's shortcut. - */ -int Shortcut_Button::handle(int e) { - when(0); type(FL_TOGGLE_BUTTON); - if (e == FL_KEYBOARD) { - if (!value()) return 0; - int v = Fl::event_text()[0]; - if ( (v > 32 && v < 0x7f) || (v > 0xa0 && v <= 0xff) ) { - if (isupper(v)) { - v = tolower(v); - v |= FL_SHIFT; - } - v = v | (Fl::event_state()&(FL_META|FL_ALT|FL_CTRL)); - } else { - v = (Fl::event_state()&(FL_META|FL_ALT|FL_CTRL|FL_SHIFT)) | Fl::event_key(); - if (v == FL_BackSpace && svalue) v = 0; - } - if (v != svalue) {svalue = v; set_changed(); redraw(); do_callback(); } - return 1; - } else if (e == FL_UNFOCUS) { - int c = changed(); value(0); if (c) set_changed(); - return 1; - } else if (e == FL_FOCUS) { - return value(); - } else { - int r = Fl_Button::handle(e); - if (e == FL_RELEASE && value() && Fl::focus() != this) take_focus(); - return r; - } -} - -/** \class Widget_Bin_Button - The Widget_Bin_Button button is a button that can be used in the widget bin to - allow the user to drag and drop widgets into a window or group. This feature - makes it easy for the user to position a widget at a specific location within - the window or group. - */ - -/** - Convert mouse dragging into a drag and drop event. - */ -int Widget_Bin_Button::handle(int inEvent) -{ - int ret = 0; - switch (inEvent) { - case FL_PUSH: - Fl_Button::handle(inEvent); - return 1; // make sure that we get drag events - case FL_DRAG: - ret = Fl_Button::handle(inEvent); - if (!user_data()) - return ret; - if (!Fl::event_is_click()) { // make it a dnd event - // fake a drag outside of the widget - Fl::e_x = x()-1; - Fl_Button::handle(inEvent); - // fake a buttton release - Fl_Button::handle(FL_RELEASE); - // make it into a dnd event - const char *type_name = (const char*)user_data(); - Fl_Type::current_dnd = Fl_Type::current; - Fl::copy(type_name, (int)strlen(type_name)+1, 0); - Fl::dnd(); - return 1; - } - return ret; - } - return Fl_Button::handle(inEvent); -} - -/** \class Widget_Bin_Window_Button - The Widget_Bin_Window_Button button is used in the widget bin to create new - windows by dragging and dropping. When the button is dragged and dropped onto - the desktop, a new window will be created at the drop location. - */ - -/** - Convert mouse dragging into a drag and drop event. - */ -int Widget_Bin_Window_Button::handle(int inEvent) -{ - static Fl_Window *drag_win = NULL; - int ret = 0; - switch (inEvent) { - case FL_PUSH: - Fl_Button::handle(inEvent); - return 1; // make sure that we get drag events - case FL_DRAG: - ret = Fl_Button::handle(inEvent); - if (!user_data()) - return ret; - if (!Fl::event_is_click()) { - if (!drag_win) { - drag_win = new Fl_Window(0, 0, 100, 100); - drag_win->border(0); - drag_win->set_non_modal(); - } - if (drag_win) { - drag_win->position(Fl::event_x_root()+1, Fl::event_y_root()+1); - drag_win->show(); - } - // Does not work outside window: fl_cursor(FL_CURSOR_HAND); - } - return ret; - case FL_RELEASE: - if (drag_win) { - Fl::delete_widget(drag_win); - drag_win = NULL; - // create a new window here - Fl_Type *prototype = typename_to_prototype((char*)user_data()); - if (prototype) { - Fl_Type *new_type = add_new_widget_from_user(prototype, kAddAfterCurrent); - if (new_type && new_type->is_window()) { - Fl_Window_Type *new_window = (Fl_Window_Type*)new_type; - Fl_Window *w = (Fl_Window *)new_window->o; - w->position(Fl::event_x_root(), Fl::event_y_root()); - } - } - widget_browser->display(Fl_Type::current); - widget_browser->rebuild(); - } - return Fl_Button::handle(inEvent); - } - return Fl_Button::handle(inEvent); -} - -/** \class Fluid_Coord_Input - The Fluid_Coord_Input widget is an input field for entering widget coordinates - and sizes. It includes basic math capabilities and allows the use of variables - in formulas. This widget is useful for specifying precise positions and - dimensions for widgets in a graphical user interface. - */ - -/** - Create an input field. - */ -Fluid_Coord_Input::Fluid_Coord_Input(int x, int y, int w, int h, const char *l) : -Fl_Input(x, y, w, h, l), -user_callback_(0L), -vars_(0L), -vars_user_data_(0L) -{ - Fl_Input::callback((Fl_Callback*)callback_handler_cb); -} - -void Fluid_Coord_Input::callback_handler_cb(Fluid_Coord_Input *This, void *v) { - This->callback_handler(v); -} - -void Fluid_Coord_Input::callback_handler(void *v) { - if (user_callback_) - (*user_callback_)(this, v); - // do *not* update the value to show the evaluated fomule here, because the - // values of the variables have already updated after the user callback. -} - -/** - Get the value of a variable. - Collects all conesecutive ASCII letters into a variable name, scans the - Variable list for that name, and then calls the corresponding callback from - the Variable array. - \param s points to the first character of the variable name, must point after - the last character of the variable name when returning. - \return the integer value that wasf= found or calculated - */ -int Fluid_Coord_Input::eval_var(uchar *&s) const { - if (!vars_) - return 0; - // find the end of the variable name - uchar *v = s; - while (isalpha(*s)) s++; - int n = (int)(s-v); - // find the variable in the list - for (Fluid_Coord_Input_Vars *vars = vars_; vars->name_; vars++) { - if (strncmp((char*)v, vars->name_, n)==0 && vars->name_[n]==0) - return vars->callback_(this, vars_user_data_); - } - return 0; -} - -/** - Evaluate a formula into an integer, recursive part. - \param s remaining text in this formula, must return a pointer to the next - character that will be interpreted. - \param prio priority of current operation - \return the value so far - */ -int Fluid_Coord_Input::eval(uchar *&s, int prio) const { - int v = 0, sgn = 1; - uchar c = *s++; - - // check for end of text - if (c==0) { s--; return sgn*v; } - - // check for unary operator - if (c=='-') { sgn = -1; c = *s++; } - else if (c=='+') { sgn = 1; c = *s++; } - - // read value, variable, or bracketed term - if (c==0) { - s--; return sgn*v; - } else if (c>='0' && c<='9') { - // numeric value - while (c>='0' && c<='9') { - v = v*10 + (c-'0'); - c = *s++; - } - } else if (isalpha(c)) { - v = eval_var(--s); - c = *s++; - } else if (c=='(') { - // opening bracket - v = eval(s, 5); - } else { - return sgn*v; // syntax error - } - if (sgn==-1) v = -v; - - // Now evaluate all following binary operators - for (;;) { - if (c==0) { - s--; - return v; - } else if (c=='+' || c=='-') { - if (prio<=4) { s--; return v; } - if (c=='+') { v += eval(s, 4); } - else if (c=='-') { v -= eval(s, 4); } - } else if (c=='*' || c=='/') { - if (prio<=3) { s--; return v; } - if (c=='*') { v *= eval(s, 3); } - else if (c=='/') { - int x = eval(s, 3); - if (x!=0) // if x is zero, don't divide - v /= x; - } - } else if (c==')') { - return v; - } else { - return v; // syntax error - } - c = *s++; - } - return v; -} - -/** - Evaluate a formula into an integer. - - The Fluid_Coord_Input widget includes a formula interpreter that allows you - to evaluate a string containing a mathematical formula and obtain the result - as an integer. The interpreter supports unary plus and minus, basic integer - math operations (such as addition, subtraction, multiplication, and division), - and brackets. It also allows you to define a list of variables by name and use - them in the formula. The interpreter does not perform error checking, so it is - assumed that the formula is entered correctly. - - \param s formula as a C string - \return the calculated value - */ -int Fluid_Coord_Input::eval(const char *s) const -{ - // duplicate the text, so we can modify it - uchar *buf = (uchar*)fl_strdup(s); - uchar *src = buf, *dst = buf; - // remove all whitespace to make the parser easier - for (;;) { - uchar c = *src++; - if (c==' ' || c=='\t') continue; - *dst++ = c; - if (c==0) break; - } - src = buf; - // now jump into the recursion - int ret = eval(src, 5); - ::free(buf); - return ret; -} - -/** - Evaluate the formula and return the result. - */ -int Fluid_Coord_Input::value() const { - return eval(text()); -} - -/** - Set the field to an integer value, replacing previous texts. - */ -void Fluid_Coord_Input::value(int v) { - char buf[32]; - fl_snprintf(buf, sizeof(buf), "%d", v); - text(buf); -} diff --git a/fluid/Shortcut_Button.h b/fluid/Shortcut_Button.h deleted file mode 100644 index 7f1755ef0..000000000 --- a/fluid/Shortcut_Button.h +++ /dev/null @@ -1,99 +0,0 @@ -// -// Shortcut header file for the Fast Light Tool Kit (FLTK). -// -// Copyright 1998-2010 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_SHORTCUT_BUTTON_H -#define _FLUID_SHORTCUT_BUTTON_H - -#include -#include - -// Button will catch and display keyboard shortcuts when activated. -class Shortcut_Button : public Fl_Button { -public: - int svalue; - int handle(int) FL_OVERRIDE; - void draw() FL_OVERRIDE; - Shortcut_Button(int X,int Y,int W,int H, const char* l = 0) : - Fl_Button(X,Y,W,H,l) {svalue = 0;} -}; - -// Adding drag and drop for dragging widgets into windows. -class Widget_Bin_Button : public Fl_Button { -public: - int handle(int) FL_OVERRIDE; - Widget_Bin_Button(int X,int Y,int W,int H, const char* l = 0) : - Fl_Button(X,Y,W,H,l) { } -}; - -// Adding drag and drop functionality to drag window prototypes onto the desktop. -class Widget_Bin_Window_Button : public Fl_Button { -public: - int handle(int) FL_OVERRIDE; - Widget_Bin_Window_Button(int X,int Y,int W,int H, const char* l = 0) : - Fl_Button(X,Y,W,H,l) { } -}; - -// Callback signature for function returning the value of a variable. -typedef int (Fluid_Coord_Callback)(class Fluid_Coord_Input const *, void*); - -// Entry for a list of variables available to an input field. -// Fluid_Coord_Input::variables() expects an array of Fluid_Coord_Input_Vars -// with the last entry's name_ set to NULL. -typedef struct Fluid_Coord_Input_Vars { - const char *name_; - Fluid_Coord_Callback *callback_; -} Fluid_Coord_Input_Vars; - -// A text input widget that understands simple math. -class Fluid_Coord_Input : public Fl_Input -{ - Fl_Callback *user_callback_; - Fluid_Coord_Input_Vars *vars_; - void *vars_user_data_; - static void callback_handler_cb(Fluid_Coord_Input *This, void *v); - void callback_handler(void *v); - int eval_var(uchar *&s) const; - int eval(uchar *&s, int prio) const; - int eval(const char *s) const; - -public: - Fluid_Coord_Input(int x, int y, int w, int h, const char *l=0L); - - /** Return the text in the widget text field. */ - const char *text() const { return Fl_Input::value(); } - - /** Set the text in the text field */ - void text(const char *v) { Fl_Input::value(v); } - - int value() const; - void value(int v); - - /** Set the general callback for this widget. */ - void callback(Fl_Callback *cb) { - user_callback_ = cb; - } - - /** Set the list of the available variables - \param vars array of variables, last entry `has name_` set to `NULL` - \param user_data is forwarded to the Variable callback */ - void variables(Fluid_Coord_Input_Vars *vars, void *user_data) { - vars_ = vars; - vars_user_data_ = user_data; - } -}; - -#endif - diff --git a/fluid/custom_widgets.cxx b/fluid/custom_widgets.cxx new file mode 100644 index 000000000..f1a12a474 --- /dev/null +++ b/fluid/custom_widgets.cxx @@ -0,0 +1,294 @@ +// +// Widget type code for the Fast Light Tool Kit (FLTK). +// +// 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 +// 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 "custom_widgets.h" + +#include "fluid.h" +#include "Fl_Window_Type.h" +#include "factory.h" +#include "widget_panel.h" +#include "widget_browser.h" + +#include +#include +#include +#include +#include +#include +#include "../src/flstring.h" + +/** \class Widget_Bin_Button + The Widget_Bin_Button button is a button that can be used in the widget bin to + allow the user to drag and drop widgets into a window or group. This feature + makes it easy for the user to position a widget at a specific location within + the window or group. + */ + +/** + Convert mouse dragging into a drag and drop event. + */ +int Widget_Bin_Button::handle(int inEvent) +{ + int ret = 0; + switch (inEvent) { + case FL_PUSH: + Fl_Button::handle(inEvent); + return 1; // make sure that we get drag events + case FL_DRAG: + ret = Fl_Button::handle(inEvent); + if (!user_data()) + return ret; + if (!Fl::event_is_click()) { // make it a dnd event + // fake a drag outside of the widget + Fl::e_x = x()-1; + Fl_Button::handle(inEvent); + // fake a buttton release + Fl_Button::handle(FL_RELEASE); + // make it into a dnd event + const char *type_name = (const char*)user_data(); + Fl_Type::current_dnd = Fl_Type::current; + Fl::copy(type_name, (int)strlen(type_name)+1, 0); + Fl::dnd(); + return 1; + } + return ret; + } + return Fl_Button::handle(inEvent); +} + +/** \class Widget_Bin_Window_Button + The Widget_Bin_Window_Button button is used in the widget bin to create new + windows by dragging and dropping. When the button is dragged and dropped onto + the desktop, a new window will be created at the drop location. + */ + +/** + Convert mouse dragging into a drag and drop event. + */ +int Widget_Bin_Window_Button::handle(int inEvent) +{ + static Fl_Window *drag_win = NULL; + int ret = 0; + switch (inEvent) { + case FL_PUSH: + Fl_Button::handle(inEvent); + return 1; // make sure that we get drag events + case FL_DRAG: + ret = Fl_Button::handle(inEvent); + if (!user_data()) + return ret; + if (!Fl::event_is_click()) { + if (!drag_win) { + drag_win = new Fl_Window(0, 0, 100, 100); + drag_win->border(0); + drag_win->set_non_modal(); + } + if (drag_win) { + drag_win->position(Fl::event_x_root()+1, Fl::event_y_root()+1); + drag_win->show(); + } + // Does not work outside window: fl_cursor(FL_CURSOR_HAND); + } + return ret; + case FL_RELEASE: + if (drag_win) { + Fl::delete_widget(drag_win); + drag_win = NULL; + // create a new window here + Fl_Type *prototype = typename_to_prototype((char*)user_data()); + if (prototype) { + Fl_Type *new_type = add_new_widget_from_user(prototype, kAddAfterCurrent); + if (new_type && new_type->is_window()) { + Fl_Window_Type *new_window = (Fl_Window_Type*)new_type; + Fl_Window *w = (Fl_Window *)new_window->o; + w->position(Fl::event_x_root(), Fl::event_y_root()); + } + } + widget_browser->display(Fl_Type::current); + widget_browser->rebuild(); + } + return Fl_Button::handle(inEvent); + } + return Fl_Button::handle(inEvent); +} + +/** \class Fluid_Coord_Input + The Fluid_Coord_Input widget is an input field for entering widget coordinates + and sizes. It includes basic math capabilities and allows the use of variables + in formulas. This widget is useful for specifying precise positions and + dimensions for widgets in a graphical user interface. + */ + +/** + Create an input field. + */ +Fluid_Coord_Input::Fluid_Coord_Input(int x, int y, int w, int h, const char *l) : +Fl_Input(x, y, w, h, l), +user_callback_(0L), +vars_(0L), +vars_user_data_(0L) +{ + Fl_Input::callback((Fl_Callback*)callback_handler_cb); +} + +void Fluid_Coord_Input::callback_handler_cb(Fluid_Coord_Input *This, void *v) { + This->callback_handler(v); +} + +void Fluid_Coord_Input::callback_handler(void *v) { + if (user_callback_) + (*user_callback_)(this, v); + // do *not* update the value to show the evaluated fomule here, because the + // values of the variables have already updated after the user callback. +} + +/** + Get the value of a variable. + Collects all conesecutive ASCII letters into a variable name, scans the + Variable list for that name, and then calls the corresponding callback from + the Variable array. + \param s points to the first character of the variable name, must point after + the last character of the variable name when returning. + \return the integer value that wasf= found or calculated + */ +int Fluid_Coord_Input::eval_var(uchar *&s) const { + if (!vars_) + return 0; + // find the end of the variable name + uchar *v = s; + while (isalpha(*s)) s++; + int n = (int)(s-v); + // find the variable in the list + for (Fluid_Coord_Input_Vars *vars = vars_; vars->name_; vars++) { + if (strncmp((char*)v, vars->name_, n)==0 && vars->name_[n]==0) + return vars->callback_(this, vars_user_data_); + } + return 0; +} + +/** + Evaluate a formula into an integer, recursive part. + \param s remaining text in this formula, must return a pointer to the next + character that will be interpreted. + \param prio priority of current operation + \return the value so far + */ +int Fluid_Coord_Input::eval(uchar *&s, int prio) const { + int v = 0, sgn = 1; + uchar c = *s++; + + // check for end of text + if (c==0) { s--; return sgn*v; } + + // check for unary operator + if (c=='-') { sgn = -1; c = *s++; } + else if (c=='+') { sgn = 1; c = *s++; } + + // read value, variable, or bracketed term + if (c==0) { + s--; return sgn*v; + } else if (c>='0' && c<='9') { + // numeric value + while (c>='0' && c<='9') { + v = v*10 + (c-'0'); + c = *s++; + } + } else if (isalpha(c)) { + v = eval_var(--s); + c = *s++; + } else if (c=='(') { + // opening bracket + v = eval(s, 5); + } else { + return sgn*v; // syntax error + } + if (sgn==-1) v = -v; + + // Now evaluate all following binary operators + for (;;) { + if (c==0) { + s--; + return v; + } else if (c=='+' || c=='-') { + if (prio<=4) { s--; return v; } + if (c=='+') { v += eval(s, 4); } + else if (c=='-') { v -= eval(s, 4); } + } else if (c=='*' || c=='/') { + if (prio<=3) { s--; return v; } + if (c=='*') { v *= eval(s, 3); } + else if (c=='/') { + int x = eval(s, 3); + if (x!=0) // if x is zero, don't divide + v /= x; + } + } else if (c==')') { + return v; + } else { + return v; // syntax error + } + c = *s++; + } + return v; +} + +/** + Evaluate a formula into an integer. + + The Fluid_Coord_Input widget includes a formula interpreter that allows you + to evaluate a string containing a mathematical formula and obtain the result + as an integer. The interpreter supports unary plus and minus, basic integer + math operations (such as addition, subtraction, multiplication, and division), + and brackets. It also allows you to define a list of variables by name and use + them in the formula. The interpreter does not perform error checking, so it is + assumed that the formula is entered correctly. + + \param s formula as a C string + \return the calculated value + */ +int Fluid_Coord_Input::eval(const char *s) const +{ + // duplicate the text, so we can modify it + uchar *buf = (uchar*)fl_strdup(s); + uchar *src = buf, *dst = buf; + // remove all whitespace to make the parser easier + for (;;) { + uchar c = *src++; + if (c==' ' || c=='\t') continue; + *dst++ = c; + if (c==0) break; + } + src = buf; + // now jump into the recursion + int ret = eval(src, 5); + ::free(buf); + return ret; +} + +/** + Evaluate the formula and return the result. + */ +int Fluid_Coord_Input::value() const { + return eval(text()); +} + +/** + Set the field to an integer value, replacing previous texts. + */ +void Fluid_Coord_Input::value(int v) { + char buf[32]; + fl_snprintf(buf, sizeof(buf), "%d", v); + text(buf); +} diff --git a/fluid/custom_widgets.h b/fluid/custom_widgets.h new file mode 100644 index 000000000..8a464ae82 --- /dev/null +++ b/fluid/custom_widgets.h @@ -0,0 +1,89 @@ +// +// Shortcut header file for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2010 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_SHORTCUT_BUTTON_H +#define _FLUID_SHORTCUT_BUTTON_H + +#include +#include + +// Adding drag and drop for dragging widgets into windows. +class Widget_Bin_Button : public Fl_Button { +public: + int handle(int) FL_OVERRIDE; + Widget_Bin_Button(int X,int Y,int W,int H, const char* l = 0) : + Fl_Button(X,Y,W,H,l) { } +}; + +// Adding drag and drop functionality to drag window prototypes onto the desktop. +class Widget_Bin_Window_Button : public Fl_Button { +public: + int handle(int) FL_OVERRIDE; + Widget_Bin_Window_Button(int X,int Y,int W,int H, const char* l = 0) : + Fl_Button(X,Y,W,H,l) { } +}; + +// Callback signature for function returning the value of a variable. +typedef int (Fluid_Coord_Callback)(class Fluid_Coord_Input const *, void*); + +// Entry for a list of variables available to an input field. +// Fluid_Coord_Input::variables() expects an array of Fluid_Coord_Input_Vars +// with the last entry's name_ set to NULL. +typedef struct Fluid_Coord_Input_Vars { + const char *name_; + Fluid_Coord_Callback *callback_; +} Fluid_Coord_Input_Vars; + +// A text input widget that understands simple math. +class Fluid_Coord_Input : public Fl_Input +{ + Fl_Callback *user_callback_; + Fluid_Coord_Input_Vars *vars_; + void *vars_user_data_; + static void callback_handler_cb(Fluid_Coord_Input *This, void *v); + void callback_handler(void *v); + int eval_var(uchar *&s) const; + int eval(uchar *&s, int prio) const; + int eval(const char *s) const; + +public: + Fluid_Coord_Input(int x, int y, int w, int h, const char *l=0L); + + /** Return the text in the widget text field. */ + const char *text() const { return Fl_Input::value(); } + + /** Set the text in the text field */ + void text(const char *v) { Fl_Input::value(v); } + + int value() const; + void value(int v); + + /** Set the general callback for this widget. */ + void callback(Fl_Callback *cb) { + user_callback_ = cb; + } + + /** Set the list of the available variables + \param vars array of variables, last entry `has name_` set to `NULL` + \param user_data is forwarded to the Variable callback */ + void variables(Fluid_Coord_Input_Vars *vars, void *user_data) { + vars_ = vars; + vars_user_data_ = user_data; + } +}; + +#endif + diff --git a/fluid/function_panel.cxx b/fluid/function_panel.cxx index 4c55c2691..c9a43b2fb 100644 --- a/fluid/function_panel.cxx +++ b/fluid/function_panel.cxx @@ -18,7 +18,7 @@ #include "function_panel.h" #include "fluid.h" -#include "Shortcut_Button.h" +#include "custom_widgets.h" #include "pixmaps.h" #include "factory.h" #include "Fl_Type.h" diff --git a/fluid/function_panel.fl b/fluid/function_panel.fl index cbe505ccc..0607f6d82 100644 --- a/fluid/function_panel.fl +++ b/fluid/function_panel.fl @@ -23,7 +23,7 @@ comment {// decl {\#include "fluid.h"} {private local } -decl {\#include "Shortcut_Button.h"} {private global +decl {\#include "custom_widgets.h"} {selected private global } decl {\#include "pixmaps.h"} {private local @@ -496,7 +496,7 @@ Function {make_comment_panel()} {open xywh {370 250 80 20} labelsize 11 hotspot } Fl_Button comment_panel_cancel { - label Cancel selected + label Cancel xywh {460 250 80 20} shortcut 0xff1b labelsize 11 } Fl_Box {} { diff --git a/fluid/widget_panel.cxx b/fluid/widget_panel.cxx index 1c8c97696..a871486bb 100644 --- a/fluid/widget_panel.cxx +++ b/fluid/widget_panel.cxx @@ -43,7 +43,7 @@ Fl_Menu_Item menu_1[] = { {"right", 0, 0, (void*)((fl_intptr_t)FL_ALIGN_RIGHT), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, {"bottom left", 0, 0, (void*)((fl_intptr_t)FL_ALIGN_BOTTOM_LEFT), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, {"bottom", 0, 0, (void*)((fl_intptr_t)FL_ALIGN_BOTTOM), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, - {"bottom right", 0, 0, (void*)((fl_intptr_t)FL_ALIGN_BOTTOM_RIGHT), 128, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, + {"bottom right", 0, 0, (void*)((fl_intptr_t)FL_ALIGN_BOTTOM_RIGHT), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, {" Outside Alignment ", 0, 0, (void*)((fl_intptr_t)0xFFFFFFFF), 1, (uchar)FL_NORMAL_LABEL, 2, 11, 0}, {"left top", 0, 0, (void*)((fl_intptr_t)FL_ALIGN_LEFT_TOP), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, {"right top", 0, 0, (void*)((fl_intptr_t)FL_ALIGN_RIGHT_TOP), 0, (uchar)FL_NORMAL_LABEL, 0, 11, 0}, @@ -562,20 +562,26 @@ sized to fit the container."); } // Fl_Box* o o->end(); } // Fl_Group* o + { Fl_Group* o = new Fl_Group(95, 210, 0, 20, "Shortcut:"); + o->labelfont(1); + o->labelsize(11); + o->align(Fl_Align(FL_ALIGN_LEFT)); + o->end(); + } // Fl_Group* o { // This is a special button that grabs keystrokes directly - Shortcut_Button* o = new Shortcut_Button(95, 210, 310, 20, "Shortcut:"); + Fl_Shortcut_Button* o = new Fl_Shortcut_Button(95, 210, 310, 20); o->tooltip("The shortcut key for the widget.\nUse \'Backspace\' key to clear."); o->box(FL_DOWN_BOX); o->color(FL_BACKGROUND2_COLOR); - o->selection_color(FL_BACKGROUND2_COLOR); + o->selection_color((Fl_Color)12); o->labeltype(FL_NORMAL_LABEL); - o->labelfont(1); + o->labelfont(0); o->labelsize(11); o->labelcolor(FL_FOREGROUND_COLOR); o->callback((Fl_Callback*)shortcut_in_cb); - o->align(Fl_Align(FL_ALIGN_LEFT)); - o->when(FL_WHEN_RELEASE); - } // Shortcut_Button* o + o->align(Fl_Align(FL_ALIGN_CENTER)); + o->when(FL_WHEN_CHANGED); + } // Fl_Shortcut_Button* o { Fl_Group* o = new Fl_Group(95, 235, 300, 20, "X Class:"); o->labelfont(1); o->labelsize(11); @@ -623,6 +629,7 @@ sized to fit the container."); } // Fl_Light_Button* o { Fl_Light_Button* o = new Fl_Light_Button(160, 260, 60, 20, "Active"); o->tooltip("Activate the widget."); + o->shortcut(0x400061); o->selection_color((Fl_Color)1); o->labelsize(11); o->callback((Fl_Callback*)active_cb); @@ -656,7 +663,6 @@ sized to fit the container."); } // Fl_Input* o { Fl_Box* o = new Fl_Box(95, 305, 300, 5); o->labelsize(11); - Fl_Group::current()->resizable(o); } // Fl_Box* o o->end(); Fl_Group::current()->resizable(o); diff --git a/fluid/widget_panel.fl b/fluid/widget_panel.fl index 317b16518..afd6bb62a 100644 --- a/fluid/widget_panel.fl +++ b/fluid/widget_panel.fl @@ -23,7 +23,7 @@ comment {// decl {\#include "Fl_Widget_Type.h"} {private global } -decl {\#include "Shortcut_Button.h"} {public global +decl {\#include "custom_widgets.h"} {public global } Function {make_widget_panel()} { @@ -49,7 +49,7 @@ Function {make_widget_panel()} { xywh {95 40 309 20} labelfont 1 labelsize 11 align 4 } { Fl_Input {} { - callback label_cb selected + callback label_cb tooltip {The label text for the widget. Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 textsize 11 resizable } @@ -244,7 +244,7 @@ or compressed in the original file format} xywh {364 90 20 20} type Toggle MenuItem {} { label {bottom right} user_data {(fl_intptr_t)FL_ALIGN_BOTTOM_RIGHT} - xywh {115 115 100 20} labelsize 11 divider + xywh {115 115 100 20} labelsize 11 } MenuItem {} { label { Outside Alignment } @@ -465,14 +465,17 @@ h, ph, sh, ch, and i} xywh {275 150 55 20} labelsize 11 align 5 textsize 11 xywh {395 185 0 20} resizable } } + Fl_Group {} { + label {Shortcut:} open + xywh {95 210 0 20} labelfont 1 labelsize 11 align 4 + } {} Fl_Button {} { - label {Shortcut:} callback shortcut_in_cb - comment {This is a special button that grabs keystrokes directly} + comment {This is a special button that grabs keystrokes directly} selected tooltip {The shortcut key for the widget. -Use 'Backspace' key to clear.} xywh {95 210 310 20} box DOWN_BOX color 7 selection_color 7 labelfont 1 labelsize 11 align 4 - code0 {\#include "Shortcut_Button.h"} - class Shortcut_Button +Use 'Backspace' key to clear.} xywh {95 210 310 20} box DOWN_BOX color 7 selection_color 12 labelsize 11 when 1 + code0 {\#include } + class Fl_Shortcut_Button } Fl_Group {} { label {X Class:} @@ -513,7 +516,7 @@ Use 'Backspace' key to clear.} xywh {95 210 310 20} box DOWN_BOX color 7 selecti Fl_Light_Button {} { label Active callback active_cb - tooltip {Activate the widget.} xywh {160 260 60 20} selection_color 1 labelsize 11 + tooltip {Activate the widget.} xywh {160 260 60 20} shortcut 0x400061 selection_color 1 labelsize 11 } Fl_Light_Button {} { label Resizable @@ -536,7 +539,7 @@ Use 'Backspace' key to clear.} xywh {95 210 310 20} box DOWN_BOX color 7 selecti Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize 11 } Fl_Box {} { - xywh {95 305 300 5} labelsize 11 resizable + xywh {95 305 300 5} labelsize 11 } } Fl_Group {} { diff --git a/fluid/widget_panel.h b/fluid/widget_panel.h index 6d6ddfe95..ddeed0b79 100644 --- a/fluid/widget_panel.h +++ b/fluid/widget_panel.h @@ -19,7 +19,7 @@ #ifndef widget_panel_h #define widget_panel_h #include -#include "Shortcut_Button.h" +#include "custom_widgets.h" #include #include #include @@ -79,8 +79,8 @@ extern void set_min_size_cb(Fl_Button*, void*); extern void max_w_cb(Fl_Value_Input*, void*); extern void max_h_cb(Fl_Value_Input*, void*); extern void set_max_size_cb(Fl_Button*, void*); -#include "Shortcut_Button.h" -extern void shortcut_in_cb(Shortcut_Button*, void*); +#include +extern void shortcut_in_cb(Fl_Shortcut_Button*, void*); extern void xclass_cb(Fl_Input*, void*); #include extern void border_cb(Fl_Light_Button*, void*); -- cgit v1.2.3