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