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