void textbox::draw_contents() { SDL_Rect const &loc = inner_location(); surface surf = video().getSurface(); draw_solid_tinted_rectangle(loc.x,loc.y,loc.w,loc.h,0,0,0, focus(NULL) ? alpha_focus_ : alpha_, surf); SDL_Rect src; if(text_image_ == NULL) { update_text_cache(true); } if(text_image_ != NULL) { src.y = yscroll_; src.w = std::min<size_t>(loc.w,text_image_->w); src.h = std::min<size_t>(loc.h,text_image_->h); src.x = text_pos_; SDL_Rect dest = screen_area(); dest.x = loc.x; dest.y = loc.y; // Fills the selected area if(is_selection()) { const int start = std::min<int>(selstart_,selend_); const int end = std::max<int>(selstart_,selend_); int startx = char_x_[start]; int starty = char_y_[start]; const int endx = char_x_[end]; const int endy = char_y_[end]; while(starty <= endy) { const size_t right = starty == endy ? endx : text_image_->w; if(right <= size_t(startx)) { break; } SDL_Rect rect = create_rect(loc.x + startx , loc.y + starty - src.y , right - startx , line_height_); const clip_rect_setter clipper(surf, &loc); Uint32 color = SDL_MapRGB(surf->format, 0, 0, 160); fill_rect_alpha(rect, color, 140, surf); starty += int(line_height_); startx = 0; } } sdl_blit(text_image_, &src, surf, &dest); } draw_cursor((cursor_pos_ == 0 ? 0 : cursor_pos_ - 1), video()); update_rect(loc); }
void textbox::append_text(const std::string& text, bool auto_scroll, const SDL_Color& color) { if(text_image_.get() == NULL) { set_text(text, color); return; } //disallow adding multi-line text to a single-line text box if(wrap_ == false && std::find_if(text.begin(),text.end(),utils::isnewline) != text.end()) { return; } const bool is_at_bottom = get_position() == get_max_position(); const wide_string& wtext = utils::string_to_wstring(text); const surface new_text = add_text_line(wtext, color); const surface new_surface = create_compatible_surface(text_image_,std::max<size_t>(text_image_->w,new_text->w),text_image_->h+new_text->h); SDL_SetAlpha(new_text.get(),0,0); SDL_SetAlpha(text_image_.get(),0,0); SDL_BlitSurface(text_image_,NULL,new_surface,NULL); SDL_Rect target = {0,text_image_->h,new_text->w,new_text->h}; SDL_BlitSurface(new_text,NULL,new_surface,&target); text_image_.assign(new_surface); text_.resize(text_.size() + wtext.size()); std::copy(wtext.begin(),wtext.end(),text_.end()-wtext.size()); set_dirty(true); update_text_cache(false); if(auto_scroll && is_at_bottom) scroll_to_bottom(); handle_text_changed(text_); }
void textbox::set_inner_location(SDL_Rect const &rect) { bg_register(rect); if (text_image_.null()) return; text_pos_ = 0; update_text_cache(false); }
void textbox::set_wrap(bool val) { if(wrap_ != val) { wrap_ = val; update_text_cache(true); set_dirty(true); } }
// set_text does not respect max_size_ void textbox::set_text(const std::string& text, const SDL_Color& color) { text_ = utils::string_to_wstring(text); cursor_ = text_.size(); text_pos_ = 0; selstart_ = -1; selend_ = -1; set_dirty(true); update_text_cache(true, color); handle_text_changed(text_); }
void textbox::clear() { text_.clear(); cursor_ = 0; cursor_pos_ = 0; text_pos_ = 0; selstart_ = -1; selend_ = -1; set_dirty(true); update_text_cache(true); handle_text_changed(text_); }
textbox::textbox(CVideo &video, int width, const std::string& text, bool editable, size_t max_size, double alpha, double alpha_focus, const bool auto_join) : scrollarea(video, auto_join), max_size_(max_size), text_(utils::string_to_wstring(text)), cursor_(text_.size()), selstart_(-1), selend_(-1), grabmouse_(false), text_pos_(0), editable_(editable), show_cursor_(true), show_cursor_at_(0), text_image_(NULL), wrap_(false), line_height_(0), yscroll_(0), alpha_(alpha), alpha_focus_(alpha_focus) { // static const SDL_Rect area = d.screen_area(); // const int height = font::draw_text(NULL,area,font_size,font::NORMAL_COLOUR,"ABCD",0,0).h; set_measurements(width, font::get_max_height(font_size)); set_scroll_rate(font::get_max_height(font_size) / 2); update_text_cache(true); }
void textbox::set_cursor_pos(const int cursor_pos) { if (!editable_) { return; } if (cursor_pos < 0 || size_t(cursor_pos) > text_.size()) { WRN_DP << "out-of-boundary selection\n"; return; } cursor_ = cursor_pos; update_text_cache(false); set_dirty(true); }
void textbox::handle_event(const SDL_Event& event) { scrollarea::handle_event(event); if(hidden()) return; bool changed = false; const int old_selstart = selstart_; const int old_selend = selend_; //Sanity check: verify that selection start and end are within text //boundaries if(is_selection() && !(size_t(selstart_) <= text_.size() && size_t(selend_) <= text_.size())) { WRN_DP << "out-of-boundary selection\n"; selstart_ = selend_ = -1; } int mousex, mousey; const Uint8 mousebuttons = SDL_GetMouseState(&mousex,&mousey); if(!(mousebuttons & SDL_BUTTON(1))) { grabmouse_ = false; } SDL_Rect const &loc = inner_location(); bool clicked_inside = !mouse_locked() && (event.type == SDL_MOUSEBUTTONDOWN && (mousebuttons & SDL_BUTTON(1)) && point_in_rect(mousex, mousey, loc)); if(clicked_inside) { set_focus(true); } if ((grabmouse_ && (!mouse_locked() && event.type == SDL_MOUSEMOTION)) || clicked_inside) { const int x = mousex - loc.x + text_pos_; const int y = mousey - loc.y; int pos = 0; int distance = x; for(unsigned int i = 1; i < char_x_.size(); ++i) { if(static_cast<int>(yscroll_) + y < char_y_[i]) { break; } // Check individually each distance (if, one day, we support // RTL languages, char_x_[c] may not be monotonous.) if(abs(x - char_x_[i]) < distance && yscroll_ + y < char_y_[i] + line_height_) { pos = i; distance = abs(x - char_x_[i]); } } cursor_ = pos; if(grabmouse_) selend_ = cursor_; update_text_cache(false); if(!grabmouse_ && mousebuttons & SDL_BUTTON(1)) { grabmouse_ = true; selstart_ = selend_ = cursor_; } else if (! (mousebuttons & SDL_BUTTON(1))) { grabmouse_ = false; } set_dirty(); } if(editable_ == false) { return; } //if we don't have the focus, then see if we gain the focus, //otherwise return if(focus(&event) == false) { if (!mouse_locked() && event.type == SDL_MOUSEMOTION && point_in_rect(mousex, mousey, loc)) events::focus_handler(this); return; } if(event.type != SDL_KEYDOWN || focus(&event) != true) { draw(); return; } const SDL_keysym& key = reinterpret_cast<const SDL_KeyboardEvent&>(event).keysym; const SDLMod modifiers = SDL_GetModState(); const int c = key.sym; const int old_cursor = cursor_; if(c == SDLK_LEFT && cursor_ > 0) --cursor_; if(c == SDLK_RIGHT && cursor_ < static_cast<int>(text_.size())) ++cursor_; // ctrl-a, ctrl-e and ctrl-u are readline style shortcuts, even on Macs if(c == SDLK_END || (c == SDLK_e && (modifiers & KMOD_CTRL))) cursor_ = text_.size(); if(c == SDLK_HOME || (c == SDLK_a && (modifiers & KMOD_CTRL))) cursor_ = 0; if((old_cursor != cursor_) && (modifiers & KMOD_SHIFT)) { if(selstart_ == -1) selstart_ = old_cursor; selend_ = cursor_; } if(c == SDLK_BACKSPACE) { changed = true; if(is_selection()) { erase_selection(); } else if(cursor_ > 0) { --cursor_; text_.erase(text_.begin()+cursor_); } } if(c == SDLK_u && (modifiers & KMOD_CTRL)) { // clear line changed = true; cursor_ = 0; text_.resize(0); } if(c == SDLK_DELETE && !text_.empty()) { changed = true; if(is_selection()) { erase_selection(); } else { if(cursor_ < static_cast<int>(text_.size())) { text_.erase(text_.begin()+cursor_); } } } wchar_t character = key.unicode; //movement characters may have a "Unicode" field on some platforms, so ignore it. if(!(c == SDLK_UP || c == SDLK_DOWN || c == SDLK_LEFT || c == SDLK_RIGHT || c == SDLK_DELETE || c == SDLK_BACKSPACE || c == SDLK_END || c == SDLK_HOME || c == SDLK_PAGEUP || c == SDLK_PAGEDOWN)) { if(character != 0) { DBG_G << "Char: " << character << ", c = " << c << "\n"; } if(event.key.keysym.mod & copypaste_modifier) { switch(c) { case SDLK_v: // paste { changed = true; if(is_selection()) erase_selection(); std::string str = copy_from_clipboard(false); //cut off anything after the first newline str.erase(std::find_if(str.begin(),str.end(),utils::isnewline),str.end()); wide_string s = utils::string_to_wstring(str); if(text_.size() < max_size_) { if(s.size() + text_.size() > max_size_) { s.resize(max_size_ - text_.size()); } text_.insert(text_.begin()+cursor_, s.begin(), s.end()); cursor_ += s.size(); } } break; case SDLK_c: // copy { const size_t beg = std::min<size_t>(size_t(selstart_),size_t(selend_)); const size_t end = std::max<size_t>(size_t(selstart_),size_t(selend_)); wide_string ws = wide_string(text_.begin() + beg, text_.begin() + end); std::string s = utils::wstring_to_string(ws); copy_to_clipboard(s, false); } break; } } else { if(character >= 32 && character != 127) { changed = true; if(is_selection()) erase_selection(); if(text_.size() + 1 <= max_size_) { text_.insert(text_.begin()+cursor_,character); ++cursor_; } } } } if(is_selection() && (selend_ != cursor_)) selstart_ = selend_ = -1; //since there has been cursor activity, make the cursor appear for //at least the next 500ms. show_cursor_ = true; show_cursor_at_ = SDL_GetTicks(); if(changed || old_cursor != cursor_ || old_selstart != selstart_ || old_selend != selend_) { text_image_ = NULL; handle_text_changed(text_); } set_dirty(true); }
void Label::update(Compositor* compositor, float delta_seconds) { ScrollablePanel::update(compositor, delta_seconds); update_text_cache(); }
void Label::append_text(const char* message) { text.append(message); cache_is_dirty = 1; update_text_cache(); }
void textbox::update_location(SDL_Rect const &rect) { scrollarea::update_location(rect); update_text_cache(true); set_dirty(true); }
void textbox::draw_contents() { SDL_Rect const &loc = inner_location(); surface surf = video().getSurface(); draw_solid_tinted_rectangle(loc.x,loc.y,loc.w,loc.h,0,0,0, focus(NULL) ? alpha_focus_ : alpha_, surf); SDL_Rect src; if(text_image_ == NULL) { update_text_cache(true); } if(text_image_ != NULL) { src.y = yscroll_; src.w = std::min<size_t>(loc.w,text_image_->w); src.h = std::min<size_t>(loc.h,text_image_->h); src.x = text_pos_; SDL_Rect dest = screen_area(); dest.x = loc.x; dest.y = loc.y; // Fills the selected area if(enabled() && is_selection()) { const int start = std::min<int>(selstart_,selend_); const int end = std::max<int>(selstart_,selend_); int startx = char_x_[start]; int starty = char_y_[start]; const int endx = char_x_[end]; const int endy = char_y_[end]; while(starty <= endy) { const size_t right = starty == endy ? endx : text_image_->w; if(right <= size_t(startx)) { break; } SDL_Rect rect = create_rect(loc.x + startx , loc.y + starty - src.y , right - startx , line_height_); const clip_rect_setter clipper(surf, &loc); Uint32 color = SDL_MapRGB(surf->format, 0, 0, 160); fill_rect_alpha(rect, color, 140, surf); starty += int(line_height_); startx = 0; } } if(enabled()) { sdl_blit(text_image_, &src, surf, &dest); } else { // HACK: using 30% opacity allows white text to look as though it is grayed out, // while not changing any applicable non-grayscale AA. Actual colored text will // not look as good, but this is not currently a concern since GUI1 textboxes // are not used much nowadays, and they will eventually all go away. sdl_blit(adjust_surface_alpha(text_image_, ftofxp(0.3)), &src, surf, &dest); } } draw_cursor((cursor_pos_ == 0 ? 0 : cursor_pos_ - 1), video()); update_rect(loc); }