PopupMenu: Add theme option for merging icon and checkbox gutters

This commit is contained in:
Haoyu Qiu
2025-11-08 22:34:25 +08:00
parent 6fd949a6dc
commit 4694ee84f6
4 changed files with 47 additions and 26 deletions

View File

@ -231,7 +231,8 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
real_t body_max_w = 0.0; // Indentation, text, and submenu arrow.
real_t icon_max_w = 0.0;
real_t accel_max_w = 0.0;
bool has_check = false;
bool has_check_gutter = false;
bool gutter_compact = theme_cache.gutter_compact;
for (int i = 0; i < items.size(); i++) {
_shape_item(i);
@ -239,7 +240,10 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
icon_max_w = MAX(_get_item_icon_size(i).width, icon_max_w);
if (items[i].checkable_type && !items[i].separator) {
has_check = true;
has_check_gutter = true;
if (items[i].icon.is_valid()) {
gutter_compact = false;
}
}
if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) {
@ -258,12 +262,16 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
minsize.width += theme_cache.item_start_padding + body_max_w + accel_max_w + theme_cache.item_end_padding;
if (icon_max_w > 0) {
minsize.width += icon_max_w + theme_cache.h_separation;
}
if (has_check) {
int check_w = MAX(theme_cache.checked->get_width(), theme_cache.radio_checked->get_width());
minsize.width += check_w + theme_cache.h_separation;
const int check_w = MAX(theme_cache.checked->get_width(), theme_cache.radio_checked->get_width());
if (gutter_compact) {
minsize.width += MAX(icon_max_w, check_w) + theme_cache.h_separation;
} else {
if (icon_max_w > 0) {
minsize.width += icon_max_w + theme_cache.h_separation;
}
if (has_check_gutter) {
minsize.width += check_w + theme_cache.h_separation;
}
}
if (is_inside_tree()) {
@ -801,31 +809,29 @@ void PopupMenu::_draw_items() {
float display_width = control->get_size().width;
// Find the widest icon and whether any items have a checkbox, and store the offsets for each.
float icon_ofs = 0.0;
bool has_check = false;
real_t icon_max_w = 0.0;
real_t check_max_w = 0.0;
bool has_check_gutter = false;
bool gutter_compact = theme_cache.gutter_compact;
for (int i = 0; i < items.size(); i++) {
if (items[i].separator) {
continue;
}
Size2 icon_size = _get_item_icon_size(i);
icon_ofs = MAX(icon_size.width, icon_ofs);
icon_max_w = MAX(_get_item_icon_size(i).width, icon_max_w);
if (items[i].checkable_type) {
has_check = true;
has_check_gutter = true;
if (items[i].icon.is_valid()) {
gutter_compact = false;
}
}
}
if (icon_ofs > 0.0) {
icon_ofs += theme_cache.h_separation;
}
float check_ofs = 0.0;
if (has_check) {
if (has_check_gutter) {
for (int i = 0; i < 4; i++) {
check_ofs = MAX(check_ofs, check[i]->get_width());
check_ofs = MAX(check_ofs, uncheck[i]->get_width());
check_max_w = MAX(check_max_w, check[i]->get_width());
check_max_w = MAX(check_max_w, uncheck[i]->get_width());
}
check_ofs += theme_cache.h_separation;
}
Point2 ofs;
@ -911,10 +917,11 @@ void PopupMenu::_draw_items() {
separator_ofs += icon_size.width + theme_cache.h_separation;
}
} else {
const real_t check_w = (gutter_compact || !has_check_gutter) ? 0 : (check_max_w + theme_cache.h_separation);
if (rtl) {
icon_pos = Size2(control->get_size().width - item_ofs.x - check_ofs - icon_size.width, item_ofs.y);
icon_pos = Size2(control->get_size().width - item_ofs.x - check_w - icon_size.width, item_ofs.y);
} else {
icon_pos = item_ofs + Size2(check_ofs, 0);
icon_pos = item_ofs + Size2(check_w, 0);
}
}
@ -941,8 +948,16 @@ void PopupMenu::_draw_items() {
items[i].text_buf->draw(ci, text_pos, theme_cache.font_separator_color);
}
} else {
item_ofs.x += icon_ofs + check_ofs;
if (gutter_compact) {
item_ofs.x += MAX(icon_max_w, check_max_w) + theme_cache.h_separation;
} else {
if (icon_max_w > 0) {
item_ofs.x += icon_max_w + theme_cache.h_separation;
}
if (has_check_gutter) {
item_ofs.x += check_max_w + theme_cache.h_separation;
}
}
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 (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) {
@ -3136,6 +3151,7 @@ void PopupMenu::_bind_methods() {
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, item_start_padding);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, item_end_padding);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, icon_max_width);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, gutter_compact);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, checked);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, checked_disabled);