diff options
| -rw-r--r-- | FL/Enumerations.H | 6 | ||||
| -rw-r--r-- | FL/Fl_Tooltip.H | 12 | ||||
| -rw-r--r-- | FL/names.h | 5 | ||||
| -rw-r--r-- | src/Fl_Tooltip.cxx | 81 | ||||
| -rw-r--r-- | test/color_chooser.cxx | 20 |
5 files changed, 98 insertions, 26 deletions
diff --git a/FL/Enumerations.H b/FL/Enumerations.H index 2478a8c58..db6465096 100644 --- a/FL/Enumerations.H +++ b/FL/Enumerations.H @@ -414,7 +414,11 @@ enum Fl_Event { // events /** A zoom event (ctrl/+/-/0/ or cmd/+/-/0/) was processed. Use Fl::add_handler() to be notified of this event. */ - FL_ZOOM_EVENT = 27 + FL_ZOOM_EVENT = 27, + /** A tooltip is about to pop up for this widget. The mouse coordinates are + available in Fl::event_x() and Fl::event_y(). Change the widget tooltip + as needed. */ + FL_TOOLTIP_EVENT = 28 // DEV NOTE: Keep this list in sync with FL/names.h }; diff --git a/FL/Fl_Tooltip.H b/FL/Fl_Tooltip.H index b79d93149..d417ba189 100644 --- a/FL/Fl_Tooltip.H +++ b/FL/Fl_Tooltip.H @@ -95,6 +95,8 @@ public: static void wrap_width(int v) { wrap_width_ = v; } /** Returns the window that is used for tooltips */ static Fl_Window* current_window(void); + /** \brief Temporarily Override Tooltip Text during an FL_TOOLTIP_EVENT. */ + static int override_text(const char *new_text); // These should not be public, but Fl_Widget::tooltip() needs them... // fabien: made it private with only a friend function access @@ -104,20 +106,22 @@ private: static void enter_(Fl_Widget* w); static void exit_(Fl_Widget *w); static void set_enter_exit_once_(); + static void tooltip_timeout_(void*); private: - static float delay_; //!< delay before a tooltip is shown - static float hidedelay_; //!< delay until tooltip is closed again - static float hoverdelay_; //!< delay between tooltips + static float delay_; //!< delay before a tooltip is shown + static float hidedelay_; //!< delay until tooltip is closed again + static float hoverdelay_; //!< delay between tooltips static Fl_Color color_; static Fl_Color textcolor_; static Fl_Font font_; static Fl_Fontsize size_; - static Fl_Widget* widget_; //!< Keeps track of the current target widget + static Fl_Widget* widget_; //!< Keeps track of the current target widget static int margin_width_; //!< distance around tooltip text left+right static int margin_height_; //!< distance around tooltip text top+bottom static int wrap_width_; //!< maximum width of tooltip text before it word wraps static const int draw_symbols_; // 1 = draw @-symbols in tooltips, 0 = no + static char *override_text_; //!< a copy of the last text for an overridden tooltip }; #endif diff --git a/FL/names.h b/FL/names.h index 984afbfe0..e47d005ec 100644 --- a/FL/names.h +++ b/FL/names.h @@ -73,9 +73,10 @@ const char * const fl_eventnames[] = "FL_FULLSCREEN", "FL_ZOOM_GESTURE", "FL_ZOOM_EVENT", - "FL_EVENT_28", // not yet defined, just in case it /will/ be defined ... + "FL_TOOLTIP_EVENT", "FL_EVENT_29", // not yet defined, just in case it /will/ be defined ... - "FL_EVENT_30" // not yet defined, just in case it /will/ be defined ... + "FL_EVENT_30", // not yet defined, just in case it /will/ be defined ... + "FL_EVENT_31" // not yet defined, just in case it /will/ be defined ... }; /** diff --git a/src/Fl_Tooltip.cxx b/src/Fl_Tooltip.cxx index 674c57a49..f80956039 100644 --- a/src/Fl_Tooltip.cxx +++ b/src/Fl_Tooltip.cxx @@ -25,6 +25,9 @@ #include <stdio.h> + +#define DEBUG + float Fl_Tooltip::delay_ = 1.0f; float Fl_Tooltip::hidedelay_ = 12.0f; float Fl_Tooltip::hoverdelay_ = 0.2f; @@ -38,6 +41,7 @@ int Fl_Tooltip::margin_width_ = 3; int Fl_Tooltip::margin_height_ = 3; int Fl_Tooltip::wrap_width_ = 400; const int Fl_Tooltip::draw_symbols_ = 1; +char *Fl_Tooltip::override_text_ = nullptr; static const char* tip; @@ -154,14 +158,49 @@ static void tooltip_hide_timeout(void*) { recent_tooltip = 0; } -static void tooltip_timeout(void*) { +/** + Use this method to temporarily change the tooltip text before it is displayed. + + When FLTK sends an FL_TOOLTIP_EVENT to the widget under the mouse pointer, + you can handle this event to modify the tooltip text dynamically. The + provided text will be copied into a local buffer. To apply the override, + the event handler must return 1. + + To disable the tooltip for the current event, set the override text to nullptr + or an empty string ("") and return 1. + + \param[in] new_text a C string that will be copied into a buffer + \return always 1, so this call can finish the FL_TOOLTIP_EVENT handling. + + \see void Fl_Widget::tooltip(const char *text). + + \see `test/color_chooser.cxx` for a usage example. +*/ +int Fl_Tooltip::override_text(const char *new_text) { + if (new_text != override_text_) { + if (window && window->label()==override_text_) + ((Fl_Widget *) window)->label(nullptr); + if (override_text_) + ::free(override_text_); + override_text_ = nullptr; + if (new_text) + override_text_ = ::strdup(new_text); + } + return 1; +} + +void Fl_Tooltip::tooltip_timeout_(void*) { #ifdef DEBUG - puts("tooltip_timeout();"); + puts("tooltip_timeout_();"); #endif // DEBUG if (recursion) return; recursion = 1; if (!top_win_iconified_()) { // no tooltip if top win iconified (STR #3157) + if (Fl_Tooltip::current()) { + if (Fl_Tooltip::current()->handle(FL_TOOLTIP_EVENT)) + tip = Fl_Tooltip::override_text_; + } if (!tip || !*tip) { if (window) window->hide(); Fl::remove_timeout(tooltip_hide_timeout); @@ -253,7 +292,7 @@ void Fl_Tooltip::exit_(Fl_Widget *w) { if (!widget_ || (w && w == window)) return; widget_ = 0; - Fl::remove_timeout(tooltip_timeout); + Fl::remove_timeout(tooltip_timeout_); Fl::remove_timeout(recent_timeout); if (window && window->visible()) { window->hide(); @@ -298,7 +337,7 @@ void Fl_Tooltip::enter_area(Fl_Widget* wid, int x,int y,int w,int h, const char* } // do nothing if it is the same: if (wid==widget_ /*&& x==X && y==currentTooltipY && w==W && h==currentTooltipH*/ && t==tip) return; - Fl::remove_timeout(tooltip_timeout); + Fl::remove_timeout(tooltip_timeout_); Fl::remove_timeout(recent_timeout); // remember it: widget_ = wid; currentTooltipY = y; currentTooltipH = h; tip = t; @@ -308,7 +347,7 @@ void Fl_Tooltip::enter_area(Fl_Widget* wid, int x,int y,int w,int h, const char* window->hide(); Fl::remove_timeout(tooltip_hide_timeout); } - Fl::add_timeout(Fl_Tooltip::hoverdelay(), tooltip_timeout); + Fl::add_timeout(Fl_Tooltip::hoverdelay(), tooltip_timeout_); } else if (Fl_Tooltip::delay() < .1) { // possible fix for the Windows titlebar, it seems to want the // window to be destroyed, moving it messes up the parenting: @@ -316,13 +355,13 @@ void Fl_Tooltip::enter_area(Fl_Widget* wid, int x,int y,int w,int h, const char* window->hide(); Fl::remove_timeout(tooltip_hide_timeout); } - tooltip_timeout(0); + tooltip_timeout_(nullptr); } else { if (window && window->visible()) { window->hide(); Fl::remove_timeout(tooltip_hide_timeout); } - Fl::add_timeout(Fl_Tooltip::delay(), tooltip_timeout); + Fl::add_timeout(Fl_Tooltip::delay(), tooltip_timeout_); } #ifdef DEBUG @@ -341,19 +380,25 @@ void Fl_Tooltip::set_enter_exit_once_() { } /** - Sets the current tooltip text. + Sets the Tooltip Text for a Widget. - Sets a string of text to display in a popup tooltip window when the user - hovers the mouse over the widget. The string is <I>not</I> copied, so - make sure any formatted string is stored in a static, global, - or allocated buffer. If you want a copy made and managed for you, - use the copy_tooltip() method, which will manage the tooltip string - automatically. + Assigns a tooltip string that appears in a popup when the user hovers over + the widget. The provided string is not copied. The caller must eensure it + remains valid by storing it in a static, global, or dynamically allocated + buffer. If you need the tooltip string to be copied and managed automatically, + use copy_tooltip(). + + By default, a widget inherits the tooltip of its parent if none is explicitly + set. If you assign a tooltip to a group but not to its child widgets, the + child widgets will display the group’s tooltip. To prevent inheritance, set + the child’s tooltip to an empty string (""). + + Tooltips can be updated dynamically before they are displayed. When a tooltip + is about to be shown, FLTK sends an `FL_TOOLTIP_EVENT` to the widget’s + `handle()` method. Developers can override the tooltip text temporarily + using `Fl_Tooltip::override_text(const char* new_text)` and returning 1 from + `handle()` to apply the change. - If no tooltip is set, the tooltip of the parent is inherited. Setting a - tooltip for a group and setting no tooltip for a child will show the - group's tooltip instead. To avoid this behavior, you can set the child's - tooltip to an empty string (""). \param[in] text New tooltip text (no copy is made) \see copy_tooltip(const char*), tooltip() */ diff --git a/test/color_chooser.cxx b/test/color_chooser.cxx index 61fbc4caf..a9a7a5ca1 100644 --- a/test/color_chooser.cxx +++ b/test/color_chooser.cxx @@ -21,6 +21,7 @@ #include <FL/fl_show_colormap.H> #include <FL/Fl_Color_Chooser.H> #include <FL/Fl_Image.H> +#include <FL/Fl_Tooltip.H> #include <FL/platform.H> #include <FL/fl_draw.H> @@ -84,6 +85,22 @@ void cb2(Fl_Widget *, void *v) { bx->parent()->redraw(); } +class Image_Box: public Fl_Box { +public: + Image_Box(int x, int y, int w, int h, const char *label = nullptr) + : Fl_Box(x, y, w, h, label) { } + int handle(int event) { + if (event == FL_TOOLTIP_EVENT) { + const char *color_name_lut[] = { "blue", "green", "black", "red" }; + int quadrant = (Fl::event_x() < x()+w()/2) + 2*(Fl::event_y() < y()+h()/2); + char buf[80]; + ::snprintf(buf, 79, "Color %s at x=%d, y=%d", color_name_lut[quadrant], Fl::event_x(), Fl::event_y()); + return Fl_Tooltip::override_text(buf); + } + return Fl_Box::handle(event); + } +}; + int main(int argc, char ** argv) { Fl::set_color(fullcolor_cell,145,159,170); Fl_Window window(400,400); @@ -98,7 +115,8 @@ int main(int argc, char ** argv) { b1.callback(cb1,&box); Fl_Button b2(120,120,180,30,"fl_color_chooser()"); b2.callback(cb2,&box); - Fl_Box image_box(160,190,width,height,0); + Image_Box image_box(160,190,width,height,0); + image_box.tooltip("Image Box"); make_image(); (new Fl_RGB_Image(image, width, height))->label(&image_box); Fl_Box b(160,310,120,30,"Example of fl_draw_image()"); |
