Exemplo n.º 1
0
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;
	}
}
Exemplo n.º 2
0
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;

	}
}
Exemplo n.º 3
0
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;
	}
}
Exemplo n.º 4
0
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);
		}
	}
}