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