From 5e4346a773bf8878798c58a8dff91da7252129e6 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Sun, 9 Aug 2026 18:29:26 +0200 Subject: [PATCH] Add `placeholder` feature to Fl_Input_ based widgets --- CHANGES.txt | 3 +++ FL/Fl_Input_.H | 9 +++++++++ src/Fl_Input_.cxx | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 91e1292df..d6783e98e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -18,12 +18,15 @@ Changes in FLTK 1.5.0 Released: xxx yy 2026 Fixes and Improvements in Fluid + - The Strings file name for internationalization can now be fully customized. + - Bigger and clearly assigned fields for custom code for widgets. Documentation Improvements Other Changes + - Added "placeholder" text field to Fl_Input_ based widgets - Removed autotools (configure/make) support - Requires C++11 or higher diff --git a/FL/Fl_Input_.H b/FL/Fl_Input_.H index 80d3869dc..4f5e0290c 100644 --- a/FL/Fl_Input_.H +++ b/FL/Fl_Input_.H @@ -101,6 +101,9 @@ class FL_EXPORT Fl_Input_ : public Fl_Widget { /** \internal Buffer memory for expanded text. \see expand() */ char* buffer; + /** \internal Store placeholder text. */ + char* placeholder_ { nullptr }; + /** \internal Size of text in bytes in the \p value_ field. */ int size_; @@ -266,6 +269,12 @@ public: double dvalue() const; + /* Set a placeholder text that is displayed when the widget is empty */ + void placeholder(const char* text); + + /* Get the placeholder text */ + const char* placeholder() const; + /* Returns the Unicode character at index \p i. */ unsigned int index(int i) const; diff --git a/src/Fl_Input_.cxx b/src/Fl_Input_.cxx index 7a577efa1..b54f58445 100644 --- a/src/Fl_Input_.cxx +++ b/src/Fl_Input_.cxx @@ -324,8 +324,25 @@ void Fl_Input_::drawtext(int X, int Y, int W, int H, bool draw_active) { draw_box(box(), X-Fl::box_dx(box()), Y-Fl::box_dy(box()), W+Fl::box_dw(box()), H+Fl::box_dh(box()), color()); } + // If there is no text, but a placeholder, draw the placeholder text in a light color + if (placeholder_ && *placeholder_) { + Fl_Color fg = textcolor(); + Fl_Color bg = color(); + if (!active_r()) { + fg = fl_inactive(fg); + bg = fl_inactive(bg); + } + fl_color(fl_color_average(fg, bg, .5f)); + fl_font(textfont(), textsize()); + fl_draw(placeholder_, X, Y, W, H, FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + } return; } + // Make sure that a previously drawn placeholder text is cleared when draw_active is set. + if (!size() && placeholder_ && do_mu) { + draw_box(box(), X-Fl::box_dx(box()), Y-Fl::box_dy(box()), + W+Fl::box_dw(box()), H+Fl::box_dh(box()), color()); + } int selstart, selend; if (!draw_active && /*Fl::selection_owner()!=this &&*/ Fl::pushed()!=this) @@ -1516,6 +1533,24 @@ double Fl_Input_::dvalue() const { return atof(value()); } +/** + Set the placeholder text. + \param [in] text the placeholder text +*/ +void Fl_Input_::placeholder(const char* text) { + if (placeholder_) free((void*)placeholder_); + placeholder_ = text ? strdup(text) : nullptr; +} + +/** + Get the placeholder text. + \return pointer to an internal buffer to the placeholder text, or nullptr. The + buffer will be freed when the widget is destroyed or a new placeholder is set. +*/ +const char* Fl_Input_::placeholder() const { + return placeholder_; +} + /** Changes the size of the widget. This call updates the text layout so that the cursor is visible. @@ -1539,6 +1574,7 @@ Fl_Input_::~Fl_Input_() { delete redo_list_; delete undo_; if (bufsize) free((void*)buffer); + if (placeholder_) free((void*)placeholder_); } /** \internal