diff --git a/src/gui/widgets/text.cpp b/src/gui/widgets/text.cpp index 19f69df075df..9c80dbc399ba 100644 --- a/src/gui/widgets/text.cpp +++ b/src/gui/widgets/text.cpp @@ -23,6 +23,8 @@ #include "utils/functional.hpp" +#include + #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__ #define LOG_HEADER LOG_SCOPE_HEADER + ':' @@ -197,6 +199,38 @@ void ttext_::set_selection_length(const int selection_length) } } +void ttext_::set_selection(size_t start, int length) +{ + const size_t text_size = text_.get_length(); + + if(start >= text_size) { + start = text_size; + } + + if(length == 0) { + set_cursor(start, false); + return; + } + + // The text pos/size type differs in both signedness and size with the + // selection length. Such is life. + const int sel_start = std::min(start, std::numeric_limits::max()); + const int sel_max_length = std::min(text_size - start, std::numeric_limits::max()); + + const bool backwards = length < 0; + + if(backwards && -length > sel_start) { + length = -sel_start; + } else if(!backwards && length > sel_max_length) { + length = sel_max_length; + } + + set_selection_start(start); + set_selection_length(length); + + update_canvas(); +} + void ttext_::set_state(const tstate state) { if(state != state_) { diff --git a/src/gui/widgets/text.hpp b/src/gui/widgets/text.hpp index 9bc7518b17b3..1d6236d325db 100644 --- a/src/gui/widgets/text.hpp +++ b/src/gui/widgets/text.hpp @@ -90,6 +90,28 @@ class ttext_ : public tcontrol text_changed_callback_ = cb; } + /** + * Sets or clears the text selection. + * + * Setting the selection range will re-position the cursor depending on the + * selection direction, specified by the length's sign. Selecting beyond the + * start or end of the text is safe; the final selection will be limited + * accordingly. + * + * @note The range extents are measured in Unicode characters, not bytes. + * Using byte offsets may produce unexpected results depending on the + * text contents. + * + * @param start Start offset, in characters. + * @param length Selection length, in characters. If zero, the + * current selection is canceled. If negative, the + * selection extends towards the start of the text + * and the cursor will be re-positioned in that + * direction as well; otherwise the selection and + * cursor extend towards the end. + */ + void set_selection(size_t start, int length); + protected: /** * Moves the cursor to the end of the line.