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