The Battle for Wesnoth  1.17.21+dev
text_box_base.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2023
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 namespace implementation
29 {
30  struct builder_styled_widget;
31 }
32 
33 /**
34  * Abstract base class for text items.
35  *
36  * All other text classes should inherit from this base class.
37  *
38  * The NOTIFY_MODIFIED event is send when the text is modified.
39  *
40  * @todo Validate whether the NOTIFY_MODIFIED is always fired properly. The
41  * current implementation is added for some quick testing so some cases might
42  * be forgotten.
43  *
44  * Common signal handlers:
45  * - connect_signal_pre_key_press
46  */
48 {
49 
50 public:
51  text_box_base(const implementation::builder_styled_widget& builder, const std::string& control_type);
52 
54 
55  /** See @ref styled_widget::set_active. */
56  virtual void set_active(const bool active) override;
57 
58  /** See @ref styled_widget::get_active. */
59  virtual bool get_active() const override;
60 
61  /** See @ref styled_widget::get_state. */
62  virtual unsigned get_state() const override;
63 
64  /***** ***** ***** ***** expose some functions ***** ***** ***** *****/
65 
66  void set_maximum_length(const std::size_t maximum_length);
67 
68  std::size_t get_length() const
69  {
70  return text_.get_length();
71  }
72 
73  /***** ***** ***** setters / getters for members ***** ****** *****/
74 
75  /**
76  * The set_value is virtual for the @ref password_box class.
77  *
78  * That class overrides the set_value function to replace it with asterisk.
79  * There might be more generic way to do it when more classes are needed.
80  */
81  virtual void set_value(const std::string& text);
82  std::string get_value() const
83  {
84  return text_.text();
85  }
86 
87  const std::string& text() const
88  {
89  return text_.text();
90  }
91 
92  /** Set the text_changed callback. */
94  std::function<void(text_box_base* textbox, const std::string text)> cb)
95  {
97  }
98 
99  /**
100  * Sets or clears the text selection.
101  *
102  * Setting the selection range will re-position the cursor depending on the
103  * selection direction, specified by the length's sign. Selecting beyond the
104  * start or end of the text is safe; the final selection will be limited
105  * accordingly.
106  *
107  * @note The range extents are measured in Unicode characters, not bytes.
108  * Using byte offsets may produce unexpected results depending on the
109  * text contents.
110  *
111  * @param start Start offset, in characters.
112  * @param length Selection length, in characters. If zero, the
113  * current selection is canceled. If negative, the
114  * selection extends towards the start of the text
115  * and the cursor will be re-positioned in that
116  * direction as well; otherwise the selection and
117  * cursor extend towards the end.
118  */
119  void set_selection(std::size_t start, int length);
120 
121 protected:
122  /** Get length of composition text by IME **/
123  size_t get_composition_length() const;
124 
125  /**
126  * Moves the cursor to the end of the line.
127  *
128  * @param select Select the text from the original cursor
129  * position till the end of the line?
130  */
131  virtual void goto_end_of_line(const bool select = false) = 0;
132 
133  /**
134  * Moves the cursor to the end of all text.
135  *
136  * For a single line text this is the same as goto_end_of_line().
137  *
138  * @param select Select the text from the original cursor
139  * position till the end of the data?
140  */
141  void goto_end_of_data(const bool select = false)
142  {
143  set_cursor(text_.get_length(), select);
144  }
145 
146  /**
147  * Moves the cursor to the beginning of the line
148  *
149  * @param select Select the text from the original cursor
150  * position till the beginning of the line?
151  */
152  virtual void goto_start_of_line(const bool select = false) = 0;
153 
154  /**
155  * Moves the cursor to the beginning of the data.
156  *
157  * @param select Select the text from the original cursor
158  * position till the beginning of the data?
159  */
160  void goto_start_of_data(const bool select = false)
161  {
162  set_cursor(0, select);
163  }
164 
165  /** Selects all text. */
166  void select_all()
167  {
168  selection_start_ = 0;
169  goto_end_of_data(true);
170  }
171 
172  /**
173  * Moves the cursor at the wanted position.
174  *
175  * @param offset The wanted new cursor position.
176  * @param select Select the text from the original cursor
177  * position till the new position?
178  */
179  void set_cursor(const std::size_t offset, const bool select);
180 
181  /**
182  * Inserts a character at the cursor.
183  *
184  * This function is preferred over set_text since it's optimized for
185  * updating the internal bookkeeping.
186  *
187  * @param unicode The unicode value of the character to insert.
188  */
189  virtual void insert_char(const std::string& unicode);
190 
191  /**
192  * Deletes the character.
193  *
194  * @param before_cursor If true it deletes the character before the
195  * cursor (backspace) else the character after
196  * the cursor (delete).
197  */
198  virtual void delete_char(const bool before_cursor) = 0;
199 
200  /** Deletes the current selection. */
201  virtual void delete_selection() = 0;
202 
203  /** Copies the current selection. */
204  virtual void copy_selection(const bool mouse);
205 
206  /** Pastes the current selection. */
207  virtual void paste_selection(const bool mouse);
208 
209  /***** ***** ***** ***** expose some functions ***** ***** ***** *****/
210 
211  point get_cursor_position(const unsigned column,
212  const unsigned line = 0) const
213  {
214  return text_.get_cursor_position(column, line);
215  }
216 
217  point get_column_line(const point& position) const
218  {
219  return text_.get_column_line(position);
220  }
221 
222  void set_font_size(const unsigned font_size)
223  {
224  text_.set_font_size(font_size);
225  }
226 
228  {
229  text_.set_font_style(font_style);
230  }
231 
232  void set_maximum_width(const int width)
233  {
234  text_.set_maximum_width(width);
235  }
236 
237  void set_maximum_height(const int height, const bool multiline)
238  {
239  text_.set_maximum_height(height, multiline);
240  }
241 
242  void set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
243  {
244  text_.set_ellipse_mode(ellipse_mode);
245  }
246 
247  /***** ***** ***** setters / getters for members ***** ****** *****/
248 
249  std::size_t get_selection_start() const
250  {
251  return selection_start_;
252  }
253  void set_selection_start(const std::size_t selection_start);
254 
255  std::size_t get_selection_length() const
256  {
257  return selection_length_;
258  }
259  void set_selection_length(const int selection_length);
260 
261  std::size_t get_composition_start() const
262  {
263  return ime_start_point_;
264  }
265 
266 public:
267  bool is_composing() const
268  {
269  return ime_composing_;
270  }
271 
272  void interrupt_composition();
273 
274  /** Note the order of the states must be the same as defined in
275  * settings.hpp. */
276  enum state_t {
281  };
282 
283 private:
284  void set_state(const state_t state);
285 
286  virtual void toggle_cursor_timer(bool enable);
287 
288  /** Implements blinking cursor functionality. */
289  virtual void cursor_timer_callback();
290 
291  virtual void reset_cursor_state();
292 
293  void update_mouse_cursor(bool enable);
294 
295  /**
296  * Current state of the widget.
297  *
298  * The state of the widget determines what to render and how the widget
299  * reacts to certain 'events'.
300  */
302 
303  /** The text entered in the widget. */
305 
306  /** Cached version of the text without any pending IME modifications. */
307  std::string text_cached_;
308 
309  /** Start of the selected text. */
310  std::size_t selection_start_;
311 
312  /**
313  * Length of the selected text.
314  *
315  * * positive selection_len_ means selection to the right.
316  * * negative selection_len_ means selection to the left.
317  * * selection_len_ == 0 means no selection.
318  */
320 
321  // Values to support input method editors
324 
325  std::size_t cursor_timer_;
326 
327  unsigned short cursor_alpha_;
328  unsigned short cursor_blink_rate_ms_;
329 
330  /****** handling of special keys first the pure virtuals *****/
331 
332  /**
333  * Every key can have several behaviors.
334  *
335  * Unmodified No modifier is pressed.
336  * Control The control key is pressed.
337  * Shift The shift key is pressed.
338  * Alt The alt key is pressed.
339  *
340  * If modifiers together do something else as the sum of the modifiers
341  * it's listed separately eg.
342  *
343  * Control Moves 10 steps at the time.
344  * Shift Selects the text.
345  * Control + Shift Inserts 42 in the text.
346  *
347  * There are some predefined actions for results.
348  * Unhandled The key/modifier is ignored and also reported
349  * unhandled.
350  * Ignored The key/modifier is ignored and it's
351  * _expected_ the inherited classes do the same.
352  * Implementation defined The key/modifier is ignored and it's expected
353  * the inherited classes will define some meaning
354  * to it.
355  */
356 
357  /**
358  * Up arrow key pressed.
359  *
360  * The behavior is implementation defined.
361  */
362  virtual void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) = 0;
363 
364  /**
365  * Down arrow key pressed.
366  *
367  * The behavior is implementation defined.
368  */
369  virtual void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) = 0;
370 
371  /**
372  * Clears the current line.
373  *
374  * Unmodified Clears the current line.
375  * Control Ignored.
376  * Shift Ignored.
377  * Alt Ignored.
378  */
379  virtual void handle_key_clear_line(SDL_Keymod modifier, bool& handled) = 0;
380 
381  /**
382  * Left arrow key pressed.
383  *
384  * Unmodified Moves the cursor a character to the left.
385  * Control Like unmodified but a word instead of a letter
386  * at the time.
387  * Shift Selects the text while moving.
388  * Alt Ignored.
389  */
390  virtual void handle_key_left_arrow(SDL_Keymod modifier, bool& handled);
391 
392  /**
393  * Right arrow key pressed.
394  *
395  * Unmodified Moves the cursor a character to the right.
396  * Control Like unmodified but a word instead of a letter
397  * at the time.
398  * Shift Selects the text while moving.
399  * Alt Ignored.
400  */
401  virtual void handle_key_right_arrow(SDL_Keymod modifier, bool& handled);
402 
403  /**
404  * Home key pressed.
405  *
406  * Unmodified Moves the cursor a to the beginning of the
407  * line.
408  * Control Like unmodified but to the beginning of the
409  * data.
410  * Shift Selects the text while moving.
411  * Alt Ignored.
412  */
413  virtual void handle_key_home(SDL_Keymod modifier, bool& handled);
414 
415  /**
416  * End key pressed.
417  *
418  * Unmodified Moves the cursor a to the end of the line.
419  * Control Like unmodified but to the end of the data.
420  * Shift Selects the text while moving.
421  * Alt Ignored.
422  */
423  virtual void handle_key_end(SDL_Keymod modifier, bool& handled);
424 
425  /**
426  * Backspace key pressed.
427  *
428  * Unmodified Deletes the character before the cursor,
429  * ignored if at the beginning of the data.
430  * Control Ignored.
431  * Shift Ignored.
432  * Alt Ignored.
433  */
434  virtual void handle_key_backspace(SDL_Keymod modifier, bool& handled);
435 
436  /**
437  * Delete key pressed.
438  *
439  * Unmodified If there is a selection that's deleted.
440  * Else if not at the end of the data the
441  * character after the cursor is deleted.
442  * Else the key is ignored.
443  * ignored if at the beginning of the data.
444  * Control Ignored.
445  * Shift Ignored.
446  * Alt Ignored.
447  */
448  virtual void handle_key_delete(SDL_Keymod modifier, bool& handled);
449 
450  /**
451  * Page up key.
452  *
453  * Unmodified Unhandled.
454  * Control Ignored.
455  * Shift Ignored.
456  * Alt Ignored.
457  */
458  virtual void handle_key_page_up(SDL_Keymod /*modifier*/, bool& /*handled*/)
459  {
460  }
461 
462  /**
463  * Page down key.
464  *
465  * Unmodified Unhandled.
466  * Control Ignored.
467  * Shift Ignored.
468  * Alt Ignored.
469  */
470  virtual void handle_key_page_down(SDL_Keymod /*modifier*/, bool& /*handled*/)
471  {
472  }
473 
474  /**
475  * Tab key.
476  *
477  * Unmodified Implementation defined.
478  * Control Implementation defined.
479  * Shift Implementation defined.
480  * Alt Implementation defined.
481  */
482  virtual void handle_key_tab(SDL_Keymod /*modifier*/, bool& /*handled*/)
483  {
484  }
485 
486 protected:
487  virtual void handle_commit(bool& handled,
488  const std::string& unicode);
489  virtual void handle_editing(bool& handled,
490  const std::string& unicode,
491  int32_t start,
492  int32_t length);
493 
494 private:
495  /**
496  * Text changed callback.
497  *
498  * This callback is called in key_press after the key_press event has been
499  * handled by the styled_widget. The parameters to the function are:
500  * - The widget invoking the callback
501  * - The new text of the textbox.
502  */
503  std::function<void(text_box_base* textbox, const std::string text)>
505 
506  /***** ***** ***** signal handlers ***** ****** *****/
507 
509  bool& handled);
510 
512  bool& handled,
513  const SDL_Keycode key,
514  SDL_Keymod modifier);
515 
517  bool& handled,
518  const std::string& unicode,
519  int32_t start,
520  int32_t len);
521 
524 
525  void signal_handler_mouse_enter(const event::ui_event event, bool& handled);
526  void signal_handler_mouse_leave(const event::ui_event event, bool& handled);
527 };
528 
529 } // namespace gui2
Text class.
Definition: text.hpp:80
pango_text & set_font_style(const FONT_STYLE font_style)
Definition: text.cpp:384
std::size_t get_length() const
Gets the length of the text in bytes.
Definition: text.hpp:233
point get_column_line(const point &position) const
Gets the column of line of the character at the position.
Definition: text.cpp:292
pango_text & set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
Definition: text.cpp:455
point get_cursor_position(const unsigned column, const unsigned line=0) const
Gets the location for the cursor, in drawing coordinates.
Definition: text.cpp:196
pango_text & set_font_size(unsigned font_size)
Definition: text.cpp:372
pango_text & set_maximum_height(int height, bool multiline)
Definition: text.cpp:430
pango_text & set_maximum_width(int width)
Definition: text.cpp:403
const std::string & text() const
Definition: text.hpp:251
Base class for all visible items.
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
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 goto_end_of_data(const bool select=false)
Moves the cursor to the end of all text.
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.
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)
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.
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)
void set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
void set_selection_start(const std::size_t selection_start)
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.
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.
void signal_handler_receive_keyboard_focus(const event::ui_event event)
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
virtual void cursor_timer_callback()
Implements blinking cursor functionality.
virtual void reset_cursor_state()
void goto_start_of_data(const bool select=false)
Moves the cursor to the beginning of the data.
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.
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:171
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.
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
Generic file dialog.
Contains the implementation details for lexical_cast and shouldn't be used directly.
Holds a 2D point.
Definition: point.hpp:25