Add dumb and manual theme caching systems to Window

This commit is contained in:
Yuri Sizov 2022-09-01 13:38:08 +03:00
parent 0c221f0284
commit 15fd025f90
12 changed files with 368 additions and 185 deletions

View file

@ -99,6 +99,12 @@
</signal>
</signals>
<theme_items>
<theme_item name="button_margin" data_type="constant" type="int" default="32">
Offset that is applied to the content of the window on the bottom, effectively moving the button row.
</theme_item>
<theme_item name="margin" data_type="constant" type="int" default="8">
Offset that is applied to the content of the window on top, left, and right.
</theme_item>
<theme_item name="panel" data_type="style" type="StyleBox">
Panel that fills up the background of the window.
</theme_item>

View file

@ -50,6 +50,14 @@ void AcceptDialog::_parent_focused() {
}
}
void AcceptDialog::_update_theme_item_cache() {
Window::_update_theme_item_cache();
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
theme_cache.margin = get_theme_constant(SNAME("margin"));
theme_cache.button_margin = get_theme_constant(SNAME("button_margin"));
}
void AcceptDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@ -69,7 +77,10 @@ void AcceptDialog::_notification(int p_what) {
} break;
case NOTIFICATION_THEME_CHANGED: {
bg->add_theme_style_override("panel", bg->get_theme_stylebox(SNAME("panel"), SNAME("AcceptDialog")));
bg->add_theme_style_override("panel", theme_cache.panel_style);
label->set_begin(Point2(theme_cache.margin, theme_cache.margin));
label->set_end(Point2(-theme_cache.margin, -theme_cache.button_margin - 10));
} break;
case NOTIFICATION_EXIT_TREE: {
@ -185,12 +196,12 @@ void AcceptDialog::_update_child_rects() {
if (label->get_text().is_empty()) {
label_size.height = 0;
}
int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
Size2 size = get_size();
Size2 hminsize = hbc->get_combined_minimum_size();
Vector2 cpos(margin, margin + label_size.height);
Vector2 csize(size.x - margin * 2, size.y - margin * 3 - hminsize.y - label_size.height);
Vector2 cpos(theme_cache.margin, theme_cache.margin + label_size.height);
Vector2 csize(size.x - theme_cache.margin * 2, size.y - theme_cache.margin * 3 - hminsize.y - label_size.height);
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@ -206,7 +217,7 @@ void AcceptDialog::_update_child_rects() {
c->set_size(csize);
}
cpos.y += csize.y + margin;
cpos.y += csize.y + theme_cache.margin;
csize.y = hminsize.y;
hbc->set_position(cpos);
@ -217,7 +228,6 @@ void AcceptDialog::_update_child_rects() {
}
Size2 AcceptDialog::_get_contents_minimum_size() const {
int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
Size2 minsize = label->get_combined_minimum_size();
for (int i = 0; i < get_child_count(); i++) {
@ -238,8 +248,8 @@ Size2 AcceptDialog::_get_contents_minimum_size() const {
Size2 hminsize = hbc->get_combined_minimum_size();
minsize.x = MAX(hminsize.x, minsize.x);
minsize.y += hminsize.y;
minsize.x += margin * 2;
minsize.y += margin * 3; //one as separation between hbc and child
minsize.x += theme_cache.margin * 2;
minsize.y += theme_cache.margin * 3; //one as separation between hbc and child
Size2 wmsize = get_min_size();
minsize.x = MAX(wmsize.x, minsize.x);
@ -350,14 +360,9 @@ AcceptDialog::AcceptDialog() {
hbc = memnew(HBoxContainer);
int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
int button_margin = hbc->get_theme_constant(SNAME("button_margin"), SNAME("Dialogs"));
label = memnew(Label);
label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
label->set_begin(Point2(margin, margin));
label->set_end(Point2(-margin, -button_margin - 10));
add_child(label, false, INTERNAL_MODE_FRONT);
add_child(hbc, false, INTERNAL_MODE_FRONT);

View file

@ -52,6 +52,12 @@ class AcceptDialog : public Window {
bool hide_on_ok = true;
bool close_on_escape = true;
struct ThemeCache {
Ref<StyleBox> panel_style;
int margin = 0;
int button_margin = 0;
} theme_cache;
void _custom_action(const String &p_action);
void _update_child_rects();
@ -62,6 +68,7 @@ class AcceptDialog : public Window {
protected:
virtual Size2 _get_contents_minimum_size() const override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -59,36 +59,26 @@ VBoxContainer *FileDialog::get_vbox() {
return vbox;
}
void FileDialog::_theme_changed() {
Color font_color = vbox->get_theme_color(SNAME("font_color"), SNAME("Button"));
Color font_hover_color = vbox->get_theme_color(SNAME("font_hover_color"), SNAME("Button"));
Color font_focus_color = vbox->get_theme_color(SNAME("font_focus_color"), SNAME("Button"));
Color font_pressed_color = vbox->get_theme_color(SNAME("font_pressed_color"), SNAME("Button"));
void FileDialog::_update_theme_item_cache() {
ConfirmationDialog::_update_theme_item_cache();
dir_up->add_theme_color_override("icon_normal_color", font_color);
dir_up->add_theme_color_override("icon_hover_color", font_hover_color);
dir_up->add_theme_color_override("icon_focus_color", font_focus_color);
dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color);
theme_cache.parent_folder = get_theme_icon(SNAME("parent_folder"));
theme_cache.forward_folder = get_theme_icon(SNAME("forward_folder"));
theme_cache.back_folder = get_theme_icon(SNAME("back_folder"));
theme_cache.reload = get_theme_icon(SNAME("reload"));
theme_cache.toggle_hidden = get_theme_icon(SNAME("toggle_hidden"));
theme_cache.folder = get_theme_icon(SNAME("folder"));
theme_cache.file = get_theme_icon(SNAME("file"));
dir_prev->add_theme_color_override("icon_color_normal", font_color);
dir_prev->add_theme_color_override("icon_color_hover", font_hover_color);
dir_prev->add_theme_color_override("icon_focus_color", font_focus_color);
dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color);
theme_cache.folder_icon_modulate = get_theme_color(SNAME("folder_icon_modulate"));
theme_cache.file_icon_modulate = get_theme_color(SNAME("file_icon_modulate"));
theme_cache.files_disabled = get_theme_color(SNAME("files_disabled"));
dir_next->add_theme_color_override("icon_color_normal", font_color);
dir_next->add_theme_color_override("icon_color_hover", font_hover_color);
dir_next->add_theme_color_override("icon_focus_color", font_focus_color);
dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color);
refresh->add_theme_color_override("icon_normal_color", font_color);
refresh->add_theme_color_override("icon_hover_color", font_hover_color);
refresh->add_theme_color_override("icon_focus_color", font_focus_color);
refresh->add_theme_color_override("icon_pressed_color", font_pressed_color);
show_hidden->add_theme_color_override("icon_normal_color", font_color);
show_hidden->add_theme_color_override("icon_hover_color", font_hover_color);
show_hidden->add_theme_color_override("icon_focus_color", font_focus_color);
show_hidden->add_theme_color_override("icon_pressed_color", font_pressed_color);
// TODO: Define own colors?
theme_cache.icon_normal_color = get_theme_color(SNAME("font_color"), SNAME("Button"));
theme_cache.icon_hover_color = get_theme_color(SNAME("font_hover_color"), SNAME("Button"));
theme_cache.icon_focus_color = get_theme_color(SNAME("font_focus_color"), SNAME("Button"));
theme_cache.icon_pressed_color = get_theme_color(SNAME("font_pressed_color"), SNAME("Button"));
}
void FileDialog::_notification(int p_what) {
@ -99,18 +89,42 @@ void FileDialog::_notification(int p_what) {
}
} break;
case NOTIFICATION_ENTER_TREE: {
dir_up->set_icon(vbox->get_theme_icon(SNAME("parent_folder"), SNAME("FileDialog")));
case NOTIFICATION_THEME_CHANGED: {
dir_up->set_icon(theme_cache.parent_folder);
if (vbox->is_layout_rtl()) {
dir_prev->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog")));
dir_next->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog")));
dir_prev->set_icon(theme_cache.forward_folder);
dir_next->set_icon(theme_cache.back_folder);
} else {
dir_prev->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog")));
dir_next->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog")));
dir_prev->set_icon(theme_cache.back_folder);
dir_next->set_icon(theme_cache.forward_folder);
}
refresh->set_icon(vbox->get_theme_icon(SNAME("reload"), SNAME("FileDialog")));
show_hidden->set_icon(vbox->get_theme_icon(SNAME("toggle_hidden"), SNAME("FileDialog")));
_theme_changed();
refresh->set_icon(theme_cache.reload);
show_hidden->set_icon(theme_cache.toggle_hidden);
dir_up->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
dir_up->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
dir_up->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
dir_up->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
dir_prev->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color);
dir_prev->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color);
dir_prev->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
dir_prev->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color);
dir_next->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color);
dir_next->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color);
dir_next->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
dir_next->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color);
refresh->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
refresh->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
refresh->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
refresh->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
show_hidden->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
show_hidden->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
show_hidden->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
show_hidden->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
@ -506,10 +520,6 @@ void FileDialog::update_file_list() {
}
TreeItem *root = tree->create_item();
Ref<Texture2D> folder = vbox->get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
Ref<Texture2D> file_icon = vbox->get_theme_icon(SNAME("file"), SNAME("FileDialog"));
const Color folder_color = vbox->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog"));
const Color file_color = vbox->get_theme_color(SNAME("file_icon_modulate"), SNAME("FileDialog"));
List<String> files;
List<String> dirs;
@ -541,8 +551,8 @@ void FileDialog::update_file_list() {
String &dir_name = dirs.front()->get();
TreeItem *ti = tree->create_item(root);
ti->set_text(0, dir_name);
ti->set_icon(0, folder);
ti->set_icon_modulate(0, folder_color);
ti->set_icon(0, theme_cache.folder);
ti->set_icon_modulate(0, theme_cache.folder_icon_modulate);
Dictionary d;
d["name"] = dir_name;
@ -601,12 +611,12 @@ void FileDialog::update_file_list() {
Ref<Texture2D> icon = get_icon_func(base_dir.path_join(files.front()->get()));
ti->set_icon(0, icon);
} else {
ti->set_icon(0, file_icon);
ti->set_icon(0, theme_cache.file);
}
ti->set_icon_modulate(0, file_color);
ti->set_icon_modulate(0, theme_cache.file_icon_modulate);
if (mode == FILE_MODE_OPEN_DIR) {
ti->set_custom_color(0, vbox->get_theme_color(SNAME("files_disabled"), SNAME("FileDialog")));
ti->set_custom_color(0, theme_cache.files_disabled);
ti->set_selectable(0, false);
}
Dictionary d;
@ -1006,7 +1016,6 @@ FileDialog::FileDialog() {
vbox = memnew(VBoxContainer);
add_child(vbox, false, INTERNAL_MODE_FRONT);
vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed));
mode = FILE_MODE_SAVE_FILE;
set_title(TTRC("Save a File"));

View file

@ -109,6 +109,25 @@ private:
bool invalidated = true;
struct ThemeCache {
Ref<Texture2D> parent_folder;
Ref<Texture2D> forward_folder;
Ref<Texture2D> back_folder;
Ref<Texture2D> reload;
Ref<Texture2D> toggle_hidden;
Ref<Texture2D> folder;
Ref<Texture2D> file;
Color folder_icon_modulate;
Color file_icon_modulate;
Color files_disabled;
Color icon_normal_color;
Color icon_hover_color;
Color icon_focus_color;
Color icon_pressed_color;
} theme_cache;
void update_dir();
void update_file_name();
void update_file_list();
@ -143,7 +162,7 @@ private:
virtual void _post_popup() override;
protected:
void _theme_changed();
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();

View file

@ -68,6 +68,12 @@ void Popup::_deinitialize_visible_parents() {
}
}
void Popup::_update_theme_item_cache() {
Window::_update_theme_item_cache();
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
}
void Popup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@ -186,8 +192,6 @@ Popup::~Popup() {
}
Size2 PopupPanel::_get_contents_minimum_size() const {
Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
@ -205,14 +209,12 @@ Size2 PopupPanel::_get_contents_minimum_size() const {
ms.y = MAX(cms.y, ms.y);
}
return ms + p->get_minimum_size();
return ms + theme_cache.panel_style->get_minimum_size();
}
void PopupPanel::_update_child_rects() {
Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
Vector2 cpos(p->get_offset());
Vector2 csize(get_size() - p->get_minimum_size());
Vector2 cpos(theme_cache.panel_style->get_offset());
Vector2 csize(get_size() - theme_cache.panel_style->get_minimum_size());
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@ -234,15 +236,17 @@ void PopupPanel::_update_child_rects() {
}
}
void PopupPanel::_update_theme_item_cache() {
Popup::_update_theme_item_cache();
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
}
void PopupPanel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY:
case NOTIFICATION_THEME_CHANGED: {
panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
} break;
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_READY: {
panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
panel->add_theme_style_override("panel", theme_cache.panel_style);
_update_child_rects();
} break;

View file

@ -43,6 +43,10 @@ class Popup : public Window {
LocalVector<Window *> visible_parents;
bool popped_up = false;
struct ThemeCache {
Ref<StyleBox> panel_style;
} theme_cache;
void _input_from_window(const Ref<InputEvent> &p_event);
void _initialize_visible_parents();
@ -52,6 +56,7 @@ protected:
void _close_pressed();
virtual Rect2i _popup_adjust_rect() const override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
@ -69,8 +74,14 @@ class PopupPanel : public Popup {
Panel *panel = nullptr;
struct ThemeCache {
Ref<StyleBox> panel_style;
} theme_cache;
protected:
void _update_child_rects();
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
virtual Size2 _get_contents_minimum_size() const override;

View file

@ -48,15 +48,12 @@ String PopupMenu::_get_accel_text(const Item &p_item) const {
}
Size2 PopupMenu::_get_contents_minimum_size() const {
int vseparation = get_theme_constant(SNAME("v_separation"));
int hseparation = get_theme_constant(SNAME("h_separation"));
Size2 minsize = get_theme_stylebox(SNAME("panel"))->get_minimum_size(); // Accounts for margin in the margin container
Size2 minsize = theme_cache.panel_style->get_minimum_size(); // Accounts for margin in the margin container
minsize.x += scroll_container->get_v_scroll_bar()->get_size().width * 2; // Adds a buffer so that the scrollbar does not render over the top of content
float max_w = 0.0;
float icon_w = 0.0;
int check_w = MAX(get_theme_icon(SNAME("checked"))->get_width(), get_theme_icon(SNAME("radio_checked"))->get_width()) + hseparation;
int check_w = MAX(theme_cache.checked->get_width(), theme_cache.radio_checked->get_width()) + theme_cache.h_separation;
int accel_max_w = 0;
bool has_check = false;
@ -67,23 +64,23 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
size.height = _get_item_height(i);
icon_w = MAX(icon_size.width, icon_w);
size.width += items[i].indent * get_theme_constant(SNAME("indent"));
size.width += items[i].indent * theme_cache.indent;
if (items[i].checkable_type && !items[i].separator) {
has_check = true;
}
size.width += items[i].text_buf->get_size().x;
size.height += vseparation;
size.height += theme_cache.v_separation;
if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) {
int accel_w = hseparation * 2;
int accel_w = theme_cache.h_separation * 2;
accel_w += items[i].accel_text_buf->get_size().x;
accel_max_w = MAX(accel_w, accel_max_w);
}
if (!items[i].submenu.is_empty()) {
size.width += get_theme_icon(SNAME("submenu"))->get_width();
size.width += theme_cache.submenu->get_width();
}
max_w = MAX(max_w, size.width);
@ -91,7 +88,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
minsize.height += size.height;
}
int item_side_padding = get_theme_constant(SNAME("item_start_padding")) + get_theme_constant(SNAME("item_end_padding"));
int item_side_padding = theme_cache.item_start_padding + theme_cache.item_end_padding;
minsize.width += max_w + icon_w + accel_max_w + item_side_padding;
if (has_check) {
@ -113,33 +110,31 @@ int PopupMenu::_get_item_height(int p_item) const {
int icon_height = items[p_item].get_icon_size().height;
if (items[p_item].checkable_type && !items[p_item].separator) {
icon_height = MAX(icon_height, MAX(get_theme_icon(SNAME("checked"))->get_height(), get_theme_icon(SNAME("radio_checked"))->get_height()));
icon_height = MAX(icon_height, MAX(theme_cache.checked->get_height(), theme_cache.radio_checked->get_height()));
}
int text_height = items[p_item].text_buf->get_size().height;
if (text_height == 0 && !items[p_item].separator) {
text_height = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")));
text_height = theme_cache.font->get_height(theme_cache.font_size);
}
int separator_height = 0;
if (items[p_item].separator) {
separator_height = MAX(get_theme_stylebox(SNAME("separator"))->get_minimum_size().height, MAX(get_theme_stylebox(SNAME("labeled_separator_left"))->get_minimum_size().height, get_theme_stylebox(SNAME("labeled_separator_right"))->get_minimum_size().height));
separator_height = MAX(theme_cache.separator_style->get_minimum_size().height, MAX(theme_cache.labeled_separator_left->get_minimum_size().height, theme_cache.labeled_separator_right->get_minimum_size().height));
}
return MAX(separator_height, MAX(text_height, icon_height));
}
int PopupMenu::_get_items_total_height() const {
int vsep = get_theme_constant(SNAME("v_separation"));
// Get total height of all items by taking max of icon height and font height
int items_total_height = 0;
for (int i = 0; i < items.size(); i++) {
items_total_height += _get_item_height(i) + vsep;
items_total_height += _get_item_height(i) + theme_cache.v_separation;
}
// Subtract a separator which is not needed for the last item.
return items_total_height - vsep;
return items_total_height - theme_cache.v_separation;
}
int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
@ -147,18 +142,15 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
return -1;
}
Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); // Accounts for margin in the margin container
int vseparation = get_theme_constant(SNAME("v_separation"));
Point2 ofs = style->get_offset() + Point2(0, vseparation / 2);
// Accounts for margin in the margin container
Point2 ofs = theme_cache.panel_style->get_offset() + Point2(0, theme_cache.v_separation / 2);
if (ofs.y > p_over.y) {
return -1;
}
for (int i = 0; i < items.size(); i++) {
ofs.y += i > 0 ? vseparation : (float)vseparation / 2;
ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2;
ofs.y += _get_item_height(i);
@ -179,9 +171,6 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
return; // Already visible.
}
Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
int vsep = get_theme_constant(SNAME("v_separation"));
Point2 this_pos = get_position();
Rect2 this_rect(this_pos, get_size());
@ -231,7 +220,7 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
// Set autohide areas.
Rect2 safe_area = this_rect;
safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2;
safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2;
safe_area.size.y = items[p_over]._height_cache;
DisplayServer::get_singleton()->window_set_popup_safe_rect(submenu_popup->get_window_id(), safe_area);
@ -240,11 +229,11 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
// Autohide area above the submenu item.
submenu_pum->clear_autohide_areas();
submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2));
submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2));
// If there is an area below the submenu item, add an autohide area there.
if (items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset <= control->get_size().height) {
int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height;
int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + theme_cache.v_separation / 2 + theme_cache.panel_style->get_offset().height;
submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from));
}
}
@ -528,34 +517,17 @@ void PopupMenu::_draw_items() {
margin_size.height = margin_container->get_theme_constant(SNAME("margin_top")) + margin_container->get_theme_constant(SNAME("margin_bottom"));
// Space between the item content and the sides of popup menu.
int item_start_padding = get_theme_constant(SNAME("item_start_padding"));
int item_end_padding = get_theme_constant(SNAME("item_end_padding"));
bool rtl = control->is_layout_rtl();
Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
Ref<StyleBox> hover = get_theme_stylebox(SNAME("hover"));
// In Item::checkable_type enum order (less the non-checkable member), with disabled repeated at the end.
Ref<Texture2D> check[] = { get_theme_icon(SNAME("checked")), get_theme_icon(SNAME("radio_checked")), get_theme_icon(SNAME("checked_disabled")), get_theme_icon(SNAME("radio_checked_disabled")) };
Ref<Texture2D> uncheck[] = { get_theme_icon(SNAME("unchecked")), get_theme_icon(SNAME("radio_unchecked")), get_theme_icon(SNAME("unchecked_disabled")), get_theme_icon(SNAME("radio_unchecked_disabled")) };
Ref<Texture2D> check[] = { theme_cache.checked, theme_cache.radio_checked, theme_cache.checked_disabled, theme_cache.radio_checked_disabled };
Ref<Texture2D> uncheck[] = { theme_cache.unchecked, theme_cache.radio_unchecked, theme_cache.unchecked_disabled, theme_cache.radio_unchecked_disabled };
Ref<Texture2D> submenu;
if (rtl) {
submenu = get_theme_icon(SNAME("submenu_mirrored"));
submenu = theme_cache.submenu_mirrored;
} else {
submenu = get_theme_icon(SNAME("submenu"));
submenu = theme_cache.submenu;
}
Ref<StyleBox> separator = get_theme_stylebox(SNAME("separator"));
Ref<StyleBox> labeled_separator_left = get_theme_stylebox(SNAME("labeled_separator_left"));
Ref<StyleBox> labeled_separator_right = get_theme_stylebox(SNAME("labeled_separator_right"));
int vseparation = get_theme_constant(SNAME("v_separation"));
int hseparation = get_theme_constant(SNAME("h_separation"));
Color font_color = get_theme_color(SNAME("font_color"));
Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
Color font_accelerator_color = get_theme_color(SNAME("font_accelerator_color"));
Color font_hover_color = get_theme_color(SNAME("font_hover_color"));
Color font_separator_color = get_theme_color(SNAME("font_separator_color"));
float scroll_width = scroll_container->get_v_scroll_bar()->is_visible_in_tree() ? scroll_container->get_v_scroll_bar()->get_size().width : 0;
float display_width = control->get_size().width - scroll_width;
@ -574,7 +546,7 @@ void PopupMenu::_draw_items() {
}
}
if (icon_ofs > 0.0) {
icon_ofs += hseparation;
icon_ofs += theme_cache.h_separation;
}
float check_ofs = 0.0;
@ -583,7 +555,7 @@ void PopupMenu::_draw_items() {
check_ofs = MAX(check_ofs, check[i]->get_width());
check_ofs = MAX(check_ofs, uncheck[i]->get_width());
}
check_ofs += hseparation;
check_ofs += theme_cache.h_separation;
}
Point2 ofs = Point2();
@ -591,7 +563,7 @@ void PopupMenu::_draw_items() {
// Loop through all items and draw each.
for (int i = 0; i < items.size(); i++) {
// For the first item only add half a separation. For all other items, add a whole separation to the offset.
ofs.y += i > 0 ? vseparation : (float)vseparation / 2;
ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2;
_shape_item(i);
@ -601,47 +573,47 @@ void PopupMenu::_draw_items() {
if (i == mouse_over) {
if (rtl) {
hover->draw(ci, Rect2(item_ofs + Point2(scroll_width, -vseparation / 2), Size2(display_width, h + vseparation)));
theme_cache.hover_style->draw(ci, Rect2(item_ofs + Point2(scroll_width, -theme_cache.v_separation / 2), Size2(display_width, h + theme_cache.v_separation)));
} else {
hover->draw(ci, Rect2(item_ofs + Point2(0, -vseparation / 2), Size2(display_width, h + vseparation)));
theme_cache.hover_style->draw(ci, Rect2(item_ofs + Point2(0, -theme_cache.v_separation / 2), Size2(display_width, h + theme_cache.v_separation)));
}
}
String text = items[i].xl_text;
// Separator
item_ofs.x += items[i].indent * get_theme_constant(SNAME("indent"));
item_ofs.x += items[i].indent * theme_cache.indent;
if (items[i].separator) {
if (!text.is_empty() || !items[i].icon.is_null()) {
int content_size = items[i].text_buf->get_size().width + hseparation * 2;
int content_size = items[i].text_buf->get_size().width + theme_cache.h_separation * 2;
if (!items[i].icon.is_null()) {
content_size += icon_size.width + hseparation;
content_size += icon_size.width + theme_cache.h_separation;
}
int content_center = display_width / 2;
int content_left = content_center - content_size / 2;
int content_right = content_center + content_size / 2;
if (content_left > item_ofs.x) {
int sep_h = labeled_separator_left->get_center_size().height + labeled_separator_left->get_minimum_size().height;
int sep_h = theme_cache.labeled_separator_left->get_center_size().height + theme_cache.labeled_separator_left->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h)));
theme_cache.labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h)));
}
if (content_right < display_width) {
int sep_h = labeled_separator_right->get_center_size().height + labeled_separator_right->get_minimum_size().height;
int sep_h = theme_cache.labeled_separator_right->get_center_size().height + theme_cache.labeled_separator_right->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h)));
theme_cache.labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h)));
}
} else {
int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
int sep_h = theme_cache.separator_style->get_center_size().height + theme_cache.separator_style->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
separator->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h)));
theme_cache.separator_style->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h)));
}
}
Color icon_color(1, 1, 1, items[i].disabled && !items[i].separator ? 0.5 : 1);
// For non-separator items, add some padding for the content.
item_ofs.x += item_start_padding;
item_ofs.x += theme_cache.item_start_padding;
// Checkboxes
if (items[i].checkable_type && !items[i].separator) {
@ -659,7 +631,7 @@ void PopupMenu::_draw_items() {
// Icon
if (!items[i].icon.is_null()) {
if (items[i].separator) {
separator_ofs -= (icon_size.width + hseparation) / 2;
separator_ofs -= (icon_size.width + theme_cache.h_separation) / 2;
if (rtl) {
items[i].icon->draw(ci, Size2(control->get_size().width - item_ofs.x - separator_ofs - icon_size.width, item_ofs.y) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
@ -678,61 +650,55 @@ void PopupMenu::_draw_items() {
// Submenu arrow on right hand side.
if (!items[i].submenu.is_empty()) {
if (rtl) {
submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
submenu->draw(ci, Point2(scroll_width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
} else {
submenu->draw(ci, Point2(display_width - style->get_margin(SIDE_RIGHT) - submenu->get_width() - item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
submenu->draw(ci, Point2(display_width - theme_cache.panel_style->get_margin(SIDE_RIGHT) - submenu->get_width() - theme_cache.item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
}
}
Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
int outline_size = get_theme_constant(SNAME("outline_size"));
// Text
if (items[i].separator) {
Color font_separator_outline_color = get_theme_color(SNAME("font_separator_outline_color"));
int separator_outline_size = get_theme_constant(SNAME("separator_outline_size"));
if (!text.is_empty()) {
Vector2 text_pos = Point2(separator_ofs, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
if (!rtl && !items[i].icon.is_null()) {
text_pos.x += icon_size.width + hseparation;
text_pos.x += icon_size.width + theme_cache.h_separation;
}
if (separator_outline_size > 0 && font_separator_outline_color.a > 0) {
items[i].text_buf->draw_outline(ci, text_pos, separator_outline_size, font_separator_outline_color);
if (theme_cache.font_separator_outline_size > 0 && theme_cache.font_separator_outline_color.a > 0) {
items[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_separator_outline_size, theme_cache.font_separator_outline_color);
}
items[i].text_buf->draw(ci, text_pos, font_separator_color);
items[i].text_buf->draw(ci, text_pos, theme_cache.font_separator_color);
}
} else {
item_ofs.x += icon_ofs + check_ofs;
if (rtl) {
Vector2 text_pos = Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
if (outline_size > 0 && font_outline_color.a > 0) {
items[i].text_buf->draw_outline(ci, text_pos, 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(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
items[i].text_buf->draw(ci, text_pos, items[i].disabled ? theme_cache.font_disabled_color : (i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_color));
} else {
Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
if (outline_size > 0 && font_outline_color.a > 0) {
items[i].text_buf->draw_outline(ci, text_pos, 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(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color));
items[i].text_buf->draw(ci, text_pos, items[i].disabled ? theme_cache.font_disabled_color : (i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_color));
}
}
// Accelerator / Shortcut
if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) {
if (rtl) {
item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding;
item_ofs.x = scroll_width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.item_end_padding;
} else {
item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - item_end_padding;
item_ofs.x = display_width - theme_cache.panel_style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - theme_cache.item_end_padding;
}
Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0));
if (outline_size > 0 && font_outline_color.a > 0) {
items[i].accel_text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color);
if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
items[i].accel_text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? font_hover_color : font_accelerator_color);
items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_accelerator_color);
}
// Cache the item vertical offset from the first item and the height.
@ -744,9 +710,8 @@ void PopupMenu::_draw_items() {
}
void PopupMenu::_draw_background() {
Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
RID ci2 = margin_container->get_canvas_item();
style->draw(ci2, Rect2(Point2(), margin_container->get_size()));
theme_cache.panel_style->draw(ci2, Rect2(Point2(), margin_container->get_size()));
}
void PopupMenu::_minimum_lifetime_timeout() {
@ -778,8 +743,8 @@ void PopupMenu::_shape_item(int p_item) {
if (items.write[p_item].dirty) {
items.write[p_item].text_buf->clear();
Ref<Font> font = get_theme_font(items[p_item].separator ? SNAME("font_separator") : SNAME("font"));
int font_size = get_theme_font_size(items[p_item].separator ? SNAME("font_separator_size") : SNAME("font_size"));
Ref<Font> font = items[p_item].separator ? theme_cache.font_separator : theme_cache.font;
int font_size = items[p_item].separator ? theme_cache.font_separator_size : theme_cache.font_size;
if (items[p_item].text_direction == Control::TEXT_DIRECTION_INHERITED) {
items.write[p_item].text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
@ -821,6 +786,51 @@ void PopupMenu::remove_child_notify(Node *p_child) {
_menu_changed();
}
void PopupMenu::_update_theme_item_cache() {
Popup::_update_theme_item_cache();
theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
theme_cache.hover_style = get_theme_stylebox(SNAME("hover"));
theme_cache.separator_style = get_theme_stylebox(SNAME("separator"));
theme_cache.labeled_separator_left = get_theme_stylebox(SNAME("labeled_separator_left"));
theme_cache.labeled_separator_right = get_theme_stylebox(SNAME("labeled_separator_right"));
theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
theme_cache.indent = get_theme_constant(SNAME("indent"));
theme_cache.item_start_padding = get_theme_constant(SNAME("item_start_padding"));
theme_cache.item_end_padding = get_theme_constant(SNAME("item_end_padding"));
theme_cache.checked = get_theme_icon(SNAME("checked"));
theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked"));
theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled"));
theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked"));
theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled"));
theme_cache.submenu = get_theme_icon(SNAME("submenu"));
theme_cache.submenu_mirrored = get_theme_icon(SNAME("submenu_mirrored"));
theme_cache.font = get_theme_font(SNAME("font"));
theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
theme_cache.font_separator = get_theme_font(SNAME("font_separator"));
theme_cache.font_separator_size = get_theme_font_size(SNAME("font_separator_size"));
theme_cache.font_color = get_theme_color(SNAME("font_color"));
theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
theme_cache.font_accelerator_color = get_theme_color(SNAME("font_accelerator_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_separator_color = get_theme_color(SNAME("font_separator_color"));
theme_cache.font_separator_outline_size = get_theme_constant(SNAME("separator_outline_size"));
theme_cache.font_separator_outline_color = get_theme_color(SNAME("font_separator_outline_color"));
}
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@ -909,11 +919,10 @@ void PopupMenu::_notification(int p_what) {
}
// Set margin on the margin container
Ref<StyleBox> panel_style = get_theme_stylebox(SNAME("panel"));
margin_container->add_theme_constant_override("margin_left", panel_style->get_margin(Side::SIDE_LEFT));
margin_container->add_theme_constant_override("margin_top", panel_style->get_margin(Side::SIDE_TOP));
margin_container->add_theme_constant_override("margin_right", panel_style->get_margin(Side::SIDE_RIGHT));
margin_container->add_theme_constant_override("margin_bottom", panel_style->get_margin(Side::SIDE_BOTTOM));
margin_container->add_theme_constant_override("margin_left", theme_cache.panel_style->get_margin(Side::SIDE_LEFT));
margin_container->add_theme_constant_override("margin_top", theme_cache.panel_style->get_margin(Side::SIDE_TOP));
margin_container->add_theme_constant_override("margin_right", theme_cache.panel_style->get_margin(Side::SIDE_RIGHT));
margin_container->add_theme_constant_override("margin_bottom", theme_cache.panel_style->get_margin(Side::SIDE_BOTTOM));
}
} break;
}

View file

@ -129,6 +129,49 @@ class PopupMenu : public Popup {
ScrollContainer *scroll_container = nullptr;
Control *control = nullptr;
struct ThemeCache {
Ref<StyleBox> panel_style;
Ref<StyleBox> hover_style;
Ref<StyleBox> separator_style;
Ref<StyleBox> labeled_separator_left;
Ref<StyleBox> labeled_separator_right;
int v_separation = 0;
int h_separation = 0;
int indent = 0;
int item_start_padding = 0;
int item_end_padding = 0;
Ref<Texture2D> checked;
Ref<Texture2D> checked_disabled;
Ref<Texture2D> unchecked;
Ref<Texture2D> unchecked_disabled;
Ref<Texture2D> radio_checked;
Ref<Texture2D> radio_checked_disabled;
Ref<Texture2D> radio_unchecked;
Ref<Texture2D> radio_unchecked_disabled;
Ref<Texture2D> submenu;
Ref<Texture2D> submenu_mirrored;
Ref<Font> font;
int font_size = 0;
Ref<Font> font_separator;
int font_separator_size = 0;
Color font_color;
Color font_hover_color;
Color font_disabled_color;
Color font_accelerator_color;
int font_outline_size = 0;
Color font_outline_color;
Color font_separator_color;
int font_separator_outline_size = 0;
Color font_separator_outline_color;
} theme_cache;
void _draw_items();
void _draw_background();
@ -137,6 +180,8 @@ class PopupMenu : public Popup {
void _menu_changed();
protected:
virtual void _update_theme_item_cache() override;
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
void _notification(int p_what);

View file

@ -799,6 +799,11 @@ Viewport *Window::_get_embedder() const {
void Window::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POSTINITIALIZE: {
_invalidate_theme_cache();
_update_theme_item_cache();
} break;
case NOTIFICATION_ENTER_TREE: {
bool embedded = false;
{
@ -858,6 +863,8 @@ void Window::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
emit_signal(SceneStringNames::get_singleton()->theme_changed);
_invalidate_theme_cache();
_update_theme_item_cache();
} break;
case NOTIFICATION_READY: {
@ -867,6 +874,9 @@ void Window::_notification(int p_what) {
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
_invalidate_theme_cache();
_update_theme_item_cache();
if (embedder) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
@ -1342,6 +1352,18 @@ void Window::_theme_changed() {
}
}
void Window::_invalidate_theme_cache() {
theme_icon_cache.clear();
theme_style_cache.clear();
theme_font_cache.clear();
theme_font_size_cache.clear();
theme_color_cache.clear();
theme_constant_cache.clear();
}
void Window::_update_theme_item_cache() {
}
void Window::set_theme_type_variation(const StringName &p_theme_type) {
theme_type_variation = p_theme_type;
if (is_inside_tree()) {
@ -1366,39 +1388,75 @@ void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<S
}
Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (theme_icon_cache.has(p_theme_type) && theme_icon_cache[p_theme_type].has(p_name)) {
return theme_icon_cache[p_theme_type][p_name];
}
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
return Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
Ref<Texture2D> icon = Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
theme_icon_cache[p_theme_type][p_name] = icon;
return icon;
}
Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
if (theme_style_cache.has(p_theme_type) && theme_style_cache[p_theme_type].has(p_name)) {
return theme_style_cache[p_theme_type][p_name];
}
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
return Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
Ref<StyleBox> style = Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
theme_style_cache[p_theme_type][p_name] = style;
return style;
}
Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
if (theme_font_cache.has(p_theme_type) && theme_font_cache[p_theme_type].has(p_name)) {
return theme_font_cache[p_theme_type][p_name];
}
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
return Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
Ref<Font> font = Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
theme_font_cache[p_theme_type][p_name] = font;
return font;
}
int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
if (theme_font_size_cache.has(p_theme_type) && theme_font_size_cache[p_theme_type].has(p_name)) {
return theme_font_size_cache[p_theme_type][p_name];
}
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
int font_size = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
theme_font_size_cache[p_theme_type][p_name] = font_size;
return font_size;
}
Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
if (theme_color_cache.has(p_theme_type) && theme_color_cache[p_theme_type].has(p_name)) {
return theme_color_cache[p_theme_type][p_name];
}
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
return Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
Color color = Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
theme_color_cache[p_theme_type][p_name] = color;
return color;
}
int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
if (theme_constant_cache.has(p_theme_type) && theme_constant_cache[p_theme_type].has(p_name)) {
return theme_constant_cache[p_theme_type][p_name];
}
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
int constant = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
theme_constant_cache[p_theme_type][p_name] = constant;
return constant;
}
bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {

View file

@ -32,12 +32,12 @@
#define WINDOW_H
#include "scene/main/viewport.h"
#include "scene/resources/theme.h"
class Control;
class Font;
class Shortcut;
class StyleBox;
class Theme;
class Window : public Viewport {
GDCLASS(Window, Viewport)
@ -141,6 +141,18 @@ private:
Window *theme_owner_window = nullptr;
StringName theme_type_variation;
mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache;
mutable HashMap<StringName, Theme::ThemeStyleMap> theme_style_cache;
mutable HashMap<StringName, Theme::ThemeFontMap> theme_font_cache;
mutable HashMap<StringName, Theme::ThemeFontSizeMap> theme_font_size_cache;
mutable HashMap<StringName, Theme::ThemeColorMap> theme_color_cache;
mutable HashMap<StringName, Theme::ThemeConstantMap> theme_constant_cache;
_FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
void _theme_changed();
void _invalidate_theme_cache();
Viewport *embedder = nullptr;
friend class Viewport; //friend back, can call the methods below
@ -158,6 +170,8 @@ protected:
Viewport *_get_embedder() const;
virtual Rect2i _popup_adjust_rect() const { return Rect2i(); }
virtual void _update_theme_item_cache();
virtual void _post_popup() {}
virtual Size2 _get_contents_minimum_size() const;
static void _bind_methods();
@ -259,11 +273,9 @@ public:
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
void _theme_changed();
void set_theme_type_variation(const StringName &p_theme_type);
StringName get_theme_type_variation() const;
_FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
Size2 get_contents_minimum_size() const;

View file

@ -609,11 +609,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// Dialogs
theme->set_constant("margin", "Dialogs", 8 * scale);
theme->set_constant("button_margin", "Dialogs", 32 * scale);
// AcceptDialog
// AcceptDialog is currently the base dialog, so this defines styles for all extending nodes.
theme->set_constant("margin", "AcceptDialog", 8 * scale);
theme->set_constant("button_margin", "AcceptDialog", 32 * scale);
theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 0, 0, 0, 0));
// File Dialog