The Battle for Wesnoth  1.19.1+dev
text_box_base.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
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 
26 namespace 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 
46 public:
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, returns length of the text in pango column offsets.
66  * See @ref font::pango_text::get_length.
67  */
68  std::size_t get_length() const
69  {
70  return text_.get_length();
71  }
72 
73  /**
74  * Wrapper function, returns a vector with the lines.
75  * See @ref font::pango_text::get_lines.
76  */
77  std::vector<std::string> get_lines()
78  {
79  return text_.get_lines();
80  }
81 
82  /**
83  * Wrapper function, return number of lines.
84  * See @ref font::pango_text::get_lines_count.
85  */
86  unsigned get_lines_count() const
87  {
88  return text_.get_lines_count();
89  }
90 
91  /**
92  * Wrapper function, returns corrected column offset from pango.
93  * See @ref font::pango_text::get_byte_offset.
94  */
95  int get_byte_offset(const unsigned column) const
96  {
97  return text_.get_byte_offset(column);
98  }
99 
100  /**
101  * Wrapper function, sets the area between column start and end
102  * offset to be highlighted in a specific color.
103  * See @ref font::pango_text::set_highlight_area.
104  */
105  void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color)
106  {
107  text_.set_highlight_area(start_offset, end_offset, color);
108  }
109 
110  /***** ***** ***** setters / getters for members ***** ****** *****/
111 
112  /**
113  * The set_value is virtual for the @ref password_box class.
114  *
115  * That class overrides the set_value function to replace it with asterisk.
116  * There might be more generic way to do it when more classes are needed.
117  */
118  virtual void set_value(const std::string& text);
119  std::string get_value() const
120  {
121  return text_.text();
122  }
123 
124  const std::string& text() const
125  {
126  return text_.text();
127  }
128 
129  /** Set the text_changed callback. */
131  std::function<void(text_box_base* textbox, const std::string text)> cb)
132  {
134  }
135 
136  /**
137  * Sets or clears the text selection.
138  *
139  * Setting the selection range will re-position the cursor depending on the
140  * selection direction, specified by the length's sign. Selecting beyond the
141  * start or end of the text is safe; the final selection will be limited
142  * accordingly.
143  *
144  * @note The range extents are measured in Unicode characters, not bytes.
145  * Using byte offsets may produce unexpected results depending on the
146  * text contents.
147  *
148  * @param start Start offset, in characters.
149  * @param length Selection length, in characters. If zero, the
150  * current selection is canceled. If negative, the
151  * selection extends towards the start of the text
152  * and the cursor will be re-positioned in that
153  * direction as well; otherwise the selection and
154  * cursor extend towards the end.
155  */
156  void set_selection(std::size_t start, int length);
157 
158  /**
159  * Set or unset whether text can be edited or not
160  * Text can only be copied and scrolled through when editable is false.
161  */
162  void set_editable(bool editable)
163  {
164  editable_ = editable;
165  update_canvas();
166  }
167 
168  /**
169  * Check whether text can be edited or not
170  */
171  bool is_editable()
172  {
173  return editable_;
174  }
175 
176 protected:
177  /** Get length of composition text by IME **/
178  size_t get_composition_length() const;
179 
180  /**
181  * Moves the cursor to the end of the line.
182  *
183  * @param select Select the text from the original cursor
184  * position till the end of the line?
185  */
186  virtual void goto_end_of_line(const bool select = false) = 0;
187 
188  /**
189  * Moves the cursor to the end of all text.
190  *
191  * For a single line text this is the same as goto_end_of_line().
192  *
193  * @param select Select the text from the original cursor
194  * position till the end of the data?
195  */
196  virtual void goto_end_of_data(const bool select = false)
197  {
198  set_cursor(text_.get_length(), select);
199  }
200 
201  /**
202  * Moves the cursor to the beginning of the line
203  *
204  * @param select Select the text from the original cursor
205  * position till the beginning of the line?
206  */
207  virtual void goto_start_of_line(const bool select = false) = 0;
208 
209  /**
210  * Moves the cursor to the beginning of the data.
211  *
212  * @param select Select the text from the original cursor
213  * position till the beginning of the data?
214  */
215  virtual void goto_start_of_data(const bool select = false)
216  {
217  set_cursor(0, select);
218  }
219 
220  /** Selects all text. */
221  void select_all()
222  {
223  selection_start_ = 0;
224  goto_end_of_data(true);
225  }
226 
227  /**
228  * Moves the cursor at the wanted position.
229  *
230  * @param offset The wanted new cursor position.
231  * @param select Select the text from the original cursor
232  * position till the new position?
233  */
234  virtual void set_cursor(const std::size_t offset, const bool select);
235 
236  /**
237  * Inserts a character at the cursor.
238  *
239  * This function is preferred over set_text since it's optimized for
240  * updating the internal bookkeeping.
241  *
242  * @param unicode The unicode value of the character to insert.
243  */
244  virtual void insert_char(const std::string& unicode);
245 
246  /**
247  * Deletes the character.
248  *
249  * @param before_cursor If true it deletes the character before the
250  * cursor (backspace) else the character after
251  * the cursor (delete).
252  */
253  virtual void delete_char(const bool before_cursor) = 0;
254 
255  /** Deletes the current selection. */
256  virtual void delete_selection() = 0;
257 
258  /** Copies the current selection. */
259  virtual void copy_selection(const bool mouse);
260 
261  /** Pastes the current selection. */
262  virtual void paste_selection(const bool mouse);
263 
264  /***** ***** ***** ***** expose some functions ***** ***** ***** *****/
265 
266  point get_cursor_position(const unsigned column,
267  const unsigned line = 0) const
268  {
269  return text_.get_cursor_position(column, line);
270  }
271 
272  point get_column_line(const point& position) const
273  {
274  return text_.get_column_line(position);
275  }
276 
278  {
279  return font_family_;
280  }
281 
283  {
284  font_family_ = fclass;
286  }
287 
288  void set_font_size(const unsigned font_size)
289  {
290  text_.set_font_size(font_size);
291  }
292 
294  {
295  text_.set_font_style(font_style);
296  }
297 
298  void set_maximum_width(const int width)
299  {
300  text_.set_maximum_width(width);
301  }
302 
303  void set_maximum_height(const int height, const bool multiline)
304  {
305  text_.set_maximum_height(height, multiline);
306  }
307 
308  void set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
309  {
310  text_.set_ellipse_mode(ellipse_mode);
311  }
312 
313  /***** ***** ***** setters / getters for members ***** ****** *****/
314 
315  std::size_t get_selection_start() const
316  {
317  return selection_start_;
318  }
319  void set_selection_start(const std::size_t selection_start);
320 
321  std::size_t get_selection_length() const
322  {
323  return selection_length_;
324  }
325  void set_selection_length(const int selection_length);
326 
327  std::size_t get_composition_start() const
328  {
329  return ime_start_point_;
330  }
331 
332 public:
333  bool is_composing() const
334  {
335  return ime_composing_;
336  }
337 
338  void interrupt_composition();
339 
340  /** Note the order of the states must be the same as defined in
341  * settings.hpp. */
342  enum state_t {
347  };
348 
349 private:
350  void set_state(const state_t state);
351 
352  virtual void toggle_cursor_timer(bool enable);
353 
354  /** Implements blinking cursor functionality. */
355  virtual void cursor_timer_callback();
356 
357  virtual void reset_cursor_state();
358 
359  void update_mouse_cursor(bool enable);
360 
361  /**
362  * Current state of the widget.
363  *
364  * The state of the widget determines what to render and how the widget
365  * reacts to certain 'events'.
366  */
368 
369  /** The text entered in the widget. */
371 
372  /** font family */
374 
375  /** Cached version of the text without any pending IME modifications. */
376  std::string text_cached_;
377 
378  /** Start of the selected text. */
379  std::size_t selection_start_;
380 
381  /**
382  * Length of the selected text.
383  *
384  * * positive selection_len_ means selection to the right.
385  * * negative selection_len_ means selection to the left.
386  * * selection_len_ == 0 means no selection.
387  */
389 
390  /** If this text_box_base is editable */
391  bool editable_;
392 
393  // Values to support input method editors
396 
397  std::size_t cursor_timer_;
398 
399  unsigned short cursor_alpha_;
400  unsigned short cursor_blink_rate_ms_;
401 
402  /****** handling of special keys first the pure virtuals *****/
403 
404  /**
405  * Every key can have several behaviors.
406  *
407  * Unmodified No modifier is pressed.
408  * Control The control key is pressed.
409  * Shift The shift key is pressed.
410  * Alt The alt key is pressed.
411  *
412  * If modifiers together do something else as the sum of the modifiers
413  * it's listed separately eg.
414  *
415  * Control Moves 10 steps at the time.
416  * Shift Selects the text.
417  * Control + Shift Inserts 42 in the text.
418  *
419  * There are some predefined actions for results.
420  * Unhandled The key/modifier is ignored and also reported
421  * unhandled.
422  * Ignored The key/modifier is ignored and it's
423  * _expected_ the inherited classes do the same.
424  * Implementation defined The key/modifier is ignored and it's expected
425  * the inherited classes will define some meaning
426  * to it.
427  */
428 
429  /**
430  * Up arrow key pressed.
431  *
432  * The behavior is implementation defined.
433  */
434  virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) = 0;
435 
436  /**
437  * Down arrow key pressed.
438  *
439  * The behavior is implementation defined.
440  */
441  virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) = 0;
442 
443  /**
444  * Clears the current line.
445  *
446  * Unmodified Clears the current line.
447  * Control Ignored.
448  * Shift Ignored.
449  * Alt Ignored.
450  */
451  virtual void handle_key_clear_line(SDL_Keymod modifier, bool& handled) = 0;
452 protected:
453  /**
454  * Left arrow key pressed.
455  *
456  * Unmodified Moves the cursor a character to the left.
457  * Control Like unmodified but a word instead of a letter
458  * at the time.
459  * Shift Selects the text while moving.
460  * Alt Ignored.
461  */
462  virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
463 
464  /**
465  * Right arrow key pressed.
466  *
467  * Unmodified Moves the cursor a character to the right.
468  * Control Like unmodified but a word instead of a letter
469  * at the time.
470  * Shift Selects the text while moving.
471  * Alt Ignored.
472  */
473  virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
474 
475 private:
476  /**
477  * Home key pressed.
478  *
479  * Unmodified Moves the cursor a to the beginning of the
480  * line.
481  * Control Like unmodified but to the beginning of the
482  * data.
483  * Shift Selects the text while moving.
484  * Alt Ignored.
485  */
486  virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
487 
488  /**
489  * End key pressed.
490  *
491  * Unmodified Moves the cursor a to the end of the line.
492  * Control Like unmodified but to the end of the data.
493  * Shift Selects the text while moving.
494  * Alt Ignored.
495  */
496  virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
497 
498  /**
499  * Backspace key pressed.
500  *
501  * Unmodified Deletes the character before the cursor,
502  * ignored if at the beginning of the data.
503  * Control Ignored.
504  * Shift Ignored.
505  * Alt Ignored.
506  */
507  virtual void handle_key_backspace(SDL_Keymod modifier, bool& handled);
508 
509  /**
510  * Delete key pressed.
511  *
512  * Unmodified If there is a selection that's deleted.
513  * Else if not at the end of the data the
514  * character after the cursor is deleted.
515  * Else the key is ignored.
516  * ignored if at the beginning of the data.
517  * Control Ignored.
518  * Shift Ignored.
519  * Alt Ignored.
520  */
521  virtual void handle_key_delete(SDL_Keymod modifier, bool& handled);
522 
523  /**
524  * Page up key.
525  *
526  * Unmodified Unhandled.
527  * Control Ignored.
528  * Shift Ignored.
529  * Alt Ignored.
530  */
531  virtual void handle_key_page_up(SDL_Keymod /*modifier*/, bool& /*handled*/)
532  {
533  }
534 
535  /**
536  * Page down key.
537  *
538  * Unmodified Unhandled.
539  * Control Ignored.
540  * Shift Ignored.
541  * Alt Ignored.
542  */
543  virtual void handle_key_page_down(SDL_Keymod /*modifier*/, bool& /*handled*/)
544  {
545  }
546 
547  /**
548  * Tab key.
549  *
550  * Unmodified Implementation defined.
551  * Control Implementation defined.
552  * Shift Implementation defined.
553  * Alt Implementation defined.
554  */
555  virtual void handle_key_tab(SDL_Keymod /*modifier*/, bool& /*handled*/)
556  {
557  }
558 
559  /**
560  * Enter key.
561  *
562  * Unmodified Handled by Window.
563  * Control Implementation defined.
564  * Shift Implementation defined.
565  * Alt Implementation defined.
566  */
567  virtual void handle_key_enter(SDL_Keymod /*modifier*/, bool& /*handled*/)
568  {
569  }
570 
571 protected:
572  virtual void handle_commit(bool& handled,
573  const std::string& unicode);
574  virtual void handle_editing(bool& handled,
575  const std::string& unicode,
576  int32_t start,
577  int32_t length);
578 
579 private:
580  /**
581  * Text changed callback.
582  *
583  * This callback is called in key_press after the key_press event has been
584  * handled by the styled_widget. The parameters to the function are:
585  * - The widget invoking the callback
586  * - The new text of the textbox.
587  */
588  std::function<void(text_box_base* textbox, const std::string text)>
590 
591  /***** ***** ***** signal handlers ***** ****** *****/
592 
594  bool& handled);
595 
597  bool& handled,
598  const SDL_Keycode key,
599  SDL_Keymod modifier);
600 
602  bool& handled,
603  const std::string& unicode,
604  int32_t start,
605  int32_t len);
606 
609 
610  void signal_handler_mouse_enter(const event::ui_event event, bool& handled);
611  void signal_handler_mouse_leave(const event::ui_event event, bool& handled);
612 };
613 
614 } // namespace gui2
Text class.
Definition: text.hpp:79
unsigned get_lines_count() const
Get number of lines in the text.
Definition: text.hpp:244
pango_text & set_font_style(const FONT_STYLE font_style)
Definition: text.cpp:597
void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t &color)
Mark a specific portion of text for highlighting.
Definition: text.cpp:497
int get_byte_offset(const unsigned column) const
Gets the correct number of columns to move the cursor from Pango.
Definition: text.cpp:199
std::size_t get_length() const
Gets the length of the text in bytes.
Definition: text.hpp:252
point get_column_line(const point &position) const
Gets the column of line of the character at the position.
Definition: text.cpp:318
pango_text & set_family_class(font::family_class fclass)
Definition: text.cpp:575
std::vector< std::string > get_lines() const
Retrieves a list of strings with contents for each rendered line.
Definition: text.cpp:1148
pango_text & set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
Definition: text.cpp:668
point get_cursor_position(const unsigned column, const unsigned line=0) const
Gets the location for the cursor, in drawing coordinates.
Definition: text.cpp:222
pango_text & set_font_size(unsigned font_size)
Definition: text.cpp:585
pango_text & set_maximum_height(int height, bool multiline)
Definition: text.cpp:643
pango_text & set_maximum_width(int width)
Definition: text.cpp:616
const std::string & text() const
Definition: text.hpp:270
virtual void update_canvas()
Updates the canvas(ses).
Abstract base class for text items.
unsigned short cursor_blink_rate_ms_
virtual void handle_key_backspace(SDL_Keymod modifier, bool &handled)
Backspace key pressed.
std::size_t get_length() const
Wrapper function, returns length of the text in pango column offsets.
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)
virtual void paste_selection(const bool mouse)
Pastes the current selection.
std::function< void(text_box_base *textbox, const std::string text)> text_changed_callback_
Text changed callback.
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_TEXTEDITING handler.
void set_state(const state_t state)
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.
virtual void toggle_cursor_timer(bool enable)
text_box_base(const implementation::builder_styled_widget &builder, const std::string &control_type)
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.
size_t get_composition_length() const
Get length of composition text by IME.
virtual void handle_key_enter(SDL_Keymod, bool &)
Enter key.
int selection_length_
Length of the selected text.
unsigned short cursor_alpha_
std::size_t cursor_timer_
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)=0
Every key can have several behaviors.
const std::string & text() const
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, return number of lines.
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.
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)
font::family_class font_family_
font family
void set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
font::family_class get_font_family()
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.
std::vector< std::string > get_lines()
Wrapper function, returns a vector with the lines.
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.
void set_text_changed_callback(std::function< void(text_box_base *textbox, const std::string text)> cb)
Set the text_changed callback.
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool &handled)=0
Down arrow key pressed.
bool is_editable()
Check whether text can be edited or not.
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)
virtual void copy_selection(const bool mouse)
Copies the current selection.
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)
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.
int get_byte_offset(const unsigned column) const
Wrapper function, returns corrected column offset from pango.
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:180
EXIT_STATUS start(bool clear_id, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
family_class
Font classes for get_font_families().
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
Generic file dialog.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
Holds a 2D point.
Definition: point.hpp:25