Add a lifecycle method for manual theme item caching to Control

This commit is contained in:
Yuri Sizov 2022-08-31 15:02:40 +03:00
parent 0c221f0284
commit 3b1aa240dc
52 changed files with 1592 additions and 910 deletions

View file

@ -44,7 +44,6 @@ void BoxContainer::_resort() {
Size2i new_size = get_size();
int sep = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer");
bool rtl = is_layout_rtl();
bool first = true;
@ -90,7 +89,7 @@ void BoxContainer::_resort() {
return;
}
int stretch_max = (vertical ? new_size.height : new_size.width) - (children_count - 1) * sep;
int stretch_max = (vertical ? new_size.height : new_size.width) - (children_count - 1) * theme_cache.separation;
int stretch_diff = stretch_max - stretch_min;
if (stretch_diff < 0) {
//avoid negative stretch space
@ -214,7 +213,7 @@ void BoxContainer::_resort() {
if (first) {
first = false;
} else {
ofs += sep;
ofs += theme_cache.separation;
}
int from = ofs;
@ -248,7 +247,6 @@ Size2 BoxContainer::get_minimum_size() const {
/* Calculate MINIMUM SIZE */
Size2i minimum;
int sep = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer");
bool first = true;
@ -273,7 +271,7 @@ Size2 BoxContainer::get_minimum_size() const {
minimum.width = size.width;
}
minimum.height += size.height + (first ? 0 : sep);
minimum.height += size.height + (first ? 0 : theme_cache.separation);
} else { /* HORIZONTAL */
@ -281,7 +279,7 @@ Size2 BoxContainer::get_minimum_size() const {
minimum.height = size.height;
}
minimum.width += size.width + (first ? 0 : sep);
minimum.width += size.width + (first ? 0 : theme_cache.separation);
}
first = false;
@ -290,6 +288,12 @@ Size2 BoxContainer::get_minimum_size() const {
return minimum;
}
void BoxContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.separation = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer");
}
void BoxContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {

View file

@ -47,11 +47,16 @@ private:
bool vertical = false;
AlignmentMode alignment = ALIGNMENT_BEGIN;
struct ThemeCache {
int separation = 0;
} theme_cache;
void _resort();
protected:
void _notification(int p_what);
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
public:

View file

@ -36,7 +36,7 @@
Size2 Button::get_minimum_size() const {
Ref<Texture2D> _icon = icon;
if (_icon.is_null() && has_theme_icon(SNAME("icon"))) {
_icon = Control::get_theme_icon(SNAME("icon"));
_icon = theme_cache.icon;
}
return get_minimum_size_for_text_and_icon("", _icon);
@ -46,6 +46,45 @@ void Button::_set_internal_margin(Side p_side, float p_value) {
_internal_margin[p_side] = p_value;
}
void Button::_update_theme_item_cache() {
BaseButton::_update_theme_item_cache();
theme_cache.normal = get_theme_stylebox(SNAME("normal"));
theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored"));
theme_cache.pressed = get_theme_stylebox(SNAME("pressed"));
theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored"));
theme_cache.hover = get_theme_stylebox(SNAME("hover"));
theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored"));
theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed"));
theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
theme_cache.disabled = get_theme_stylebox(SNAME("disabled"));
theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored"));
theme_cache.focus = get_theme_stylebox(SNAME("focus"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.icon_normal_color = get_theme_color(SNAME("icon_normal_color"));
theme_cache.icon_focus_color = get_theme_color(SNAME("icon_focus_color"));
theme_cache.icon_pressed_color = get_theme_color(SNAME("icon_pressed_color"));
theme_cache.icon_hover_color = get_theme_color(SNAME("icon_hover_color"));
theme_cache.icon_hover_pressed_color = get_theme_color(SNAME("icon_hover_pressed_color"));
theme_cache.icon_disabled_color = get_theme_color(SNAME("icon_disabled_color"));
theme_cache.icon = get_theme_icon(SNAME("icon"));
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
}
void Button::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
@ -73,15 +112,15 @@ void Button::_notification(int p_what) {
Color color;
Color color_icon(1, 1, 1, 1);
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
switch (get_draw_mode()) {
case DRAW_NORMAL: {
if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) {
style = get_theme_stylebox(SNAME("normal_mirrored"));
style = theme_cache.normal_mirrored;
} else {
style = get_theme_stylebox(SNAME("normal"));
style = theme_cache.normal;
}
if (!flat) {
@ -90,14 +129,14 @@ void Button::_notification(int p_what) {
// Focus colors only take precedence over normal state.
if (has_focus()) {
color = get_theme_color(SNAME("font_focus_color"));
color = theme_cache.font_focus_color;
if (has_theme_color(SNAME("icon_focus_color"))) {
color_icon = get_theme_color(SNAME("icon_focus_color"));
color_icon = theme_cache.icon_focus_color;
}
} else {
color = get_theme_color(SNAME("font_color"));
color = theme_cache.font_color;
if (has_theme_color(SNAME("icon_normal_color"))) {
color_icon = get_theme_color(SNAME("icon_normal_color"));
color_icon = theme_cache.icon_normal_color;
}
}
} break;
@ -105,19 +144,19 @@ void Button::_notification(int p_what) {
// Edge case for CheckButton and CheckBox.
if (has_theme_stylebox("hover_pressed")) {
if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) {
style = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
style = theme_cache.hover_pressed_mirrored;
} else {
style = get_theme_stylebox(SNAME("hover_pressed"));
style = theme_cache.hover_pressed;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
if (has_theme_color(SNAME("font_hover_pressed_color"))) {
color = get_theme_color(SNAME("font_hover_pressed_color"));
color = theme_cache.font_hover_pressed_color;
}
if (has_theme_color(SNAME("icon_hover_pressed_color"))) {
color_icon = get_theme_color(SNAME("icon_hover_pressed_color"));
color_icon = theme_cache.icon_hover_pressed_color;
}
break;
@ -126,53 +165,53 @@ void Button::_notification(int p_what) {
}
case DRAW_PRESSED: {
if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) {
style = get_theme_stylebox(SNAME("pressed_mirrored"));
style = theme_cache.pressed_mirrored;
} else {
style = get_theme_stylebox(SNAME("pressed"));
style = theme_cache.pressed;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
if (has_theme_color(SNAME("font_pressed_color"))) {
color = get_theme_color(SNAME("font_pressed_color"));
color = theme_cache.font_pressed_color;
} else {
color = get_theme_color(SNAME("font_color"));
color = theme_cache.font_color;
}
if (has_theme_color(SNAME("icon_pressed_color"))) {
color_icon = get_theme_color(SNAME("icon_pressed_color"));
color_icon = theme_cache.icon_pressed_color;
}
} break;
case DRAW_HOVER: {
if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) {
style = get_theme_stylebox(SNAME("hover_mirrored"));
style = theme_cache.hover_mirrored;
} else {
style = get_theme_stylebox(SNAME("hover"));
style = theme_cache.hover;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
color = get_theme_color(SNAME("font_hover_color"));
color = theme_cache.font_hover_color;
if (has_theme_color(SNAME("icon_hover_color"))) {
color_icon = get_theme_color(SNAME("icon_hover_color"));
color_icon = theme_cache.icon_hover_color;
}
} break;
case DRAW_DISABLED: {
if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) {
style = get_theme_stylebox(SNAME("disabled_mirrored"));
style = theme_cache.disabled_mirrored;
} else {
style = get_theme_stylebox(SNAME("disabled"));
style = theme_cache.disabled;
}
if (!flat) {
style->draw(ci, Rect2(Point2(0, 0), size));
}
color = get_theme_color(SNAME("font_disabled_color"));
color = theme_cache.font_disabled_color;
if (has_theme_color(SNAME("icon_disabled_color"))) {
color_icon = get_theme_color(SNAME("icon_disabled_color"));
color_icon = theme_cache.icon_disabled_color;
} else {
color_icon.a = 0.4;
}
@ -181,13 +220,13 @@ void Button::_notification(int p_what) {
}
if (has_focus()) {
Ref<StyleBox> style2 = get_theme_stylebox(SNAME("focus"));
Ref<StyleBox> style2 = theme_cache.focus;
style2->draw(ci, Rect2(Point2(), size));
}
Ref<Texture2D> _icon;
if (icon.is_null() && has_theme_icon(SNAME("icon"))) {
_icon = Control::get_theme_icon(SNAME("icon"));
_icon = theme_cache.icon;
} else {
_icon = icon;
}
@ -217,21 +256,21 @@ void Button::_notification(int p_what) {
if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) {
style_offset.x = style->get_margin(SIDE_LEFT);
if (_internal_margin[SIDE_LEFT] > 0) {
icon_ofs_region = _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation"));
icon_ofs_region = _internal_margin[SIDE_LEFT] + theme_cache.h_separation;
}
} else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) {
style_offset.x = 0.0;
} else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_RIGHT) {
style_offset.x = -style->get_margin(SIDE_RIGHT);
if (_internal_margin[SIDE_RIGHT] > 0) {
icon_ofs_region = -_internal_margin[SIDE_RIGHT] - get_theme_constant(SNAME("h_separation"));
icon_ofs_region = -_internal_margin[SIDE_RIGHT] - theme_cache.h_separation;
}
}
style_offset.y = style->get_margin(SIDE_TOP);
if (expand_icon) {
Size2 _size = get_size() - style->get_offset() * 2;
int icon_text_separation = text.is_empty() ? 0 : get_theme_constant(SNAME("h_separation"));
int icon_text_separation = text.is_empty() ? 0 : theme_cache.h_separation;
_size.width -= icon_text_separation + icon_ofs_region;
if (!clip_text && icon_align_rtl_checked != HORIZONTAL_ALIGNMENT_CENTER) {
_size.width -= text_buf->get_size().width;
@ -261,7 +300,7 @@ void Button::_notification(int p_what) {
}
}
Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_theme_constant(SNAME("h_separation")), 0) : Point2();
Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + theme_cache.h_separation, 0) : Point2();
if (align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER && icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) {
icon_ofs.x = 0.0;
}
@ -271,10 +310,10 @@ void Button::_notification(int p_what) {
int text_width = MAX(1, (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x);
if (_internal_margin[SIDE_LEFT] > 0) {
text_clip -= _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation"));
text_clip -= _internal_margin[SIDE_LEFT] + theme_cache.h_separation;
}
if (_internal_margin[SIDE_RIGHT] > 0) {
text_clip -= _internal_margin[SIDE_RIGHT] + get_theme_constant(SNAME("h_separation"));
text_clip -= _internal_margin[SIDE_RIGHT] + theme_cache.h_separation;
}
Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0;
@ -288,7 +327,7 @@ void Button::_notification(int p_what) {
icon_ofs.x = 0.0;
}
if (_internal_margin[SIDE_LEFT] > 0) {
text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation"));
text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + theme_cache.h_separation;
} else {
text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x;
}
@ -305,7 +344,7 @@ void Button::_notification(int p_what) {
} break;
case HORIZONTAL_ALIGNMENT_RIGHT: {
if (_internal_margin[SIDE_RIGHT] > 0) {
text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant(SNAME("h_separation"));
text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - theme_cache.h_separation;
} else {
text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width;
}
@ -316,8 +355,8 @@ void Button::_notification(int p_what) {
} break;
}
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
Color font_outline_color = theme_cache.font_outline_color;
int outline_size = theme_cache.outline_size;
if (outline_size > 0 && font_outline_color.a > 0) {
text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color);
}
@ -346,7 +385,7 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
minsize.width += p_icon->get_width();
if (!xl_text.is_empty() || !p_text.is_empty()) {
minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
minsize.width += MAX(0, theme_cache.h_separation);
}
} else {
minsize.width = MAX(minsize.width, p_icon->get_width());
@ -354,12 +393,12 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
}
if (!xl_text.is_empty() || !p_text.is_empty()) {
Ref<Font> font = get_theme_font(SNAME("font"));
float font_height = font->get_height(get_theme_font_size(SNAME("font_size")));
Ref<Font> font = theme_cache.font;
float font_height = font->get_height(theme_cache.font_size);
minsize.height = MAX(font_height, minsize.height);
}
return get_theme_stylebox(SNAME("normal"))->get_minimum_size() + minsize;
return theme_cache.normal->get_minimum_size() + minsize;
}
void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) {
@ -371,10 +410,15 @@ void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) {
p_text = xl_text;
}
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
p_paragraph->clear();
Ref<Font> font = theme_cache.font;
int font_size = theme_cache.font_size;
if (font.is_null() || font_size == 0) {
// Can't shape without a valid font and a non-zero size.
return;
}
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
} else {

View file

@ -54,10 +54,48 @@ private:
HorizontalAlignment icon_alignment = HORIZONTAL_ALIGNMENT_LEFT;
float _internal_margin[4] = {};
struct ThemeCache {
Ref<StyleBox> normal;
Ref<StyleBox> normal_mirrored;
Ref<StyleBox> pressed;
Ref<StyleBox> pressed_mirrored;
Ref<StyleBox> hover;
Ref<StyleBox> hover_mirrored;
Ref<StyleBox> hover_pressed;
Ref<StyleBox> hover_pressed_mirrored;
Ref<StyleBox> disabled;
Ref<StyleBox> disabled_mirrored;
Ref<StyleBox> focus;
Color font_color;
Color font_focus_color;
Color font_pressed_color;
Color font_hover_color;
Color font_hover_pressed_color;
Color font_disabled_color;
Ref<Font> font;
int font_size = 0;
int outline_size = 0;
Color font_outline_color;
Color icon_normal_color;
Color icon_focus_color;
Color icon_pressed_color;
Color icon_hover_color;
Color icon_hover_pressed_color;
Color icon_disabled_color;
Ref<Texture2D> icon;
int h_separation = 0;
} theme_cache;
void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = "");
protected:
void _set_internal_margin(Side p_side, float p_value);
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -33,39 +33,30 @@
#include "servers/rendering_server.h"
Size2 CheckBox::get_icon_size() const {
Ref<Texture2D> checked = Control::get_theme_icon(SNAME("checked"));
Ref<Texture2D> unchecked = Control::get_theme_icon(SNAME("unchecked"));
Ref<Texture2D> radio_checked = Control::get_theme_icon(SNAME("radio_checked"));
Ref<Texture2D> radio_unchecked = Control::get_theme_icon(SNAME("radio_unchecked"));
Ref<Texture2D> checked_disabled = Control::get_theme_icon(SNAME("checked_disabled"));
Ref<Texture2D> unchecked_disabled = Control::get_theme_icon(SNAME("unchecked_disabled"));
Ref<Texture2D> radio_checked_disabled = Control::get_theme_icon(SNAME("radio_checked_disabled"));
Ref<Texture2D> radio_unchecked_disabled = Control::get_theme_icon(SNAME("radio_unchecked_disabled"));
Size2 tex_size = Size2(0, 0);
if (!checked.is_null()) {
tex_size = Size2(checked->get_width(), checked->get_height());
if (!theme_cache.checked.is_null()) {
tex_size = Size2(theme_cache.checked->get_width(), theme_cache.checked->get_height());
}
if (!unchecked.is_null()) {
tex_size = Size2(MAX(tex_size.width, unchecked->get_width()), MAX(tex_size.height, unchecked->get_height()));
if (!theme_cache.unchecked.is_null()) {
tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked->get_width()), MAX(tex_size.height, theme_cache.unchecked->get_height()));
}
if (!radio_checked.is_null()) {
tex_size = Size2(MAX(tex_size.width, radio_checked->get_width()), MAX(tex_size.height, radio_checked->get_height()));
if (!theme_cache.radio_checked.is_null()) {
tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked->get_width()), MAX(tex_size.height, theme_cache.radio_checked->get_height()));
}
if (!radio_unchecked.is_null()) {
tex_size = Size2(MAX(tex_size.width, radio_unchecked->get_width()), MAX(tex_size.height, radio_unchecked->get_height()));
if (!theme_cache.radio_unchecked.is_null()) {
tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked->get_height()));
}
if (!checked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, checked_disabled->get_width()), MAX(tex_size.height, checked_disabled->get_height()));
if (!theme_cache.checked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, theme_cache.checked_disabled->get_width()), MAX(tex_size.height, theme_cache.checked_disabled->get_height()));
}
if (!unchecked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, unchecked_disabled->get_width()), MAX(tex_size.height, unchecked_disabled->get_height()));
if (!theme_cache.unchecked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.unchecked_disabled->get_height()));
}
if (!radio_checked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, radio_checked_disabled->get_width()), MAX(tex_size.height, radio_checked_disabled->get_height()));
if (!theme_cache.radio_checked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_checked_disabled->get_height()));
}
if (!radio_unchecked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, radio_unchecked_disabled->get_width()), MAX(tex_size.height, radio_unchecked_disabled->get_height()));
if (!theme_cache.radio_unchecked_disabled.is_null()) {
tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked_disabled->get_height()));
}
return tex_size;
}
@ -75,14 +66,30 @@ Size2 CheckBox::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0) {
minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
minsize.width += MAX(0, theme_cache.h_separation);
}
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM));
minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM));
return minsize;
}
void CheckBox::_update_theme_item_cache() {
Button::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.check_v_adjust = get_theme_constant(SNAME("check_v_adjust"));
theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
theme_cache.checked = get_theme_icon(SNAME("checked"));
theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked"));
theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked"));
theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled"));
theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled"));
}
void CheckBox::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
@ -100,22 +107,39 @@ void CheckBox::_notification(int p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Ref<Texture2D> on = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_checked" : "checked", is_disabled() ? "_disabled" : ""));
Ref<Texture2D> off = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_unchecked" : "unchecked", is_disabled() ? "_disabled" : ""));
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
Ref<Texture2D> on_tex;
Ref<Texture2D> off_tex;
if (is_radio()) {
if (is_disabled()) {
on_tex = theme_cache.radio_checked_disabled;
off_tex = theme_cache.radio_unchecked_disabled;
} else {
on_tex = theme_cache.radio_checked;
off_tex = theme_cache.radio_unchecked;
}
} else {
if (is_disabled()) {
on_tex = theme_cache.checked_disabled;
off_tex = theme_cache.unchecked_disabled;
} else {
on_tex = theme_cache.checked;
off_tex = theme_cache.unchecked;
}
}
Vector2 ofs;
if (is_layout_rtl()) {
ofs.x = get_size().x - sb->get_margin(SIDE_RIGHT) - get_icon_size().width;
ofs.x = get_size().x - theme_cache.normal_style->get_margin(SIDE_RIGHT) - get_icon_size().width;
} else {
ofs.x = sb->get_margin(SIDE_LEFT);
ofs.x = theme_cache.normal_style->get_margin(SIDE_LEFT);
}
ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant(SNAME("check_v_adjust"));
ofs.y = int((get_size().height - get_icon_size().height) / 2) + theme_cache.check_v_adjust;
if (is_pressed()) {
on->draw(ci, ofs);
on_tex->draw(ci, ofs);
} else {
off->draw(ci, ofs);
off_tex->draw(ci, ofs);
}
} break;
}

