void menu::draw_contents() { // KP: now draw a nice frame! SDL_Rect frame_rect = inner_location(); gui::dialog_frame f(video(), "", gui::dialog_frame::preview_style, false); f.layout(frame_rect); // f.draw_background(); f.draw_border(); SDL_Rect heading_rect = inner_location(); heading_rect.h = heading_height(); style_->draw_row(*this,0,heading_rect,HEADING_ROW); // KP: make sure to clip SDL_Rect content_rect = inner_location(); content_rect.y += heading_rect.h; content_rect.h -= heading_rect.h; clip_rect_setter clippy(content_rect); for(size_t i = 0; i != item_pos_.size(); ++i) { style_->draw_row(*this,item_pos_[i],get_item_rect(i), (!out_ && item_pos_[i] == selected_) ? SELECTED_ROW : NORMAL_ROW); } }
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 help_text_area::draw_contents() { SDL_Rect const &loc = inner_location(); bg_restore(); surface screen = video().getSurface(); clip_rect_setter clip_rect_set(screen, &loc); for(std::list<item>::const_iterator it = items_.begin(), end = items_.end(); it != end; ++it) { SDL_Rect dst = it->rect; dst.y -= get_position(); if (dst.y < static_cast<int>(loc.h) && dst.y + it->rect.h > 0) { dst.x += loc.x; dst.y += loc.y; if (it->box) { for (int i = 0; i < box_width; ++i) { sdl::draw_rectangle(dst.x, dst.y, it->rect.w - i * 2, it->rect.h - i * 2, 0, screen); ++dst.x; ++dst.y; } } sdl_blit(it->surf, NULL, screen, &dst); } } update_rect(loc); }
int menu::hit_heading(int x, int y) const { const size_t height = heading_height(); const SDL_Rect& loc = inner_location(); if(y >= loc.y && static_cast<size_t>(y) < loc.y + height) { return hit_column(x); } else { return -1; } }
void menu::draw_contents() { SDL_Rect heading_rect = inner_location(); heading_rect.h = heading_height(); style_->draw_row(*this,0,heading_rect,HEADING_ROW); for(size_t i = 0; i != item_pos_.size(); ++i) { style_->draw_row(*this,item_pos_[i],get_item_rect(i), (!out_ && item_pos_[i] == selected_) ? SELECTED_ROW : NORMAL_ROW); } }
int menu::hit(int x, int y) const { SDL_Rect const &loc = inner_location(); if (x >= loc.x && x < loc.x + loc.w && y >= loc.y && y < loc.y + loc.h) { for(size_t i = 0; i != items_.size(); ++i) { const SDL_Rect& rect = get_item_rect(i); if (y >= rect.y && y < rect.y + rect.h) return i; } } return -1; }
void scrollarea::handle_event(const SDL_Event& event) { if (mouse_locked() || hidden() || event.type != SDL_MOUSEBUTTONDOWN) return; SDL_MouseButtonEvent const &e = event.button; if (point_in_rect(e.x, e.y, inner_location())) { if (e.button == SDL_BUTTON_WHEELDOWN) { scrollbar_.scroll_down(); } else if (e.button == SDL_BUTTON_WHEELUP) { scrollbar_.scroll_up(); } } }
SDL_Rect menu::get_item_rect_internal(size_t item) const { //unsigned int first_item_on_screen = get_position(); unsigned int first_item_on_screen = get_position() / item_height_; unsigned int leftovers = get_position() - (first_item_on_screen * item_height_); if (item < first_item_on_screen || size_t(item) >= first_item_on_screen + max_items_onscreen() + 2) { return empty_rect; } const std::map<int,SDL_Rect>::const_iterator i = itemRects_.find(item); if(i != itemRects_.end()) return i->second; SDL_Rect const &loc = inner_location(); int y = loc.y + heading_height(); if (item != first_item_on_screen) { const SDL_Rect& prev = get_item_rect_internal(item-1); y = prev.y + prev.h; } else { // KP: sub-item scrolling y -= leftovers; } SDL_Rect res = { loc.x, y, loc.w, get_item_height(item) }; SDL_Rect const &screen_area = ::screen_area(); if(res.x > screen_area.w) { return empty_rect; } else if(res.x + res.w > screen_area.w) { res.w = screen_area.w - res.x; } if(res.y > screen_area.h) { return empty_rect; } else if(res.y + res.h > screen_area.h) { res.h = screen_area.h - res.y; } //only insert into the cache if the menu's co-ordinates have //been initialized if (loc.x > 0 && loc.y > 0) itemRects_.insert(std::pair<int,SDL_Rect>(item,res)); return res; }
void help_text_area::add_img_item(const std::string& path, const std::string& alignment, const bool floating, const bool box) { surface surf(image::get_image(path)); if (surf.null()) return; ALIGNMENT align = str_to_align(alignment); if (align == HERE && floating) { WRN_DP << "Floating image with align HERE, aligning left." << std::endl; align = LEFT; } const int width = surf->w + (box ? box_width * 2 : 0); int xpos; int ypos = curr_loc_.second; int text_width = inner_location().w; switch (align) { case HERE: xpos = curr_loc_.first; break; case LEFT: default: xpos = 0; break; case MIDDLE: xpos = text_width / 2 - width / 2 - (box ? box_width : 0); break; case RIGHT: xpos = text_width - width - (box ? box_width * 2 : 0); break; } if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_) && (xpos < curr_loc_.first || xpos + width > text_width)) { down_one_line(); add_img_item(path, alignment, floating, box); } else { if (!floating) { curr_loc_.first = xpos; } else { ypos = get_y_for_floating_img(width, xpos, ypos); } add_item(item(surf, xpos, ypos, floating, box, align)); } }
int help_text_area::get_max_x(const int y, const int height) { int text_width = inner_location().w; int max_x = text_width; for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) { const item& itm = *it; if (itm.floating) { if (itm.rect.y < y + height && itm.rect.y + itm.rect.h > y) { if (itm.align == RIGHT) { max_x = std::min<int>(max_x, text_width - itm.rect.w - 5); } else if (itm.align == MIDDLE) { max_x = std::min<int>(max_x, text_width / 2 - itm.rect.w / 2 - 5); } } } } return max_x; }
void menu::draw() { if(hidden()) { return; } if(!dirty()) { for(std::set<int>::const_iterator i = invalid_.begin(); i != invalid_.end(); ++i) { if(*i == -1) { SDL_Rect heading_rect = inner_location(); heading_rect.h = heading_height(); bg_restore(heading_rect); style_->draw_row(*this,0,heading_rect,HEADING_ROW); update_rect(heading_rect); } else if(*i >= 0 && *i < int(item_pos_.size())) { const unsigned int pos = item_pos_[*i]; const SDL_Rect& rect = get_item_rect(*i); bg_restore(rect); style_->draw_row(*this,pos,rect, (!out_ && pos == selected_) ? SELECTED_ROW : NORMAL_ROW); update_rect(rect); } } invalid_.clear(); return; } invalid_.clear(); bg_restore(); util::scoped_ptr<clip_rect_setter> clipper(NULL); if(clip_rect()) clipper.assign(new clip_rect_setter(video().getSurface(), *clip_rect())); draw_contents(); update_rect(location()); set_dirty(false); }
void scrollarea::handle_event(const SDL_Event& event) { gui::widget::handle_event(event); if (mouse_locked() || hidden()) return; if (event.type != SDL_MOUSEWHEEL) return; const SDL_MouseWheelEvent &ev = event.wheel; int x, y; SDL_GetMouseState(&x, &y); if (sdl::point_in_rect(x, y, inner_location())) { if (ev.y > 0) { scrollbar_.scroll_up(); } else if (ev.y < 0) { scrollbar_.scroll_down(); } } }
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); }
surface textbox::add_text_line(const wide_string& text, const SDL_Color& color) { line_height_ = font::get_max_height(font_size); if(char_y_.empty()) { char_y_.push_back(0); } else { char_y_.push_back(char_y_.back() + line_height_); } char_x_.push_back(0); // Re-calculate the position of each glyph. We approximate this by asking the // width of each substring, but this is a flawed assumption which won't work with // some more complex scripts (that is, RTL languages). This part of the work should // actually be done by the font-rendering system. std::string visible_string; wide_string wrapped_text; wide_string::const_iterator backup_itor = text.end(); wide_string::const_iterator itor = text.begin(); while(itor != text.end()) { //If this is a space, save copies of the current state so we can roll back if(char(*itor) == ' ') { backup_itor = itor; } visible_string.append(utils::wchar_to_string(*itor)); if(char(*itor) == '\n') { backup_itor = text.end(); visible_string = ""; } int w = font::line_width(visible_string, font_size); if(wrap_ && w >= inner_location().w) { if(backup_itor != text.end()) { int backup = itor - backup_itor; itor = backup_itor + 1; if(backup > 0) { char_x_.erase(char_x_.end()-backup, char_x_.end()); char_y_.erase(char_y_.end()-backup, char_y_.end()); wrapped_text.erase(wrapped_text.end()-backup, wrapped_text.end()); } } backup_itor = text.end(); wrapped_text.push_back(wchar_t('\n')); char_x_.push_back(0); char_y_.push_back(char_y_.back() + line_height_); visible_string = ""; } else { wrapped_text.push_back(*itor); char_x_.push_back(w); char_y_.push_back(char_y_.back() + (char(*itor) == '\n' ? line_height_ : 0)); ++itor; } } const std::string s = utils::wstring_to_string(wrapped_text); const surface res(font::get_rendered_text(s, font_size, color)); return res; }
void help_text_area::set_items() { last_row_.clear(); items_.clear(); curr_loc_.first = 0; curr_loc_.second = 0; curr_row_height_ = min_row_height_; // Add the title item. const std::string show_title = font::make_text_ellipsis(shown_topic_->title, title_size, inner_location().w); surface surf(font::get_rendered_text(show_title, title_size, font::NORMAL_COLOR, TTF_STYLE_BOLD)); if (surf != NULL) { add_item(item(surf, 0, 0, show_title)); curr_loc_.second = title_spacing_; contents_height_ = title_spacing_; down_one_line(); } // Parse and add the text. std::vector<std::string> const &parsed_items = shown_topic_->text.parsed_text(); std::vector<std::string>::const_iterator it; for (it = parsed_items.begin(); it != parsed_items.end(); ++it) { if (*it != "" && (*it)[0] == '[') { // Should be parsed as WML. try { config cfg; std::istringstream stream(*it); read(cfg, stream); #define TRY(name) do { \ if (config &child = cfg.child(#name)) \ handle_##name##_cfg(child); \ } while (0) TRY(ref); TRY(img); TRY(bold); TRY(italic); TRY(header); TRY(jump); TRY(format); #undef TRY } catch (config::error& e) { std::stringstream msg; msg << "Error when parsing help markup as WML: '" << e.message << "'"; throw parse_error(msg.str()); } } else { add_text_item(*it); } } down_one_line(); // End the last line. int h = height(); set_position(0); set_full_size(contents_height_); set_shown_size(h); }
void menu::draw_row(const size_t row_index, const SDL_Rect& rect, ROW_TYPE type) { //called from style, draws one row's contents in a generic and adaptable way const std::vector<std::string>& row = (type == HEADING_ROW) ? heading_ : items_[row_index].fields; SDL_Rect const &area = screen_area(); SDL_Rect const &loc = inner_location(); const std::vector<int>& widths = column_widths(); bool lang_rtl = current_language_rtl(); int dir = (lang_rtl) ? -1 : 1; SDL_Rect column = loc; int xpos = rect.x; if(lang_rtl) xpos += rect.w; for(size_t i = 0; i != row.size(); ++i) { if(lang_rtl) xpos -= widths[i]; if(type == HEADING_ROW && highlight_heading_ == int(i)) { draw_solid_tinted_rectangle(xpos,rect.y,widths[i],rect.h,255,255,255,0.3,video().getSurface()); } const int last_x = xpos; column.w = widths[i]; std::string str = row[i]; std::vector<std::string> img_text_items = utils::split(str, IMG_TEXT_SEPARATOR, utils::REMOVE_EMPTY); for (std::vector<std::string>::const_iterator it = img_text_items.begin(); it != img_text_items.end(); it++) { str = *it; if (!str.empty() && str[0] == IMAGE_PREFIX) { const std::string image_name(str.begin()+1,str.end()); const surface img = style_->get_item_image(image_name); const int remaining_width = max_width_ < 0 ? area.w : std::min<int>(max_width_, ((lang_rtl)? xpos - rect.x : rect.x + rect.w - xpos)); if(img != NULL && img->w <= remaining_width && rect.y + img->h < area.h) { const size_t y = rect.y + (rect.h - img->h)/2; const size_t w = img->w + 5; const size_t x = xpos + ((lang_rtl) ? widths[i] - w : 0); video().blit_surface(x,y,img); if(!lang_rtl) xpos += w; column.w -= w; } } else { column.x = xpos; const bool has_wrap = (str.find_first_of("\r\n") != std::string::npos); //prevent ellipsis calculation if there is any line wrapping const std::string to_show = (use_ellipsis_ && !has_wrap) ? font::make_text_ellipsis(str, style_->get_font_size(), loc.w - (xpos - rect.x) - 2*style_->get_thickness(), false, true) : str; const SDL_Rect& text_size = font::text_area(str,style_->get_font_size()); const size_t y = rect.y + (rect.h - text_size.h)/2; font::draw_text(&video(),column,style_->get_font_size(),font::NORMAL_COLOUR,to_show,xpos,y); if(type == HEADING_ROW && sortby_ == int(i)) { const surface sort_img = image::get_image(sortreversed_ ? "misc/sort-arrow.png" : "misc/sort-arrow-reverse.png"); if(sort_img != NULL && sort_img->w <= widths[i] && sort_img->h <= rect.h) { const size_t sort_x = xpos + widths[i] - sort_img->w; const size_t sort_y = rect.y + rect.h/2 - sort_img->h/2; video().blit_surface(sort_x,sort_y,sort_img); } } xpos += dir * (text_size.w + 5); } } if(lang_rtl) xpos = last_x; else xpos = last_x + widths[i]; } }
void scrollarea::handle_event(const SDL_Event& event) { gui::widget::handle_event(event); if (mouse_locked() || hidden()) return; if (event.type == SDL_MOUSEWHEEL) { const SDL_MouseWheelEvent &ev = event.wheel; int x, y; SDL_GetMouseState(&x, &y); if (sdl::point_in_rect(x, y, inner_location())) { if (ev.y > 0) { scrollbar_.scroll_up(); } else if (ev.y < 0) { scrollbar_.scroll_down(); } } } if (event.type == SDL_FINGERUP) { swipe_dy_ = 0; } if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) { SDL_Rect r = video().screen_area(); auto tx = static_cast<int>(event.tfinger.x * r.w); auto ty = static_cast<int>(event.tfinger.y * r.h); auto dy = static_cast<int>(event.tfinger.dy * r.h); if (event.type == SDL_FINGERDOWN) { swipe_dy_ = 0; swipe_origin_.x = tx; swipe_origin_.y = ty; } if (event.type == SDL_FINGERMOTION) { swipe_dy_ += dy; if (scrollbar_.get_max_position() == 0) { return; } int scrollbar_step = scrollbar_.height() / scrollbar_.get_max_position(); if (scrollbar_step <= 0) { return; } if (sdl::point_in_rect(swipe_origin_.x, swipe_origin_.y, inner_location()) && abs(swipe_dy_) >= scrollbar_step) { unsigned int pos = std::max( static_cast<int>(scrollbar_.get_position() - swipe_dy_ / scrollbar_step), 0); scrollbar_.set_position(pos); swipe_dy_ %= scrollbar_step; } } } }
bool scrollarea::handle_drag_event(const SDL_Event& event) { // KP: added content dragging for iPhone static bool isDragging = false; static int startDrag = 0; static int startPos = 0; static bool didDrag = false; SDL_MouseButtonEvent const &e = event.button; if (point_in_rect(e.x, e.y, inner_location())) { switch(event.type) { case SDL_MOUSEBUTTONUP: { isDragging = false; break; } case SDL_MOUSEBUTTONDOWN: { isDragging = true; startDrag = e.y; startPos = get_position(); didDrag = false; break; } case SDL_MOUSEMOTION: { if (isDragging) { int changeY = startDrag - e.y; //SDL_Rect inner_loc = inner_location(); //float pixelsPerScroll = item_height_ / ((float) (item_height_ * nitems()) / inner_loc.h); //int move = changeY / pixelsPerScroll; int move = changeY; if (move != 0) { int newPos = startPos + move; if (newPos < 0) newPos = 0; if (newPos > get_max_position()) newPos = get_max_position(); set_position(newPos); didDrag = true; // fixes dragging off of control startDrag = e.y; startPos = newPos; } } break; } default: break; } } else if (event.type == SDL_MOUSEBUTTONUP) { isDragging = false; } // do not select after dragging if (didDrag == true && isDragging == false) { didDrag = false; return true; } return false; // END iPhone content dragging }
int multimenu::hit_checkbox(int x, int y) const { int cb_width = image::get_image("buttons/checkbox-pressed.png")->w; return x > inner_location().x + cb_width ? -1 : hit(x, y); }
void menu::draw_row(const size_t row_index, const SDL_Rect& rect, ROW_TYPE type) { //called from style, draws one row's contents in a generic and adaptable way const std::vector<std::string>& row = (type == HEADING_ROW) ? heading_ : items_[row_index].fields; SDL_Rect const &area = screen_area(); SDL_Rect const &loc = inner_location(); const std::vector<int>& widths = column_widths(); bool lang_rtl = current_language_rtl(); int dir = (lang_rtl) ? -1 : 1; SDL_Rect column = loc; int xpos = rect.x; if(lang_rtl) xpos += rect.w; for(size_t i = 0; i != row.size(); ++i) { if(lang_rtl) xpos -= widths[i]; if(type == HEADING_ROW) { #ifdef SDL_GPU const SDL_Rect pos = sdl::create_rect(xpos, rect.y, widths[i], rect.h); if(highlight_heading_ == int(i)) { sdl::fill_rect(video(), pos, 255, 255, 255, 75); } else if(sortby_ == int(i)) { sdl::fill_rect(video(), pos, 255, 255, 255, 25); } } const int last_x = xpos; column.w = widths[i]; std::string str = row[i]; std::vector<std::string> img_text_items = utils::split(str, IMG_TEXT_SEPARATOR, utils::REMOVE_EMPTY); for (std::vector<std::string>::const_iterator it = img_text_items.begin(); it != img_text_items.end(); ++it) { str = *it; if (!str.empty() && str[0] == IMAGE_PREFIX) { const std::string image_name(str.begin()+1,str.end()); sdl::timage img = style_->get_item_image(image_name); const int remaining_width = max_width_ < 0 ? area.w : std::min<int>(max_width_, ((lang_rtl)? xpos - rect.x : rect.x + rect.w - xpos)); if(!img.null() && img.width() <= remaining_width && rect.y + img.height() < area.h) { const size_t y = rect.y + (rect.h - img.height())/2; const size_t w = img.width() + 5; const size_t x = xpos + ((lang_rtl) ? widths[i] - w : 0); video().draw_texture(img, x, y); if(!lang_rtl) xpos += w; column.w -= w; } } else { column.x = xpos; const bool has_wrap = (str.find_first_of("\r\n") != std::string::npos); //prevent ellipsis calculation if there is any line wrapping std::string to_show = str; if (use_ellipsis_ && !has_wrap) { int fs = style_->get_font_size(); int style = TTF_STYLE_NORMAL; int w = loc.w - (xpos - rect.x) - 2 * style_->get_thickness(); std::string::const_iterator i_beg = to_show.begin(), i_end = to_show.end(), i = font::parse_markup(i_beg, i_end, &fs, nullptr, &style); if (i != i_end) { std::string tmp(i, i_end); to_show.erase(i - i_beg, i_end - i_beg); to_show += font::make_text_ellipsis(tmp, fs, w, style); } } const SDL_Rect& text_size = font::text_area(str,style_->get_font_size()); const size_t y = rect.y + (rect.h - text_size.h)/2; const size_t padding = 2; sdl::timage text_img = font::draw_text_to_texture(column,style_->get_font_size(),font::NORMAL_COLOR,to_show); video().draw_texture(text_img, (type == HEADING_ROW ? xpos+padding : xpos), y); if(type == HEADING_ROW && sortby_ == int(i)) { sdl::timage sort_img = image::get_texture("buttons/sliders/slider_arrow_blue.png"); sort_img.set_rotation(sortreversed_ ? 0 : 180); if(!sort_img.null() && sort_img.width() <= widths[i] && sort_img.height() <= rect.h) { const size_t sort_x = xpos + widths[i] - sort_img.width() - padding; const size_t sort_y = rect.y + rect.h/2 - sort_img.height()/2; video().draw_texture(sort_img, sort_x, sort_y); } } xpos += dir * (text_size.w + 5); } } if(lang_rtl) xpos = last_x; else xpos = last_x + widths[i]; } #else if(highlight_heading_ == int(i)) { sdl::draw_solid_tinted_rectangle(xpos,rect.y,widths[i],rect.h,255,255,255,0.3,video().getSurface()); } else if(sortby_ == int(i)) { sdl::draw_solid_tinted_rectangle(xpos,rect.y,widths[i],rect.h,255,255,255,0.1,video().getSurface()); } }
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); }