void TextureProgress::_notification(int p_what) { const float corners[12] = { -0.125, -0.375, -0.625, -0.875, 0.125, 0.375, 0.625, 0.875, 1.125, 1.375, 1.625, 1.875 }; switch (p_what) { case NOTIFICATION_DRAW: { if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP)) { if (under.is_valid()) { draw_nine_patch_stretched(under, FILL_LEFT_TO_RIGHT, 1.0, tint_under); } if (progress.is_valid()) { draw_nine_patch_stretched(progress, mode, get_as_ratio(), tint_progress); } if (over.is_valid()) { draw_nine_patch_stretched(over, FILL_LEFT_TO_RIGHT, 1.0, tint_over); } } else { if (under.is_valid()) draw_texture(under, Point2(), tint_under); if (progress.is_valid()) { Size2 s = progress->get_size(); switch (mode) { case FILL_LEFT_TO_RIGHT: { Rect2 region = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_RIGHT_TO_LEFT: { Rect2 region = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_TOP_TO_BOTTOM: { Rect2 region = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio())); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_BOTTOM_TO_TOP: { Rect2 region = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { Rect2 region = Rect2(Point2(), s); draw_texture_rect_region(progress, region, region, tint_progress); } else if (val != 0) { Array pts; float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1; float start; if (mode == FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE) { start = rad_init_angle / 360 - val / 2; } else { start = rad_init_angle / 360; } float end = start + direction * val; pts.append(start); pts.append(end); float from = MIN(start, end); float to = MAX(start, end); for (int i = 0; i < 12; i++) if (corners[i] > from && corners[i] < to) pts.append(corners[i]); pts.sort(); Vector<Point2> uvs; Vector<Point2> points; uvs.push_back(get_relative_center()); points.push_back(Point2(s.x * get_relative_center().x, s.y * get_relative_center().y)); for (int i = 0; i < pts.size(); i++) { Point2 uv = unit_val_to_uv(pts[i]); if (uvs.find(uv) >= 0) continue; uvs.push_back(uv); points.push_back(Point2(uv.x * s.x, uv.y * s.y)); } Vector<Color> colors; colors.push_back(tint_progress); draw_polygon(points, colors, uvs, progress); } if (Engine::get_singleton()->is_editor_hint()) { Point2 p = progress->get_size(); p.x *= get_relative_center().x; p.y *= get_relative_center().y; p = p.floor(); draw_line(p - Point2(8, 0), p + Point2(8, 0), Color(0.9, 0.5, 0.5), 2); draw_line(p - Point2(0, 8), p + Point2(0, 8), Color(0.9, 0.5, 0.5), 2); } } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); draw_texture_rect_region(progress, region, region, tint_progress); } break; default: draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); } } if (over.is_valid()) draw_texture(over, Point2(), tint_over); } } break; } }
void ItemList::_notification(int p_what) { if (p_what==NOTIFICATION_RESIZED) { shape_changed=true; update(); } if (p_what==NOTIFICATION_DRAW) { VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true); Ref<StyleBox> bg = get_stylebox("bg"); int mw = scroll_bar->get_minimum_size().x; scroll_bar->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,mw+bg->get_margin(MARGIN_RIGHT)); scroll_bar->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,bg->get_margin(MARGIN_RIGHT)); scroll_bar->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,bg->get_margin(MARGIN_TOP)); scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,bg->get_margin(MARGIN_BOTTOM)); Size2 size = get_size(); float page = size.height-bg->get_minimum_size().height; int width = size.width - mw - bg->get_minimum_size().width; scroll_bar->set_page(page); draw_style_box(bg,Rect2(Point2(),size)); int hseparation = get_constant("hseparation"); int vseparation = get_constant("vseparation"); int icon_margin = get_constant("icon_margin"); int line_separation = get_constant("line_separation"); Ref<StyleBox> sbsel = has_focus()?get_stylebox("selected_focus"):get_stylebox("selected"); Ref<StyleBox> cursor = has_focus()?get_stylebox("cursor"):get_stylebox("cursor_unfocused"); Ref<Font> font = get_font("font"); Color guide_color = get_color("guide_color"); Color font_color = get_color("font_color"); Color font_color_selected = get_color("font_color_selected"); int font_height = font->get_height(); Vector<int> line_size_cache; Vector<int> line_limit_cache; if (max_text_lines) { line_size_cache.resize(max_text_lines); line_limit_cache.resize(max_text_lines); } if (has_focus()) { VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(),true); draw_style_box(get_stylebox("bg_focus"),Rect2(Point2(),size)); VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(),false); } if (shape_changed) { //1- compute item minimum sizes for(int i=0;i<items.size();i++) { Size2 minsize; if (items[i].icon.is_valid()) { minsize=items[i].get_icon_size(); if (min_icon_size.x!=0) minsize.x = MAX(minsize.x,min_icon_size.x); if (min_icon_size.y!=0) minsize.y = MAX(minsize.y,min_icon_size.y); if (items[i].text!="") { if (icon_mode==ICON_MODE_TOP) { minsize.y+=icon_margin; } else { minsize.x+=icon_margin; } } } if (items[i].text!="") { Size2 s = font->get_string_size(items[i].text); //s.width=MIN(s.width,fixed_column_width); if (icon_mode==ICON_MODE_TOP) { minsize.x=MAX(minsize.x,s.width); if (max_text_lines>0) { minsize.y+=(font_height+line_separation)*max_text_lines; } else { minsize.y+=s.height; } } else { minsize.y=MAX(minsize.y,s.height); minsize.x+=s.width; } } items[i].rect_cache.size=minsize; if (fixed_column_width>0) items[i].rect_cache.size.x=fixed_column_width; } int fit_size = size.x - bg->get_minimum_size().width - mw; //2-attempt best fit current_columns = 0x7FFFFFFF; if (max_columns>0) current_columns=max_columns; while(true) { //repeat util all fits //print_line("try with "+itos(current_columns)); bool all_fit=true; Vector2 ofs; int col=0; int max_h=0; separators.clear();; for(int i=0;i<items.size();i++) { if (current_columns>1 && items[i].rect_cache.size.width+ofs.x > fit_size) { //went past current_columns=MAX(col,1); all_fit=false; break; } items[i].rect_cache.pos=ofs; max_h=MAX(max_h,items[i].rect_cache.size.y); ofs.x+=items[i].rect_cache.size.x; //print_line("item "+itos(i)+" ofs "+rtos(items[i].rect_cache.size.x)); if (col>0) ofs.x+=hseparation; col++; if (col==current_columns) { if (i<items.size()-1) separators.push_back(ofs.y+max_h+vseparation/2); ofs.x=0; ofs.y+=max_h+vseparation; col=0; max_h=0; } } if (all_fit) { float max = MAX(page,ofs.y+max_h); scroll_bar->set_max(max); //print_line("max: "+rtos(max)+" page "+rtos(page)); if (max<=page) { scroll_bar->set_val(0); scroll_bar->hide(); } else { scroll_bar->show(); } break; } } shape_changed=false; } Vector2 base_ofs = bg->get_offset(); base_ofs.y-=int(scroll_bar->get_val()); Rect2 clip(Point2(),size-bg->get_minimum_size()+Vector2(0,scroll_bar->get_val())); for(int i=0;i<items.size();i++) { Rect2 rcache = items[i].rect_cache; if (!clip.intersects(rcache)) continue; if (current_columns==1) { rcache.size.width = width-rcache.pos.x; } Rect2 r=rcache; r.pos+=base_ofs; // Use stylebox to dimension potential bg color, even if not selected r.pos.x-=sbsel->get_margin(MARGIN_LEFT); r.size.x+=sbsel->get_margin(MARGIN_LEFT)+sbsel->get_margin(MARGIN_RIGHT); r.pos.y-=sbsel->get_margin(MARGIN_TOP); r.size.y+=sbsel->get_margin(MARGIN_TOP)+sbsel->get_margin(MARGIN_BOTTOM); if (items[i].selected) { draw_style_box(sbsel,r); } if (items[i].custom_bg.a>0.001) { r.pos.x+=2; r.size.x-=4; r.pos.y+=2; r.size.y-=4; draw_rect(r,items[i].custom_bg); } Vector2 text_ofs; if (items[i].icon.is_valid()) { Size2 icon_size = items[i].get_icon_size(); Vector2 icon_ofs; if (min_icon_size!=Vector2()) { icon_ofs = (min_icon_size - icon_size)/2; } Point2 pos = items[i].rect_cache.pos + icon_ofs + base_ofs; if (icon_mode==ICON_MODE_TOP) { pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width)/2); text_ofs.y = MAX(icon_size.height, min_icon_size.y) + icon_margin; } else { pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height)/2); text_ofs.x = MAX(icon_size.width, min_icon_size.x) + icon_margin; } if (items[i].icon_region.has_no_area()) draw_texture(items[i].icon, pos); else draw_texture_rect_region(items[i].icon, Rect2(pos, icon_size), items[i].icon_region); } if (items[i].tag_icon.is_valid()) { draw_texture(items[i].tag_icon,items[i].rect_cache.pos+base_ofs); } if (items[i].text!="") { int max_len=-1; Vector2 size = font->get_string_size(items[i].text); if (fixed_column_width) max_len=fixed_column_width; else max_len=size.x; if (icon_mode==ICON_MODE_TOP && max_text_lines>0) { int ss = items[i].text.length(); float ofs=0; int line=0; for(int j=0;j<=ss;j++) { int cs = j<ss?font->get_char_size(items[i].text[j],items[i].text[j+1]).x:0; if (ofs+cs>max_len || j==ss) { line_limit_cache[line]=j; line_size_cache[line]=ofs; line++; ofs=0; if (line>=max_text_lines) break; } else { ofs+=cs; } } line=0; ofs=0; text_ofs.y+=font->get_ascent(); text_ofs=text_ofs.floor(); text_ofs+=base_ofs; text_ofs+=items[i].rect_cache.pos; for(int j=0;j<ss;j++) { if (j==line_limit_cache[line]) { line++; ofs=0; if (line>=max_text_lines) break; } ofs+=font->draw_char(get_canvas_item(),text_ofs+Vector2(ofs+(max_len-line_size_cache[line])/2,line*(font_height+line_separation)).floor(),items[i].text[j],items[i].text[j+1],items[i].selected?font_color_selected:font_color); } //special multiline mode } else { if (fixed_column_width>0) size.x=MIN(size.x,fixed_column_width); if (icon_mode==ICON_MODE_TOP) { text_ofs.x+=(items[i].rect_cache.size.width-size.x)/2; } else { text_ofs.y+=(items[i].rect_cache.size.height-size.y)/2; } text_ofs.y+=font->get_ascent(); text_ofs=text_ofs.floor(); text_ofs+=base_ofs; text_ofs+=items[i].rect_cache.pos; draw_string(font,text_ofs,items[i].text,items[i].selected?font_color_selected:font_color,max_len+1); } } if (select_mode==SELECT_MULTI && i==current) { Rect2 r=rcache; r.pos+=base_ofs; draw_style_box(cursor,r); } } for(int i=0;i<separators.size();i++) { draw_line(Vector2(bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),Vector2(size.width-bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),guide_color); } if (ensure_selected_visible && current>=0 && current <=items.size()) { Rect2 r = items[current].rect_cache; int from = scroll_bar->get_val(); int to = from + scroll_bar->get_page(); if (r.pos.y < from) { scroll_bar->set_val(r.pos.y); } else if (r.pos.y+r.size.y > to) { scroll_bar->set_val(r.pos.y+r.size.y - (to-from)); } } ensure_selected_visible=false; } }
void TextureButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { DrawMode draw_mode = get_draw_mode(); Ref<Texture> texdraw; switch (draw_mode) { case DRAW_NORMAL: { if (normal.is_valid()) texdraw = normal; } break; case DRAW_PRESSED: { if (pressed.is_null()) { if (hover.is_null()) { if (normal.is_valid()) texdraw = normal; } else texdraw = hover; } else texdraw = pressed; } break; case DRAW_HOVER: { if (hover.is_null()) { if (pressed.is_valid() && is_pressed()) texdraw = pressed; else if (normal.is_valid()) texdraw = normal; } else texdraw = hover; } break; case DRAW_DISABLED: { if (disabled.is_null()) { if (normal.is_valid()) texdraw = normal; } else texdraw = disabled; } break; } if (texdraw.is_valid()) { Point2 ofs; Size2 size = texdraw->get_size(); Rect2 tex_regin = Rect2(Point2(), texdraw->get_size()); bool tile = false; if (expand) { switch (stretch_mode) { case STRETCH_KEEP: size = texdraw->get_size(); break; case STRETCH_SCALE: size = get_size(); break; case STRETCH_TILE: size = get_size(); tile = true; break; case STRETCH_KEEP_CENTERED: ofs = (get_size() - texdraw->get_size()) / 2; size = texdraw->get_size(); break; case STRETCH_KEEP_ASPECT_CENTERED: case STRETCH_KEEP_ASPECT: { Size2 _size = get_size(); float tex_width = texdraw->get_width() * _size.height / texdraw->get_height(); float tex_height = _size.height; if (tex_width > _size.width) { tex_width = _size.width; tex_height = texdraw->get_height() * tex_width / texdraw->get_width(); } if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { ofs.x = (_size.width - tex_width) / 2; ofs.y = (_size.height - tex_height) / 2; } size.width = tex_width; size.height = tex_height; } break; case STRETCH_KEEP_ASPECT_COVERED: { size = get_size(); Size2 tex_size = texdraw->get_size(); Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height); float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height; Size2 scaledTexSize = tex_size * scale; Point2 ofs = ((scaledTexSize - size) / scale).abs() / 2.0f; tex_regin = Rect2(ofs, size / scale); } break; } } if (tile) draw_texture_rect(texdraw, Rect2(ofs, size), tile); else draw_texture_rect_region(texdraw, Rect2(ofs, size), tex_regin); } if (has_focus() && focused.is_valid()) { Rect2 drect(Point2(), get_size()); draw_texture_rect(focused, drect, false); }; } break; } }
void ItemList::_notification(int p_what) { if (p_what == NOTIFICATION_RESIZED) { shape_changed = true; update(); } if (p_what == NOTIFICATION_DRAW) { Ref<StyleBox> bg = get_stylebox("bg"); int mw = scroll_bar->get_minimum_size().x; scroll_bar->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -mw); scroll_bar->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); scroll_bar->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, bg->get_margin(MARGIN_TOP)); scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -bg->get_margin(MARGIN_BOTTOM)); Size2 size = get_size(); int width = size.width - bg->get_minimum_size().width; if (scroll_bar->is_visible()) { width -= mw + bg->get_margin(MARGIN_RIGHT); } draw_style_box(bg, Rect2(Point2(), size)); int hseparation = get_constant("hseparation"); int vseparation = get_constant("vseparation"); int icon_margin = get_constant("icon_margin"); int line_separation = get_constant("line_separation"); Ref<StyleBox> sbsel = has_focus() ? get_stylebox("selected_focus") : get_stylebox("selected"); Ref<StyleBox> cursor = has_focus() ? get_stylebox("cursor") : get_stylebox("cursor_unfocused"); Ref<Font> font = get_font("font"); Color guide_color = get_color("guide_color"); Color font_color = get_color("font_color"); Color font_color_selected = get_color("font_color_selected"); int font_height = font->get_height(); Vector<int> line_size_cache; Vector<int> line_limit_cache; if (max_text_lines) { line_size_cache.resize(max_text_lines); line_limit_cache.resize(max_text_lines); } if (has_focus()) { draw_style_box(get_stylebox("bg_focus"), Rect2(Point2(), size)); } if (shape_changed) { float max_column_width = 0; //1- compute item minimum sizes for (int i = 0; i < items.size(); i++) { Size2 minsize; if (items[i].icon.is_valid()) { if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { minsize = fixed_icon_size * icon_scale; } else { minsize = items[i].get_icon_size() * icon_scale; } if (items[i].text != "") { if (icon_mode == ICON_MODE_TOP) { minsize.y += icon_margin; } else { minsize.x += icon_margin; } } } if (items[i].text != "") { Size2 s = font->get_string_size(items[i].text); //s.width=MIN(s.width,fixed_column_width); if (icon_mode == ICON_MODE_TOP) { minsize.x = MAX(minsize.x, s.width); if (max_text_lines > 0) { minsize.y += (font_height + line_separation) * max_text_lines; } else { minsize.y += s.height; } } else { minsize.y = MAX(minsize.y, s.height); minsize.x += s.width; } } if (fixed_column_width > 0) minsize.x = fixed_column_width; max_column_width = MAX(max_column_width, minsize.x); // elements need to adapt to the selected size minsize.y += vseparation; minsize.x += hseparation; items[i].rect_cache.size = minsize; items[i].min_rect_cache.size = minsize; } int fit_size = size.x - bg->get_minimum_size().width - mw; //2-attempt best fit current_columns = 0x7FFFFFFF; if (max_columns > 0) current_columns = max_columns; while (true) { //repeat util all fits bool all_fit = true; Vector2 ofs; int col = 0; int max_h = 0; separators.clear(); for (int i = 0; i < items.size(); i++) { if (current_columns > 1 && items[i].rect_cache.size.width + ofs.x > fit_size) { //went past current_columns = MAX(col, 1); all_fit = false; break; } if (same_column_width) items[i].rect_cache.size.x = max_column_width; items[i].rect_cache.position = ofs; max_h = MAX(max_h, items[i].rect_cache.size.y); ofs.x += items[i].rect_cache.size.x + hseparation; col++; if (col == current_columns) { if (i < items.size() - 1) separators.push_back(ofs.y + max_h + vseparation / 2); for (int j = i; j >= 0 && col > 0; j--, col--) { items[j].rect_cache.size.y = max_h; } ofs.x = 0; ofs.y += max_h + vseparation; col = 0; max_h = 0; } } for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) { items[j].rect_cache.size.y = max_h; } if (all_fit) { float page = size.height - bg->get_minimum_size().height; float max = MAX(page, ofs.y + max_h); if (auto_height) auto_height_value = ofs.y + max_h + bg->get_minimum_size().height; scroll_bar->set_max(max); scroll_bar->set_page(page); if (max <= page) { scroll_bar->set_value(0); scroll_bar->hide(); } else { scroll_bar->show(); } break; } } shape_changed = false; } //ensure_selected_visible needs to be checked before we draw the list. if (ensure_selected_visible && current >= 0 && current <= items.size()) { Rect2 r = items[current].rect_cache; int from = scroll_bar->get_value(); int to = from + scroll_bar->get_page(); if (r.position.y < from) { scroll_bar->set_value(r.position.y); } else if (r.position.y + r.size.y > to) { scroll_bar->set_value(r.position.y + r.size.y - (to - from)); } } ensure_selected_visible = false; Vector2 base_ofs = bg->get_offset(); base_ofs.y -= int(scroll_bar->get_value()); Rect2 clip(Point2(), size - bg->get_minimum_size() + Vector2(0, scroll_bar->get_value())); for (int i = 0; i < items.size(); i++) { Rect2 rcache = items[i].rect_cache; if (!clip.intersects(rcache)) continue; if (current_columns == 1) { rcache.size.width = width - rcache.position.x; } if (items[i].selected) { Rect2 r = rcache; r.position += base_ofs; r.position.y -= vseparation / 2; r.size.y += vseparation; r.position.x -= hseparation / 2; r.size.x += hseparation; draw_style_box(sbsel, r); } if (items[i].custom_bg.a > 0.001) { Rect2 r = rcache; r.position += base_ofs; // Size rect to make the align the temperature colors r.position.y -= vseparation / 2; r.size.y += vseparation; r.position.x -= hseparation / 2; r.size.x += hseparation; draw_rect(r, items[i].custom_bg); } Vector2 text_ofs; if (items[i].icon.is_valid()) { Size2 icon_size; //= _adjust_to_max_size(items[i].get_icon_size(),fixed_icon_size) * icon_scale; if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { icon_size = fixed_icon_size * icon_scale; } else { icon_size = items[i].get_icon_size() * icon_scale; } Vector2 icon_ofs; Point2 pos = items[i].rect_cache.position + icon_ofs + base_ofs; if (icon_mode == ICON_MODE_TOP) { pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2); pos.y += MIN( Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2), items[i].rect_cache.size.height - items[i].min_rect_cache.size.height); text_ofs.y = icon_size.height + icon_margin; text_ofs.y += items[i].rect_cache.size.height - items[i].min_rect_cache.size.height; } else { pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2); text_ofs.x = icon_size.width + icon_margin; } Rect2 draw_rect = Rect2(pos, icon_size); if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { Rect2 adj = _adjust_to_max_size(items[i].get_icon_size() * icon_scale, icon_size); draw_rect.position += adj.position; draw_rect.size = adj.size; } Color modulate = Color(1, 1, 1, 1); if (items[i].disabled) modulate.a *= 0.5; if (items[i].icon_region.has_no_area()) draw_texture_rect(items[i].icon, draw_rect, false, modulate); else draw_texture_rect_region(items[i].icon, draw_rect, items[i].icon_region, modulate); } if (items[i].tag_icon.is_valid()) { draw_texture(items[i].tag_icon, items[i].rect_cache.position + base_ofs); } if (items[i].text != "") { int max_len = -1; Vector2 size = font->get_string_size(items[i].text); if (fixed_column_width) max_len = fixed_column_width; else if (same_column_width) max_len = items[i].rect_cache.size.x; else max_len = size.x; Color modulate = items[i].selected ? font_color_selected : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color); if (items[i].disabled) modulate.a *= 0.5; if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { int ss = items[i].text.length(); float ofs = 0; int line = 0; for (int j = 0; j <= ss; j++) { int cs = j < ss ? font->get_char_size(items[i].text[j], items[i].text[j + 1]).x : 0; if (ofs + cs > max_len || j == ss) { line_limit_cache[line] = j; line_size_cache[line] = ofs; line++; ofs = 0; if (line >= max_text_lines) break; } else { ofs += cs; } } line = 0; ofs = 0; text_ofs.y += font->get_ascent(); text_ofs = text_ofs.floor(); text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; for (int j = 0; j < ss; j++) { if (j == line_limit_cache[line]) { line++; ofs = 0; if (line >= max_text_lines) break; } ofs += font->draw_char(get_canvas_item(), text_ofs + Vector2(ofs + (max_len - line_size_cache[line]) / 2, line * (font_height + line_separation)).floor(), items[i].text[j], items[i].text[j + 1], modulate); } //special multiline mode } else { if (fixed_column_width > 0) size.x = MIN(size.x, fixed_column_width); if (icon_mode == ICON_MODE_TOP) { text_ofs.x += (items[i].rect_cache.size.width - size.x) / 2; } else { text_ofs.y += (items[i].rect_cache.size.height - size.y) / 2; } text_ofs.y += font->get_ascent(); text_ofs = text_ofs.floor(); text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; draw_string(font, text_ofs, items[i].text, modulate, max_len + 1); } } if (select_mode == SELECT_MULTI && i == current) { Rect2 r = rcache; r.position += base_ofs; r.position.y -= vseparation / 2; r.size.y += vseparation; r.position.x -= hseparation / 2; r.size.x += hseparation; draw_style_box(cursor, r); } } for (int i = 0; i < separators.size(); i++) { draw_line(Vector2(bg->get_margin(MARGIN_LEFT), base_ofs.y + separators[i]), Vector2(size.width - bg->get_margin(MARGIN_RIGHT), base_ofs.y + separators[i]), guide_color); } } }