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