The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
text_box_base.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by Mark de Wever <koraq@xs4all.nl>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#pragma once
17
18//#include "gui/core/event/dispatcher.hpp"
20#include "font/text.hpp" // We want the file in src/
21
22#include <string>
23
24#include <functional>
25
26namespace gui2
27{
28
29/**
30 * Abstract base class for text items.
31 *
32 * All other text classes should inherit from this base class.
33 *
34 * The NOTIFY_MODIFIED event is send when the text is modified.
35 *
36 * @todo Validate whether the NOTIFY_MODIFIED is always fired properly. The
37 * current implementation is added for some quick testing so some cases might
38 * be forgotten.
39 *
40 * Common signal handlers:
41 * - connect_signal_pre_key_press
42 */
44{
45
46public:
47 text_box_base(const implementation::builder_styled_widget& builder, const std::string& control_type);
48
50
51 /** See @ref styled_widget::set_active. */
52 virtual void set_active(const bool active) override;
53
54 /** See @ref styled_widget::get_active. */
55 virtual bool get_active() const override;
56
57 /** See @ref styled_widget::get_state. */
58 virtual unsigned get_state() const override;
59
60 /***** ***** ***** ***** expose some functions ***** ***** ***** *****/
61
62 void set_maximum_length(const std::size_t maximum_length);
63
64 /**
65 * Wrapper function, see @ref font::pango_text::get_length.
66 *
67 * @returns length of the text in pango column offsets.
68 */
69 std::size_t get_length() const
70 {
71 return text_.get_length();
72 }
73
74 /**
75 * Wrapper function, see @ref font::pango_text::get_lines.
76 *
77 * @returns returns a vector with the lines.
78 */
79 std::vector<std::string> get_lines()
80 {
81 return text_.get_lines();
82 }
83
84 /**
85 * Wrapper function, see @ref font::pango_text::get_line.
86 *
87 * @returns the line corresponding to index.
88 */
89 PangoLayoutLine* get_line(int index)
90 {
91 return text_.get_line(index);
92 }
93
94 /**
95 * Wrapper function, see @ref font::pango_text::index_to_line_x.
96 *
97 * @returns the line number given the byte index.
98 */
99 int get_line_number(const unsigned offset)
100 {
101 return text_.index_to_line_x(offset).first;
102 }
103
104 /**
105 * Wrapper function, see @ref font::pango_text::get_cursor_pos_from_index.
106 *
107 * @returns the cursor position given the byte index.
108 */
109 point get_cursor_pos_from_index(const unsigned offset) const
110 {
111 return text_.get_cursor_pos_from_index(offset);
112 }
113
114 /**
115 * Wrapper function, see @ref font::pango_text::get_lines_count.
116 *
117 * @returns the number of lines.
118 */
119 unsigned get_lines_count() const
120 {
121 return text_.get_lines_count();
122 }
123
124 /**
125 * Wrapper function, sets the area between column start and end
126 * offset to be highlighted in a specific color.
127 * See @ref font::add_attribute_bg_color.
128 */
129 void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color);
130
131 /***** ***** ***** setters / getters for members ***** ****** *****/
132
133 /**
134 * The set_value is virtual for the @ref password_box class.
135 *
136 * That class overrides the set_value function to replace it with asterisk.
137 * There might be more generic way to do it when more classes are needed.
138 */
139 virtual void set_value(const std::string& text);
140 std::string get_value() const
141 {
142 return text_.text();
143 }
144
145 const std::string& text() const
146 {
147 return text_.text();
148 }
149
150 std::string plain_text()
151 {
152 char* plain_text = nullptr;
153 pango_parse_markup(text().c_str(), text().size(), 0, nullptr, &plain_text, nullptr, nullptr);
154 return plain_text ? std::string(plain_text) : std::string();
155 }
156
157 /**
158 * Registers a NOTIFY_MODIFIED handler.
159 *
160 * For convenience, the handler is invoked with a text_box_base reference
161 * as its first (and only) argument, rather than the usual widget reference.
162 *
163 * @todo Should we pass the other callback parameters to the handler?
164 */
165 template<typename Func>
166 void on_modified(const Func& f)
167 {
168 connect_signal<event::NOTIFY_MODIFIED>(
169 [f](widget& w, auto&&...) { f(dynamic_cast<text_box_base&>(w)); });
170 }
171
172 /**
173 * Sets or clears the text selection.
174 *
175 * Setting the selection range will re-position the cursor depending on the
176 * selection direction, specified by the length's sign. Selecting beyond the
177 * start or end of the text is safe; the final selection will be limited
178 * accordingly.
179 *
180 * @note The range extents are measured in Unicode characters, not bytes.
181 * Using byte offsets may produce unexpected results depending on the
182 * text contents.
183 *
184 * @param start Start offset, in characters.
185 * @param length Selection length, in characters. If zero, the
186 * current selection is canceled. If negative, the
187 * selection extends towards the start of the text
188 * and the cursor will be re-positioned in that
189 * direction as well; otherwise the selection and
190 * cursor extend towards the end.
191 */
192 void set_selection(std::size_t start, int length);
193
194 /**
195 * Set or unset whether text can be edited or not
196 * Text can only be copied and scrolled through when editable is false.
197 */
198 void set_editable(bool editable)
199 {
200 editable_ = editable;
202 }
203
204 /**
205 * Check whether text can be edited or not
206 */
207 bool is_editable() const
208 {
209 return editable_;
210 }
211
212protected:
213 /** Get length of composition text by IME **/
214 std::size_t get_composition_length() const;
215
216 /**
217 * Moves the cursor to the end of the line.
218 *
219 * @param select Select the text from the original cursor
220 * position till the end of the line?
221 */
222 virtual void goto_end_of_line(const bool select = false) = 0;
223
224 /**
225 * Moves the cursor to the end of all text.
226 *
227 * For a single line text this is the same as goto_end_of_line().
228 *
229 * @param select Select the text from the original cursor
230 * position till the end of the data?
231 */
232 virtual void goto_end_of_data(const bool select = false)
233 {
234 set_cursor(text_.get_length(), select);
235 }
236
237 /**
238 * Moves the cursor to the beginning of the line
239 *
240 * @param select Select the text from the original cursor
241 * position till the beginning of the line?
242 */
243 virtual void goto_start_of_line(const bool select = false) = 0;
244
245 /**
246 * Moves the cursor to the beginning of the data.
247 *
248 * @param select Select the text from the original cursor
249 * position till the beginning of the data?
250 */
251 virtual void goto_start_of_data(const bool select = false)
252 {
253 set_cursor(0, select);
254 }
255
256 /** Selects all text. */
258 {
260 goto_end_of_data(true);
261 }
262
263 /**
264 * Moves the cursor at the wanted position.
265 *
266 * @param offset The wanted new cursor position.
267 * @param select Select the text from the original cursor
268 * position till the new position?
269 */
270 virtual void set_cursor(const std::size_t offset, const bool select);
271
272 /**
273 * Inserts a character at the cursor.
274 *
275 * This function is preferred over set_text since it's optimized for
276 * updating the internal bookkeeping.
277 *
278 * @param unicode The unicode value of the character to insert.
279 */
280 virtual void insert_char(const std::string& unicode);
281
282 /**
283 * Deletes the character.
284 *
285 * @param before_cursor If true it deletes the character before the
286 * cursor (backspace) else the character after
287 * the cursor (delete).
288 */
289 virtual void delete_char(const bool before_cursor) = 0;
290
291 /** Deletes the current selection. */
292 virtual void delete_selection() = 0;
293
294 /** Copies the current selection. */
295 virtual void copy_selection();
296
297 /** Pastes the current selection. */
298 virtual void paste_selection();
299
300 /***** ***** ***** ***** expose some functions ***** ***** ***** *****/
301
302 point get_cursor_position(const unsigned column,
303 const unsigned line = 0) const
304 {
305 return text_.get_cursor_position(column, line);
306 }
307
308 point get_column_line(const point& position) const
309 {
310 return text_.get_column_line(position);
311 }
312
314 {
315 text_.set_family_class(fclass);
316 }
317
318 void set_font_size(const unsigned font_size)
319 {
320 text_.set_font_size(font_size);
321 }
322
324 {
325 text_.set_font_style(font_style);
326 }
327
328 void set_maximum_width(const int width)
329 {
331 }
332
333 void set_maximum_height(const int height, const bool multiline)
334 {
335 text_.set_maximum_height(height, multiline);
336 }
337
338 void set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
339 {
340 text_.set_ellipse_mode(ellipse_mode);
341 }
342
343 /***** ***** ***** setters / getters for members ***** ****** *****/
344
345public:
346 std::size_t get_selection_start() const
347 {
348 return selection_start_;
349 }
350 void set_selection_start(const std::size_t selection_start);
351
352 std::size_t get_selection_length() const
353 {
354 return selection_length_;
355 }
356 void set_selection_length(const int selection_length);
357
358 bool is_composing() const
359 {
360 return ime_composing_;
361 }
362
363 std::size_t get_composition_start() const
364 {
365 return ime_start_point_;
366 }
367
369
370 /** Note the order of the states must be the same as defined in
371 * settings.hpp. */
378
379private:
380 void set_state(const state_t state);
381
382 virtual void toggle_cursor_timer(bool enable);
383
384 /** Implements blinking cursor functionality. */
385 virtual void cursor_timer_callback();
386
387 virtual void reset_cursor_state();
388
389 void update_mouse_cursor(bool enable);
390
391 /**
392 * Current state of the widget.
393 *
394 * The state of the widget determines what to render and how the widget
395 * reacts to certain 'events'.
396 */
398
399 /** The text entered in the widget. */
401
402 /** Cached version of the text without any pending IME modifications. */
403 std::string text_cached_;
404
405 /** Start of the selected text. */
406 std::size_t selection_start_;
407
408 /**
409 * Length of the selected text.
410 *
411 * * positive selection_len_ means selection to the right.
412 * * negative selection_len_ means selection to the left.
413 * * selection_len_ == 0 means no selection.
414 */
416
417 /** If this text_box_base is editable */
419
420 // Values to support input method editors
423
424 std::size_t cursor_timer_;
425
426 unsigned short cursor_alpha_;
427 std::chrono::milliseconds cursor_blink_rate_;
428
429 /****** handling of special keys first the pure virtuals *****/
430
431 /**
432 * Every key can have several behaviors.
433 *
434 * Unmodified No modifier is pressed.
435 * Control The control key is pressed.
436 * Shift The shift key is pressed.
437 * Alt The alt key is pressed.
438 *
439 * If modifiers together do something else as the sum of the modifiers
440 * it's listed separately eg.
441 *
442 * Control Moves 10 steps at the time.
443 * Shift Selects the text.
444 * Control + Shift Inserts 42 in the text.
445 *
446 * There are some predefined actions for results.
447 * Unhandled The key/modifier is ignored and also reported
448 * unhandled.
449 * Ignored The key/modifier is ignored and it's
450 * _expected_ the inherited classes do the same.
451 * Implementation defined The key/modifier is ignored and it's expected
452 * the inherited classes will define some meaning
453 * to it.
454 */
455
456 /**
457 * Up arrow key pressed.
458 *
459 * The behavior is implementation defined.
460 */
461 virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) = 0;
462
463 /**
464 * Down arrow key pressed.
465 *
466 * The behavior is implementation defined.
467 */
468 virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) = 0;
469
470 /**
471 * Clears the current line.
472 *
473 * Unmodified Clears the current line.
474 * Control Ignored.
475 * Shift Ignored.
476 * Alt Ignored.
477 */
478 virtual void handle_key_clear_line(SDL_Keymod modifier, bool& handled) = 0;
479protected:
480 /**
481 * Left arrow key pressed.
482 *
483 * Unmodified Moves the cursor a character to the left.
484 * Control Like unmodified but a word instead of a letter
485 * at the time.
486 * Shift Selects the text while moving.
487 * Alt Ignored.
488 */
489 virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
490
491 /**
492 * Right arrow key pressed.
493 *
494 * Unmodified Moves the cursor a character to the right.
495 * Control Like unmodified but a word instead of a letter
496 * at the time.
497 * Shift Selects the text while moving.
498 * Alt Ignored.
499 */
500 virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
501
502private:
503 /**
504 * Home key pressed.
505 *
506 * Unmodified Moves the cursor a to the beginning of the
507 * line.
508 * Control Like unmodified but to the beginning of the
509 * data.
510 * Shift Selects the text while moving.
511 * Alt Ignored.
512 */
513 virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
514
515 /**
516 * End key pressed.
517 *
518 * Unmodified Moves the cursor a to the end of the line.
519 * Control Like unmodified but to the end of the data.
520 * Shift Selects the text while moving.
521 * Alt Ignored.
522 */
523 virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
524
525 /**
526 * Backspace key pressed.
527 *
528 * Unmodified Deletes the character before the cursor,
529 * ignored if at the beginning of the data.
530 * Control Ignored.
531 * Shift Ignored.
532 * Alt Ignored.
533 */
534 virtual void handle_key_backspace(SDL_Keymod modifier, bool& handled);
535
536 /**
537 * Delete key pressed.
538 *
539 * Unmodified If there is a selection that's deleted.
540 * Else if not at the end of the data the
541 * character after the cursor is deleted.
542 * Else the key is ignored.
543 * ignored if at the beginning of the data.
544 * Control Ignored.
545 * Shift Ignored.
546 * Alt Ignored.
547 */
548 virtual void handle_key_delete(SDL_Keymod modifier, bool& handled);
549
550 /**
551 * Page up key.
552 *
553 * Unmodified Unhandled.
554 * Control Ignored.
555 * Shift Ignored.
556 * Alt Ignored.
557 */
558 virtual void handle_key_page_up(SDL_Keymod /*modifier*/, bool& /*handled*/)
559 {
560 }
561
562 /**
563 * Page down key.
564 *
565 * Unmodified Unhandled.
566 * Control Ignored.
567 * Shift Ignored.
568 * Alt Ignored.
569 */
570 virtual void handle_key_page_down(SDL_Keymod /*modifier*/, bool& /*handled*/)
571 {
572 }
573
574 /**
575 * Tab key.
576 *
577 * Unmodified Implementation defined.
578 * Control Implementation defined.
579 * Shift Implementation defined.
580 * Alt Implementation defined.
581 */
582 virtual void handle_key_tab(SDL_Keymod /*modifier*/, bool& /*handled*/)
583 {
584 }
585
586 /**
587 * Enter key.
588 *
589 * Unmodified Handled by Window.
590 * Control Implementation defined.
591 * Shift Implementation defined.
592 * Alt Implementation defined.
593 */
594 virtual void handle_key_enter(SDL_Keymod /*modifier*/, bool& /*handled*/)
595 {
596 }
597
598protected:
599 virtual void handle_commit(bool& handled,
600 const std::string& unicode);
601 virtual void handle_editing(bool& handled,
602 const std::string& unicode,
603 int32_t start,
604 int32_t length);
605
606private:
607 /***** ***** ***** signal handlers ***** ****** *****/
608
610 bool& handled);
611
613 bool& handled,
614 const SDL_Keycode key,
615 SDL_Keymod modifier);
616
618 bool& handled,
619 const std::string& unicode,
620 int32_t start,
621 int32_t len);
622
625
626 void signal_handler_mouse_enter(const event::ui_event event, bool& handled);
627 void signal_handler_mouse_leave(const event::ui_event event, bool& handled);
628};
629
630} // namespace gui2
Text class.
Definition text.hpp:78
unsigned get_lines_count() const
Get number of lines in the text.
Definition text.hpp:294
const std::string & text() const
Definition text.hpp:322
pango_text & set_font_style(const FONT_STYLE font_style)
Definition text.cpp:381
std::size_t get_length() const
Gets the length of the text in bytes.
Definition text.hpp:304
point get_column_line(const point &position) const
Gets the column of line of the character at the position.
Definition text.cpp:278
PangoLayoutLine * get_line(int index)
Get a specific line from the pango layout.
Definition text.cpp:940
pango_text & set_family_class(font::family_class fclass)
Definition text.cpp:359
std::vector< std::string > get_lines() const
Retrieves a list of strings with contents for each rendered line.
Definition text.cpp:914
point get_cursor_position(const unsigned offset, const unsigned line=0) const
Gets the location for the cursor, in drawing coordinates.
Definition text.cpp:225
pango_text & set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
Definition text.cpp:452
std::pair< int, int > index_to_line_x(const unsigned offset, const bool trailing=0) const
Given a byte index, find out at which line the corresponding character is located.
Definition text.cpp:945
pango_text & set_font_size(unsigned font_size)
Definition text.cpp:369
point get_cursor_pos_from_index(const unsigned offset) const
Gets the location for the cursor, in drawing coordinates.
Definition text.cpp:231
pango_text & set_maximum_height(int height, bool multiline)
Definition text.cpp:427
pango_text & set_maximum_width(int width)
Definition text.cpp:400
virtual void update_canvas()
Updates the canvas(ses).
Abstract base class for text items.
std::size_t get_composition_length() const
Get length of composition text by IME.
virtual void handle_key_backspace(SDL_Keymod modifier, bool &handled)
Backspace key pressed.
std::size_t get_length() const
Wrapper function, see font::pango_text::get_length.
virtual void handle_commit(bool &handled, const std::string &unicode)
virtual bool get_active() const override
See styled_widget::get_active.
virtual unsigned get_state() const override
See styled_widget::get_state.
void set_font_size(const unsigned font_size)
PangoLayoutLine * get_line(int index)
Wrapper function, see font::pango_text::get_line.
void update_mouse_cursor(bool enable)
point get_column_line(const point &position) const
virtual void goto_start_of_line(const bool select=false)=0
Moves the cursor to the beginning of the line.
virtual void handle_key_delete(SDL_Keymod modifier, bool &handled)
Delete key pressed.
virtual void insert_char(const std::string &unicode)
Inserts a character at the cursor.
virtual void handle_editing(bool &handled, const std::string &unicode, int32_t start, int32_t length)
SDL_EVENT_TEXT_EDITING handler.
void set_state(const state_t state)
std::chrono::milliseconds cursor_blink_rate_
const std::string & text() const
virtual void copy_selection()
Copies the current selection.
void signal_handler_sdl_text_input(const event::ui_event event, bool &handled, const std::string &unicode, int32_t start, int32_t len)
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
void on_modified(const Func &f)
Registers a NOTIFY_MODIFIED handler.
virtual void toggle_cursor_timer(bool enable)
point get_cursor_pos_from_index(const unsigned offset) const
Wrapper function, see font::pango_text::get_cursor_pos_from_index.
std::string get_value() const
void set_editable(bool editable)
Set or unset whether text can be edited or not Text can only be copied and scrolled through when edit...
void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t &color)
Wrapper function, sets the area between column start and end offset to be highlighted in a specific c...
state_t state_
Current state of the widget.
virtual void goto_end_of_line(const bool select=false)=0
Moves the cursor to the end of the line.
std::size_t get_composition_start() const
void signal_handler_mouse_leave(const event::ui_event event, bool &handled)
void set_selection(std::size_t start, int length)
Sets or clears the text selection.
std::size_t selection_start_
Start of the selected text.
std::string plain_text()
virtual void handle_key_enter(SDL_Keymod, bool &)
Enter key.
int selection_length_
Length of the selected text.
unsigned short cursor_alpha_
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)=0
Every key can have several behaviors.
std::vector< std::string > get_lines()
Wrapper function, see font::pango_text::get_lines.
point get_cursor_position(const unsigned column, const unsigned line=0) const
void set_font_style(const font::pango_text::FONT_STYLE font_style)
unsigned get_lines_count() const
Wrapper function, see font::pango_text::get_lines_count.
void signal_handler_mouse_enter(const event::ui_event event, bool &handled)
virtual void handle_key_tab(SDL_Keymod, bool &)
Tab key.
std::string text_cached_
Cached version of the text without any pending IME modifications.
void set_font_family(font::family_class fclass)
virtual void set_value(const std::string &text)
The set_value is virtual for the password_box class.
virtual void paste_selection()
Pastes the current selection.
state_t
Note the order of the states must be the same as defined in settings.hpp.
font::pango_text text_
The text entered in the widget.
void signal_handler_lose_keyboard_focus(const event::ui_event event)
void signal_handler_sdl_key_down(const event::ui_event event, bool &handled, const SDL_Keycode key, SDL_Keymod modifier)
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)
Right arrow key pressed.
std::size_t get_selection_length() const
virtual void handle_key_clear_line(SDL_Keymod modifier, bool &handled)=0
Clears the current line.
void set_maximum_height(const int height, const bool multiline)
void set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
void set_selection_start(const std::size_t selection_start)
virtual void set_cursor(const std::size_t offset, const bool select)
Moves the cursor at the wanted position.
void set_maximum_width(const int width)
virtual void handle_key_page_up(SDL_Keymod, bool &)
Page up key.
virtual void handle_key_home(SDL_Keymod modifier, bool &handled)
Home key pressed.
bool is_editable() const
Check whether text can be edited or not.
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool &handled)=0
Down arrow key pressed.
void signal_handler_receive_keyboard_focus(const event::ui_event event)
virtual void goto_end_of_data(const bool select=false)
Moves the cursor to the end of all text.
void signal_handler_middle_button_click(const event::ui_event event, bool &handled)
virtual void handle_key_end(SDL_Keymod modifier, bool &handled)
End key pressed.
virtual void handle_key_page_down(SDL_Keymod, bool &)
Page down key.
std::size_t get_selection_start() const
virtual void set_active(const bool active) override
See styled_widget::set_active.
void set_selection_length(const int selection_length)
bool is_composing() const
bool editable_
If this text_box_base is editable.
virtual void goto_start_of_data(const bool select=false)
Moves the cursor to the beginning of the data.
virtual void cursor_timer_callback()
Implements blinking cursor functionality.
virtual void reset_cursor_state()
void set_maximum_length(const std::size_t maximum_length)
int get_line_number(const unsigned offset)
Wrapper function, see font::pango_text::index_to_line_x.
virtual void delete_selection()=0
Deletes the current selection.
virtual void delete_char(const bool before_cursor)=0
Deletes the character.
void select_all()
Selects all text.
Base class for all widgets.
Definition widget.hpp:55
ui_event
The event sent to the dispatcher.
Definition handler.hpp:115
Generic file dialog.
int w
Definition pathfind.cpp:188
The basic class for representing 8-bit RGB or RGBA colour values.
Definition color.hpp:51
Holds a 2D point.
Definition point.hpp:25
#define f