View file

@ -36,9 +36,26 @@
class CheckBox : public Button {
GDCLASS(CheckBox, Button);
struct ThemeCache {
int h_separation = 0;
int check_v_adjust = 0;
Ref<StyleBox> normal_style;
Ref<Texture2D> checked;
Ref<Texture2D> unchecked;
Ref<Texture2D> radio_checked;
Ref<Texture2D> radio_unchecked;
Ref<Texture2D> checked_disabled;
Ref<Texture2D> unchecked_disabled;
Ref<Texture2D> radio_checked_disabled;
Ref<Texture2D> radio_unchecked_disabled;
} theme_cache;
protected:
Size2 get_icon_size() const;
Size2 get_minimum_size() const override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
bool is_radio();

View file

@ -34,14 +34,33 @@
#include "servers/rendering_server.h"
Size2 CheckButton::get_icon_size() const {
Ref<Texture2D> on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on");
Ref<Texture2D> off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off");
Size2 tex_size = Size2(0, 0);
if (!on.is_null()) {
tex_size = Size2(on->get_width(), on->get_height());
Ref<Texture2D> on_tex;
Ref<Texture2D> off_tex;
if (is_layout_rtl()) {
if (is_disabled()) {
on_tex = theme_cache.checked_disabled_mirrored;
off_tex = theme_cache.unchecked_disabled_mirrored;
} else {
on_tex = theme_cache.checked_mirrored;
off_tex = theme_cache.unchecked_mirrored;
}
} else {
if (is_disabled()) {
on_tex = theme_cache.checked_disabled;
off_tex = theme_cache.unchecked_disabled;
} else {
on_tex = theme_cache.checked;
off_tex = theme_cache.unchecked;
}
}
if (!off.is_null()) {
tex_size = Size2(MAX(tex_size.width, off->get_width()), MAX(tex_size.height, off->get_height()));
Size2 tex_size = Size2(0, 0);
if (!on_tex.is_null()) {
tex_size = Size2(on_tex->get_width(), on_tex->get_height());
}
if (!off_tex.is_null()) {
tex_size = Size2(MAX(tex_size.width, off_tex->get_width()), MAX(tex_size.height, off_tex->get_height()));
}
return tex_size;
@ -52,14 +71,30 @@ Size2 CheckButton::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0) {
minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
minsize.width += MAX(0, theme_cache.h_separation);
}
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM));
minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM));
return minsize;
}
void CheckButton::_update_theme_item_cache() {
Button::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.check_v_adjust = get_theme_constant(SNAME("check_v_adjust"));
theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
theme_cache.checked = get_theme_icon(SNAME("on"));
theme_cache.unchecked = get_theme_icon(SNAME("off"));
theme_cache.checked_disabled = get_theme_icon(SNAME("on_disabled"));
theme_cache.unchecked_disabled = get_theme_icon(SNAME("off_disabled"));
theme_cache.checked_mirrored = get_theme_icon(SNAME("on_mirrored"));
theme_cache.unchecked_mirrored = get_theme_icon(SNAME("off_mirrored"));
theme_cache.checked_disabled_mirrored = get_theme_icon(SNAME("on_disabled_mirrored"));
theme_cache.unchecked_disabled_mirrored = get_theme_icon(SNAME("off_disabled_mirrored"));
}
void CheckButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
@ -78,34 +113,41 @@ void CheckButton::_notification(int p_what) {
RID ci = get_canvas_item();
bool rtl = is_layout_rtl();
Ref<Texture2D> on;
Ref<Texture2D> on_tex;
Ref<Texture2D> off_tex;
if (rtl) {
on = Control::get_theme_icon(is_disabled() ? "on_disabled_mirrored" : "on_mirrored");
if (is_disabled()) {
on_tex = theme_cache.checked_disabled_mirrored;
off_tex = theme_cache.unchecked_disabled_mirrored;
} else {
on_tex = theme_cache.checked_mirrored;
off_tex = theme_cache.unchecked_mirrored;
}
} else {
on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on");
}
Ref<Texture2D> off;
if (rtl) {
off = Control::get_theme_icon(is_disabled() ? "off_disabled_mirrored" : "off_mirrored");
} else {
off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off");
if (is_disabled()) {
on_tex = theme_cache.checked_disabled;
off_tex = theme_cache.unchecked_disabled;
} else {
on_tex = theme_cache.checked;
off_tex = theme_cache.unchecked;
}
}
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
Vector2 ofs;
Size2 tex_size = get_icon_size();
if (rtl) {
ofs.x = sb->get_margin(SIDE_LEFT);
ofs.x = theme_cache.normal_style->get_margin(SIDE_LEFT);
} else {
ofs.x = get_size().width - (tex_size.width + sb->get_margin(SIDE_RIGHT));
ofs.x = get_size().width - (tex_size.width + theme_cache.normal_style->get_margin(SIDE_RIGHT));
}
ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant(SNAME("check_v_adjust"));
ofs.y = (get_size().height - tex_size.height) / 2 + theme_cache.check_v_adjust;
if (is_pressed()) {
on->draw(ci, ofs);
on_tex->draw(ci, ofs);
} else {
off->draw(ci, ofs);
off_tex->draw(ci, ofs);
}
} break;
}

View file

