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