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