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