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