The Battle for Wesnoth  1.19.22+dev
text_box_base.cpp
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 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
20 #include "cursor.hpp"
21 #include "desktop/clipboard.hpp"
22 #include "font/attributes.hpp"
24 #include "gui/core/log.hpp"
25 #include "gui/core/timer.hpp"
26 #include "gui/widgets/window.hpp"
28 
29 #include <SDL2/SDL_keyboard.h>
30 
31 #include <functional>
32 #include <limits>
33 
34 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
35 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
36 
37 using namespace std::chrono_literals;
38 
39 namespace gui2
40 {
41 
42 text_box_base::text_box_base(const implementation::builder_styled_widget& builder, const std::string& control_type)
43  : styled_widget(builder, control_type)
44  , state_(ENABLED)
45  , text_()
46  , selection_start_(0)
47  , selection_length_(0)
48  , editable_(true)
49  , ime_composing_(false)
50  , ime_start_point_(0)
51  , cursor_timer_(0)
52  , cursor_alpha_(0)
53  , cursor_blink_rate_(750ms)
54 {
55  set_font_family(get_config()->text_font_family);
56 
57 #ifdef __unix__
58  // pastes on UNIX systems.
59  connect_signal<event::MIDDLE_BUTTON_CLICK>(std::bind(
60  &text_box_base::signal_handler_middle_button_click, this, std::placeholders::_2, std::placeholders::_3));
61 
62 #endif
63 
64  connect_signal<event::SDL_KEY_DOWN>(std::bind(
65  &text_box_base::signal_handler_sdl_key_down, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5, std::placeholders::_6));
66  connect_signal<event::SDL_TEXT_INPUT>(std::bind(&text_box_base::handle_commit, this, std::placeholders::_3, std::placeholders::_5));
67  connect_signal<event::SDL_TEXT_EDITING>(std::bind(&text_box_base::handle_editing, this, std::placeholders::_3, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7));
68 
69  connect_signal<event::RECEIVE_KEYBOARD_FOCUS>(std::bind(
70  &text_box_base::signal_handler_receive_keyboard_focus, this, std::placeholders::_2));
71  connect_signal<event::LOSE_KEYBOARD_FOCUS>(
72  std::bind(&text_box_base::signal_handler_lose_keyboard_focus, this, std::placeholders::_2));
73 
74  connect_signal<event::MOUSE_ENTER>(
75  std::bind(&text_box_base::signal_handler_mouse_enter, this, std::placeholders::_2, std::placeholders::_3));
76  connect_signal<event::MOUSE_LEAVE>(
77  std::bind(&text_box_base::signal_handler_mouse_leave, this, std::placeholders::_2, std::placeholders::_3));
78 
79  toggle_cursor_timer(true);
80 }
81 
83 {
84  toggle_cursor_timer(false);
85  update_mouse_cursor(false);
86 }
87 
88 void text_box_base::set_active(const bool active)
89 {
90  if(get_active() != active) {
91  set_state(active ? ENABLED : DISABLED);
92  }
93 }
94 
96 {
97  return state_ != DISABLED;
98 }
99 
100 unsigned text_box_base::get_state() const
101 {
102  return state_;
103 }
104 
105 void text_box_base::set_maximum_length(const std::size_t maximum_length)
106 {
107  if(maximum_length == 0) {
108  return;
109  }
110 
111  const bool need_update = text_.get_length() > maximum_length;
112 
113  text_.set_maximum_length(maximum_length);
114 
115  if(need_update) {
116  if(selection_start_ > maximum_length) {
117  selection_start_ = maximum_length;
118  selection_length_ = 0;
119  } else if(selection_start_ + selection_length_ > maximum_length) {
120  selection_length_ = maximum_length - selection_start_;
121  }
122  update_canvas();
123  queue_redraw();
124  }
125 }
126 
127 void text_box_base::set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color)
128 {
129  font::attribute_list attrs;
130  add_attribute_bg_color(attrs, start_offset, end_offset, color);
131  text_.apply_attributes(attrs);
132 }
133 
134 void text_box_base::set_value(const std::string& text)
135 {
136  if(text != text_.text()) {
138 
139  // default to put the cursor at the end of the buffer.
141  selection_length_ = 0;
142  update_canvas();
143  queue_redraw();
144  }
145 }
146 
147 void text_box_base::set_cursor(const std::size_t offset, const bool select)
148 {
150 
151  if(select) {
152  selection_length_ = (selection_start_ == offset) ? 0 : -static_cast<int>(selection_start_ - offset);
153  } else {
154  selection_start_ = (offset <= text_.get_length()) ? offset : 0;
155  selection_length_ = 0;
156  }
157 
158  update_canvas();
159  queue_redraw();
160 }
161 
162 void text_box_base::insert_char(const std::string& unicode)
163 {
164  if(!editable_)
165  {
166  return;
167  }
168 
170 
172  // Update status
173  std::size_t plain_text_len = utf8::size(plain_text());
174  std::size_t cursor_pos = selection_start_ + utf8::size(unicode);
175  if (get_use_markup() && (selection_start_ + utf8::size(unicode) > plain_text_len + 1)) {
176  cursor_pos = plain_text_len;
177  }
178  set_cursor(cursor_pos, false);
179  update_canvas();
180  queue_redraw();
181  }
182 }
183 
185 {
186  if(!is_composing()) {
187  return 0;
188  }
189 
190  std::size_t text_length = utf8::size(text_.text());
191  std::size_t text_cached_length = utf8::size(text_cached_);
192  if(text_length < text_cached_length) {
193  return 0;
194  }
195 
197 }
198 
200 {
201  ime_composing_ = false;
202 #ifndef __ANDROID__
203  // We need to inform the IME that text input is no longer in progress.
204  SDL_StopTextInput();
205  SDL_StartTextInput();
206 #endif
207 }
208 
210 {
211  if(selection_length_ == 0) {
212  return;
213  }
214 
215  unsigned end, start = selection_start_;
216  const std::string txt = get_use_markup() ? plain_text() : text_.text();
217 
218  if(selection_length_ > 0) {
219  end = utf8::index(txt, start + selection_length_);
220  start = utf8::index(txt, start);
221  } else {
222  // inverse selection: selection_start_ is in fact the end
223  end = utf8::index(txt, start);
225  }
227 }
228 
230 {
231  if(!editable_)
232  {
233  return;
234  }
235 
236  const std::string& text = desktop::clipboard::copy_from_clipboard();
237  if(text.empty()) {
238  return;
239  }
240 
242 
244 
245  update_canvas();
246  queue_redraw();
247  fire(event::NOTIFY_MODIFIED, *this, nullptr);
248 }
249 
250 void text_box_base::set_selection_start(const std::size_t selection_start)
251 {
252  if(selection_start != selection_start_) {
253  selection_start_ = selection_start;
254  queue_redraw();
255  }
256 }
257 
258 void text_box_base::set_selection_length(const int selection_length)
259 {
260  if(selection_length != selection_length_) {
261  selection_length_ = selection_length;
262  queue_redraw();
263  }
264 }
265 
266 void text_box_base::set_selection(std::size_t start, int length)
267 {
268  const std::size_t text_size = text_.get_length();
269 
270  if(start >= text_size) {
271  start = text_size;
272  }
273 
274  if(length == 0) {
275  set_cursor(start, false);
276  return;
277  }
278 
279  // The text pos/size type differs in both signedness and size with the
280  // selection length. Such is life.
281  const int sel_start = std::min<std::size_t>(start, std::numeric_limits<int>::max());
282  const int sel_max_length = std::min<std::size_t>(text_size - start, std::numeric_limits<int>::max());
283 
284  const bool backwards = length < 0;
285 
286  if(backwards && -length > sel_start) {
287  length = -sel_start;
288  } else if(!backwards && length > sel_max_length) {
289  length = sel_max_length;
290  }
291 
293  set_selection_length(length);
294 
295  update_canvas();
296 }
297 
299 {
300  if(state != state_) {
301  state_ = state;
302  queue_redraw();
303  }
304 }
305 
307 {
308  if(cursor_blink_rate_ == 0ms) {
309  return;
310  }
311 
312  if(cursor_timer_) {
314  }
315 
316  cursor_timer_ = enable
318  : 0;
319 }
320 
322 {
323  unsigned was_alpha = cursor_alpha_;
324  switch(state_) {
325  case DISABLED:
326  cursor_alpha_ = 0;
327  return;
328  case ENABLED:
329  cursor_alpha_ = 255;
330  return;
331  default:
332  // FIXME: very hacky way to check if the widget's owner is the top window
333  // back() on an empty vector is UB and was causing a crash when run on Wayland (see #7104 on github)
334  const auto& dispatchers = event::get_all_dispatchers();
335  if(!dispatchers.empty() && static_cast<event::dispatcher*>(get_window()) != dispatchers.back()) {
336  cursor_alpha_ = 0;
337  } else {
338  cursor_alpha_ = (~cursor_alpha_) & 0xFF;
339  }
340  }
341 
342  if(was_alpha == cursor_alpha_) {
343  return;
344  }
345 
346  for(auto& tmp : get_canvases()) {
347  tmp.set_variable("cursor_alpha", wfl::variant(cursor_alpha_));
348  }
349 
350  queue_redraw();
351 }
352 
354 {
355  if(cursor_blink_rate_ == 0ms) {
356  return;
357  }
358 
359  cursor_alpha_ = 255;
360 
361  for(auto& tmp : get_canvases()) {
362  tmp.set_variable("cursor_alpha", wfl::variant(cursor_alpha_));
363  }
364 
365  // Restart the blink timer.
366  toggle_cursor_timer(true);
367 }
368 
369 void text_box_base::handle_key_left_arrow(SDL_Keymod modifier, bool& handled)
370 {
371  /** @todo implement the ctrl key. */
373 
374  handled = true;
375  const int offset = selection_start_ - 1 + selection_length_;
376  if(offset >= 0) {
377  set_cursor(offset, (modifier & KMOD_SHIFT) != 0);
378  }
379 }
380 
381 void text_box_base::handle_key_right_arrow(SDL_Keymod modifier, bool& handled)
382 {
383  /** @todo implement the ctrl key. */
385 
386  handled = true;
387  const std::size_t offset = selection_start_ + 1 + selection_length_;
388  if(offset <= (get_use_markup() ? utf8::size(plain_text()) : text_.get_length())) {
389  set_cursor(offset, (modifier & KMOD_SHIFT) != 0);
390  }
391 }
392 
393 void text_box_base::handle_key_home(SDL_Keymod modifier, bool& handled)
394 {
396 
397  handled = true;
398  if(modifier & KMOD_CTRL) {
399  goto_start_of_data((modifier & KMOD_SHIFT) != 0);
400  } else {
401  goto_start_of_line((modifier & KMOD_SHIFT) != 0);
402  }
403 }
404 
405 void text_box_base::handle_key_end(SDL_Keymod modifier, bool& handled)
406 {
408 
409  handled = true;
410  if(modifier & KMOD_CTRL) {
411  goto_end_of_data((modifier & KMOD_SHIFT) != 0);
412  } else {
413  goto_end_of_line((modifier & KMOD_SHIFT) != 0);
414  }
415 }
416 
417 void text_box_base::handle_key_backspace(SDL_Keymod /*modifier*/, bool& handled)
418 {
420 
421  handled = true;
422  if(selection_length_ != 0) {
424  } else if(selection_start_) {
425  delete_char(true);
426  if(is_composing()) {
427  if(get_composition_length() == 0) {
428  ime_composing_ = false;
429  }
430  }
431  }
432  fire(event::NOTIFY_MODIFIED, *this, nullptr);
433 }
434 
435 void text_box_base::handle_key_delete(SDL_Keymod /*modifier*/, bool& handled)
436 {
438 
439  handled = true;
440  if(selection_length_ != 0) {
442  } else if(selection_start_ < text_.get_length()) {
443  delete_char(false);
444  if(is_composing()) {
445  if(get_composition_length() == 0) {
446  ime_composing_ = false;
447  }
448  }
449  }
450  fire(event::NOTIFY_MODIFIED, *this, nullptr);
451 }
452 
453 void text_box_base::handle_commit(bool& handled, const std::string& unicode)
454 {
456 
457  if(unicode.size() > 1 || unicode[0] != 0) {
458  handled = true;
459  if(is_composing()) {
461  ime_composing_ = false;
462  }
463  insert_char(unicode);
464  fire(event::NOTIFY_MODIFIED, *this, nullptr);
465  }
466 }
467 
468 /**
469  * SDL_TEXTEDITING handler. See example at https://wiki.libsdl.org/Tutorials/TextInput
470  */
471 void text_box_base::handle_editing(bool& handled, const std::string& unicode, int32_t start, int32_t len)
472 {
473  if(unicode.size() > 1 || unicode[0] != 0) {
474  handled = true;
475  std::size_t new_len = utf8::size(unicode);
476  if(!is_composing()) {
477  ime_composing_ = true;
480  text_cached_ = text_.text();
481  rect rect = get_rectangle();
482  if(new_len > 0) {
484  rect.w = get_cursor_position(ime_start_point_ + new_len).x - rect.x;
485  } else {
486  rect.x += get_cursor_position(ime_start_point_ + new_len).x;
488  }
489  SDL_SetTextInputRect(&rect);
490  }
491 
492 #ifdef __unix__
493  // In SDL_TextEditingEvent, size of editing_text is limited
494  // If length of composition text is more than the limit,
495  // Linux (ibus) implementation of SDL separates it into multiple
496  // SDL_TextEditingEvent.
497  // start is start position of the separated event in entire composition text
498  if(start == 0) {
500  }
502 #else
503  std::string new_text(text_cached_);
504  utf8::insert(new_text, ime_start_point_, unicode);
505  text_.set_text(new_text, get_use_markup());
506 
507 #endif
508  int maximum_length = text_.get_length();
509 
510  // Update status
511  set_cursor(std::min(maximum_length, ime_start_point_ + start), false);
512  if(len > 0) {
513  set_cursor(std::min(maximum_length, ime_start_point_ + start + len), true);
514  }
515  update_canvas();
516  queue_redraw();
517  }
518 }
519 
521  bool& handled)
522 {
523  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
524 
525  paste_selection();
526 
527  handled = true;
528 }
529 
531  bool& handled,
532  const SDL_Keycode key,
533  SDL_Keymod modifier)
534 {
535 
536  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
537 
538 /*
539  * For copy, cut and paste we use a different key on the MAC. Even for 'select
540  * all', contradicting the comment in widgets/textbox.cpp:495.
541  *
542  * The reason for that is, by coupling 'select all' to the behavior for copy,
543  * cut and paste, the text box behavior as a whole gets consistent with default
544  * macOS hotkey idioms.
545  */
546 #ifdef __APPLE__
547  // Idiomatic modifier key in macOS computers.
548  const SDL_Keycode modifier_key = KMOD_GUI;
549 #else
550  // Idiomatic modifier key in Microsoft desktop environments. Common in
551  // GNU/Linux as well, to some extent.
552  const SDL_Keycode modifier_key = KMOD_CTRL;
553 #endif
554 
555  switch(key) {
556 
557  case SDLK_LEFT:
558  handle_key_left_arrow(modifier, handled);
559  break;
560 
561  case SDLK_RIGHT:
562  handle_key_right_arrow(modifier, handled);
563  break;
564 
565  case SDLK_UP:
566  handle_key_up_arrow(modifier, handled);
567  break;
568 
569  case SDLK_DOWN:
570  handle_key_down_arrow(modifier, handled);
571  break;
572 
573  case SDLK_PAGEUP:
574  handle_key_page_up(modifier, handled);
575  break;
576 
577  case SDLK_PAGEDOWN:
578  handle_key_page_down(modifier, handled);
579  break;
580 
581  case SDLK_a:
582  if(!(modifier & modifier_key)) {
583  return;
584  }
585 
586  select_all();
587  break;
588 
589  case SDLK_HOME:
590  handle_key_home(modifier, handled);
591  break;
592 
593  case SDLK_END:
594  handle_key_end(modifier, handled);
595  break;
596 
597  case SDLK_BACKSPACE:
598  if (!is_editable())
599  {
600  return;
601  }
602 
603  handle_key_backspace(modifier, handled);
604  break;
605 
606  case SDLK_u:
607  if( !(modifier & KMOD_CTRL) || !is_editable() ) {
608  return;
609  }
610 
611  handle_key_clear_line(modifier, handled);
612  break;
613 
614  case SDLK_DELETE:
615  if (!is_editable())
616  {
617  return;
618  }
619 
620  handle_key_delete(modifier, handled);
621  break;
622 
623  case SDLK_c:
624  if(!(modifier & modifier_key)) {
625  return;
626  }
627 
628  // atm we don't care whether there is something to copy or paste
629  // if nothing is there we still don't want to be chained.
630  copy_selection();
631  handled = true;
632  break;
633 
634  case SDLK_x:
635  if( !(modifier & modifier_key) ) {
636  return;
637  }
638 
639  copy_selection();
640 
641  if ( is_editable() ) {
643  }
644  handled = true;
645  break;
646 
647  case SDLK_v:
648  if( !(modifier & modifier_key) || !is_editable() ) {
649  return;
650  }
651 
652  paste_selection();
653  handled = true;
654  break;
655 
656  case SDLK_RETURN:
657  case SDLK_KP_ENTER:
658 
659 // TODO: check if removing the following check causes any side effects
660 // To be removed if there aren't any text rendering problems.
661 // if(!is_composing()) {
662 // return;
663 // }
664 
665  handle_key_enter(modifier, handled);
666  break;
667 
668  case SDLK_AC_BACK:
669  case SDLK_ESCAPE:
670  if(!is_composing() || (modifier & (KMOD_CTRL | KMOD_ALT | KMOD_GUI | KMOD_SHIFT))) {
671  return;
672  }
674  handled = true;
675  break;
676 
677  case SDLK_TAB:
678  handle_key_tab(modifier, handled);
679  break;
680 
681  default:
682  return;
683  }
684 }
685 
687 {
688  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
689 #if defined(__ANDROID__) || defined(__IPHONEOS__)
690  SDL_StartTextInput();
691 #endif
693 }
694 
696 {
697  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
698 #if defined(__ANDROID__) || defined(__IPHONEOS__)
699  SDL_StopTextInput();
700 #endif
702 }
703 
705  bool& handled)
706 {
707  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
708  if(state_ != FOCUSED) {
710  }
711 
712  update_mouse_cursor(true);
713 
714  handled = true;
715 }
716 
718  bool& handled)
719 {
720  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
721 
722  if(state_ != FOCUSED) {
724  }
725 
726  update_mouse_cursor(false);
727 
728  handled = true;
729 }
730 
732 {
733  // Someone else may set the mouse cursor for us to something unusual (e.g.
734  // the WAIT cursor) so we ought to mess with that only if it's set to
735  // NORMAL or IBEAM.
736 
737  if(enable && cursor::get() == cursor::NORMAL) {
739  } else if(!enable && cursor::get() == cursor::IBEAM) {
741  }
742 }
743 
744 
745 } // namespace gui2
Helper class to encapsulate the management of a PangoAttrList.
Definition: attributes.hpp:28
std::size_t get_length() const
Gets the length of the text in bytes.
Definition: text.hpp:304
pango_text & set_maximum_length(const std::size_t maximum_length)
Definition: text.cpp:482
unsigned insert_text(const unsigned offset, const std::string &text, const bool use_markup=false)
Inserts UTF-8 text.
Definition: text.cpp:169
void apply_attributes(const font::attribute_list &attrs)
Definition: text.cpp:324
bool set_text(const std::string &text, const bool markedup)
Sets the text to render.
Definition: text.cpp:333
const std::string & text() const
Definition: text.hpp:322
Base class for event handling.
Definition: dispatcher.hpp:150
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:74
std::vector< canvas > & get_canvases()
virtual void update_canvas()
Updates the canvas(ses).
resolution_definition_ptr get_config()
bool get_use_markup() const
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.
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 update_mouse_cursor(bool enable)
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)
std::chrono::milliseconds cursor_blink_rate_
virtual void copy_selection()
Copies the current selection.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
virtual void toggle_cursor_timer(bool enable)
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.
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_
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 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.
virtual void handle_key_clear_line(SDL_Keymod modifier, bool &handled)=0
Clears the current line.
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.
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.
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)
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 queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:464
window * get_window()
Get the parent window.
Definition: widget.cpp:117
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:321
Define the common log macros for the gui toolkit.
#define DBG_GUI_E
Definition: log.hpp:35
This file contains the window object, this object is a top level container which has the event manage...
CURSOR_TYPE get()
Definition: cursor.cpp:206
@ NORMAL
Definition: cursor.hpp:28
@ IBEAM
Definition: cursor.hpp:28
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:172
void copy_to_clipboard(const std::string &text)
Copies text to the clipboard.
Definition: clipboard.cpp:27
std::string copy_from_clipboard()
Copies text from the clipboard.
Definition: clipboard.cpp:32
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.
void add_attribute_bg_color(attribute_list &list, unsigned offset_start, unsigned offset_end, const color_t &color)
Mark a specific portion of text for highlighting.
Definition: attributes.cpp:135
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
@ NOTIFY_MODIFIED
Definition: handler.hpp:175
std::vector< dispatcher * > & get_all_dispatchers()
Gets all event dispatchers in the Z order.
Definition: handler.cpp:883
Generic file dialog.
std::size_t add_timer(const std::chrono::milliseconds &interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:123
bool remove_timer(const std::size_t id)
Removes a timer.
Definition: timer.cpp:164
std::string & insert(std::string &str, const std::size_t pos, const std::string &insert)
Insert a UTF-8 string at the specified position.
Definition: unicode.cpp:100
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:81
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:51
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:49
#define LOG_HEADER
#define LOG_SCOPE_HEADER
Contains the gui2 timer routines.