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