The Battle for Wesnoth  1.19.24+dev
textbox.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2025
3  by David White <dave@whitevine.net>
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 
18 #include "widgets/textbox.hpp"
19 
20 #include "cursor.hpp"
21 #include "desktop/clipboard.hpp"
22 #include "draw.hpp"
23 #include "font/sdl_ttf_compat.hpp"
24 #include "log.hpp"
25 #include "sdl/rect.hpp"
27 #include "sdl/input.hpp" // get_mouse_state
28 #if defined(__ANDROID__) || defined(__IPHONEOS__)
29 #include "video.hpp"
30 #endif
31 
32 #include <SDL3/SDL_timer.h>
33 
34 static lg::log_domain log_display("display");
35 #define WRN_DP LOG_STREAM(warn, log_display)
36 #define DBG_G LOG_STREAM(debug, lg::general())
37 
38 namespace gui {
39 
40 textbox::textbox(int width, const std::string& text, bool editable, std::size_t max_size, int font_size, double alpha, double alpha_focus, const bool auto_join)
41  : scrollarea(auto_join), max_size_(max_size), font_size_(font_size), text_(unicode_cast<std::u32string>(text)),
42  cursor_(text_.size()), selstart_(-1), selend_(-1),
43  grabmouse_(false), text_pos_(0), editable_(editable),
44  show_cursor_(true), show_cursor_at_(0), text_image_(nullptr),
45  wrap_(false), line_height_(0), yscroll_(0), alpha_(alpha),
46  alpha_focus_(alpha_focus),
47  edit_target_(nullptr)
48  ,listening_(false)
49 {
52  update_text_cache(true);
53 }
54 
56 {
57  // Restore the cursor on destruction if we (probably) set it to IBEAM
58  if(cursor::get() == cursor::IBEAM) {
60  }
61 }
62 
64 {
66  update_text_cache(true);
67  queue_redraw();
68 }
69 
70 void textbox::set_inner_location(const rect& /*rect*/)
71 {
72  if (!text_image_) return;
73  text_pos_ = 0;
74  update_text_cache(false);
75 }
76 
77 const std::string textbox::text() const
78 {
79  const std::string &ret = unicode_cast<std::string>(text_);
80  return ret;
81 }
82 
83 // set_text does not respect max_size_
84 void textbox::set_text(const std::string& text, const color_t& color)
85 {
86  text_ = unicode_cast<std::u32string>(text);
87  cursor_ = text_.size();
88  text_pos_ = 0;
89  selstart_ = -1;
90  selend_ = -1;
91  queue_redraw();
92  update_text_cache(true, color);
94 }
95 
96 void textbox::append_text(const std::string& text, bool auto_scroll, const color_t& color)
97 {
98  if(!text_image_) {
99  set_text(text, color);
100  return;
101  }
102 
103  //disallow adding multi-line text to a single-line text box
104  if(wrap_ == false && std::find_if(text.begin(),text.end(),utils::isnewline) != text.end()) {
105  return;
106  }
107 
108  const std::u32string& wtext = unicode_cast<std::u32string>(text);
109  text_.insert(text_.end(), wtext.begin(), wtext.end());
110 
112 
113  queue_redraw();
114  update_text_cache(false);
115  const bool is_at_bottom = get_position() == get_max_position();
116  if(auto_scroll && is_at_bottom) scroll_to_bottom();
118 }
119 
121 {
122  text_.clear();
123  cursor_ = 0;
124  cursor_pos_ = 0;
125  text_pos_ = 0;
126  selstart_ = -1;
127  selend_ = -1;
128  queue_redraw();
129  update_text_cache(true);
131 }
132 
133 void textbox::set_selection(const int selstart, const int selend)
134 {
135  if (!editable_) {
136  return;
137  }
138  if (selstart < 0 || selend < 0 || std::size_t(selstart) > text_.size() ||
139  std::size_t(selend) > text_.size()) {
140  WRN_DP << "out-of-boundary selection";
141  return;
142  }
143  selstart_= selstart;
144  selend_ = selend;
145  queue_redraw();
146 }
147 
148 void textbox::set_cursor_pos(const int cursor_pos)
149 {
150  if (!editable_) {
151  return;
152  }
153  if (cursor_pos < 0 || std::size_t(cursor_pos) > text_.size()) {
154  WRN_DP << "out-of-boundary selection";
155  return;
156  }
157 
158  cursor_ = cursor_pos;
159  update_text_cache(false);
160  queue_redraw();
161 }
162 
163 void textbox::draw_cursor(int pos) const
164 {
165  if(show_cursor_ && editable_ && enabled()) {
166  rect rect {
167  location().x + pos
168  , location().y
169  , 1
170  , location().h
171  };
172 
173  draw::fill(rect, 255, 255, 255, 255);
174  }
175 }
176 
178 {
179  if(text_image_ == nullptr) {
180  update_text_cache(true);
181  }
182 }
183 
185 {
186  const rect& loc = inner_location();
187 
188  color_t c(0, 0, 0);
189 
190  double& alpha = focus(nullptr) ? alpha_focus_ : alpha_;
191  c.a = 255 * alpha;
192 
193  draw::fill(loc, c);
194 
195  rect src;
196 
197  if(text_image_ != nullptr) {
198  src.y = yscroll_;
199  src.w = std::min<std::size_t>(loc.w,text_image_.w());
200  src.h = std::min<std::size_t>(loc.h,text_image_.h());
201  src.x = text_pos_;
202  rect dest{loc.x, loc.y, src.w, src.h};
203 
204  // Fills the selected area
205  if(enabled() && is_selection()) {
206  const int start = std::min<int>(selstart_,selend_);
207  const int end = std::max<int>(selstart_,selend_);
208  int startx = char_x_[start];
209  int starty = char_y_[start];
210  const int endx = char_x_[end];
211  const int endy = char_y_[end];
212 
213  auto clipper = draw::reduce_clip(loc);
214 
215  while(starty <= endy) {
216  const std::size_t right = starty == endy ? endx : text_image_.w();
217  if(right <= std::size_t(startx)) {
218  break;
219  }
220 
221  rect r(loc.x + startx
222  , loc.y + starty - src.y
223  , right - startx
224  , line_height_);
225 
226  draw::fill(r, 0, 0, 160, 140);
227 
228  starty += int(line_height_);
229  startx = 0;
230  }
231  }
232 
233  // Set the source region on the texture.
235 
236  if(enabled()) {
237  draw::blit(text_image_, dest);
238  } else {
239  // HACK: using 30% opacity allows white text to look as though it is grayed out,
240  // while not changing any applicable non-grayscale AA. Actual colored text will
241  // not look as good, but this is not currently a concern since GUI1 textboxes
242  // are not used much nowadays, and they will eventually all go away.
244  draw::blit(text_image_, dest);
246  }
247 
248  // This doesn't really need to be cleared, but why not.
250  }
251 
252  draw_cursor(cursor_pos_ == 0 ? 0 : cursor_pos_ - 1);
253 }
254 
255 void textbox::set_editable(bool value)
256 {
257  editable_ = value;
258 }
259 
260 bool textbox::editable() const
261 {
262  return editable_;
263 }
264 
266 {
267  return font_size_;
268 }
269 
271 {
272  font_size_ = fs;
273 }
274 
276 {
278 }
279 
280 void textbox::set_wrap(bool val)
281 {
282  if(wrap_ != val) {
283  wrap_ = val;
284  update_text_cache(true);
285  queue_redraw();
286  }
287 }
288 
289 void textbox::scroll(unsigned int pos)
290 {
291  yscroll_ = pos;
292  queue_redraw();
293 }
294 
295 texture textbox::add_text_line(const std::u32string& text, const color_t& color)
296 {
298 
299  if(char_y_.empty()) {
300  char_y_.push_back(0);
301  } else {
302  char_y_.push_back(char_y_.back() + line_height_);
303  }
304 
305  char_x_.push_back(0);
306 
307  // Re-calculate the position of each glyph. We approximate this by asking the
308  // width of each substring, but this is a flawed assumption which won't work with
309  // some more complex scripts (that is, RTL languages). This part of the work should
310  // actually be done by the font-rendering system.
311  std::string visible_string;
312  std::u32string wrapped_text;
313 
314  std::u32string::const_iterator backup_itor = text.end();
315 
316  std::u32string::const_iterator itor = text.begin();
317  while(itor != text.end()) {
318  //If this is a space, save copies of the current state so we can roll back
319  if(char(*itor) == ' ') {
320  backup_itor = itor;
321  }
322  visible_string.append(unicode_cast<std::string>(*itor));
323 
324  if(char(*itor) == '\n') {
325  backup_itor = text.end();
326  visible_string = "";
327  }
328 
329  auto [w, _] = font::pango_line_size(visible_string, font_size_);
330 
331  if(wrap_ && w >= inner_location().w) {
332  if(backup_itor != text.end()) {
333  int backup = itor - backup_itor;
334  itor = backup_itor + 1;
335  if(backup > 0) {
336  char_x_.erase(char_x_.end()-backup, char_x_.end());
337  char_y_.erase(char_y_.end()-backup, char_y_.end());
338  wrapped_text.erase(wrapped_text.end()-backup, wrapped_text.end());
339  }
340  } else {
341  if (visible_string == std::string("").append(unicode_cast<std::string>(*itor))) {
342  break; //breaks infinite loop where when running with a fake display, we word wrap a single character infinitely.
343  }
344  }
345  backup_itor = text.end();
346  wrapped_text.push_back(char32_t('\n'));
347  char_x_.push_back(0);
348  char_y_.push_back(char_y_.back() + line_height_);
349  visible_string = "";
350  } else {
351  wrapped_text.push_back(*itor);
352  char_x_.push_back(w);
353  char_y_.push_back(char_y_.back() + (char(*itor) == '\n' ? line_height_ : 0));
354  ++itor;
355  }
356  }
357 
358  const std::string s = unicode_cast<std::string>(wrapped_text);
359  return font::pango_render_text(s, font_size_, color);
360 }
361 
362 
363 void textbox::update_text_cache(bool changed, const color_t& color)
364 {
365  if(changed) {
366  char_x_.clear();
367  char_y_.clear();
368 
369  text_image_ = add_text_line(text_, color);
370  }
371 
372  int cursor_x = char_x_[cursor_];
373 
374  if(cursor_x - text_pos_ > location().w) {
375  text_pos_ = cursor_x - location().w;
376  } else if(cursor_x - text_pos_ < 0) {
377  text_pos_ = cursor_x;
378  }
379  cursor_pos_ = cursor_x - text_pos_;
380 
381  if (text_image_) {
384  }
385 }
386 
388 {
389  return (selstart_ != -1) && (selend_ != -1) && (selstart_ != selend_);
390 }
391 
393 {
394  if(!is_selection())
395  return;
396 
397  std::u32string::iterator itor = text_.begin() + std::min(selstart_, selend_);
398  text_.erase(itor, itor + std::abs(selend_ - selstart_));
399  cursor_ = std::min(selstart_, selend_);
400  selstart_ = selend_ = -1;
401 }
402 
403 namespace {
404  const unsigned int copypaste_modifier =
405 #ifdef __APPLE__
406  SDL_KMOD_LGUI | SDL_KMOD_RGUI
407 #else
408  SDL_KMOD_CTRL
409 #endif
410  ;
411 }
412 
413 bool textbox::requires_event_focus(const SDL_Event* event) const
414 {
415  if(!focus_ || hidden() || !enabled()) {
416  return false;
417  }
418  if(event == nullptr) {
419  //when event is not specified, signal that focus may be desired later
420  return true;
421  }
422 
423  if(event->type == SDL_EVENT_KEY_DOWN) {
424  SDL_Keycode key = event->key.key;
425  switch(key) {
426  case SDLK_UP:
427  case SDLK_DOWN:
428  case SDLK_PAGEUP:
429  case SDLK_PAGEDOWN:
430  //in the future we may need to check for input history or multi-line support
431  //for now, just return false since these events are not handled.
432  return false;
433  default:
434  return true;
435  }
436  }
437  //mouse events are processed regardless of focus
438  return false;
439 }
440 
441 void textbox::handle_event(const SDL_Event& event)
442 {
444  handle_event(event, false);
445 }
446 
447 bool textbox::handle_text_input(const SDL_Event& event)
448 {
449  bool changed = false;
450  std::string str = event.text.text;
451  std::u32string s = unicode_cast<std::u32string>(str);
452 
453  DBG_G << "Char: " << str;
454 
455  if (editable_) {
456  changed = true;
457  if (is_selection())
458  erase_selection();
459 
460  if (text_.size() + 1 <= max_size_) {
461 
462  text_.insert(text_.begin() + cursor_, s.begin(), s.end());
463  cursor_ += s.size();
464  }
465  } else {
466  pass_event_to_target(event);
467  }
468  return changed;
469 }
470 
471 bool textbox::handle_key_down(const SDL_Event &event)
472 {
473  bool changed = false;
474 
475  const SDL_Keymod modifiers = SDL_GetModState();
476 
477  const int c = reinterpret_cast<const SDL_KeyboardEvent&>(event).key;
478  const int old_cursor = cursor_;
479 
480  listening_ = true;
481 
482  if(editable_) {
483  if(c == SDLK_LEFT && cursor_ > 0)
484  --cursor_;
485 
486  if(c == SDLK_RIGHT && cursor_ < static_cast<int>(text_.size()))
487  ++cursor_;
488 
489  // ctrl-a, ctrl-e and ctrl-u are readline style shortcuts, even on Macs
490  if(c == SDLK_END || (c == SDLK_E && (modifiers & SDL_KMOD_CTRL)))
491  cursor_ = text_.size();
492 
493  if(c == SDLK_HOME || (c == SDLK_A && (modifiers & SDL_KMOD_CTRL)))
494  cursor_ = 0;
495 
496  if((old_cursor != cursor_) && (modifiers & SDL_KMOD_SHIFT)) {
497  if(selstart_ == -1)
498  selstart_ = old_cursor;
499  selend_ = cursor_;
500  }
501  } else if(c == SDLK_LEFT || c == SDLK_RIGHT || c == SDLK_END || c == SDLK_HOME) {
502  pass_event_to_target(event);
503  }
504 
505  if(editable_) {
506  if(c == SDLK_BACKSPACE) {
507  changed = true;
508  if(is_selection()) {
509  erase_selection();
510  } else if(cursor_ > 0) {
511  --cursor_;
512  text_.erase(text_.begin()+cursor_);
513  }
514  }
515 
516  if(c == SDLK_U && (modifiers & SDL_KMOD_CTRL)) { // clear line
517  changed = true;
518  cursor_ = 0;
519  text_.resize(0);
520  }
521 
522  if(c == SDLK_DELETE && !text_.empty()) {
523  changed = true;
524  if(is_selection()) {
525  erase_selection();
526  } else {
527  if(cursor_ < static_cast<int>(text_.size())) {
528  text_.erase(text_.begin()+cursor_);
529  }
530  }
531  }
532  } else if(c == SDLK_BACKSPACE || c == SDLK_DELETE || (c == SDLK_U && (modifiers & SDL_KMOD_CTRL))) {
533  pass_event_to_target(event);
534  }
535 
536 
537  //movement characters may have a "Unicode" field on some platforms, so ignore it.
538  if(!(c == SDLK_UP || c == SDLK_DOWN || c == SDLK_LEFT || c == SDLK_RIGHT ||
539  c == SDLK_DELETE || c == SDLK_BACKSPACE || c == SDLK_END || c == SDLK_HOME ||
540  c == SDLK_PAGEUP || c == SDLK_PAGEDOWN)) {
541  if((event.key.mod & copypaste_modifier)
542  //on windows SDL fires for AltGr lctrl+ralt (needed to access @ etc on certain keyboards)
543 #ifdef _WIN32
544  //&& !(event.key.keysym.mod & SDL_KMOD_ALT)
545 #endif
546  ) {
547  switch(c) {
548  case SDLK_V: // paste
549  {
550  if(!editable()) {
551  pass_event_to_target(event);
552  break;
553  }
554 
555  changed = true;
556  if(is_selection())
557  erase_selection();
558 
559  std::string str = desktop::clipboard::copy_from_clipboard();
560 
561  //cut off anything after the first newline
562  str.erase(std::find_if(str.begin(),str.end(),utils::isnewline),str.end());
563 
564  std::u32string s = unicode_cast<std::u32string>(str);
565 
566  if(text_.size() < max_size_) {
567  if(s.size() + text_.size() > max_size_) {
568  s.resize(max_size_ - text_.size());
569  }
570  text_.insert(text_.begin()+cursor_, s.begin(), s.end());
571  cursor_ += s.size();
572  }
573 
574  }
575 
576  break;
577 
578  case SDLK_C: // copy
579  {
580  if(is_selection())
581  {
582  const std::size_t beg = std::min<std::size_t>(std::size_t(selstart_),std::size_t(selend_));
583  const std::size_t end = std::max<std::size_t>(std::size_t(selstart_),std::size_t(selend_));
584 
585  std::u32string ws(text_.begin() + beg, text_.begin() + end);
586  std::string s = unicode_cast<std::string>(ws);
588  }
589  }
590  break;
591 
592  case SDLK_X: // cut
593  {
594  if(is_selection())
595  {
596  const std::size_t beg = std::min<std::size_t>(std::size_t(selstart_),std::size_t(selend_));
597  const std::size_t end = std::max<std::size_t>(std::size_t(selstart_),std::size_t(selend_));
598 
599  std::u32string ws(text_.begin() + beg, text_.begin() + end);
600  std::string s = unicode_cast<std::string>(ws);
602  erase_selection();
603  }
604  break;
605  }
606  case SDLK_A: // selectall
607  {
608  set_selection(0, text_.size());
609  break;
610  }
611  }//end switch
612  }
613  else {
614  pass_event_to_target(event);
615  }
616  }
617 
618  return changed;
619 }
620 
621 void textbox::handle_event(const SDL_Event& event, bool was_forwarded)
622 {
623  if(!enabled())
624  return;
625 
627  if(hidden())
628  return;
629 
630  bool changed = false;
631 
632  const int old_selstart = selstart_;
633  const int old_selend = selend_;
634 
635  //Sanity check: verify that selection start and end are within text
636  //boundaries
637  if(is_selection() && !(std::size_t(selstart_) <= text_.size() && std::size_t(selend_) <= text_.size())) {
638  WRN_DP << "out-of-boundary selection";
639  selstart_ = selend_ = -1;
640  }
641 
642  float mousex, mousey;
643  const uint8_t mousebuttons = sdl::get_mouse_state(&mousex,&mousey);
644  if(!(mousebuttons & SDL_BUTTON_MASK(1))) {
645  grabmouse_ = false;
646  }
647 
648  const rect loc = inner_location();
649 
650  const bool mouse_inside = loc.contains(mousex, mousey);
651 
652 #if defined(__ANDROID__) || defined(__IPHONEOS__)
653  if(mouse_inside) {
654  // Show onscreen keyboard
655  SDL_StartTextInput(video::get_window());
656  }
657 #endif
658 
659  // Someone else may set the mouse cursor for us to something unusual (e.g.
660  // the WAIT cursor) so we ought to mess with that only if it's set to
661  // NORMAL or IBEAM.
662 
663  if(mouse_inside && cursor::get() == cursor::NORMAL) {
665  } else if(!mouse_inside && cursor::get() == cursor::IBEAM) {
667  }
668 
669  bool clicked_inside = !mouse_locked() && (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN
670  && (mousebuttons & SDL_BUTTON_MASK(1))
671  && mouse_inside);
672  if(clicked_inside) {
673  set_focus(true);
674  }
675  if ((grabmouse_ && (!mouse_locked() && event.type == SDL_EVENT_MOUSE_MOTION)) || clicked_inside) {
676  const int x = mousex - loc.x + text_pos_;
677  const int y = mousey - loc.y;
678  int pos = 0;
679  int distance = x;
680 
681  for(unsigned int i = 1; i < char_x_.size(); ++i) {
682  if(static_cast<int>(yscroll_) + y < char_y_[i]) {
683  break;
684  }
685 
686  // Check individually each distance (if, one day, we support
687  // RTL languages, char_x_[c] may not be monotonous.)
688  if(std::abs(x - char_x_[i]) < distance && yscroll_ + y < char_y_[i] + line_height_) {
689  pos = i;
690  distance = std::abs(x - char_x_[i]);
691  }
692  }
693 
694  cursor_ = pos;
695 
696  if(grabmouse_)
697  selend_ = cursor_;
698 
699  update_text_cache(false);
700 
701  if(!grabmouse_ && (mousebuttons & SDL_BUTTON_MASK(1))) {
702  grabmouse_ = true;
704  } else if (! (mousebuttons & SDL_BUTTON_MASK(1))) {
705  grabmouse_ = false;
706  }
707 
708  queue_redraw();
709  }
710 
711  //if we don't have the focus, then see if we gain the focus,
712  //otherwise return
713  if(!was_forwarded && focus(&event) == false) {
714  if (!mouse_locked() && event.type == SDL_EVENT_MOUSE_MOTION && loc.contains(mousex, mousey))
715  events::focus_handler(this);
716 
717  return;
718  }
719 
720  const int old_cursor = cursor_;
721 
722  if (event.type == SDL_EVENT_TEXT_INPUT && listening_) {
723  changed = handle_text_input(event);
724  } else if (event.type == SDL_EVENT_KEY_DOWN) {
725  changed = handle_key_down(event);
726  }
727 
728  if(is_selection() && (selend_ != cursor_))
729  selstart_ = selend_ = -1;
730 
731  //since there has been cursor activity, make the cursor appear for
732  //at least the next 500ms.
733  show_cursor_ = true;
734  show_cursor_at_ = SDL_GetTicks();
735 
736  if(changed || old_cursor != cursor_ || old_selstart != selstart_ || old_selend != selend_) {
737  text_image_.reset();
739  }
740 
741  queue_redraw();
742 }
743 
744 void textbox::pass_event_to_target(const SDL_Event& event)
745 {
747  edit_target_->handle_event(event, true);
748  }
749 }
750 
752 {
753  edit_target_ = target;
754 }
755 
756 } //end namespace gui
map_location loc
Definition: move.cpp:172
virtual void update_location(const rect &rect)
Definition: scrollarea.cpp:45
unsigned get_max_position() const
Definition: scrollarea.cpp:86
void set_shown_size(unsigned h)
Definition: scrollarea.cpp:106
unsigned get_position() const
Definition: scrollarea.cpp:81
void set_full_size(unsigned h)
Definition: scrollarea.cpp:113
void set_position(unsigned pos)
Definition: scrollarea.cpp:91
rect inner_location() const
Definition: scrollarea.cpp:134
virtual void handle_event(const SDL_Event &event)
Definition: scrollarea.cpp:147
void set_scroll_rate(unsigned r)
Definition: scrollarea.cpp:120
bool handle_text_input(const SDL_Event &event)
Definition: textbox.cpp:447
double alpha_focus_
Definition: textbox.hpp:96
textbox(int width, const std::string &text="", bool editable=true, std::size_t max_size=256, int font_size=font::SIZE_PLUS, double alpha=0.4, double alpha_focus=0.2, const bool auto_join=true)
Definition: textbox.cpp:40
int font_size_
Definition: textbox.hpp:67
int show_cursor_at_
Definition: textbox.hpp:88
virtual void set_inner_location(const rect &) override
Definition: textbox.cpp:70
virtual void scroll(unsigned int pos) override
Definition: textbox.cpp:289
void set_wrap(bool val)
Definition: textbox.cpp:280
void scroll_to_bottom()
Definition: textbox.cpp:275
const std::string text() const
Definition: textbox.cpp:77
void erase_selection()
Definition: textbox.cpp:392
void set_cursor_pos(const int cursor_pos)
Definition: textbox.cpp:148
void set_selection(const int selstart, const int selend)
Definition: textbox.cpp:133
std::size_t line_height_
Definition: textbox.hpp:93
bool editable() const
Definition: textbox.cpp:260
void pass_event_to_target(const SDL_Event &event)
Definition: textbox.cpp:744
bool show_cursor_
Definition: textbox.hpp:83
void set_text(const std::string &text, const color_t &color=font::NORMAL_COLOR)
Definition: textbox.cpp:84
virtual void draw_contents() override
Definition: textbox.cpp:184
virtual ~textbox()
Definition: textbox.cpp:55
void draw_cursor(int pos) const
Definition: textbox.cpp:163
void set_font_size(int fs)
Definition: textbox.cpp:270
void set_editable(bool value)
Definition: textbox.cpp:255
bool grabmouse_
Definition: textbox.hpp:75
bool editable_
Definition: textbox.hpp:81
textbox * edit_target_
Definition: textbox.hpp:98
std::size_t yscroll_
Definition: textbox.hpp:93
void clear()
Definition: textbox.cpp:120
void handle_event(const SDL_Event &event, bool was_forwarded)
Definition: textbox.cpp:621
bool wrap_
Definition: textbox.hpp:91
bool is_selection()
Definition: textbox.cpp:387
int selstart_
Definition: textbox.hpp:73
bool handle_key_down(const SDL_Event &event)
Definition: textbox.cpp:471
std::vector< int > char_x_
Definition: textbox.hpp:79
bool requires_event_focus(const SDL_Event *event=nullptr) const override
Definition: textbox.cpp:413
bool listening_
Definition: textbox.hpp:104
int font_size() const
Definition: textbox.cpp:265
std::u32string text_
Definition: textbox.hpp:69
double alpha_
Definition: textbox.hpp:95
virtual void layout() override
Called by draw_manager to validate layout.
Definition: textbox.cpp:177
void set_edit_target(textbox *target)
Definition: textbox.cpp:751
texture text_image_
Definition: textbox.hpp:89
int cursor_pos_
Definition: textbox.hpp:78
void append_text(const std::string &text, bool auto_scroll=false, const color_t &color=font::NORMAL_COLOR)
Definition: textbox.cpp:96
void update_text_cache(bool reset=false, const color_t &color=font::NORMAL_COLOR)
Definition: textbox.cpp:363
int text_pos_
Definition: textbox.hpp:77
std::vector< int > char_y_
Definition: textbox.hpp:79
std::size_t max_size_
Definition: textbox.hpp:65
virtual void update_location(const rect &rect) override
Definition: textbox.cpp:63
texture add_text_line(const std::u32string &text, const color_t &color=font::NORMAL_COLOR)
Definition: textbox.cpp:295
virtual void handle_text_changed(const std::u32string &)
Definition: textbox.hpp:63
virtual void handle_event(const SDL_Event &) override
Definition: widget.hpp:90
bool focus(const SDL_Event *event)
Definition: widget.cpp:136
void set_measurements(int w, int h)
Definition: widget.cpp:108
const rect & location() const
Definition: widget.cpp:123
int width() const
Definition: widget.cpp:113
void queue_redraw()
Indicate that the widget should be redrawn.
Definition: widget.cpp:215
bool enabled() const
Definition: widget.cpp:175
void set_focus(bool focus)
Definition: widget.cpp:128
bool hidden() const
Definition: widget.cpp:161
bool mouse_locked() const
Definition: widget.cpp:64
bool focus_
Definition: widget.hpp:90
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:33
int w() const
The draw-space width of the texture, in pixels.
Definition: texture.hpp:103
void reset()
Releases ownership of the managed texture and resets the ptr to null.
Definition: texture.cpp:202
void set_src(const rect &r)
Set the source region of the texture used for drawing operations.
Definition: texture.cpp:122
int h() const
The draw-space height of the texture, in pixels.
Definition: texture.hpp:112
void set_alpha_mod(uint8_t alpha)
Alpha modifier.
Definition: texture.cpp:146
void clear_src()
Clear the source region.
Definition: texture.hpp:165
Drawing functions, for drawing things on the screen.
std::size_t i
Definition: function.cpp:1031
static std::string _(const char *str)
Definition: gettext.hpp:97
Contains functions for cleanly handling SDL input.
Standard logging facilities (interface).
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
clip_setter reduce_clip(const ::rect &clip)
Set the clipping area to the intersection of the current clipping area and the given rectangle.
Definition: draw.cpp:595
void fill(const ::rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:62
void blit(const texture &tex, const ::rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition: draw.cpp:409
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 focus_handler(const sdl_handler *ptr)
Definition: events.cpp:402
int get_max_height(unsigned size, font::family_class fclass, pango_text::FONT_STYLE style)
Returns the maximum glyph height of a font, in pixels.
Definition: text.cpp:965
std::pair< int, int > pango_line_size(const std::string &line, int font_size, font::pango_text::FONT_STYLE font_style)
Determine the width and height of a line of text given a certain font size.
texture pango_render_text(const std::string &text, int size, const color_t &color, font::pango_text::FONT_STYLE style, bool use_markup, int max_width)
Returns a SDL texture containing the rendered text.
General purpose widgets.
uint32_t get_mouse_state(float *x, float *y)
A wrapper for SDL_GetMouseState that gives coordinates in draw space.
Definition: input.cpp:27
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:81
auto * find_if(Container &container, const Predicate &predicate)
Convenience wrapper for using find_if on a container without needing to comare to end()
Definition: general.hpp:151
bool isnewline(const char c)
SDL_Window * get_window()
Definition: video.cpp:697
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
int w
Definition: pathfind.cpp:188
Contains the SDL_Rect helper code.
Transitional API for porting SDL_ttf-based code to Pango.
rect src
Non-transparent portion of the surface to compose.
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
mock_char c
static map_location::direction s
#define WRN_DP
Definition: textbox.cpp:35
static lg::log_domain log_display("display")
#define DBG_G
Definition: textbox.cpp:36
ucs4_convert_impl::enableif< TD, typename TS::value_type >::type unicode_cast(const TS &source)
#define h