@ -36,9 +36,26 @@
class CheckButton : public Button {
GDCLASS(CheckButton, Button);
struct ThemeCache {
int h_separation = 0;
int check_v_adjust = 0;
Ref<StyleBox> normal_style;
Ref<Texture2D> checked;
Ref<Texture2D> unchecked;
Ref<Texture2D> checked_disabled;
Ref<Texture2D> unchecked_disabled;
Ref<Texture2D> checked_mirrored;
Ref<Texture2D> unchecked_mirrored;
Ref<Texture2D> checked_disabled_mirrored;
Ref<Texture2D> unchecked_disabled_mirrored;
} theme_cache;
protected:
Size2 get_icon_size() const;
virtual Size2 get_minimum_size() const override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
public:

View file

@ -2330,6 +2330,9 @@ void Control::_invalidate_theme_cache() {
data.theme_constant_cache.clear();
}
void Control::_update_theme_item_cache() {
}
void Control::set_theme(const Ref<Theme> &p_theme) {
if (data.theme == p_theme) {
return;
@ -3103,6 +3106,11 @@ void Control::remove_child_notify(Node *p_child) {
void Control::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_POSTINITIALIZE: {
_invalidate_theme_cache();
_update_theme_item_cache();
} break;
case NOTIFICATION_ENTER_TREE: {
// Need to defer here, because theme owner information might be set in
// add_child_notify, which doesn't get called until right after this.
@ -3236,6 +3244,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_THEME_CHANGED: {
emit_signal(SceneStringNames::get_singleton()->theme_changed);
_invalidate_theme_cache();
_update_theme_item_cache();
update_minimum_size();
queue_redraw();
} break;
@ -3257,6 +3266,7 @@ void Control::_notification(int p_notification) {
if (is_inside_tree()) {
data.is_rtl_dirty = true;
_invalidate_theme_cache();
_update_theme_item_cache();
_size_changed();
}
} break;

View file

@ -325,6 +325,10 @@ protected:
bool _property_can_revert(const StringName &p_name) const;
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
// Theming.
virtual void _update_theme_item_cache();
// Internationalization.
virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;

View file

@ -44,9 +44,6 @@ void FlowContainer::_resort() {
return;
}
int separation_horizontal = get_theme_constant(SNAME("h_separation"));
int separation_vertical = get_theme_constant(SNAME("v_separation"));
bool rtl = is_layout_rtl();
HashMap<Control *, Size2i> children_minsize_cache;
@ -74,14 +71,14 @@ void FlowContainer::_resort() {
if (vertical) { /* VERTICAL */
if (children_in_current_line > 0) {
ofs.y += separation_vertical;
ofs.y += theme_cache.v_separation;
}
if (ofs.y + child_msc.y > current_container_size) {
line_length = ofs.y - separation_vertical;
line_length = ofs.y - theme_cache.v_separation;
lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total });
// Move in new column (vertical line).
ofs.x += line_height + separation_horizontal;
ofs.x += line_height + theme_cache.h_separation;
ofs.y = 0;
line_height = 0;
line_stretch_ratio_total = 0;
@ -96,14 +93,14 @@ void FlowContainer::_resort() {
} else { /* HORIZONTAL */
if (children_in_current_line > 0) {
ofs.x += separation_horizontal;
ofs.x += theme_cache.h_separation;
}
if (ofs.x + child_msc.x > current_container_size) {
line_length = ofs.x - separation_horizontal;
line_length = ofs.x - theme_cache.h_separation;
lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total });
// Move in new line.
ofs.y += line_height + separation_vertical;
ofs.y += line_height + theme_cache.v_separation;
ofs.x = 0;
line_height = 0;
line_stretch_ratio_total = 0;
@ -146,11 +143,11 @@ void FlowContainer::_resort() {
current_line_idx++;
child_idx_in_line = 0;
if (vertical) {
ofs.x += line_data.min_line_height + separation_horizontal;
ofs.x += line_data.min_line_height + theme_cache.h_separation;
ofs.y = 0;
} else {
ofs.x = 0;
ofs.y += line_data.min_line_height + separation_vertical;
ofs.y += line_data.min_line_height + theme_cache.v_separation;
}
line_data = lines_data[current_line_idx];
}
@ -184,9 +181,9 @@ void FlowContainer::_resort() {
fit_child_in_rect(child, child_rect);
if (vertical) { /* VERTICAL */
ofs.y += child_size.height + separation_vertical;
ofs.y += child_size.height + theme_cache.v_separation;
} else { /* HORIZONTAL */
ofs.x += child_size.width + separation_horizontal;
ofs.x += child_size.width + theme_cache.h_separation;
}
child_idx_in_line++;
@ -250,6 +247,13 @@ Vector<int> FlowContainer::get_allowed_size_flags_vertical() const {
return flags;
}
void FlowContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
}
void FlowContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {

View file

@ -42,11 +42,17 @@ private:
bool vertical = false;
struct ThemeCache {
int h_separation = 0;
int v_separation = 0;
} theme_cache;
void _resort();
protected:
void _notification(int p_what);
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
public:

View file

@ -31,6 +31,13 @@
#include "grid_container.h"
#include "core/templates/rb_set.h"
void GridContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
}
void GridContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
@ -39,9 +46,6 @@ void GridContainer::_notification(int p_what) {
RBSet<int> col_expanded; // Columns which have the SIZE_EXPAND flag set.
RBSet<int> row_expanded; // Rows which have the SIZE_EXPAND flag set.
int hsep = get_theme_constant(SNAME("h_separation"));
int vsep = get_theme_constant(SNAME("v_separation"));
// Compute the per-column/per-row data.
int valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
@ -98,8 +102,8 @@ void GridContainer::_notification(int p_what) {
remaining_space.height -= E.value;
}
}
remaining_space.height -= vsep * MAX(max_row - 1, 0);
remaining_space.width -= hsep * MAX(max_col - 1, 0);
remaining_space.height -= theme_cache.v_separation * MAX(max_row - 1, 0);
remaining_space.width -= theme_cache.h_separation * MAX(max_col - 1, 0);
bool can_fit = false;
while (!can_fit && col_expanded.size() > 0) {
@ -202,7 +206,7 @@ void GridContainer::_notification(int p_what) {
col_ofs = 0;
}
if (row > 0) {
row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + vsep;
row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + theme_cache.v_separation;
if (row_expanded.has(row - 1) && row - 1 < row_remaining_pixel_index) {
// Apply the remaining pixel of the previous row.
@ -224,11 +228,11 @@ void GridContainer::_notification(int p_what) {
if (rtl) {
Point2 p(col_ofs - s.width, row_ofs);
fit_child_in_rect(c, Rect2(p, s));
col_ofs -= s.width + hsep;
col_ofs -= s.width + theme_cache.h_separation;
} else {
Point2 p(col_ofs, row_ofs);
fit_child_in_rect(c, Rect2(p, s));
col_ofs += s.width + hsep;
col_ofs += s.width + theme_cache.h_separation;
}
}
} break;
@ -271,9 +275,6 @@ Size2 GridContainer::get_minimum_size() const {
RBMap<int, int> col_minw;
RBMap<int, int> row_minh;
int hsep = get_theme_constant(SNAME("h_separation"));
int vsep = get_theme_constant(SNAME("v_separation"));
int max_row = 0;
int max_col = 0;
@ -313,8 +314,8 @@ Size2 GridContainer::get_minimum_size() const {
ms.height += E.value;
}
ms.height += vsep * max_row;
ms.width += hsep * max_col;
ms.height += theme_cache.v_separation * max_row;
ms.width += theme_cache.h_separation * max_col;
return ms;
}

View file

@ -38,7 +38,14 @@ class GridContainer : public Container {
int columns = 1;
struct ThemeCache {
int h_separation = 0;
int v_separation = 0;
} theme_cache;
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -43,7 +43,7 @@ void ItemList::_shape(int p_idx) {
} else {
item.text_buf->set_direction((TextServer::Direction)item.text_direction);
}
item.text_buf->add_string(item.text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), item.language);
item.text_buf->add_string(item.text, theme_cache.font, theme_cache.font_size, item.language);
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES);
} else {
@ -655,8 +655,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed()) {
search_string = ""; //any mousepress cancels
Vector2 pos = mb->get_position();
Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
pos -= bg->get_offset();
pos -= theme_cache.bg_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@ -980,6 +979,31 @@ static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) {
return Rect2(ofs_x, ofs_y, tex_width, tex_height);
}
void ItemList::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
theme_cache.bg_focus_style = get_theme_stylebox(SNAME("bg_focus"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.line_separation = get_theme_constant(SNAME("line_separation"));
theme_cache.icon_margin = get_theme_constant(SNAME("icon_margin"));
theme_cache.selected_style = get_theme_stylebox(SNAME("selected"));
theme_cache.selected_focus_style = get_theme_stylebox(SNAME("selected_focus"));
theme_cache.cursor_style = get_theme_stylebox(SNAME("cursor_unfocused"));
theme_cache.cursor_focus_style = get_theme_stylebox(SNAME("cursor"));
theme_cache.guide_color = get_theme_color(SNAME("guide_color"));
}
void ItemList::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_RESIZED: {
@ -998,37 +1022,32 @@ void ItemList::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
int mw = scroll_bar->get_minimum_size().x;
scroll_bar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -mw);
scroll_bar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, bg->get_margin(SIDE_TOP));
scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM));
scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, theme_cache.bg_style->get_margin(SIDE_TOP));
scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.bg_style->get_margin(SIDE_BOTTOM));
Size2 size = get_size();
int width = size.width - bg->get_minimum_size().width;
int width = size.width - theme_cache.bg_style->get_minimum_size().width;
draw_style_box(bg, Rect2(Point2(), size));
draw_style_box(theme_cache.bg_style, Rect2(Point2(), size));
int hseparation = get_theme_constant(SNAME("h_separation"));
int vseparation = get_theme_constant(SNAME("v_separation"));
int icon_margin = get_theme_constant(SNAME("icon_margin"));
int line_separation = get_theme_constant(SNAME("line_separation"));
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
Ref<StyleBox> sbsel;
Ref<StyleBox> cursor;
Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox(SNAME("selected_focus")) : get_theme_stylebox(SNAME("selected"));
Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox(SNAME("cursor")) : get_theme_stylebox(SNAME("cursor_unfocused"));
if (has_focus()) {
sbsel = theme_cache.selected_focus_style;
cursor = theme_cache.cursor_focus_style;
} else {
sbsel = theme_cache.selected_style;
cursor = theme_cache.cursor_style;
}
bool rtl = is_layout_rtl();
Color guide_color = get_theme_color(SNAME("guide_color"));
Color font_color = get_theme_color(SNAME("font_color"));
Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
if (has_focus()) {
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
draw_style_box(get_theme_stylebox(SNAME("bg_focus")), Rect2(Point2(), size));
draw_style_box(theme_cache.bg_focus_style, Rect2(Point2(), size));
RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false);
}
@ -1047,9 +1066,9 @@ void ItemList::_notification(int p_what) {
if (!items[i].text.is_empty()) {
if (icon_mode == ICON_MODE_TOP) {
minsize.y += icon_margin;
minsize.y += theme_cache.icon_margin;
} else {
minsize.x += icon_margin;
minsize.x += theme_cache.icon_margin;
}
}
}
@ -1067,7 +1086,7 @@ void ItemList::_notification(int p_what) {
if (icon_mode == ICON_MODE_TOP) {
minsize.x = MAX(minsize.x, s.width);
if (max_text_lines > 0) {
minsize.y += s.height + line_separation * max_text_lines;
minsize.y += s.height + theme_cache.line_separation * max_text_lines;
} else {
minsize.y += s.height;
}
@ -1084,13 +1103,13 @@ void ItemList::_notification(int p_what) {
max_column_width = MAX(max_column_width, minsize.x);
// elements need to adapt to the selected size
minsize.y += vseparation;
minsize.x += hseparation;
minsize.y += theme_cache.v_separation;
minsize.x += theme_cache.h_separation;
items.write[i].rect_cache.size = minsize;
items.write[i].min_rect_cache.size = minsize;
}
int fit_size = size.x - bg->get_minimum_size().width - mw;
int fit_size = size.x - theme_cache.bg_style->get_minimum_size().width - mw;
//2-attempt best fit
current_columns = 0x7FFFFFFF;
@ -1118,11 +1137,11 @@ void ItemList::_notification(int p_what) {
}
items.write[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;
ofs.x += items[i].rect_cache.size.x + theme_cache.h_separation;
col++;
if (col == current_columns) {
if (i < items.size() - 1) {
separators.push_back(ofs.y + max_h + vseparation / 2);
separators.push_back(ofs.y + max_h + theme_cache.v_separation / 2);
}
for (int j = i; j >= 0 && col > 0; j--, col--) {
@ -1130,7 +1149,7 @@ void ItemList::_notification(int p_what) {
}
ofs.x = 0;
ofs.y += max_h + vseparation;
ofs.y += max_h + theme_cache.v_separation;
col = 0;
max_h = 0;
}
@ -1141,10 +1160,10 @@ void ItemList::_notification(int p_what) {
}
if (all_fit) {
float page = MAX(0, size.height - bg->get_minimum_size().height);
float page = MAX(0, size.height - theme_cache.bg_style->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;
auto_height_value = ofs.y + max_h + theme_cache.bg_style->get_minimum_size().height;
}
scroll_bar->set_max(max);
scroll_bar->set_page(page);
@ -1185,7 +1204,7 @@ void ItemList::_notification(int p_what) {
ensure_selected_visible = false;
Vector2 base_ofs = bg->get_offset();
Vector2 base_ofs = theme_cache.bg_style->get_offset();
base_ofs.y -= int(scroll_bar->get_value());
const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there
@ -1229,10 +1248,10 @@ void ItemList::_notification(int p_what) {
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;
r.position.y -= theme_cache.v_separation / 2;
r.size.y += theme_cache.v_separation;
r.position.x -= theme_cache.h_separation / 2;
r.size.x += theme_cache.h_separation;
if (rtl) {
r.position.x = size.width - r.position.x - r.size.x;
@ -1245,10 +1264,10 @@ void ItemList::_notification(int p_what) {
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;
r.position.y -= theme_cache.v_separation / 2;
r.size.y += theme_cache.v_separation;
r.position.x -= theme_cache.h_separation / 2;
r.size.x += theme_cache.h_separation;
if (rtl) {
r.position.x = size.width - r.position.x - r.size.x;
@ -1274,11 +1293,11 @@ void ItemList::_notification(int p_what) {
if (icon_mode == ICON_MODE_TOP) {
pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2);
pos.y += icon_margin;
text_ofs.y = icon_size.height + icon_margin * 2;
pos.y += theme_cache.icon_margin;
text_ofs.y = icon_size.height + theme_cache.icon_margin * 2;
} else {
pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2);
text_ofs.x = icon_size.width + icon_margin;
text_ofs.x = icon_size.width + theme_cache.icon_margin;
}
Rect2 draw_rect = Rect2(pos, icon_size);
@ -1329,7 +1348,7 @@ void ItemList::_notification(int p_what) {
max_len = size2.x;
}
Color modulate = items[i].selected ? font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color);
Color modulate = items[i].selected ? theme_cache.font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : theme_cache.font_color);
if (items[i].disabled) {
modulate.a *= 0.5;
}
@ -1344,8 +1363,8 @@ void ItemList::_notification(int p_what) {
items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_CENTER);
if (outline_size > 0 && font_outline_color.a > 0) {
items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
@ -1375,8 +1394,8 @@ void ItemList::_notification(int p_what) {
items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_LEFT);
}
if (outline_size > 0 && font_outline_color.a > 0) {
items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color);
if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
if (width - text_ofs.x > 0) {
@ -1388,10 +1407,10 @@ void ItemList::_notification(int p_what) {
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;
r.position.y -= theme_cache.v_separation / 2;
r.size.y += theme_cache.v_separation;
r.position.x -= theme_cache.h_separation / 2;
r.size.x += theme_cache.h_separation;
if (rtl) {
r.position.x = size.width - r.position.x - r.size.x;
@ -1423,7 +1442,7 @@ void ItemList::_notification(int p_what) {
}
const int y = base_ofs.y + separators[i];
draw_line(Vector2(bg->get_margin(SIDE_LEFT), y), Vector2(width, y), guide_color);
draw_line(Vector2(theme_cache.bg_style->get_margin(SIDE_LEFT), y), Vector2(width, y), theme_cache.guide_color);
}
} break;
}
@ -1435,8 +1454,7 @@ void ItemList::_scroll_changed(double) {
int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
Vector2 pos = p_pos;
Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
pos -= bg->get_offset();
pos -= theme_cache.bg_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {
@ -1473,8 +1491,7 @@ bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const {
}
Vector2 pos = p_pos;
Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
pos -= bg->get_offset();
pos -= theme_cache.bg_style->get_offset();
pos.y += scroll_bar->get_value();
if (is_layout_rtl()) {

View file

@ -109,23 +109,45 @@ private:
int max_columns = 1;
Size2 fixed_icon_size;
Size2 max_item_size_cache;
int defer_select_single = -1;
bool allow_rmb_select = false;
bool allow_reselect = false;
real_t icon_scale = 1.0;
bool do_autoscroll_to_bottom = false;
struct ThemeCache {
int h_separation = 0;
int v_separation = 0;
Ref<StyleBox> bg_style;
Ref<StyleBox> bg_focus_style;
Ref<Font> font;
int font_size = 0;
Color font_color;
Color font_selected_color;
int font_outline_size = 0;
Color font_outline_color;
int line_separation = 0;
int icon_margin = 0;
Ref<StyleBox> selected_style;
Ref<StyleBox> selected_focus_style;
Ref<StyleBox> cursor_style;
Ref<StyleBox> cursor_focus_style;
Color guide_color;
} theme_cache;
void _scroll_changed(double);
void _shape(int p_idx);
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;

View file

@ -71,7 +71,7 @@ bool Label::is_uppercase() const {
}
int Label::get_line_height(int p_line) const {
Ref<Font> font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
Ref<Font> font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
if (p_line >= 0 && p_line < lines_rid.size()) {
return TS->shaped_text_get_size(lines_rid[p_line]).y;
} else if (lines_rid.size() > 0) {
@ -81,13 +81,13 @@ int Label::get_line_height(int p_line) const {
}
return h;
} else {
int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size"));
int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
return font->get_height(font_size);
}
}
void Label::_shape() {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label"));
Ref<StyleBox> style = theme_cache.normal_style;
int width = (get_size().width - style->get_minimum_size().width);
if (dirty || font_dirty) {
@ -99,8 +99,8 @@ void Label::_shape() {
} else {
TS->shaped_text_set_direction(text_rid, (TextServer::Direction)text_direction);
}
const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size"));
const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
ERR_FAIL_COND(font.is_null());
String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
@ -232,8 +232,8 @@ void Label::_shape() {
}
void Label::_update_visible() {
int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"), SNAME("Label"));
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label"));
int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing;
Ref<StyleBox> style = theme_cache.normal_style;
int lines_visible = lines_rid.size();
if (max_lines_visible >= 0 && lines_visible > max_lines_visible) {
@ -272,6 +272,22 @@ inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Col
}
}
void Label::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.line_spacing = get_theme_constant(SNAME("line_spacing"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
theme_cache.font_shadow_offset = Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y")));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
}
void Label::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
@ -307,15 +323,15 @@ void Label::_notification(int p_what) {
Size2 string_size;
Size2 size = get_size();
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<Font> font = (has_settings && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
Color font_color = has_settings ? settings->get_font_color() : get_theme_color(SNAME("font_color"));
Color font_shadow_color = has_settings ? settings->get_shadow_color() : get_theme_color(SNAME("font_shadow_color"));
Point2 shadow_ofs = has_settings ? settings->get_shadow_offset() : Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y")));
int line_spacing = has_settings ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"));
Color font_outline_color = has_settings ? settings->get_outline_color() : get_theme_color(SNAME("font_outline_color"));
int outline_size = has_settings ? settings->get_outline_size() : get_theme_constant(SNAME("outline_size"));
int shadow_outline_size = has_settings ? settings->get_shadow_size() : get_theme_constant(SNAME("shadow_outline_size"));
Ref<StyleBox> style = theme_cache.normal_style;
Ref<Font> font = (has_settings && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
Color font_color = has_settings ? settings->get_font_color() : theme_cache.font_color;
Color font_shadow_color = has_settings ? settings->get_shadow_color() : theme_cache.font_shadow_color;
Point2 shadow_ofs = has_settings ? settings->get_shadow_offset() : theme_cache.font_shadow_offset;
int line_spacing = has_settings ? settings->get_line_spacing() : theme_cache.line_spacing;
Color font_outline_color = has_settings ? settings->get_outline_color() : theme_cache.font_outline_color;
int outline_size = has_settings ? settings->get_outline_size() : theme_cache.font_outline_size;
int shadow_outline_size = has_settings ? settings->get_shadow_size() : theme_cache.font_shadow_outline_size;
bool rtl = (TS->shaped_text_get_inferred_direction(text_rid) == TextServer::DIRECTION_RTL);
bool rtl_layout = is_layout_rtl();
@ -562,12 +578,12 @@ Size2 Label::get_minimum_size() const {
Size2 min_size = minsize;
const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font"));
int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size"));
const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
min_size.height = MAX(min_size.height, font->get_height(font_size) + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM));
Size2 min_style = get_theme_stylebox(SNAME("normal"))->get_minimum_size();
Size2 min_style = theme_cache.normal_style->get_minimum_size();
if (autowrap_mode != TextServer::AUTOWRAP_OFF) {
return Size2(1, (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? 1 : min_size.height) + min_style;
} else {
@ -590,8 +606,8 @@ int Label::get_line_count() const {
}
int Label::get_visible_line_count() const {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"));
Ref<StyleBox> style = theme_cache.normal_style;
int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing;
int lines_visible = 0;
float total_h = 0.0;
for (int64_t i = lines_skipped; i < lines_rid.size(); i++) {

View file

@ -67,13 +67,28 @@ private:
Ref<LabelSettings> settings;
struct ThemeCache {
Ref<StyleBox> normal_style;
Ref<Font> font;
int font_size = 0;
int line_spacing = 0;
Color font_color;
Color font_shadow_color;
Point2 font_shadow_offset;
Color font_outline_color;
int font_outline_size;
int font_shadow_outline_size;
} theme_cache;
void _update_visible();
void _shape();
void _invalidate();
protected:
void _notification(int p_what);
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
public:

View file

@ -448,7 +448,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (context_menu_enabled) {
if (k->is_action("ui_menu", true)) {
_ensure_menu();
Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")))) / 2);
Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2);
menu->set_position(get_screen_position() + pos);
menu->reset_size();
menu->popup();
@ -696,11 +696,38 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const {
if (!clear_button_enabled || !has_point(p_pos)) {
return false;
}
Ref<Texture2D> icon = Control::get_theme_icon(SNAME("clear"));
int x_ofs = get_theme_stylebox(SNAME("normal"))->get_margin(SIDE_RIGHT);
Ref<Texture2D> icon = theme_cache.clear_icon;
int x_ofs = theme_cache.normal->get_margin(SIDE_RIGHT);
return p_pos.x > get_size().width - icon->get_width() - x_ofs;
}
void LineEdit::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.normal = get_theme_stylebox(SNAME("normal"));
theme_cache.read_only = get_theme_stylebox(SNAME("read_only"));
theme_cache.focus = get_theme_stylebox(SNAME("focus"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_uneditable_color = get_theme_color(SNAME("font_uneditable_color"));
theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.font_placeholder_color = get_theme_color(SNAME("font_placeholder_color"));
theme_cache.caret_width = get_theme_constant(SNAME("caret_width"));
theme_cache.caret_color = get_theme_color(SNAME("caret_color"));
theme_cache.minimum_character_width = get_theme_constant(SNAME("minimum_character_width"));
theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
theme_cache.clear_icon = get_theme_icon(SNAME("clear"));
theme_cache.clear_button_color = get_theme_color(SNAME("clear_button_color"));
theme_cache.clear_button_color_pressed = get_theme_color(SNAME("clear_button_color_pressed"));
theme_cache.base_scale = get_theme_default_base_scale();
}
void LineEdit::_notification(int p_what) {
switch (p_what) {
#ifdef TOOLS_ENABLED
@ -771,19 +798,19 @@ void LineEdit::_notification(int p_what) {
RID ci = get_canvas_item();
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
if (!is_editable()) {
style = get_theme_stylebox(SNAME("read_only"));
style = theme_cache.read_only;
draw_caret = false;
}
Ref<Font> font = get_theme_font(SNAME("font"));
Ref<Font> font = theme_cache.font;
if (!flat) {
style->draw(ci, Rect2(Point2(), size));
}
if (has_focus()) {
get_theme_stylebox(SNAME("focus"))->draw(ci, Rect2(Point2(), size));
theme_cache.focus->draw(ci, Rect2(Point2(), size));
}
int x_ofs = 0;
@ -821,25 +848,30 @@ void LineEdit::_notification(int p_what) {
int y_area = height - style->get_minimum_size().height;
int y_ofs = style->get_offset().y + (y_area - text_height) / 2;
Color selection_color = get_theme_color(SNAME("selection_color"));
Color font_color = get_theme_color(is_editable() ? SNAME("font_color") : SNAME("font_uneditable_color"));
Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
Color caret_color = get_theme_color(SNAME("caret_color"));
Color selection_color = theme_cache.selection_color;
Color font_color;
if (is_editable()) {
font_color = theme_cache.font_color;
} else {
font_color = theme_cache.font_uneditable_color;
}
Color font_selected_color = theme_cache.font_selected_color;
Color caret_color = theme_cache.caret_color;
// Draw placeholder color.
if (using_placeholder) {
font_color = get_theme_color(SNAME("font_placeholder_color"));
font_color = theme_cache.font_placeholder_color;
}
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon;
Color color_icon(1, 1, 1, !is_editable() ? .5 * .9 : .9);
if (display_clear_icon) {
if (clear_button_status.press_attempt && clear_button_status.pressing_inside) {
color_icon = get_theme_color(SNAME("clear_button_color_pressed"));
color_icon = theme_cache.clear_button_color_pressed;
} else {
color_icon = get_theme_color(SNAME("clear_button_color"));
color_icon = theme_cache.clear_button_color;
}
}
@ -879,8 +911,8 @@ void LineEdit::_notification(int p_what) {
// Draw text.
ofs.y += TS->shaped_text_get_ascent(text_rid);
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
Color font_outline_color = theme_cache.font_outline_color;
int outline_size = theme_cache.font_outline_size;
if (outline_size > 0 && font_outline_color.a > 0) {
Vector2 oofs = ofs;
for (int i = 0; i < gl_size; i++) {
@ -918,7 +950,7 @@ void LineEdit::_notification(int p_what) {
ofs.x = x_ofs + scroll_offset;
if (draw_caret || drag_caret_force_displayed) {
// Prevent carets from disappearing at theme scales below 1.0 (if the caret width is 1).
const int caret_width = get_theme_constant(SNAME("caret_width")) * MAX(1, get_theme_default_base_scale());
const int caret_width = theme_cache.caret_width * MAX(1, theme_cache.base_scale);
if (ime_text.length() == 0) {
// Normal caret.
@ -926,7 +958,7 @@ void LineEdit::_notification(int p_what) {
if (caret.l_caret == Rect2() && caret.t_caret == Rect2()) {
// No carets, add one at the start.
int h = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")));
int h = theme_cache.font->get_height(theme_cache.font_size);
int y = style->get_offset().y + (y_area - h) / 2;
if (rtl) {
caret.l_dir = TextServer::DIRECTION_RTL;
@ -1193,7 +1225,7 @@ void LineEdit::shift_selection_check_post(bool p_shift) {
}
void LineEdit::set_caret_at_pixel_pos(int p_x) {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@ -1226,7 +1258,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) {
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon;
if (alignment == HORIZONTAL_ALIGNMENT_CENTER) {
if (Math::is_zero_approx(scroll_offset)) {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
@ -1241,7 +1273,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) {
}
Vector2 LineEdit::get_caret_pixel_pos() {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@ -1274,7 +1306,7 @@ Vector2 LineEdit::get_caret_pixel_pos() {
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon;
if (alignment == HORIZONTAL_ALIGNMENT_CENTER) {
if (Math::is_zero_approx(scroll_offset)) {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
@ -1559,7 +1591,7 @@ void LineEdit::set_caret_column(int p_column) {
return;
}
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
bool rtl = is_layout_rtl();
int x_ofs = 0;
@ -1593,7 +1625,7 @@ void LineEdit::set_caret_column(int p_column) {
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon;
if (alignment == HORIZONTAL_ALIGNMENT_CENTER) {
if (Math::is_zero_approx(scroll_offset)) {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
@ -1664,15 +1696,15 @@ void LineEdit::clear_internal() {
}
Size2 LineEdit::get_minimum_size() const {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
Ref<StyleBox> style = theme_cache.normal;
Ref<Font> font = theme_cache.font;
int font_size = theme_cache.font_size;
Size2 min_size;
// Minimum size of text.
float em_space_size = font->get_char_size('M', font_size).x;
min_size.width = get_theme_constant(SNAME("minimum_character_width")) * em_space_size;
min_size.width = theme_cache.minimum_character_width * em_space_size;
if (expand_to_text_length) {
// Add a space because some fonts are too exact, and because caret needs a bit more when at the end.
@ -1688,9 +1720,8 @@ Size2 LineEdit::get_minimum_size() const {
icon_max_width = right_icon->get_width();
}
if (clear_button_enabled) {
Ref<Texture2D> clear_icon = Control::get_theme_icon(SNAME("clear"));
min_size.height = MAX(min_size.height, clear_icon->get_height());
icon_max_width = MAX(icon_max_width, clear_icon->get_width());
min_size.height = MAX(min_size.height, theme_cache.clear_icon->get_height());
icon_max_width = MAX(icon_max_width, theme_cache.clear_icon->get_width());
}
min_size.width += icon_max_width;
@ -2155,8 +2186,8 @@ void LineEdit::_shape() {
}
TS->shaped_text_set_preserve_control(text_rid, draw_control_chars);
const Ref<Font> &font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
const Ref<Font> &font = theme_cache.font;
int font_size = theme_cache.font_size;
ERR_FAIL_COND(font.is_null());
TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language);
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
@ -2176,12 +2207,12 @@ void LineEdit::_shape() {
void LineEdit::_fit_to_width() {
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
int t_width = get_size().width - style->get_margin(SIDE_RIGHT) - style->get_margin(SIDE_LEFT);
bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon;
t_width -= r_icon->get_width();
}
TS->shaped_text_fit_to_width(text_rid, MAX(t_width, full_width));

View file

@ -174,6 +174,31 @@ private:
double caret_blink_timer = 0.0;
bool caret_blinking = false;
struct ThemeCache {
Ref<StyleBox> normal;
Ref<StyleBox> read_only;
Ref<StyleBox> focus;
Ref<Font> font;
int font_size = 0;
Color font_color;
Color font_uneditable_color;
Color font_selected_color;
int font_outline_size;
Color font_outline_color;
Color font_placeholder_color;
int caret_width = 0;
Color caret_color;
int minimum_character_width = 0;
Color selection_color;
Ref<Texture2D> clear_icon;
Color clear_button_color;
Color clear_button_color_pressed;
int base_scale = 0;
} theme_cache;
bool _is_over_clear_button(const Point2 &p_pos) const;
void _clear_undo_stack();
@ -215,6 +240,7 @@ private:
void _ensure_menu();
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;

View file

@ -33,8 +33,8 @@
#include "core/string/translation.h"
void LinkButton::_shape() {
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
Ref<Font> font = theme_cache.font;
int font_size = theme_cache.font_size;
text_buf->clear();
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
@ -125,6 +125,26 @@ Size2 LinkButton::get_minimum_size() const {
return text_buf->get_size();
}
void LinkButton::_update_theme_item_cache() {
BaseButton::_update_theme_item_cache();
theme_cache.focus = get_theme_stylebox(SNAME("focus"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.underline_spacing = get_theme_constant(SNAME("underline_spacing"));
}
void LinkButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
@ -153,9 +173,9 @@ void LinkButton::_notification(int p_what) {
switch (get_draw_mode()) {
case DRAW_NORMAL: {
if (has_focus()) {
color = get_theme_color(SNAME("font_focus_color"));
color = theme_cache.font_focus_color;
} else {
color = get_theme_color(SNAME("font_color"));
color = theme_cache.font_color;
}
do_underline = underline_mode == UNDERLINE_MODE_ALWAYS;
@ -163,35 +183,35 @@ void LinkButton::_notification(int p_what) {
case DRAW_HOVER_PRESSED:
case DRAW_PRESSED: {
if (has_theme_color(SNAME("font_pressed_color"))) {
color = get_theme_color(SNAME("font_pressed_color"));
color = theme_cache.font_pressed_color;
} else {
color = get_theme_color(SNAME("font_color"));
color = theme_cache.font_color;
}
do_underline = underline_mode != UNDERLINE_MODE_NEVER;
} break;
case DRAW_HOVER: {
color = get_theme_color(SNAME("font_hover_color"));
color = theme_cache.font_hover_color;
do_underline = underline_mode != UNDERLINE_MODE_NEVER;
} break;
case DRAW_DISABLED: {
color = get_theme_color(SNAME("font_disabled_color"));
color = theme_cache.font_disabled_color;
do_underline = underline_mode == UNDERLINE_MODE_ALWAYS;
} break;
}
if (has_focus()) {
Ref<StyleBox> style = get_theme_stylebox(SNAME("focus"));
Ref<StyleBox> style = theme_cache.focus;
style->draw(ci, Rect2(Point2(), size));
}
int width = text_buf->get_line_width();
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
Color font_outline_color = theme_cache.font_outline_color;
int outline_size = theme_cache.outline_size;
if (is_layout_rtl()) {
if (outline_size > 0 && font_outline_color.a > 0) {
text_buf->draw_outline(get_canvas_item(), Vector2(size.width - width, 0), outline_size, font_outline_color);
@ -205,7 +225,7 @@ void LinkButton::_notification(int p_what) {
}
if (do_underline) {
int underline_spacing = get_theme_constant(SNAME("underline_spacing")) + text_buf->get_line_underline_position();
int underline_spacing = theme_cache.underline_spacing + text_buf->get_line_underline_position();
int y = text_buf->get_line_ascent() + underline_spacing;
if (is_layout_rtl()) {

View file

@ -55,10 +55,29 @@ private:
TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
Array st_args;
struct ThemeCache {
Ref<StyleBox> focus;
Color font_color;
Color font_focus_color;
Color font_pressed_color;
Color font_hover_color;
Color font_hover_pressed_color;
Color font_disabled_color;
Ref<Font> font;
int font_size = 0;
int outline_size = 0;
Color font_outline_color;
int underline_spacing = 0;
} theme_cache;
void _shape();
protected:
virtual Size2 get_minimum_size() const override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -30,12 +30,16 @@
#include "margin_container.h"
Size2 MarginContainer::get_minimum_size() const {
int margin_left = get_theme_constant(SNAME("margin_left"));
int margin_top = get_theme_constant(SNAME("margin_top"));
int margin_right = get_theme_constant(SNAME("margin_right"));
int margin_bottom = get_theme_constant(SNAME("margin_bottom"));
void MarginContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.margin_left = get_theme_constant(SNAME("margin_left"));
theme_cache.margin_top = get_theme_constant(SNAME("margin_top"));
theme_cache.margin_right = get_theme_constant(SNAME("margin_right"));
theme_cache.margin_bottom = get_theme_constant(SNAME("margin_bottom"));
}
Size2 MarginContainer::get_minimum_size() const {
Size2 max;
for (int i = 0; i < get_child_count(); i++) {
@ -59,8 +63,8 @@ Size2 MarginContainer::get_minimum_size() const {
}
}
max.width += (margin_left + margin_right);
max.height += (margin_top + margin_bottom);
max.width += (theme_cache.margin_left + theme_cache.margin_right);
max.height += (theme_cache.margin_top + theme_cache.margin_bottom);
return max;
}
@ -86,11 +90,6 @@ Vector<int> MarginContainer::get_allowed_size_flags_vertical() const {
void MarginContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
int margin_left = get_theme_constant(SNAME("margin_left"));
int margin_top = get_theme_constant(SNAME("margin_top"));
int margin_right = get_theme_constant(SNAME("margin_right"));
int margin_bottom = get_theme_constant(SNAME("margin_bottom"));
Size2 s = get_size();
for (int i = 0; i < get_child_count(); i++) {
@ -102,9 +101,9 @@ void MarginContainer::_notification(int p_what) {
continue;
}
int w = s.width - margin_left - margin_right;
int h = s.height - margin_top - margin_bottom;
fit_child_in_rect(c, Rect2(margin_left, margin_top, w, h));
int w = s.width - theme_cache.margin_left - theme_cache.margin_right;
int h = s.height - theme_cache.margin_top - theme_cache.margin_bottom;
fit_child_in_rect(c, Rect2(theme_cache.margin_left, theme_cache.margin_top, w, h));
}
} break;

View file

@ -36,7 +36,16 @@
class MarginContainer : public Container {
GDCLASS(MarginContainer, Container);
struct ThemeCache {
int margin_left = 0;
int margin_top = 0;
int margin_right = 0;
int margin_bottom = 0;
} theme_cache;
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
public:

View file

@ -340,6 +340,35 @@ void MenuBar::_update_menu() {
queue_redraw();
}
void MenuBar::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.normal = get_theme_stylebox(SNAME("normal"));
theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored"));
theme_cache.disabled = get_theme_stylebox(SNAME("disabled"));
theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored"));
theme_cache.pressed = get_theme_stylebox(SNAME("pressed"));
theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored"));
theme_cache.hover = get_theme_stylebox(SNAME("hover"));
theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored"));
theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed"));
theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
}
void MenuBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@ -394,8 +423,7 @@ void MenuBar::_notification(int p_what) {
}
int MenuBar::_get_index_at_point(const Point2 &p_point) const {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
int hsep = get_theme_constant(SNAME("h_separation"));
Ref<StyleBox> style = theme_cache.normal;
int offset = 0;
for (int i = 0; i < menu_cache.size(); i++) {
if (menu_cache[i].hidden) {
@ -407,7 +435,7 @@ int MenuBar::_get_index_at_point(const Point2 &p_point) const {
return i;
}
}
offset += size.x + hsep;
offset += size.x + theme_cache.h_separation;
}
return -1;
}
@ -415,8 +443,7 @@ int MenuBar::_get_index_at_point(const Point2 &p_point) const {
Rect2 MenuBar::_get_menu_item_rect(int p_index) const {
ERR_FAIL_INDEX_V(p_index, menu_cache.size(), Rect2());
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
int hsep = get_theme_constant(SNAME("h_separation"));
Ref<StyleBox> style = theme_cache.normal;
int offset = 0;
for (int i = 0; i < p_index; i++) {
@ -424,7 +451,7 @@ Rect2 MenuBar::_get_menu_item_rect(int p_index) const {
continue;
}
Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
offset += size.x + hsep;
offset += size.x + theme_cache.h_separation;
}
return Rect2(Point2(offset, 0), menu_cache[p_index].text_buf->get_size() + style->get_minimum_size());
@ -443,76 +470,76 @@ void MenuBar::_draw_menu_item(int p_index) {
}
Color color;
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
Rect2 item_rect = _get_menu_item_rect(p_index);
if (menu_cache[p_index].disabled) {
if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) {
style = get_theme_stylebox(SNAME("disabled_mirrored"));
style = theme_cache.disabled_mirrored;
} else {
style = get_theme_stylebox(SNAME("disabled"));
style = theme_cache.disabled;
}
if (!flat) {
style->draw(ci, item_rect);
}
color = get_theme_color(SNAME("font_disabled_color"));
color = theme_cache.font_disabled_color;
} else if (hovered && pressed && has_theme_stylebox("hover_pressed")) {
if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) {
style = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
style = theme_cache.hover_pressed_mirrored;
} else {
style = get_theme_stylebox(SNAME("hover_pressed"));
style = theme_cache.hover_pressed;
}
if (!flat) {
style->draw(ci, item_rect);
}
if (has_theme_color(SNAME("font_hover_pressed_color"))) {
color = get_theme_color(SNAME("font_hover_pressed_color"));
color = theme_cache.font_hover_pressed_color;
}
} else if (pressed) {
if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) {
style = get_theme_stylebox(SNAME("pressed_mirrored"));
style = theme_cache.pressed_mirrored;
} else {
style = get_theme_stylebox(SNAME("pressed"));
style = theme_cache.pressed;
}
if (!flat) {
style->draw(ci, item_rect);
}
if (has_theme_color(SNAME("font_pressed_color"))) {
color = get_theme_color(SNAME("font_pressed_color"));
color = theme_cache.font_pressed_color;
} else {
color = get_theme_color(SNAME("font_color"));
color = theme_cache.font_color;
}
} else if (hovered) {
if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) {
style = get_theme_stylebox(SNAME("hover_mirrored"));
style = theme_cache.hover_mirrored;
} else {
style = get_theme_stylebox(SNAME("hover"));
style = theme_cache.hover;
}
if (!flat) {
style->draw(ci, item_rect);
}
color = get_theme_color(SNAME("font_hover_color"));
color = theme_cache.font_hover_color;
} else {
if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) {
style = get_theme_stylebox(SNAME("normal_mirrored"));
style = theme_cache.normal_mirrored;
} else {
style = get_theme_stylebox(SNAME("normal"));
style = theme_cache.normal;
}
if (!flat) {
style->draw(ci, item_rect);
}
// Focus colors only take precedence over normal state.
if (has_focus()) {
color = get_theme_color(SNAME("font_focus_color"));
color = theme_cache.font_focus_color;
} else {
color = get_theme_color(SNAME("font_color"));
color = theme_cache.font_color;
}
}
Point2 text_ofs = item_rect.position + Point2(style->get_margin(SIDE_LEFT), style->get_margin(SIDE_TOP));
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
Color font_outline_color = theme_cache.font_outline_color;
int outline_size = theme_cache.outline_size;
if (outline_size > 0 && font_outline_color.a > 0) {
menu_cache[p_index].text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color);
}
@ -520,16 +547,13 @@ void MenuBar::_draw_menu_item(int p_index) {
}
void MenuBar::shape(Menu &p_menu) {
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
p_menu.text_buf->clear();
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
p_menu.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
} else {
p_menu.text_buf->set_direction((TextServer::Direction)text_direction);
}
p_menu.text_buf->add_string(p_menu.name, font, font_size, language);
p_menu.text_buf->add_string(p_menu.name, theme_cache.font, theme_cache.font_size, language);
}
void MenuBar::_refresh_menu_names() {
@ -759,7 +783,7 @@ Size2 MenuBar::get_minimum_size() const {
return Size2();
}
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
Ref<StyleBox> style = theme_cache.normal;
Vector2 size;
for (int i = 0; i < menu_cache.size(); i++) {
@ -771,7 +795,7 @@ Size2 MenuBar::get_minimum_size() const {
size.x += sz.x;
}
if (menu_cache.size() > 1) {
size.x += get_theme_constant(SNAME("h_separation")) * (menu_cache.size() - 1);
size.x += theme_cache.h_separation * (menu_cache.size() - 1);
}
return size;
}

View file

@ -76,6 +76,33 @@ class MenuBar : public Control {
Vector2i old_mouse_pos;
ObjectID shortcut_context;
struct ThemeCache {
Ref<StyleBox> normal;
Ref<StyleBox> normal_mirrored;
Ref<StyleBox> disabled;
Ref<StyleBox> disabled_mirrored;
Ref<StyleBox> pressed;
Ref<StyleBox> pressed_mirrored;
Ref<StyleBox> hover;
Ref<StyleBox> hover_mirrored;
Ref<StyleBox> hover_pressed;
Ref<StyleBox> hover_pressed_mirrored;
Ref<Font> font;
int font_size = 0;
int outline_size = 0;
Color font_outline_color;
Color font_color;
Color font_disabled_color;
Color font_pressed_color;
Color font_hover_color;
Color font_hover_pressed_color;
Color font_focus_color;
int h_separation = 0;
} theme_cache;
int _get_index_at_point(const Point2 &p_point) const;
Rect2 _get_menu_item_rect(int p_index) const;
void _draw_menu_item(int p_index);
@ -96,6 +123,7 @@ class MenuBar : public Control {
protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;

View file

@ -43,11 +43,11 @@ Size2 OptionButton::get_minimum_size() const {
}
if (has_theme_icon(SNAME("arrow"))) {
const Size2 padding = get_theme_stylebox(SNAME("normal"))->get_minimum_size();
const Size2 arrow_size = Control::get_theme_icon(SNAME("arrow"))->get_size();
const Size2 padding = theme_cache.normal->get_minimum_size();
const Size2 arrow_size = theme_cache.arrow_icon->get_size();
Size2 content_size = minsize - padding;
content_size.width += arrow_size.width + MAX(0, get_theme_constant(SNAME("h_separation")));
content_size.width += arrow_size.width + MAX(0, theme_cache.h_separation);
content_size.height = MAX(content_size.height, arrow_size.height);
minsize = content_size + padding;
@ -56,35 +56,63 @@ Size2 OptionButton::get_minimum_size() const {
return minsize;
}
void OptionButton::_update_theme_item_cache() {
Button::_update_theme_item_cache();
theme_cache.normal = get_theme_stylebox(SNAME("normal"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.arrow_icon = get_theme_icon(SNAME("arrow"));
theme_cache.arrow_margin = get_theme_constant(SNAME("arrow_margin"));
theme_cache.modulate_arrow = get_theme_constant(SNAME("modulate_arrow"));
}
void OptionButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POSTINITIALIZE: {
if (has_theme_icon(SNAME("arrow"))) {
if (is_layout_rtl()) {
_set_internal_margin(SIDE_LEFT, theme_cache.arrow_icon->get_width());
} else {
_set_internal_margin(SIDE_RIGHT, theme_cache.arrow_icon->get_width());
}
}
} break;
case NOTIFICATION_DRAW: {
if (!has_theme_icon(SNAME("arrow"))) {
return;
}
RID ci = get_canvas_item();
Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow"));
Color clr = Color(1, 1, 1);
if (get_theme_constant(SNAME("modulate_arrow"))) {
if (theme_cache.modulate_arrow) {
switch (get_draw_mode()) {
case DRAW_PRESSED:
clr = get_theme_color(SNAME("font_pressed_color"));
clr = theme_cache.font_pressed_color;
break;
case DRAW_HOVER:
clr = get_theme_color(SNAME("font_hover_color"));
clr = theme_cache.font_hover_color;
break;
case DRAW_HOVER_PRESSED:
clr = get_theme_color(SNAME("font_hover_pressed_color"));
clr = theme_cache.font_hover_pressed_color;
break;
case DRAW_DISABLED:
clr = get_theme_color(SNAME("font_disabled_color"));
clr = theme_cache.font_disabled_color;
break;
default:
if (has_focus()) {
clr = get_theme_color(SNAME("font_focus_color"));
clr = theme_cache.font_focus_color;
} else {
clr = get_theme_color(SNAME("font_color"));
clr = theme_cache.font_color;
}
}
}
@ -93,11 +121,11 @@ void OptionButton::_notification(int p_what) {
Point2 ofs;
if (is_layout_rtl()) {
ofs = Point2(get_theme_constant(SNAME("arrow_margin")), int(Math::abs((size.height - arrow->get_height()) / 2)));
ofs = Point2(theme_cache.arrow_margin, int(Math::abs((size.height - theme_cache.arrow_icon->get_height()) / 2)));
} else {
ofs = Point2(size.width - arrow->get_width() - get_theme_constant(SNAME("arrow_margin")), int(Math::abs((size.height - arrow->get_height()) / 2)));
ofs = Point2(size.width - theme_cache.arrow_icon->get_width() - theme_cache.arrow_margin, int(Math::abs((size.height - theme_cache.arrow_icon->get_height()) / 2)));
}
arrow->draw(ci, ofs, clr);
theme_cache.arrow_icon->draw(ci, ofs, clr);
} break;
case NOTIFICATION_TRANSLATION_CHANGED:
@ -108,11 +136,11 @@ void OptionButton::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
if (has_theme_icon(SNAME("arrow"))) {
if (is_layout_rtl()) {
_set_internal_margin(SIDE_LEFT, Control::get_theme_icon(SNAME("arrow"))->get_width());
_set_internal_margin(SIDE_LEFT, theme_cache.arrow_icon->get_width());
_set_internal_margin(SIDE_RIGHT, 0.f);
} else {
_set_internal_margin(SIDE_LEFT, 0.f);
_set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width());
_set_internal_margin(SIDE_RIGHT, theme_cache.arrow_icon->get_width());
}
}
_refresh_size_cache();
@ -540,15 +568,6 @@ OptionButton::OptionButton(const String &p_text) :
Button(p_text) {
set_toggle_mode(true);
set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
if (is_layout_rtl()) {
if (has_theme_icon(SNAME("arrow"))) {
_set_internal_margin(SIDE_LEFT, Control::get_theme_icon(SNAME("arrow"))->get_width());
}
} else {
if (has_theme_icon(SNAME("arrow"))) {
_set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width());
}
}
set_action_mode(ACTION_MODE_BUTTON_PRESS);
popup = memnew(PopupMenu);

View file

@ -43,6 +43,23 @@ class OptionButton : public Button {
Vector2 _cached_size;
bool cache_refresh_pending = false;
struct ThemeCache {
Ref<StyleBox> normal;
Color font_color;
Color font_focus_color;
Color font_pressed_color;
Color font_hover_color;
Color font_hover_pressed_color;
Color font_disabled_color;
int h_separation = 0;
Ref<Texture2D> arrow_icon;
int arrow_margin = 0;
int modulate_arrow = 0;
} theme_cache;
void _focused(int p_which);
void _selected(int p_which);
void _select(int p_which, bool p_emit = false);
@ -54,6 +71,7 @@ class OptionButton : public Button {
protected:
Size2 get_minimum_size() const override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;

View file

@ -30,12 +30,17 @@
#include "panel.h"
void Panel::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
}
void Panel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
style->draw(ci, Rect2(Point2(), get_size()));
theme_cache.panel_style->draw(ci, Rect2(Point2(), get_size()));
} break;
}
}

View file

@ -36,7 +36,13 @@
class Panel : public Control {
GDCLASS(Panel, Control);
struct ThemeCache {
Ref<StyleBox> panel_style;
} theme_cache;
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
public:

View file

@ -31,14 +31,6 @@
#include "panel_container.h"
Size2 PanelContainer::get_minimum_size() const {
Ref<StyleBox> style;
if (has_theme_stylebox(SNAME("panel"))) {
style = get_theme_stylebox(SNAME("panel"));
} else {
style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer"));
}
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@ -54,8 +46,8 @@ Size2 PanelContainer::get_minimum_size() const {
ms.height = MAX(ms.height, minsize.height);
}
if (style.is_valid()) {
ms += style->get_minimum_size();
if (theme_cache.panel_style.is_valid()) {
ms += theme_cache.panel_style->get_minimum_size();
}
return ms;
}
@ -78,35 +70,25 @@ Vector<int> PanelContainer::get_allowed_size_flags_vertical() const {
return flags;
}
void PanelContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
}
void PanelContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Ref<StyleBox> style;
if (has_theme_stylebox(SNAME("panel"))) {
style = get_theme_stylebox(SNAME("panel"));
} else {
style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer"));
}
style->draw(ci, Rect2(Point2(), get_size()));
theme_cache.panel_style->draw(ci, Rect2(Point2(), get_size()));
} break;
case NOTIFICATION_SORT_CHILDREN: {
Ref<StyleBox> style;
if (has_theme_stylebox(SNAME("panel"))) {
style = get_theme_stylebox(SNAME("panel"));
} else {
style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer"));
}
Size2 size = get_size();
Point2 ofs;
if (style.is_valid()) {
size -= style->get_minimum_size();
ofs += style->get_offset();
if (theme_cache.panel_style.is_valid()) {
size -= theme_cache.panel_style->get_minimum_size();
ofs += theme_cache.panel_style->get_offset();
}
for (int i = 0; i < get_child_count(); i++) {

View file

@ -36,7 +36,12 @@
class PanelContainer : public Container {
GDCLASS(PanelContainer, Container);
struct ThemeCache {
Ref<StyleBox> panel_style;
} theme_cache;
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
public:

View file

@ -33,18 +33,13 @@
#include "scene/resources/text_line.h"
Size2 ProgressBar::get_minimum_size() const {
Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg"));
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
Size2 minimum_size = bg->get_minimum_size();
minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height);
minimum_size.width = MAX(minimum_size.width, fg->get_minimum_size().width);
Size2 minimum_size = theme_cache.bg_style->get_minimum_size();
minimum_size.height = MAX(minimum_size.height, theme_cache.fg_style->get_minimum_size().height);
minimum_size.width = MAX(minimum_size.width, theme_cache.fg_style->get_minimum_size().width);
if (percent_visible) {
String txt = "100%";
TextLine tl = TextLine(txt, font, font_size);
minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + tl.get_size().y);
TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
minimum_size.height = MAX(minimum_size.height, theme_cache.bg_style->get_minimum_size().height + tl.get_size().y);
} else { // this is needed, else the progressbar will collapse
minimum_size.width = MAX(minimum_size.width, 1);
minimum_size.height = MAX(minimum_size.height, 1);
@ -52,23 +47,30 @@ Size2 ProgressBar::get_minimum_size() const {
return minimum_size;
}
void ProgressBar::_update_theme_item_cache() {
Range::_update_theme_item_cache();
theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
theme_cache.fg_style = get_theme_stylebox(SNAME("fg"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
}
void ProgressBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"));
Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg"));
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
Color font_color = get_theme_color(SNAME("font_color"));
draw_style_box(bg, Rect2(Point2(), get_size()));
draw_style_box(theme_cache.bg_style, Rect2(Point2(), get_size()));
float r = get_as_ratio();
switch (mode) {
case FILL_BEGIN_TO_END:
case FILL_END_TO_BEGIN: {
int mp = fg->get_minimum_size().width;
int mp = theme_cache.fg_style->get_minimum_size().width;
int p = round(r * (get_size().width - mp));
// We want FILL_BEGIN_TO_END to map to right to left when UI layout is RTL,
// and left to right otherwise. And likewise for FILL_END_TO_BEGIN.
@ -76,23 +78,23 @@ void ProgressBar::_notification(int p_what) {
if (p > 0) {
if (right_to_left) {
int p_remaining = round((1.0 - r) * (get_size().width - mp));
draw_style_box(fg, Rect2(Point2(p_remaining, 0), Size2(p + fg->get_minimum_size().width, get_size().height)));
draw_style_box(theme_cache.fg_style, Rect2(Point2(p_remaining, 0), Size2(p + theme_cache.fg_style->get_minimum_size().width, get_size().height)));
} else {
draw_style_box(fg, Rect2(Point2(0, 0), Size2(p + fg->get_minimum_size().width, get_size().height)));
draw_style_box(theme_cache.fg_style, Rect2(Point2(0, 0), Size2(p + theme_cache.fg_style->get_minimum_size().width, get_size().height)));
}
}
} break;
case FILL_TOP_TO_BOTTOM:
case FILL_BOTTOM_TO_TOP: {
int mp = fg->get_minimum_size().height;
int mp = theme_cache.fg_style->get_minimum_size().height;
int p = round(r * (get_size().height - mp));
if (p > 0) {
if (mode == FILL_TOP_TO_BOTTOM) {
draw_style_box(fg, Rect2(Point2(0, 0), Size2(get_size().width, p + fg->get_minimum_size().height)));
draw_style_box(theme_cache.fg_style, Rect2(Point2(0, 0), Size2(get_size().width, p + theme_cache.fg_style->get_minimum_size().height)));
} else {
int p_remaining = round((1.0 - r) * (get_size().height - mp));
draw_style_box(fg, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + fg->get_minimum_size().height)));
draw_style_box(theme_cache.fg_style, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + theme_cache.fg_style->get_minimum_size().height)));
}
}
} break;
@ -102,14 +104,14 @@ void ProgressBar::_notification(int p_what) {
if (percent_visible) {
String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign();
TextLine tl = TextLine(txt, font, font_size);
TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size);
Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round();
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
if (outline_size > 0 && font_outline_color.a > 0) {
tl.draw_outline(get_canvas_item(), text_pos, outline_size, font_outline_color);
if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
tl.draw_outline(get_canvas_item(), text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
tl.draw(get_canvas_item(), text_pos, font_color);
tl.draw(get_canvas_item(), text_pos, theme_cache.font_color);
}
} break;
}

View file

@ -38,7 +38,20 @@ class ProgressBar : public Range {
bool percent_visible = true;
struct ThemeCache {
Ref<StyleBox> bg_style;
Ref<StyleBox> fg_style;
Ref<Font> font;
int font_size = 0;
Color font_color;
int font_outline_size = 0;
Color font_outline_color;
} theme_cache;
protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -70,8 +70,8 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
if (b->is_pressed()) {
double ofs = orientation == VERTICAL ? b->get_position().y : b->get_position().x;
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = theme_cache.decrement_icon;
Ref<Texture2D> incr = theme_cache.increment_icon;
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width();
@ -146,7 +146,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
if (drag.active) {
double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x;
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
Ref<Texture2D> decr = theme_cache.decrement_icon;
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
ofs -= decr_size;
@ -156,8 +156,8 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
set_as_ratio(drag.value_at_click + diff);
} else {
double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x;
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = theme_cache.decrement_icon;
Ref<Texture2D> incr = theme_cache.increment_icon;
double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width();
double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width();
@ -217,6 +217,24 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
void ScrollBar::_update_theme_item_cache() {
Range::_update_theme_item_cache();
theme_cache.scroll_style = get_theme_stylebox(SNAME("scroll"));
theme_cache.scroll_focus_style = get_theme_stylebox(SNAME("scroll_focus"));
theme_cache.scroll_offset_style = get_theme_stylebox(SNAME("hscroll"));
theme_cache.grabber_style = get_theme_stylebox(SNAME("grabber"));
theme_cache.grabber_hl_style = get_theme_stylebox(SNAME("grabber_highlight"));
theme_cache.grabber_pressed_style = get_theme_stylebox(SNAME("grabber_pressed"));
theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
theme_cache.increment_pressed_icon = get_theme_icon(SNAME("increment_pressed"));
theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
theme_cache.decrement_pressed_icon = get_theme_icon(SNAME("decrement_pressed"));
}
void ScrollBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@ -225,30 +243,30 @@ void ScrollBar::_notification(int p_what) {
Ref<Texture2D> decr, incr;
if (decr_active) {
decr = get_theme_icon(SNAME("decrement_pressed"));
decr = theme_cache.decrement_pressed_icon;
} else if (highlight == HIGHLIGHT_DECR) {
decr = get_theme_icon(SNAME("decrement_highlight"));
decr = theme_cache.decrement_hl_icon;
} else {
decr = get_theme_icon(SNAME("decrement"));
decr = theme_cache.decrement_icon;
}
if (incr_active) {
incr = get_theme_icon(SNAME("increment_pressed"));
incr = theme_cache.increment_pressed_icon;
} else if (highlight == HIGHLIGHT_INCR) {
incr = get_theme_icon(SNAME("increment_highlight"));
incr = theme_cache.increment_hl_icon;
} else {
incr = get_theme_icon(SNAME("increment"));
incr = theme_cache.increment_icon;
}
Ref<StyleBox> bg = has_focus() ? get_theme_stylebox(SNAME("scroll_focus")) : get_theme_stylebox(SNAME("scroll"));
Ref<StyleBox> bg = has_focus() ? theme_cache.scroll_focus_style : theme_cache.scroll_style;
Ref<StyleBox> grabber;
if (drag.active) {
grabber = get_theme_stylebox(SNAME("grabber_pressed"));
grabber = theme_cache.grabber_pressed_style;
} else if (highlight == HIGHLIGHT_RANGE) {
grabber = get_theme_stylebox(SNAME("grabber_highlight"));
grabber = theme_cache.grabber_hl_style;
} else {
grabber = get_theme_stylebox(SNAME("grabber"));
grabber = theme_cache.grabber_style;
}
Point2 ofs;
@ -414,7 +432,7 @@ void ScrollBar::_notification(int p_what) {
}
double ScrollBar::get_grabber_min_size() const {
Ref<StyleBox> grabber = get_theme_stylebox(SNAME("grabber"));
Ref<StyleBox> grabber = theme_cache.grabber_style;
Size2 gminsize = grabber->get_minimum_size() + grabber->get_center_size();
return (orientation == VERTICAL) ? gminsize.height : gminsize.width;
}
@ -435,17 +453,17 @@ double ScrollBar::get_area_size() const {
switch (orientation) {
case VERTICAL: {
double area = get_size().height;
area -= get_theme_stylebox(SNAME("scroll"))->get_minimum_size().height;
area -= get_theme_icon(SNAME("increment"))->get_height();
area -= get_theme_icon(SNAME("decrement"))->get_height();
area -= theme_cache.scroll_style->get_minimum_size().height;
area -= theme_cache.increment_icon->get_height();
area -= theme_cache.decrement_icon->get_height();
area -= get_grabber_min_size();
return area;
} break;
case HORIZONTAL: {
double area = get_size().width;
area -= get_theme_stylebox(SNAME("scroll"))->get_minimum_size().width;
area -= get_theme_icon(SNAME("increment"))->get_width();
area -= get_theme_icon(SNAME("decrement"))->get_width();
area -= theme_cache.scroll_style->get_minimum_size().width;
area -= theme_cache.increment_icon->get_width();
area -= theme_cache.decrement_icon->get_width();
area -= get_grabber_min_size();
return area;
} break;
@ -459,13 +477,13 @@ double ScrollBar::get_area_offset() const {
double ofs = 0.0;
if (orientation == VERTICAL) {
ofs += get_theme_stylebox(SNAME("hscroll"))->get_margin(SIDE_TOP);
ofs += get_theme_icon(SNAME("decrement"))->get_height();
ofs += theme_cache.scroll_offset_style->get_margin(SIDE_TOP);
ofs += theme_cache.decrement_icon->get_height();
}
if (orientation == HORIZONTAL) {
ofs += get_theme_stylebox(SNAME("hscroll"))->get_margin(SIDE_LEFT);
ofs += get_theme_icon(SNAME("decrement"))->get_width();
ofs += theme_cache.scroll_offset_style->get_margin(SIDE_LEFT);
ofs += theme_cache.decrement_icon->get_width();
}
return ofs;
@ -476,9 +494,9 @@ double ScrollBar::get_grabber_offset() const {
}
Size2 ScrollBar::get_minimum_size() const {
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
Ref<StyleBox> bg = get_theme_stylebox(SNAME("scroll"));
Ref<Texture2D> incr = theme_cache.increment_icon;
Ref<Texture2D> decr = theme_cache.decrement_icon;
Ref<StyleBox> bg = theme_cache.scroll_style;
Size2 minsize;
if (orientation == VERTICAL) {

View file

@ -86,14 +86,31 @@ class ScrollBar : public Range {
double target_scroll = 0.0;
bool smooth_scroll_enabled = false;
struct ThemeCache {
Ref<StyleBox> scroll_style;
Ref<StyleBox> scroll_focus_style;
Ref<StyleBox> scroll_offset_style;
Ref<StyleBox> grabber_style;
Ref<StyleBox> grabber_hl_style;
Ref<StyleBox> grabber_pressed_style;
Ref<Texture2D> increment_icon;
Ref<Texture2D> increment_hl_icon;
Ref<Texture2D> increment_pressed_icon;
Ref<Texture2D> decrement_icon;
Ref<Texture2D> decrement_hl_icon;
Ref<Texture2D> decrement_pressed_icon;
} theme_cache;
void _drag_node_exit();
void _drag_node_input(const Ref<InputEvent> &p_input);
virtual void gui_input(const Ref<InputEvent> &p_event) override;
protected:
void _notification(int p_what);
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
public:

View file

@ -35,7 +35,6 @@
#include "scene/main/window.h"
Size2 ScrollContainer::get_minimum_size() const {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
Size2 min_size;
// Calculated in this function, as it needs to traverse all child controls once to calculate;
@ -77,10 +76,16 @@ Size2 ScrollContainer::get_minimum_size() const {
min_size.x += v_scroll->get_minimum_size().x;
}
min_size += sb->get_minimum_size();
min_size += theme_cache.bg_style->get_minimum_size();
return min_size;
}
void ScrollContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.bg_style = get_theme_stylebox(SNAME("bg"));
}
void ScrollContainer::_cancel_drag() {
set_physics_process_internal(false);
drag_touching_deaccel = false;
@ -271,9 +276,8 @@ void ScrollContainer::_reposition_children() {
Size2 size = get_size();
Point2 ofs;
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
size -= sb->get_minimum_size();
ofs += sb->get_offset();
size -= theme_cache.bg_style->get_minimum_size();
ofs += theme_cache.bg_style->get_offset();
bool rtl = is_layout_rtl();
if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons
@ -337,8 +341,7 @@ void ScrollContainer::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
draw_style_box(sb, Rect2(Vector2(), get_size()));
draw_style_box(theme_cache.bg_style, Rect2(Vector2(), get_size()));
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@ -413,8 +416,7 @@ void ScrollContainer::_notification(int p_what) {
void ScrollContainer::update_scrollbars() {
Size2 size = get_size();
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
size -= sb->get_minimum_size();
size -= theme_cache.bg_style->get_minimum_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();

View file

@ -69,9 +69,14 @@ private:
int deadzone = 0;
bool follow_focus = false;
struct ThemeCache {
Ref<StyleBox> bg_style;
} theme_cache;
void _cancel_drag();
protected:
virtual void _update_theme_item_cache() override;
Size2 get_minimum_size() const override;
void _gui_focus_changed(Control *p_control);

View file

@ -33,24 +33,30 @@
Size2 Separator::get_minimum_size() const {
Size2 ms(3, 3);
if (orientation == VERTICAL) {
ms.x = get_theme_constant(SNAME("separation"));
ms.x = theme_cache.separation;
} else { // HORIZONTAL
ms.y = get_theme_constant(SNAME("separation"));
ms.y = theme_cache.separation;
}
return ms;
}
void Separator::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.separation = get_theme_constant(SNAME("separation"));
theme_cache.separator_style = get_theme_stylebox(SNAME("separator"));
}
void Separator::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
Size2i size = get_size();
Ref<StyleBox> style = get_theme_stylebox(SNAME("separator"));
Size2i ssize = style->get_minimum_size() + style->get_center_size();
Size2i ssize = theme_cache.separator_style->get_minimum_size() + theme_cache.separator_style->get_center_size();
if (orientation == VERTICAL) {
style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y));
theme_cache.separator_style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y));
} else {
style->draw(get_canvas_item(), Rect2(0, (size.y - ssize.y) / 2, size.x, ssize.y));
theme_cache.separator_style->draw(get_canvas_item(), Rect2(0, (size.y - ssize.y) / 2, size.x, ssize.y));
}
} break;
}

View file

@ -35,8 +35,16 @@
class Separator : public Control {
GDCLASS(Separator, Control);
struct ThemeCache {
int separation = 0;
Ref<StyleBox> separator_style;
} theme_cache;
protected:
Orientation orientation = Orientation::HORIZONTAL;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
public:

View file

@ -33,11 +33,8 @@
#include "core/os/keyboard.h"
Size2 Slider::get_minimum_size() const {
Ref<StyleBox> style = get_theme_stylebox(SNAME("slider"));
Size2i ss = style->get_minimum_size() + style->get_center_size();
Ref<Texture2D> grabber = get_theme_icon(SNAME("grabber"));
Size2i rs = grabber->get_size();
Size2i ss = theme_cache.slider_style->get_minimum_size() + theme_cache.slider_style->get_center_size();
Size2i rs = theme_cache.grabber_icon->get_size();
if (orientation == HORIZONTAL) {
return Size2i(ss.width, MAX(ss.height, rs.height));
@ -58,7 +55,13 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
Ref<Texture2D> grabber = get_theme_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber");
Ref<Texture2D> grabber;
if (mouse_inside || has_focus()) {
grabber = theme_cache.grabber_hl_icon;
} else {
grabber = theme_cache.grabber_icon;
}
grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x;
double grab_width = (double)grabber->get_size().width;
@ -95,7 +98,7 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
if (grab.active) {
Size2i size = get_size();
Ref<Texture2D> grabber = get_theme_icon(SNAME("grabber"));
Ref<Texture2D> grabber = theme_cache.grabber_icon;
double motion = (orientation == VERTICAL ? mm->get_position().y : mm->get_position().x) - grab.pos;
if (orientation == VERTICAL) {
motion = -motion;
@ -145,6 +148,19 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
}
}
void Slider::_update_theme_item_cache() {
Range::_update_theme_item_cache();
theme_cache.slider_style = get_theme_stylebox(SNAME("slider"));
theme_cache.grabber_area_style = get_theme_stylebox(SNAME("grabber_area"));
theme_cache.grabber_area_hl_style = get_theme_stylebox(SNAME("grabber_area_highlight"));
theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
theme_cache.grabber_hl_icon = get_theme_icon(SNAME("grabber_highlight"));
theme_cache.grabber_disabled_icon = get_theme_icon(SNAME("grabber_disabled"));
theme_cache.tick_icon = get_theme_icon(SNAME("tick"));
}
void Slider::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
@ -171,13 +187,30 @@ void Slider::_notification(int p_what) {
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
Size2i size = get_size();
Ref<StyleBox> style = get_theme_stylebox(SNAME("slider"));
bool highlighted = mouse_inside || has_focus();
Ref<StyleBox> grabber_area = get_theme_stylebox(highlighted ? "grabber_area_highlight" : "grabber_area");
Ref<Texture2D> grabber = get_theme_icon(editable ? (highlighted ? "grabber_highlight" : "grabber") : "grabber_disabled");
Ref<Texture2D> tick = get_theme_icon(SNAME("tick"));
double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio();
Ref<StyleBox> style = theme_cache.slider_style;
Ref<Texture2D> tick = theme_cache.tick_icon;
bool highlighted = mouse_inside || has_focus();
Ref<Texture2D> grabber;
if (editable) {
if (highlighted) {
grabber = theme_cache.grabber_hl_icon;
} else {
grabber = theme_cache.grabber_icon;
}
} else {
grabber = theme_cache.grabber_disabled_icon;
}
Ref<StyleBox> grabber_area;
if (highlighted) {
grabber_area = theme_cache.grabber_area_hl_style;
} else {
grabber_area = theme_cache.grabber_area_style;
}
if (orientation == VERTICAL) {
int widget_width = style->get_minimum_size().width + style->get_center_size().width;
double areasize = size.height - grabber->get_size().height;

View file

@ -49,11 +49,24 @@ class Slider : public Range {
bool editable = true;
bool scrollable = true;
struct ThemeCache {
Ref<StyleBox> slider_style;
Ref<StyleBox> grabber_area_style;
Ref<StyleBox> grabber_area_hl_style;
Ref<Texture2D> grabber_icon;
Ref<Texture2D> grabber_hl_icon;
Ref<Texture2D> grabber_disabled_icon;
Ref<Texture2D> tick_icon;
} theme_cache;
protected:
bool ticks_on_borders = false;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
bool ticks_on_borders = false;
public:
virtual Size2 get_minimum_size() const override;

View file

@ -210,25 +210,29 @@ inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) {
}
}
void SpinBox::_update_theme_item_cache() {
Range::_update_theme_item_cache();
theme_cache.updown_icon = get_theme_icon(SNAME("updown"));
}
void SpinBox::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
Ref<Texture2D> updown = get_theme_icon(SNAME("updown"));
_adjust_width_for_icon(updown);
_adjust_width_for_icon(theme_cache.updown_icon);
RID ci = get_canvas_item();
Size2i size = get_size();
if (is_layout_rtl()) {
updown->draw(ci, Point2i(0, (size.height - updown->get_height()) / 2));
theme_cache.updown_icon->draw(ci, Point2i(0, (size.height - theme_cache.updown_icon->get_height()) / 2));
} else {
updown->draw(ci, Point2i(size.width - updown->get_width(), (size.height - updown->get_height()) / 2));
theme_cache.updown_icon->draw(ci, Point2i(size.width - theme_cache.updown_icon->get_width(), (size.height - theme_cache.updown_icon->get_height()) / 2));
}
} break;
case NOTIFICATION_ENTER_TREE: {
_adjust_width_for_icon(get_theme_icon(SNAME("updown")));
_adjust_width_for_icon(theme_cache.updown_icon);
_value_changed(0);
} break;

View file

@ -69,9 +69,14 @@ class SpinBox : public Range {
inline void _adjust_width_for_icon(const Ref<Texture2D> &icon);
struct ThemeCache {
Ref<Texture2D> updown_icon;
} theme_cache;
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -76,9 +76,7 @@ void SplitContainer::_resort() {
bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
// Determine the separation between items
Ref<Texture2D> g = get_theme_icon(SNAME("grabber"));
int sep = get_theme_constant(SNAME("separation"));
sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? theme_cache.grabber_icon->get_height() : theme_cache.grabber_icon->get_width()) : 0;
// Compute the minimum size
Size2 ms_first = first->get_combined_minimum_size();
@ -131,9 +129,7 @@ Size2 SplitContainer::get_minimum_size() const {
/* Calculate MINIMUM SIZE */
Size2i minimum;
Ref<Texture2D> g = get_theme_icon(SNAME("grabber"));
int sep = get_theme_constant(SNAME("separation"));
sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? theme_cache.grabber_icon->get_height() : theme_cache.grabber_icon->get_width()) : 0;
for (int i = 0; i < 2; i++) {
if (!_getch(i)) {
@ -162,6 +158,14 @@ Size2 SplitContainer::get_minimum_size() const {
return minimum;
}
void SplitContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.separation = get_theme_constant(SNAME("separation"));
theme_cache.autohide = get_theme_constant(SNAME("autohide"));
theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
}
void SplitContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
@ -175,7 +179,7 @@ void SplitContainer::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
mouse_inside = false;
if (get_theme_constant(SNAME("autohide"))) {
if (theme_cache.autohide) {
queue_redraw();
}
} break;
@ -185,7 +189,7 @@ void SplitContainer::_notification(int p_what) {
return;
}
if (collapsed || (!dragging && !mouse_inside && get_theme_constant(SNAME("autohide")))) {
if (collapsed || (!dragging && !mouse_inside && theme_cache.autohide)) {
return;
}
@ -193,8 +197,8 @@ void SplitContainer::_notification(int p_what) {
return;
}
int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_theme_constant(SNAME("separation")) : 0;
Ref<Texture2D> tex = get_theme_icon(SNAME("grabber"));
int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? theme_cache.separation : 0;
Ref<Texture2D> tex = theme_cache.grabber_icon;
Size2 size = get_size();
if (vertical) {
@ -222,16 +226,14 @@ void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
int sep = get_theme_constant(SNAME("separation"));
if (vertical) {
if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + sep) {
if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + theme_cache.separation) {
dragging = true;
drag_from = mb->get_position().y;
drag_ofs = split_offset;
}
} else {
if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + sep) {
if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + theme_cache.separation) {
dragging = true;
drag_from = mb->get_position().x;
drag_ofs = split_offset;
@ -248,14 +250,14 @@ void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) {
bool mouse_inside_state = false;
if (vertical) {
mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_theme_constant(SNAME("separation"));
mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + theme_cache.separation;
} else {
mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_theme_constant(SNAME("separation"));
mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + theme_cache.separation;
}
if (mouse_inside != mouse_inside_state) {
mouse_inside = mouse_inside_state;
if (get_theme_constant(SNAME("autohide"))) {
if (theme_cache.autohide) {
queue_redraw();
}
}
@ -281,14 +283,12 @@ Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const
}
if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) {
int sep = get_theme_constant(SNAME("separation"));
if (vertical) {
if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) {
if (p_pos.y > middle_sep && p_pos.y < middle_sep + theme_cache.separation) {
return CURSOR_VSPLIT;
}
} else {
if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) {
if (p_pos.x > middle_sep && p_pos.x < middle_sep + theme_cache.separation) {
return CURSOR_HSPLIT;
}
}

View file

@ -55,12 +55,20 @@ private:
DraggerVisibility dragger_visibility = DRAGGER_VISIBLE;
bool mouse_inside = false;
struct ThemeCache {
int separation = 0;
int autohide = 0;
Ref<Texture2D> grabber_icon;
} theme_cache;
Control *_getch(int p_idx) const;
void _resort();
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -44,14 +44,7 @@ Size2 TabBar::get_minimum_size() const {
return ms;
}
Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
Ref<StyleBox> button_highlight = get_theme_stylebox(SNAME("button_highlight"));
Ref<Texture2D> close = get_theme_icon(SNAME("close"));
int hseparation = get_theme_constant(SNAME("h_separation"));
int y_margin = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height);
int y_margin = MAX(MAX(theme_cache.tab_unselected_style->get_minimum_size().height, theme_cache.tab_selected_style->get_minimum_size().height), theme_cache.tab_disabled_style->get_minimum_size().height);
for (int i = 0; i < tabs.size(); i++) {
if (tabs[i].hidden) {
@ -62,22 +55,22 @@ Size2 TabBar::get_minimum_size() const {
Ref<StyleBox> style;
if (tabs[i].disabled) {
style = tab_disabled;
style = theme_cache.tab_disabled_style;
} else if (current == i) {
style = tab_selected;
style = theme_cache.tab_selected_style;
} else {
style = tab_unselected;
style = theme_cache.tab_unselected_style;
}
ms.width += style->get_minimum_size().width;
Ref<Texture2D> tex = tabs[i].icon;
if (tex.is_valid()) {
ms.height = MAX(ms.height, tex->get_size().height + y_margin);
ms.width += tex->get_size().width + hseparation;
ms.width += tex->get_size().width + theme_cache.h_separation;
}
if (!tabs[i].text.is_empty()) {
ms.width += tabs[i].size_text + hseparation;
ms.width += tabs[i].size_text + theme_cache.h_separation;
}
ms.height = MAX(ms.height, tabs[i].text_buf->get_size().y + y_margin);
@ -87,22 +80,22 @@ Size2 TabBar::get_minimum_size() const {
Ref<Texture2D> rb = tabs[i].right_button;
if (close_visible) {
ms.width += button_highlight->get_minimum_size().width + rb->get_width();
ms.width += theme_cache.button_hl_style->get_minimum_size().width + rb->get_width();
} else {
ms.width += button_highlight->get_margin(SIDE_LEFT) + rb->get_width() + hseparation;
ms.width += theme_cache.button_hl_style->get_margin(SIDE_LEFT) + rb->get_width() + theme_cache.h_separation;
}
ms.height = MAX(ms.height, rb->get_height() + y_margin);
}
if (close_visible) {
ms.width += button_highlight->get_margin(SIDE_LEFT) + close->get_width() + hseparation;
ms.width += theme_cache.button_hl_style->get_margin(SIDE_LEFT) + theme_cache.close_icon->get_width() + theme_cache.h_separation;
ms.height = MAX(ms.height, close->get_height() + y_margin);
ms.height = MAX(ms.height, theme_cache.close_icon->get_height() + y_margin);
}
if (ms.width - ofs > style->get_minimum_size().width) {
ms.width -= hseparation;
ms.width -= theme_cache.h_separation;
}
}
@ -122,16 +115,13 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
Point2 pos = mm->get_position();
if (buttons_visible) {
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
if (is_layout_rtl()) {
if (pos.x < decr->get_width()) {
if (pos.x < theme_cache.decrement_icon->get_width()) {
if (highlight_arrow != 1) {
highlight_arrow = 1;
queue_redraw();
}
} else if (pos.x < incr->get_width() + decr->get_width()) {
} else if (pos.x < theme_cache.increment_icon->get_width() + theme_cache.decrement_icon->get_width()) {
if (highlight_arrow != 0) {
highlight_arrow = 0;
queue_redraw();
@ -141,8 +131,8 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
queue_redraw();
}
} else {
int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
if (pos.x > limit_minus_buttons + decr->get_width()) {
int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
if (pos.x > limit_minus_buttons + theme_cache.decrement_icon->get_width()) {
if (highlight_arrow != 1) {
highlight_arrow = 1;
queue_redraw();
@ -214,18 +204,15 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
Point2 pos = mb->get_position();
if (buttons_visible) {
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
if (is_layout_rtl()) {
if (pos.x < decr->get_width()) {
if (pos.x < theme_cache.decrement_icon->get_width()) {
if (missing_right) {
offset++;
_update_cache();
queue_redraw();
}
return;
} else if (pos.x < incr->get_width() + decr->get_width()) {
} else if (pos.x < theme_cache.increment_icon->get_width() + theme_cache.decrement_icon->get_width()) {
if (offset > 0) {
offset--;
_update_cache();
@ -234,8 +221,8 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
return;
}
} else {
int limit = get_size().width - incr->get_width() - decr->get_width();
if (pos.x > limit + decr->get_width()) {
int limit = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
if (pos.x > limit + theme_cache.decrement_icon->get_width()) {
if (missing_right) {
offset++;
_update_cache();
@ -299,9 +286,6 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
void TabBar::_shape(int p_tab) {
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
tabs.write[p_tab].xl_text = atr(tabs[p_tab].text);
tabs.write[p_tab].text_buf->clear();
tabs.write[p_tab].text_buf->set_width(-1);
@ -311,7 +295,37 @@ void TabBar::_shape(int p_tab) {
tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction);
}
tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, font, font_size, tabs[p_tab].language);
tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, theme_cache.font, theme_cache.font_size, tabs[p_tab].language);
}
void TabBar::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected"));
theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled"));
theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark"));
theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.close_icon = get_theme_icon(SNAME("close"));
theme_cache.button_pressed_style = get_theme_stylebox(SNAME("button_pressed"));
theme_cache.button_hl_style = get_theme_stylebox(SNAME("button_highlight"));
}
void TabBar::_notification(int p_what) {
@ -352,18 +366,9 @@ void TabBar::_notification(int p_what) {
return;
}
Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
Color font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
bool rtl = is_layout_rtl();
Vector2 size = get_size();
int limit_minus_buttons = size.width - incr->get_width() - decr->get_width();
int limit_minus_buttons = size.width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int ofs = tabs[offset].ofs_cache;
@ -378,14 +383,14 @@ void TabBar::_notification(int p_what) {
Color col;
if (tabs[i].disabled) {
sb = tab_disabled;
col = font_disabled_color;
sb = theme_cache.tab_disabled_style;
col = theme_cache.font_disabled_color;
} else if (i == current) {
sb = tab_selected;
col = font_selected_color;
sb = theme_cache.tab_selected_style;
col = theme_cache.font_selected_color;
} else {
sb = tab_unselected;
col = font_unselected_color;
sb = theme_cache.tab_unselected_style;
col = theme_cache.font_unselected_color;
}
_draw_tab(sb, col, i, rtl ? size.width - ofs - tabs[i].size_cache : ofs);
@ -396,41 +401,38 @@ void TabBar::_notification(int p_what) {
// Draw selected tab in the front, but only if it's visible.
if (current >= offset && current <= max_drawn_tab && !tabs[current].hidden) {
Ref<StyleBox> sb = tabs[current].disabled ? tab_disabled : tab_selected;
Ref<StyleBox> sb = tabs[current].disabled ? theme_cache.tab_disabled_style : theme_cache.tab_selected_style;
float x = rtl ? size.width - tabs[current].ofs_cache - tabs[current].size_cache : tabs[current].ofs_cache;
_draw_tab(sb, font_selected_color, current, x);
_draw_tab(sb, theme_cache.font_selected_color, current, x);
}
if (buttons_visible) {
Ref<Texture2D> incr_hl = get_theme_icon(SNAME("increment_highlight"));
Ref<Texture2D> decr_hl = get_theme_icon(SNAME("decrement_highlight"));
int vofs = (size.height - incr->get_size().height) / 2;
int vofs = (size.height - theme_cache.increment_icon->get_size().height) / 2;
if (rtl) {
if (missing_right) {
draw_texture(highlight_arrow == 1 ? decr_hl : decr, Point2(0, vofs));
draw_texture(highlight_arrow == 1 ? theme_cache.decrement_hl_icon : theme_cache.decrement_icon, Point2(0, vofs));
} else {
draw_texture(decr, Point2(0, vofs), Color(1, 1, 1, 0.5));
draw_texture(theme_cache.decrement_icon, Point2(0, vofs), Color(1, 1, 1, 0.5));
}
if (offset > 0) {
draw_texture(highlight_arrow == 0 ? incr_hl : incr, Point2(incr->get_size().width, vofs));
draw_texture(highlight_arrow == 0 ? theme_cache.increment_hl_icon : theme_cache.increment_icon, Point2(theme_cache.increment_icon->get_size().width, vofs));
} else {
draw_texture(incr, Point2(incr->get_size().width, vofs), Color(1, 1, 1, 0.5));
draw_texture(theme_cache.increment_icon, Point2(theme_cache.increment_icon->get_size().width, vofs), Color(1, 1, 1, 0.5));
}
} else {
if (offset > 0) {
draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit_minus_buttons, vofs));
draw_texture(highlight_arrow == 0 ? theme_cache.decrement_hl_icon : theme_cache.decrement_icon, Point2(limit_minus_buttons, vofs));
} else {
draw_texture(decr, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5));
draw_texture(theme_cache.decrement_icon, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5));
}
if (missing_right) {
draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit_minus_buttons + decr->get_size().width, vofs));
draw_texture(highlight_arrow == 1 ? theme_cache.increment_hl_icon : theme_cache.increment_icon, Point2(limit_minus_buttons + theme_cache.decrement_icon->get_size().width, vofs));
} else {
draw_texture(incr, Point2(limit_minus_buttons + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
draw_texture(theme_cache.increment_icon, Point2(limit_minus_buttons + theme_cache.decrement_icon->get_size().width, vofs), Color(1, 1, 1, 0.5));
}
}
}
@ -462,10 +464,7 @@ void TabBar::_notification(int p_what) {
}
}
Ref<Texture2D> drop_mark = get_theme_icon(SNAME("drop_mark"));
Color drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
drop_mark->draw(get_canvas_item(), Point2(x - drop_mark->get_width() / 2, (size.height - drop_mark->get_height()) / 2), drop_mark_color);
theme_cache.drop_mark_icon->draw(get_canvas_item(), Point2(x - theme_cache.drop_mark_icon->get_width() / 2, (size.height - theme_cache.drop_mark_icon->get_height()) / 2), theme_cache.drop_mark_color);
}
} break;
}
@ -475,10 +474,6 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
RID ci = get_canvas_item();
bool rtl = is_layout_rtl();
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
int hseparation = get_theme_constant(SNAME("h_separation"));
Rect2 sb_rect = Rect2(p_x, 0, tabs[p_index].size_cache, get_size().height);
p_tab_style->draw(ci, sb_rect);
@ -491,7 +486,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
if (icon.is_valid()) {
icon->draw(ci, Point2i(rtl ? p_x - icon->get_width() : p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2));
p_x = rtl ? p_x - icon->get_width() - hseparation : p_x + icon->get_width() + hseparation;
p_x = rtl ? p_x - icon->get_width() - theme_cache.h_separation : p_x + icon->get_width() + theme_cache.h_separation;
}
// Draw the text.
@ -499,17 +494,17 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
Point2i text_pos = Point2i(rtl ? p_x - tabs[p_index].size_text : p_x,
p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[p_index].text_buf->get_size().y) / 2);
if (outline_size > 0 && font_outline_color.a > 0) {
tabs[p_index].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
if (theme_cache.outline_size > 0 && theme_cache.font_outline_color.a > 0) {
tabs[p_index].text_buf->draw_outline(ci, text_pos, theme_cache.outline_size, theme_cache.font_outline_color);
}
tabs[p_index].text_buf->draw(ci, text_pos, p_font_color);
p_x = rtl ? p_x - tabs[p_index].size_text - hseparation : p_x + tabs[p_index].size_text + hseparation;
p_x = rtl ? p_x - tabs[p_index].size_text - theme_cache.h_separation : p_x + tabs[p_index].size_text + theme_cache.h_separation;
}
// Draw and calculate rect of the right button.
if (tabs[p_index].right_button.is_valid()) {
Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight"));
Ref<StyleBox> style = theme_cache.button_hl_style;
Ref<Texture2D> rb = tabs[p_index].right_button;
Rect2 rb_rect;
@ -521,7 +516,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
if (rb_hover == p_index) {
if (rb_pressing) {
get_theme_stylebox(SNAME("button_pressed"))->draw(ci, rb_rect);
theme_cache.button_pressed_style->draw(ci, rb_rect);
} else {
style->draw(ci, rb_rect);
}
@ -534,8 +529,8 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
// Draw and calculate rect of the close button.
if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_index == current)) {
Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight"));
Ref<Texture2D> cb = get_theme_icon(SNAME("close"));
Ref<StyleBox> style = theme_cache.button_hl_style;
Ref<Texture2D> cb = theme_cache.close_icon;
Rect2 cb_rect;
cb_rect.size = style->get_minimum_size() + cb->get_size();
@ -546,7 +541,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
if (!tabs[p_index].disabled && cb_hover == p_index) {
if (cb_pressing) {
get_theme_stylebox(SNAME("button_pressed"))->draw(ci, cb_rect);
theme_cache.button_pressed_style->draw(ci, cb_rect);
} else {
style->draw(ci, cb_rect);
}
@ -849,14 +844,8 @@ void TabBar::_update_cache() {
return;
}
Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
int limit = get_size().width;
int limit_minus_buttons = limit - incr->get_width() - decr->get_width();
int limit_minus_buttons = limit - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int w = 0;
@ -1258,52 +1247,47 @@ void TabBar::move_tab(int p_from, int p_to) {
int TabBar::get_tab_width(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, tabs.size(), 0);
Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
int hseparation = get_theme_constant(SNAME("h_separation"));
Ref<StyleBox> style;
if (tabs[p_idx].disabled) {
style = tab_disabled;
style = theme_cache.tab_disabled_style;
} else if (current == p_idx) {
style = tab_selected;
style = theme_cache.tab_selected_style;
} else {
style = tab_unselected;
style = theme_cache.tab_unselected_style;
}
int x = style->get_minimum_size().width;
Ref<Texture2D> tex = tabs[p_idx].icon;
if (tex.is_valid()) {
x += tex->get_width() + hseparation;
x += tex->get_width() + theme_cache.h_separation;
}
if (!tabs[p_idx].text.is_empty()) {
x += tabs[p_idx].size_text + hseparation;
x += tabs[p_idx].size_text + theme_cache.h_separation;
}
bool close_visible = cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx == current);
if (tabs[p_idx].right_button.is_valid()) {
Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight"));
Ref<StyleBox> btn_style = theme_cache.button_hl_style;
Ref<Texture2D> rb = tabs[p_idx].right_button;
if (close_visible) {
x += btn_style->get_minimum_size().width + rb->get_width();
} else {
x += btn_style->get_margin(SIDE_LEFT) + rb->get_width() + hseparation;
x += btn_style->get_margin(SIDE_LEFT) + rb->get_width() + theme_cache.h_separation;
}
}
if (close_visible) {
Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight"));
Ref<Texture2D> cb = get_theme_icon(SNAME("close"));
x += btn_style->get_margin(SIDE_LEFT) + cb->get_width() + hseparation;
Ref<StyleBox> btn_style = theme_cache.button_hl_style;
Ref<Texture2D> cb = theme_cache.close_icon;
x += btn_style->get_margin(SIDE_LEFT) + cb->get_width() + theme_cache.h_separation;
}
if (x > style->get_minimum_size().width) {
x -= hseparation;
x -= theme_cache.h_separation;
}
return x;
@ -1314,9 +1298,7 @@ void TabBar::_ensure_no_over_offset() {
return;
}
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int prev_offset = offset;
@ -1359,9 +1341,7 @@ void TabBar::ensure_tab_visible(int p_idx) {
return;
}
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width();
int total_w = tabs[max_drawn_tab].ofs_cache - tabs[offset].ofs_cache;
for (int i = max_drawn_tab; i <= p_idx; i++) {

View file

@ -104,6 +104,34 @@ private:
bool scroll_to_selected = true;
int tabs_rearrange_group = -1;
struct ThemeCache {
int h_separation = 0;
Ref<StyleBox> tab_unselected_style;
Ref<StyleBox> tab_selected_style;
Ref<StyleBox> tab_disabled_style;
Ref<Texture2D> increment_icon;
Ref<Texture2D> increment_hl_icon;
Ref<Texture2D> decrement_icon;
Ref<Texture2D> decrement_hl_icon;
Ref<Texture2D> drop_mark_icon;
Color drop_mark_color;
Ref<Font> font;
int font_size;
int outline_size = 0;
Color font_selected_color;
Color font_unselected_color;
Color font_disabled_color;
Color font_outline_color;
Ref<Texture2D> close_icon;
Ref<StyleBox> button_pressed_style;
Ref<StyleBox> button_hl_style;
} theme_cache;
int get_tab_width(int p_idx) const;
void _ensure_no_over_offset();
@ -117,6 +145,7 @@ private:
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void _update_theme_item_cache() override;
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;

View file

@ -60,26 +60,24 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
}
// Handle menu button.
Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
if (is_layout_rtl()) {
if (popup && pos.x < menu->get_width()) {
if (popup && pos.x < theme_cache.menu_icon->get_width()) {
emit_signal(SNAME("pre_popup_pressed"));
Vector2 popup_pos = get_screen_position();
popup_pos.y += menu->get_height();
popup_pos.y += theme_cache.menu_icon->get_height();
popup->set_position(popup_pos);
popup->popup();
return;
}
} else {
if (popup && pos.x > size.width - menu->get_width()) {
if (popup && pos.x > size.width - theme_cache.menu_icon->get_width()) {
emit_signal(SNAME("pre_popup_pressed"));
Vector2 popup_pos = get_screen_position();
popup_pos.x += size.width - popup->get_size().width;
popup_pos.y += menu->get_height();
popup_pos.y += theme_cache.menu_icon->get_height();
popup->set_position(popup_pos);
popup->popup();
@ -103,10 +101,9 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
return;
}
Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
if (popup) {
if (is_layout_rtl()) {
if (pos.x <= menu->get_width()) {
if (pos.x <= theme_cache.menu_icon->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
queue_redraw();
@ -117,7 +114,7 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
queue_redraw();
}
} else {
if (pos.x >= size.width - menu->get_width()) {
if (pos.x >= size.width - theme_cache.menu_icon->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
queue_redraw();
@ -136,6 +133,41 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
}
}
void TabContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
theme_cache.side_margin = get_theme_constant(SNAME("side_margin"));
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
theme_cache.tabbar_style = get_theme_stylebox(SNAME("tabbar_background"));
theme_cache.menu_icon = get_theme_icon(SNAME("menu"));
theme_cache.menu_hl_icon = get_theme_icon(SNAME("menu_highlight"));
// TabBar overrides.
theme_cache.icon_separation = get_theme_constant(SNAME("icon_separation"));
theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected"));
theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled"));
theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark"));
theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.tab_font = get_theme_font(SNAME("font"));
theme_cache.tab_font_size = get_theme_font_size(SNAME("font_size"));
}
void TabContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@ -155,31 +187,26 @@ void TabContainer::_notification(int p_what) {
Size2 size = get_size();
// Draw only the tab area if the header is hidden.
Ref<StyleBox> panel = get_theme_stylebox(SNAME("panel"));
if (!tabs_visible) {
panel->draw(canvas, Rect2(0, 0, size.width, size.height));
theme_cache.panel_style->draw(canvas, Rect2(0, 0, size.width, size.height));
return;
}
int header_height = _get_top_margin();
// Draw background for the tabbar.
Ref<StyleBox> tabbar_background = get_theme_stylebox(SNAME("tabbar_background"));
tabbar_background->draw(canvas, Rect2(0, 0, size.width, header_height));
theme_cache.tabbar_style->draw(canvas, Rect2(0, 0, size.width, header_height));
// Draw the background for the tab's content.
panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
theme_cache.panel_style->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
// Draw the popup menu.
if (get_popup()) {
Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight"));
int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width();
int x = is_layout_rtl() ? 0 : get_size().width - theme_cache.menu_icon->get_width();
if (menu_hovered) {
menu_hl->draw(get_canvas_item(), Point2(x, (header_height - menu_hl->get_height()) / 2));
theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_hl_icon->get_height()) / 2));
} else {
menu->draw(get_canvas_item(), Point2(x, (header_height - menu->get_height()) / 2));
theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_icon->get_height()) / 2));
}
}
} break;
@ -198,23 +225,27 @@ void TabContainer::_on_theme_changed() {
return;
}
tab_bar->add_theme_style_override(SNAME("tab_unselected"), get_theme_stylebox(SNAME("tab_unselected")));
tab_bar->add_theme_style_override(SNAME("tab_selected"), get_theme_stylebox(SNAME("tab_selected")));
tab_bar->add_theme_style_override(SNAME("tab_disabled"), get_theme_stylebox(SNAME("tab_disabled")));
tab_bar->add_theme_icon_override(SNAME("increment"), get_theme_icon(SNAME("increment")));
tab_bar->add_theme_icon_override(SNAME("increment_highlight"), get_theme_icon(SNAME("increment_highlight")));
tab_bar->add_theme_icon_override(SNAME("decrement"), get_theme_icon(SNAME("decrement")));
tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), get_theme_icon(SNAME("decrement_highlight")));
tab_bar->add_theme_icon_override(SNAME("drop_mark"), get_theme_icon(SNAME("drop_mark")));
tab_bar->add_theme_color_override(SNAME("drop_mark_color"), get_theme_color(SNAME("drop_mark_color")));
tab_bar->add_theme_color_override(SNAME("font_selected_color"), get_theme_color(SNAME("font_selected_color")));
tab_bar->add_theme_color_override(SNAME("font_unselected_color"), get_theme_color(SNAME("font_unselected_color")));
tab_bar->add_theme_color_override(SNAME("font_disabled_color"), get_theme_color(SNAME("font_disabled_color")));
tab_bar->add_theme_color_override(SNAME("font_outline_color"), get_theme_color(SNAME("font_outline_color")));
tab_bar->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("font")));
tab_bar->add_theme_font_size_override(SNAME("font_size"), get_theme_font_size(SNAME("font_size")));
tab_bar->add_theme_constant_override(SNAME("h_separation"), get_theme_constant(SNAME("icon_separation")));
tab_bar->add_theme_constant_override(SNAME("outline_size"), get_theme_constant(SNAME("outline_size")));
tab_bar->add_theme_style_override(SNAME("tab_unselected"), theme_cache.tab_unselected_style);
tab_bar->add_theme_style_override(SNAME("tab_selected"), theme_cache.tab_selected_style);
tab_bar->add_theme_style_override(SNAME("tab_disabled"), theme_cache.tab_disabled_style);
tab_bar->add_theme_icon_override(SNAME("increment"), theme_cache.increment_icon);
tab_bar->add_theme_icon_override(SNAME("increment_highlight"), theme_cache.increment_hl_icon);
tab_bar->add_theme_icon_override(SNAME("decrement"), theme_cache.decrement_icon);
tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), theme_cache.decrement_hl_icon);
tab_bar->add_theme_icon_override(SNAME("drop_mark"), theme_cache.drop_mark_icon);
tab_bar->add_theme_color_override(SNAME("drop_mark_color"), theme_cache.drop_mark_color);
tab_bar->add_theme_color_override(SNAME("font_selected_color"), theme_cache.font_selected_color);
tab_bar->add_theme_color_override(SNAME("font_unselected_color"), theme_cache.font_unselected_color);
tab_bar->add_theme_color_override(SNAME("font_disabled_color"), theme_cache.font_disabled_color);
tab_bar->add_theme_color_override(SNAME("font_outline_color"), theme_cache.font_outline_color);
tab_bar->add_theme_font_override(SNAME("font"), theme_cache.tab_font);
tab_bar->add_theme_font_size_override(SNAME("font_size"), theme_cache.tab_font_size);
tab_bar->add_theme_constant_override(SNAME("h_separation"), theme_cache.icon_separation);
tab_bar->add_theme_constant_override(SNAME("outline_size"), theme_cache.outline_size);
_update_margins();
if (get_tab_count() > 0) {
@ -228,7 +259,6 @@ void TabContainer::_on_theme_changed() {
}
void TabContainer::_repaint() {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"));
Vector<Control *> controls = _get_tab_controls();
int current = get_current_tab();
@ -243,10 +273,10 @@ void TabContainer::_repaint() {
c->set_offset(SIDE_TOP, _get_top_margin());
}
c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + sb->get_margin(SIDE_TOP));
c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + sb->get_margin(SIDE_LEFT));
c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - sb->get_margin(SIDE_RIGHT));
c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - sb->get_margin(SIDE_BOTTOM));
c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_TOP));
c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_LEFT));
c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - theme_cache.panel_style->get_margin(SIDE_RIGHT));
c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - theme_cache.panel_style->get_margin(SIDE_BOTTOM));
} else {
c->hide();
}
@ -256,8 +286,7 @@ void TabContainer::_repaint() {
}
void TabContainer::_update_margins() {
int menu_width = get_theme_icon(SNAME("menu"))->get_width();
int side_margin = get_theme_constant(SNAME("side_margin"));
int menu_width = theme_cache.menu_icon->get_width();
// Directly check for validity, to avoid errors when quitting.
bool has_popup = popup_obj_id.is_valid();
@ -271,7 +300,7 @@ void TabContainer::_update_margins() {
switch (get_tab_alignment()) {
case TabBar::ALIGNMENT_LEFT: {
tab_bar->set_offset(SIDE_LEFT, side_margin);
tab_bar->set_offset(SIDE_LEFT, theme_cache.side_margin);
tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
} break;
@ -293,10 +322,10 @@ void TabContainer::_update_margins() {
int total_tabs_width = last_tab_rect.position.x - first_tab_pos + last_tab_rect.size.width;
// Calculate if all the tabs would still fit if the margin was present.
if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + side_margin) > get_size().width))) {
if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + theme_cache.side_margin) > get_size().width))) {
tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
} else {
tab_bar->set_offset(SIDE_RIGHT, -side_margin);
tab_bar->set_offset(SIDE_RIGHT, -theme_cache.side_margin);
}
} break;
@ -798,13 +827,12 @@ Size2 TabContainer::get_minimum_size() const {
if (!get_clip_tabs()) {
if (get_popup()) {
ms.x += get_theme_icon(SNAME("menu"))->get_width();
ms.x += theme_cache.menu_icon->get_width();
}
int side_margin = get_theme_constant(SNAME("side_margin"));
if (side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER &&
if (theme_cache.side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER &&
(get_tab_alignment() != TabBar::ALIGNMENT_RIGHT || !get_popup())) {
ms.x += side_margin;
ms.x += theme_cache.side_margin;
}
}
}
@ -824,7 +852,7 @@ Size2 TabContainer::get_minimum_size() const {
}
ms.y += max_control_height;
Size2 panel_ms = get_theme_stylebox(SNAME("panel"))->get_minimum_size();
Size2 panel_ms = theme_cache.panel_style->get_minimum_size();
ms.x = MAX(ms.x, panel_ms.x);
ms.y += panel_ms.y;

View file

@ -48,6 +48,39 @@ class TabContainer : public Container {
bool theme_changing = false;
Node *child_removing = nullptr;
struct ThemeCache {
int side_margin = 0;
Ref<StyleBox> panel_style;
Ref<StyleBox> tabbar_style;
Ref<Texture2D> menu_icon;
Ref<Texture2D> menu_hl_icon;
// TabBar overrides.
int icon_separation = 0;
int outline_size = 0;
Ref<StyleBox> tab_unselected_style;
Ref<StyleBox> tab_selected_style;
Ref<StyleBox> tab_disabled_style;
Ref<Texture2D> increment_icon;
Ref<Texture2D> increment_hl_icon;
Ref<Texture2D> decrement_icon;
Ref<Texture2D> decrement_hl_icon;
Ref<Texture2D> drop_mark_icon;
Color drop_mark_color;
Color font_selected_color;
Color font_unselected_color;
Color font_disabled_color;
Color font_outline_color;
Ref<Font> tab_font;
int tab_font_size;
} theme_cache;
int _get_top_margin() const;
Vector<Control *> _get_tab_controls() const;
void _on_theme_changed();
@ -65,6 +98,8 @@ class TabContainer : public Container {
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;

File diff suppressed because it is too large Load diff

View file

@ -482,12 +482,13 @@ private:
void propagate_set_columns(TreeItem *p_item);
struct Cache {
struct ThemeCache {
Ref<Font> font;
Ref<Font> tb_font;
int font_size = 0;
int tb_font_size = 0;
Ref<StyleBox> bg;
Ref<StyleBox> bg_focus;
Ref<StyleBox> selected;
Ref<StyleBox> selected_focus;
Ref<StyleBox> cursor;
@ -505,8 +506,9 @@ private:
Ref<Texture2D> checked;
Ref<Texture2D> unchecked;
Ref<Texture2D> indeterminate;
Ref<Texture2D> arrow_collapsed;
Ref<Texture2D> arrow;
Ref<Texture2D> arrow_collapsed;
Ref<Texture2D> arrow_collapsed_mirrored;
Ref<Texture2D> select_arrow;
Ref<Texture2D> updown;
@ -536,7 +538,9 @@ private:
int scroll_border = 0;
int scroll_speed = 0;
int font_outline_size = 0;
} theme_cache;
struct Cache {
enum ClickType {
CLICK_NONE,
CLICK_TITLE,
@ -559,7 +563,6 @@ private:
Point2i text_editor_position;
bool rtl = false;
} cache;
int _get_title_button_height() const;
@ -572,7 +575,6 @@ private:
bool v_scroll_enabled = true;
Size2 get_internal_min_size() const;
void update_cache();
void update_scrollbars();
Rect2 search_item_rect(TreeItem *p_from, TreeItem *p_item);
@ -620,6 +622,8 @@ private:
bool _scroll(bool p_horizontal, float p_pages);
protected:
virtual void _update_theme_item_cache() override;
static void _bind_methods();
public: