Make icons of scripted and custom classes fit the editor UI
Also: - Add an option to limit the icon size in PopupMenu. This is similar to how this works in Tree and TreeItem. - Add the same option to TabBar. - Add a theme constant for Tree, PopupMenu, Button, and TabBar to apply this limit on the control level. Co-authored-by: Daylily-Zeleen <daylily-zeleen@foxmail.com>
This commit is contained in:
parent
9fae65404a
commit
1522762dc9
28 changed files with 339 additions and 89 deletions
|
@ -48,7 +48,7 @@
|
|||
When this property is enabled, text that is too large to fit the button is clipped, when disabled the Button will always be wide enough to hold the text.
|
||||
</member>
|
||||
<member name="expand_icon" type="bool" setter="set_expand_icon" getter="is_expand_icon" default="false">
|
||||
When enabled, the button's icon will expand/shrink to fit the button's size while keeping its aspect.
|
||||
When enabled, the button's icon will expand/shrink to fit the button's size while keeping its aspect. See also [theme_item icon_max_width].
|
||||
</member>
|
||||
<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
|
||||
Flat buttons don't display decoration.
|
||||
|
@ -116,6 +116,9 @@
|
|||
<theme_item name="h_separation" data_type="constant" type="int" default="2">
|
||||
The horizontal space between [Button]'s icon and text. Negative values will be treated as [code]0[/code] when used.
|
||||
</theme_item>
|
||||
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
|
||||
The maximum allowed width of the [Button]'s icon. This limit is applied on top of the default size of the icon, or its expanded size if [member expand_icon] is [code]true[/code]. The height is adjusted according to the icon's ratio.
|
||||
</theme_item>
|
||||
<theme_item name="outline_size" data_type="constant" type="int" default="0">
|
||||
The size of the text outline.
|
||||
[b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
|
||||
|
|
|
@ -202,6 +202,13 @@
|
|||
Returns the icon of the item at the given [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_item_icon_max_width" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<description>
|
||||
Returns the maximum allowed width of the icon for the item at the given [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_item_id" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="index" type="int" />
|
||||
|
@ -397,6 +404,14 @@
|
|||
Replaces the [Texture2D] icon of the item at the given [param index].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_item_icon_max_width">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
<param index="1" name="width" type="int" />
|
||||
<description>
|
||||
Sets the maximum allowed width of the icon for the item at the given [param index]. This limit is applied on top of the default size of the icon and on top of [theme_item icon_max_width]. The height is adjusted according to the icon's ratio.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_item_id">
|
||||
<return type="void" />
|
||||
<param index="0" name="index" type="int" />
|
||||
|
@ -573,6 +588,9 @@
|
|||
<theme_item name="h_separation" data_type="constant" type="int" default="4">
|
||||
The horizontal space between the item's elements.
|
||||
</theme_item>
|
||||
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
|
||||
The maximum allowed width of the item's icon. This limit is applied on top of the default size of the icon, but before the value set with [method set_item_icon_max_width]. The height is adjusted according to the icon's ratio.
|
||||
</theme_item>
|
||||
<theme_item name="indent" data_type="constant" type="int" default="10">
|
||||
Width of the single indentation level.
|
||||
</theme_item>
|
||||
|
|
|
@ -46,14 +46,21 @@
|
|||
<return type="Texture2D" />
|
||||
<param index="0" name="tab_idx" type="int" />
|
||||
<description>
|
||||
Returns the [Texture2D] for the right button of the tab at index [param tab_idx] or [code]null[/code] if the button has no [Texture2D].
|
||||
Returns the icon for the right button of the tab at index [param tab_idx] or [code]null[/code] if the right button has no icon.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_tab_icon" qualifiers="const">
|
||||
<return type="Texture2D" />
|
||||
<param index="0" name="tab_idx" type="int" />
|
||||
<description>
|
||||
Returns the [Texture2D] for the tab at index [param tab_idx] or [code]null[/code] if the tab has no [Texture2D].
|
||||
Returns the icon for the tab at index [param tab_idx] or [code]null[/code] if the tab has no icon.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_tab_icon_max_width" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="tab_idx" type="int" />
|
||||
<description>
|
||||
Returns the maximum allowed width of the icon for the tab at index [param tab_idx].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_tab_idx_at_point" qualifiers="const">
|
||||
|
@ -158,6 +165,14 @@
|
|||
Sets an [param icon] for the tab at index [param tab_idx].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_tab_icon_max_width">
|
||||
<return type="void" />
|
||||
<param index="0" name="tab_idx" type="int" />
|
||||
<param index="1" name="width" type="int" />
|
||||
<description>
|
||||
Sets the maximum allowed width of the icon for the tab at index [param tab_idx]. This limit is applied on top of the default size of the icon and on top of [theme_item icon_max_width]. The height is adjusted according to the icon's ratio.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_tab_language">
|
||||
<return type="void" />
|
||||
<param index="0" name="tab_idx" type="int" />
|
||||
|
@ -323,6 +338,9 @@
|
|||
<theme_item name="h_separation" data_type="constant" type="int" default="4">
|
||||
The horizontal separation between the elements inside tabs.
|
||||
</theme_item>
|
||||
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
|
||||
The maximum allowed width of the tab's icon. This limit is applied on top of the default size of the icon, but before the value set with [method set_tab_icon_max_width]. The height is adjusted according to the icon's ratio.
|
||||
</theme_item>
|
||||
<theme_item name="outline_size" data_type="constant" type="int" default="0">
|
||||
The size of the tab text outline.
|
||||
[b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
|
||||
|
|
|
@ -209,6 +209,9 @@
|
|||
<theme_item name="font_unselected_color" data_type="color" type="Color" default="Color(0.7, 0.7, 0.7, 1)">
|
||||
Font color of the other, unselected tabs.
|
||||
</theme_item>
|
||||
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
|
||||
The maximum allowed width of the tab's icon. This limit is applied on top of the default size of the icon, but before the value set with [method TabBar.set_tab_icon_max_width]. The height is adjusted according to the icon's ratio.
|
||||
</theme_item>
|
||||
<theme_item name="icon_separation" data_type="constant" type="int" default="4">
|
||||
Space between tab's name and its icon.
|
||||
</theme_item>
|
||||
|
|
|
@ -518,6 +518,9 @@
|
|||
<theme_item name="h_separation" data_type="constant" type="int" default="4">
|
||||
The horizontal space between item cells. This is also used as the margin at the start of an item when folding is disabled.
|
||||
</theme_item>
|
||||
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
|
||||
The maximum allowed width of the icon in item's cells. This limit is applied on top of the default size of the icon, but before the value set with [method TreeItem.set_icon_max_width]. The height is adjusted according to the icon's ratio.
|
||||
</theme_item>
|
||||
<theme_item name="item_margin" data_type="constant" type="int" default="16">
|
||||
The horizontal margin at the start of an item. This is used when folding is enabled for the item.
|
||||
</theme_item>
|
||||
|
|
|
@ -183,7 +183,7 @@
|
|||
<return type="int" />
|
||||
<param index="0" name="column" type="int" />
|
||||
<description>
|
||||
Returns the column's icon's maximum width.
|
||||
Returns the maximum allowed width of the icon in the given [param column].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_icon_modulate" qualifiers="const">
|
||||
|
@ -545,7 +545,7 @@
|
|||
<param index="0" name="column" type="int" />
|
||||
<param index="1" name="width" type="int" />
|
||||
<description>
|
||||
Sets the given column's icon's maximum width.
|
||||
Sets the maximum allowed width of the icon in the given [param column]. This limit is applied on top of the default size of the icon and on top of [theme_item Tree.icon_max_width]. The height is adjusted according to the icon's ratio.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_icon_modulate">
|
||||
|
|
|
@ -462,6 +462,11 @@ void CreateDialog::_notification(int p_what) {
|
|||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
const int icon_width = get_theme_constant(SNAME("class_icon_size"), SNAME("Editor"));
|
||||
search_options->add_theme_constant_override("icon_max_width", icon_width);
|
||||
favorites->add_theme_constant_override("icon_max_width", icon_width);
|
||||
recent->set_fixed_icon_size(Size2(icon_width, icon_width));
|
||||
|
||||
_update_theme();
|
||||
} break;
|
||||
}
|
||||
|
|
|
@ -1030,13 +1030,11 @@ void EditorData::script_class_load_icon_paths() {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<ImageTexture> EditorData::_load_script_icon(const String &p_path) const {
|
||||
if (p_path.length()) {
|
||||
Ref<Image> img = memnew(Image);
|
||||
Error err = ImageLoader::load_image(p_path, img);
|
||||
if (err == OK) {
|
||||
img->resize(16 * EDSCALE, 16 * EDSCALE, Image::INTERPOLATE_LANCZOS);
|
||||
return ImageTexture::create_from_image(img);
|
||||
Ref<Texture2D> EditorData::_load_script_icon(const String &p_path) const {
|
||||
if (!p_path.is_empty() && ResourceLoader::exists(p_path)) {
|
||||
Ref<Texture2D> icon = ResourceLoader::load(p_path);
|
||||
if (icon.is_valid()) {
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -1051,9 +1049,9 @@ Ref<Texture2D> EditorData::get_script_icon(const Ref<Script> &p_script) {
|
|||
Ref<Script> base_scr = p_script;
|
||||
while (base_scr.is_valid()) {
|
||||
// Check for scripted classes.
|
||||
StringName name = script_class_get_name(base_scr->get_path());
|
||||
String icon_path = script_class_get_icon_path(name);
|
||||
Ref<ImageTexture> icon = _load_script_icon(icon_path);
|
||||
StringName class_name = script_class_get_name(base_scr->get_path());
|
||||
String icon_path = script_class_get_icon_path(class_name);
|
||||
Ref<Texture2D> icon = _load_script_icon(icon_path);
|
||||
if (icon.is_valid()) {
|
||||
_script_icon_cache[p_script] = icon;
|
||||
return icon;
|
||||
|
|
|
@ -146,7 +146,7 @@ private:
|
|||
HashMap<String, StringName> _script_class_file_to_path;
|
||||
HashMap<Ref<Script>, Ref<Texture>> _script_icon_cache;
|
||||
|
||||
Ref<ImageTexture> _load_script_icon(const String &p_path) const;
|
||||
Ref<Texture2D> _load_script_icon(const String &p_path) const;
|
||||
|
||||
public:
|
||||
EditorPlugin *get_editor(Object *p_object);
|
||||
|
|
|
@ -668,7 +668,7 @@ void EditorHelp::_update_doc() {
|
|||
String inherits = cd.inherits;
|
||||
|
||||
while (!inherits.is_empty()) {
|
||||
_add_type_icon(inherits, 0, "ArrowRight");
|
||||
_add_type_icon(inherits, theme_cache.doc_font_size, "ArrowRight");
|
||||
class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
|
||||
_add_type(inherits);
|
||||
|
||||
|
@ -701,7 +701,7 @@ void EditorHelp::_update_doc() {
|
|||
if (prev) {
|
||||
class_desc->add_text(" , ");
|
||||
}
|
||||
_add_type_icon(E.value.name, 0, "ArrowRight");
|
||||
_add_type_icon(E.value.name, theme_cache.doc_font_size, "ArrowRight");
|
||||
class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
|
||||
_add_type(E.value.name);
|
||||
prev = true;
|
||||
|
|
|
@ -1134,17 +1134,21 @@ void EditorInspectorCategory::_notification(int p_what) {
|
|||
int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
|
||||
|
||||
int hs = get_theme_constant(SNAME("h_separation"), SNAME("Tree"));
|
||||
int icon_size = get_theme_constant(SNAME("class_icon_size"), SNAME("Editor"));
|
||||
|
||||
int w = font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width;
|
||||
if (icon.is_valid()) {
|
||||
w += hs + icon->get_width();
|
||||
w += hs + icon_size;
|
||||
}
|
||||
|
||||
int ofs = (get_size().width - w) / 2;
|
||||
|
||||
if (icon.is_valid()) {
|
||||
draw_texture(icon, Point2(ofs, (get_size().height - icon->get_height()) / 2).floor());
|
||||
ofs += hs + icon->get_width();
|
||||
Size2 rect_size = Size2(icon_size, icon_size);
|
||||
Point2 rect_pos = Point2(ofs, (get_size().height - icon_size) / 2).floor();
|
||||
draw_texture_rect(icon, Rect2(rect_pos, rect_size));
|
||||
|
||||
ofs += hs + icon_size;
|
||||
}
|
||||
|
||||
Color color = get_theme_color(SNAME("font_color"), SNAME("Tree"));
|
||||
|
|
|
@ -681,10 +681,6 @@ void EditorNode::_notification(int p_what) {
|
|||
editor_data.clear_edited_scenes();
|
||||
} break;
|
||||
|
||||
case Control::NOTIFICATION_THEME_CHANGED: {
|
||||
scene_tab_add_ph->set_custom_minimum_size(scene_tab_add->get_minimum_size());
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
{
|
||||
_initializing_plugins = true;
|
||||
|
@ -772,6 +768,9 @@ void EditorNode::_notification(int p_what) {
|
|||
bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("BottomPanel"), SNAME("EditorStyles")));
|
||||
tabbar_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer")));
|
||||
|
||||
scene_tabs->add_theme_constant_override("icon_max_width", gui_base->get_theme_constant(SNAME("class_icon_size"), SNAME("Editor")));
|
||||
scene_tab_add_ph->set_custom_minimum_size(scene_tab_add->get_minimum_size());
|
||||
|
||||
main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
|
||||
}
|
||||
|
||||
|
@ -7114,6 +7113,7 @@ EditorNode::EditorNode() {
|
|||
scene_tabs->set_select_with_rmb(true);
|
||||
scene_tabs->add_tab("unsaved");
|
||||
scene_tabs->set_tab_close_display_policy((TabBar::CloseButtonDisplayPolicy)EDITOR_GET("interface/scene_tabs/display_close_button").operator int());
|
||||
scene_tabs->add_theme_constant_override("icon_max_width", gui_base->get_theme_constant(SNAME("class_icon_size"), SNAME("Editor")));
|
||||
scene_tabs->set_max_tab_width(int(EDITOR_GET("interface/scene_tabs/maximum_width")) * EDSCALE);
|
||||
scene_tabs->set_drag_to_rearrange_enabled(true);
|
||||
scene_tabs->set_auto_translate(false);
|
||||
|
|
|
@ -201,8 +201,12 @@ void EditorPath::_notification(int p_what) {
|
|||
case NOTIFICATION_THEME_CHANGED: {
|
||||
update_path();
|
||||
|
||||
sub_objects_icon->set_texture(get_theme_icon(SNAME("arrow"), SNAME("OptionButton")));
|
||||
int icon_size = get_theme_constant(SNAME("class_icon_size"), SNAME("Editor"));
|
||||
|
||||
current_object_icon->set_custom_minimum_size(Size2(icon_size, icon_size));
|
||||
current_object_label->add_theme_font_override("font", get_theme_font(SNAME("main"), SNAME("EditorFonts")));
|
||||
sub_objects_icon->set_texture(get_theme_icon(SNAME("arrow"), SNAME("OptionButton")));
|
||||
sub_objects_menu->add_theme_constant_override("icon_max_width", icon_size);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
|
@ -227,7 +231,8 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) {
|
|||
main_mc->add_child(main_hb);
|
||||
|
||||
current_object_icon = memnew(TextureRect);
|
||||
current_object_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
|
||||
current_object_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
|
||||
current_object_icon->set_expand_mode(TextureRect::EXPAND_IGNORE_SIZE);
|
||||
main_hb->add_child(current_object_icon);
|
||||
|
||||
current_object_label = memnew(Label);
|
||||
|
|
|
@ -784,6 +784,7 @@ void EditorResourcePicker::_notification(int p_what) {
|
|||
[[fallthrough]];
|
||||
}
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
assign_button->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), SNAME("Editor")));
|
||||
edit_button->set_icon(get_theme_icon(SNAME("select_arrow"), SNAME("Tree")));
|
||||
} break;
|
||||
|
||||
|
@ -923,6 +924,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {
|
|||
assign_button = memnew(Button);
|
||||
assign_button->set_flat(true);
|
||||
assign_button->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
assign_button->set_expand_icon(true);
|
||||
assign_button->set_clip_text(true);
|
||||
assign_button->set_auto_translate(false);
|
||||
SET_DRAG_FORWARDING_GCD(assign_button, EditorResourcePicker);
|
||||
|
|
|
@ -587,9 +587,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
|
|||
} else {
|
||||
theme->set_color("highend_color", "Editor", Color(1.0, 0.0, 0.0));
|
||||
}
|
||||
|
||||
const int thumb_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
|
||||
theme->set_constant("scale", "Editor", EDSCALE);
|
||||
theme->set_constant("thumb_size", "Editor", thumb_size);
|
||||
theme->set_constant("class_icon_size", "Editor", 16 * EDSCALE);
|
||||
theme->set_constant("dark_theme", "Editor", dark_theme);
|
||||
theme->set_constant("color_picker_button_height", "Editor", 28 * EDSCALE);
|
||||
|
||||
|
|
|
@ -1278,13 +1278,6 @@ void SceneTreeDock::_notification(int p_what) {
|
|||
spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
|
||||
spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
|
||||
|
||||
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
|
||||
button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
|
||||
button_create_script->set_icon(get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons")));
|
||||
button_detach_script->set_icon(get_theme_icon(SNAME("ScriptRemove"), SNAME("EditorIcons")));
|
||||
button_tree_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
|
||||
|
||||
filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
|
||||
filter->set_clear_button_enabled(true);
|
||||
|
||||
// create_root_dialog
|
||||
|
@ -1366,19 +1359,35 @@ void SceneTreeDock::_notification(int p_what) {
|
|||
|
||||
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
||||
scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
|
||||
button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
|
||||
button_create_script->set_icon(get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons")));
|
||||
button_detach_script->set_icon(get_theme_icon(SNAME("ScriptRemove"), SNAME("EditorIcons")));
|
||||
button_tree_menu->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
|
||||
button_2d->set_icon(get_theme_icon(SNAME("Node2D"), SNAME("EditorIcons")));
|
||||
button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
|
||||
button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
|
||||
button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
|
||||
button_clipboard->set_icon(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")));
|
||||
|
||||
filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
|
||||
filter->set_clear_button_enabled(true);
|
||||
|
||||
// These buttons are created on READY, because reasons...
|
||||
if (button_2d) {
|
||||
button_2d->set_icon(get_theme_icon(SNAME("Node2D"), SNAME("EditorIcons")));
|
||||
}
|
||||
if (button_3d) {
|
||||
button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
|
||||
}
|
||||
if (button_ui) {
|
||||
button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
|
||||
}
|
||||
if (button_custom) {
|
||||
button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
|
||||
}
|
||||
if (button_clipboard) {
|
||||
button_clipboard->set_icon(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")));
|
||||
}
|
||||
|
||||
menu_subresources->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), SNAME("Editor")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PROCESS: {
|
||||
|
|
|
@ -878,6 +878,8 @@ void SceneTreeEditor::_notification(int p_what) {
|
|||
} break;
|
||||
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
tree->add_theme_constant_override("icon_max_width", get_theme_constant(SNAME("class_icon_size"), SNAME("Editor")));
|
||||
|
||||
_update_tree();
|
||||
} break;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ void Button::_update_theme_item_cache() {
|
|||
theme_cache.icon = get_theme_icon(SNAME("icon"));
|
||||
|
||||
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
|
||||
theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
|
||||
}
|
||||
|
||||
void Button::_notification(int p_what) {
|
||||
|
@ -252,7 +253,6 @@ void Button::_notification(int p_what) {
|
|||
|
||||
float icon_ofs_region = 0.0;
|
||||
Point2 style_offset;
|
||||
Size2 icon_size = _icon->get_size();
|
||||
if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) {
|
||||
style_offset.x = style->get_margin(SIDE_LEFT);
|
||||
if (_internal_margin[SIDE_LEFT] > 0) {
|
||||
|
@ -268,6 +268,7 @@ void Button::_notification(int p_what) {
|
|||
}
|
||||
style_offset.y = style->get_margin(SIDE_TOP);
|
||||
|
||||
Size2 icon_size = _icon->get_size();
|
||||
if (expand_icon) {
|
||||
Size2 _size = get_size() - style->get_offset() * 2;
|
||||
int icon_text_separation = text.is_empty() ? 0 : theme_cache.h_separation;
|
||||
|
@ -285,6 +286,7 @@ void Button::_notification(int p_what) {
|
|||
|
||||
icon_size = Size2(icon_width, icon_height);
|
||||
}
|
||||
icon_size = _fit_icon_size(icon_size);
|
||||
|
||||
if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) {
|
||||
icon_region = Rect2(style_offset + Point2(icon_ofs_region, Math::floor((valign - icon_size.y) * 0.5)), icon_size);
|
||||
|
@ -365,6 +367,18 @@ void Button::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
Size2 Button::_fit_icon_size(const Size2 &p_size) const {
|
||||
int max_width = theme_cache.icon_max_width;
|
||||
Size2 icon_size = p_size;
|
||||
|
||||
if (max_width > 0 && icon_size.width > max_width) {
|
||||
icon_size.height = icon_size.height * max_width / icon_size.width;
|
||||
icon_size.width = max_width;
|
||||
}
|
||||
|
||||
return icon_size;
|
||||
}
|
||||
|
||||
Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Texture2D> p_icon) const {
|
||||
Ref<TextParagraph> paragraph;
|
||||
if (p_text.is_empty()) {
|
||||
|
@ -380,15 +394,16 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
|
|||
}
|
||||
|
||||
if (!expand_icon && p_icon.is_valid()) {
|
||||
minsize.height = MAX(minsize.height, p_icon->get_height());
|
||||
Size2 icon_size = _fit_icon_size(p_icon->get_size());
|
||||
minsize.height = MAX(minsize.height, icon_size.height);
|
||||
|
||||
if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
|
||||
minsize.width += p_icon->get_width();
|
||||
minsize.width += icon_size.width;
|
||||
if (!xl_text.is_empty() || !p_text.is_empty()) {
|
||||
minsize.width += MAX(0, theme_cache.h_separation);
|
||||
}
|
||||
} else {
|
||||
minsize.width = MAX(minsize.width, p_icon->get_width());
|
||||
minsize.width = MAX(minsize.width, icon_size.width);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,8 +89,11 @@ private:
|
|||
Ref<Texture2D> icon;
|
||||
|
||||
int h_separation = 0;
|
||||
int icon_max_width = 0;
|
||||
} theme_cache;
|
||||
|
||||
Size2 _fit_icon_size(const Size2 &p_size) const;
|
||||
|
||||
void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = "");
|
||||
|
||||
protected:
|
||||
|
|
|
@ -47,6 +47,26 @@ String PopupMenu::_get_accel_text(const Item &p_item) const {
|
|||
return String();
|
||||
}
|
||||
|
||||
Size2 PopupMenu::_get_item_icon_size(int p_item) const {
|
||||
const PopupMenu::Item &item = items[p_item];
|
||||
Size2 icon_size = item.get_icon_size();
|
||||
|
||||
int max_width = 0;
|
||||
if (theme_cache.icon_max_width > 0) {
|
||||
max_width = theme_cache.icon_max_width;
|
||||
}
|
||||
if (item.icon_max_width > 0 && (max_width == 0 || item.icon_max_width < max_width)) {
|
||||
max_width = item.icon_max_width;
|
||||
}
|
||||
|
||||
if (max_width > 0 && icon_size.width > max_width) {
|
||||
icon_size.height = icon_size.height * max_width / icon_size.width;
|
||||
icon_size.width = max_width;
|
||||
}
|
||||
|
||||
return icon_size;
|
||||
}
|
||||
|
||||
Size2 PopupMenu::_get_contents_minimum_size() const {
|
||||
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
|
||||
|
@ -61,7 +81,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
|
|||
Size2 item_size;
|
||||
const_cast<PopupMenu *>(this)->_shape_item(i);
|
||||
|
||||
Size2 icon_size = items[i].get_icon_size();
|
||||
Size2 icon_size = _get_item_icon_size(i);
|
||||
item_size.height = _get_item_height(i);
|
||||
icon_w = MAX(icon_size.width, icon_w);
|
||||
|
||||
|
@ -109,7 +129,8 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
|
|||
int PopupMenu::_get_item_height(int p_item) const {
|
||||
ERR_FAIL_INDEX_V(p_item, items.size(), 0);
|
||||
|
||||
int icon_height = items[p_item].get_icon_size().height;
|
||||
Size2 icon_size = _get_item_icon_size(p_item);
|
||||
int icon_height = icon_size.height;
|
||||
if (items[p_item].checkable_type && !items[p_item].separator) {
|
||||
icon_height = MAX(icon_height, MAX(theme_cache.checked->get_height(), theme_cache.radio_checked->get_height()));
|
||||
}
|
||||
|
@ -540,7 +561,8 @@ void PopupMenu::_draw_items() {
|
|||
continue;
|
||||
}
|
||||
|
||||
icon_ofs = MAX(items[i].get_icon_size().width, icon_ofs);
|
||||
Size2 icon_size = _get_item_icon_size(i);
|
||||
icon_ofs = MAX(icon_size.width, icon_ofs);
|
||||
|
||||
if (items[i].checkable_type) {
|
||||
has_check = true;
|
||||
|
@ -569,7 +591,7 @@ void PopupMenu::_draw_items() {
|
|||
_shape_item(i);
|
||||
|
||||
Point2 item_ofs = ofs;
|
||||
Size2 icon_size = items[i].get_icon_size();
|
||||
Size2 icon_size = _get_item_icon_size(i);
|
||||
float h = _get_item_height(i);
|
||||
|
||||
if (i == mouse_over) {
|
||||
|
@ -631,21 +653,26 @@ void PopupMenu::_draw_items() {
|
|||
|
||||
// Icon
|
||||
if (!items[i].icon.is_null()) {
|
||||
const Point2 icon_offset = Point2(0, Math::floor((h - icon_size.height) / 2.0));
|
||||
Point2 icon_pos;
|
||||
|
||||
if (items[i].separator) {
|
||||
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);
|
||||
icon_pos = Size2(control->get_size().width - item_ofs.x - separator_ofs - icon_size.width, item_ofs.y);
|
||||
} else {
|
||||
items[i].icon->draw(ci, item_ofs + Size2(separator_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
|
||||
icon_pos = item_ofs + Size2(separator_ofs, 0);
|
||||
}
|
||||
} else {
|
||||
if (rtl) {
|
||||
items[i].icon->draw(ci, Size2(control->get_size().width - item_ofs.x - check_ofs - icon_size.width, item_ofs.y) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
|
||||
icon_pos = Size2(control->get_size().width - item_ofs.x - check_ofs - icon_size.width, item_ofs.y);
|
||||
} else {
|
||||
items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
|
||||
icon_pos = item_ofs + Size2(check_ofs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
items[i].icon->draw_rect(ci, Rect2(icon_pos + icon_offset, icon_size), false, icon_color);
|
||||
}
|
||||
|
||||
// Submenu arrow on right hand side.
|
||||
|
@ -802,6 +829,7 @@ void PopupMenu::_update_theme_item_cache() {
|
|||
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.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
|
||||
|
||||
theme_cache.checked = get_theme_icon(SNAME("checked"));
|
||||
theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
|
||||
|
@ -946,8 +974,10 @@ void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) {
|
|||
Item item;
|
||||
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
notify_property_list_changed();
|
||||
_menu_changed();
|
||||
|
@ -958,8 +988,10 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe
|
|||
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
|
||||
item.icon = p_icon;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
notify_property_list_changed();
|
||||
_menu_changed();
|
||||
|
@ -970,8 +1002,10 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) {
|
|||
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -982,8 +1016,10 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &
|
|||
item.icon = p_icon;
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
}
|
||||
|
||||
|
@ -992,8 +1028,10 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, Key p_acce
|
|||
ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1004,8 +1042,10 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St
|
|||
item.icon = p_icon;
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1016,8 +1056,10 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
|
|||
item.max_states = p_max_states;
|
||||
item.state = p_default_state;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1035,8 +1077,10 @@ void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_g
|
|||
Item item;
|
||||
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1046,8 +1090,10 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortc
|
|||
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
|
||||
item.icon = p_icon;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1057,8 +1103,10 @@ void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bo
|
|||
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1069,8 +1117,10 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
|
|||
item.icon = p_icon;
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1080,8 +1130,10 @@ void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_
|
|||
ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1092,8 +1144,10 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
|
|||
item.icon = p_icon;
|
||||
item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1105,8 +1159,10 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
|
|||
item.id = p_id == -1 ? items.size() : p_id;
|
||||
item.submenu = p_submenu;
|
||||
items.push_back(item);
|
||||
|
||||
_shape_item(items.size() - 1);
|
||||
control->queue_redraw();
|
||||
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
@ -1176,6 +1232,23 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
|
|||
_menu_changed();
|
||||
}
|
||||
|
||||
void PopupMenu::set_item_icon_max_width(int p_idx, int p_width) {
|
||||
if (p_idx < 0) {
|
||||
p_idx += get_item_count();
|
||||
}
|
||||
ERR_FAIL_INDEX(p_idx, items.size());
|
||||
|
||||
if (items[p_idx].icon_max_width == p_width) {
|
||||
return;
|
||||
}
|
||||
|
||||
items.write[p_idx].icon_max_width = p_width;
|
||||
|
||||
control->queue_redraw();
|
||||
child_controls_changed();
|
||||
_menu_changed();
|
||||
}
|
||||
|
||||
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
|
||||
if (p_idx < 0) {
|
||||
p_idx += get_item_count();
|
||||
|
@ -1314,6 +1387,11 @@ Ref<Texture2D> PopupMenu::get_item_icon(int p_idx) const {
|
|||
return items[p_idx].icon;
|
||||
}
|
||||
|
||||
int PopupMenu::get_item_icon_max_width(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, items.size(), 0);
|
||||
return items[p_idx].icon_max_width;
|
||||
}
|
||||
|
||||
Key PopupMenu::get_item_accelerator(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, items.size(), Key::NONE);
|
||||
return items[p_idx].accel;
|
||||
|
@ -2023,6 +2101,7 @@ void PopupMenu::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_item_text_direction", "index", "direction"), &PopupMenu::set_item_text_direction);
|
||||
ClassDB::bind_method(D_METHOD("set_item_language", "index", "language"), &PopupMenu::set_item_language);
|
||||
ClassDB::bind_method(D_METHOD("set_item_icon", "index", "icon"), &PopupMenu::set_item_icon);
|
||||
ClassDB::bind_method(D_METHOD("set_item_icon_max_width", "index", "width"), &PopupMenu::set_item_icon_max_width);
|
||||
ClassDB::bind_method(D_METHOD("set_item_checked", "index", "checked"), &PopupMenu::set_item_checked);
|
||||
ClassDB::bind_method(D_METHOD("set_item_id", "index", "id"), &PopupMenu::set_item_id);
|
||||
ClassDB::bind_method(D_METHOD("set_item_accelerator", "index", "accel"), &PopupMenu::set_item_accelerator);
|
||||
|
@ -2045,6 +2124,7 @@ void PopupMenu::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_item_text_direction", "index"), &PopupMenu::get_item_text_direction);
|
||||
ClassDB::bind_method(D_METHOD("get_item_language", "index"), &PopupMenu::get_item_language);
|
||||
ClassDB::bind_method(D_METHOD("get_item_icon", "index"), &PopupMenu::get_item_icon);
|
||||
ClassDB::bind_method(D_METHOD("get_item_icon_max_width", "index"), &PopupMenu::get_item_icon_max_width);
|
||||
ClassDB::bind_method(D_METHOD("is_item_checked", "index"), &PopupMenu::is_item_checked);
|
||||
ClassDB::bind_method(D_METHOD("get_item_id", "index"), &PopupMenu::get_item_id);
|
||||
ClassDB::bind_method(D_METHOD("get_item_index", "id"), &PopupMenu::get_item_index);
|
||||
|
|
|
@ -42,6 +42,7 @@ class PopupMenu : public Popup {
|
|||
|
||||
struct Item {
|
||||
Ref<Texture2D> icon;
|
||||
int icon_max_width = 0;
|
||||
String text;
|
||||
String xl_text;
|
||||
Ref<TextLine> text_buf;
|
||||
|
@ -103,6 +104,7 @@ class PopupMenu : public Popup {
|
|||
|
||||
int _get_item_height(int p_item) const;
|
||||
int _get_items_total_height() const;
|
||||
Size2 _get_item_icon_size(int p_item) const;
|
||||
|
||||
void _shape_item(int p_item);
|
||||
|
||||
|
@ -144,6 +146,7 @@ class PopupMenu : public Popup {
|
|||
int indent = 0;
|
||||
int item_start_padding = 0;
|
||||
int item_end_padding = 0;
|
||||
int icon_max_width = 0;
|
||||
|
||||
Ref<Texture2D> checked;
|
||||
Ref<Texture2D> checked_disabled;
|
||||
|
@ -222,6 +225,7 @@ public:
|
|||
void set_item_text_direction(int p_idx, Control::TextDirection p_text_direction);
|
||||
void set_item_language(int p_idx, const String &p_language);
|
||||
void set_item_icon(int p_idx, const Ref<Texture2D> &p_icon);
|
||||
void set_item_icon_max_width(int p_idx, int p_width);
|
||||
void set_item_checked(int p_idx, bool p_checked);
|
||||
void set_item_id(int p_idx, int p_id);
|
||||
void set_item_accelerator(int p_idx, Key p_accel);
|
||||
|
@ -245,6 +249,7 @@ public:
|
|||
String get_item_language(int p_idx) const;
|
||||
int get_item_idx_from_text(const String &text) const;
|
||||
Ref<Texture2D> get_item_icon(int p_idx) const;
|
||||
int get_item_icon_max_width(int p_idx) const;
|
||||
bool is_item_checked(int p_idx) const;
|
||||
int get_item_id(int p_idx) const;
|
||||
int get_item_index(int p_id) const;
|
||||
|
|
|
@ -63,10 +63,10 @@ Size2 TabBar::get_minimum_size() const {
|
|||
}
|
||||
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 + theme_cache.h_separation;
|
||||
if (tabs[i].icon.is_valid()) {
|
||||
const Size2 icon_size = _get_tab_icon_size(i);
|
||||
ms.height = MAX(ms.height, icon_size.height + y_margin);
|
||||
ms.width += icon_size.width + theme_cache.h_separation;
|
||||
}
|
||||
|
||||
if (!tabs[i].text.is_empty()) {
|
||||
|
@ -304,6 +304,7 @@ void TabBar::_update_theme_item_cache() {
|
|||
Control::_update_theme_item_cache();
|
||||
|
||||
theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
|
||||
theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
|
||||
|
||||
theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
|
||||
theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected"));
|
||||
|
@ -492,9 +493,11 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in
|
|||
// Draw the icon.
|
||||
Ref<Texture2D> icon = tabs[p_index].icon;
|
||||
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));
|
||||
const Size2 icon_size = _get_tab_icon_size(p_index);
|
||||
const Point2 icon_pos = Point2i(rtl ? p_x - icon_size.width : p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon_size.height) / 2);
|
||||
icon->draw_rect(ci, Rect2(icon_pos, icon_size));
|
||||
|
||||
p_x = rtl ? p_x - icon->get_width() - theme_cache.h_separation : p_x + icon->get_width() + theme_cache.h_separation;
|
||||
p_x = rtl ? p_x - icon_size.width - theme_cache.h_separation : p_x + icon_size.width + theme_cache.h_separation;
|
||||
}
|
||||
|
||||
// Draw the text.
|
||||
|
@ -719,6 +722,29 @@ Ref<Texture2D> TabBar::get_tab_icon(int p_tab) const {
|
|||
return tabs[p_tab].icon;
|
||||
}
|
||||
|
||||
void TabBar::set_tab_icon_max_width(int p_tab, int p_width) {
|
||||
ERR_FAIL_INDEX(p_tab, tabs.size());
|
||||
|
||||
if (tabs[p_tab].icon_max_width == p_width) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabs.write[p_tab].icon_max_width = p_width;
|
||||
|
||||
_update_cache();
|
||||
_ensure_no_over_offset();
|
||||
if (scroll_to_selected) {
|
||||
ensure_tab_visible(current);
|
||||
}
|
||||
queue_redraw();
|
||||
update_minimum_size();
|
||||
}
|
||||
|
||||
int TabBar::get_tab_icon_max_width(int p_tab) const {
|
||||
ERR_FAIL_INDEX_V(p_tab, tabs.size(), 0);
|
||||
return tabs[p_tab].icon_max_width;
|
||||
}
|
||||
|
||||
void TabBar::set_tab_disabled(int p_tab, bool p_disabled) {
|
||||
ERR_FAIL_INDEX(p_tab, tabs.size());
|
||||
|
||||
|
@ -1023,9 +1049,14 @@ Variant TabBar::get_drag_data(const Point2 &p_point) {
|
|||
HBoxContainer *drag_preview = memnew(HBoxContainer);
|
||||
|
||||
if (!tabs[tab_over].icon.is_null()) {
|
||||
const Size2 icon_size = _get_tab_icon_size(tab_over);
|
||||
|
||||
TextureRect *tf = memnew(TextureRect);
|
||||
tf->set_texture(tabs[tab_over].icon);
|
||||
tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
|
||||
tf->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
|
||||
tf->set_expand_mode(TextureRect::EXPAND_IGNORE_SIZE);
|
||||
tf->set_custom_minimum_size(icon_size);
|
||||
|
||||
drag_preview->add_child(tf);
|
||||
}
|
||||
|
||||
|
@ -1270,9 +1301,9 @@ int TabBar::get_tab_width(int p_idx) const {
|
|||
}
|
||||
int x = style->get_minimum_size().width;
|
||||
|
||||
Ref<Texture2D> tex = tabs[p_idx].icon;
|
||||
if (tex.is_valid()) {
|
||||
x += tex->get_width() + theme_cache.h_separation;
|
||||
if (tabs[p_idx].icon.is_valid()) {
|
||||
const Size2 icon_size = _get_tab_icon_size(p_idx);
|
||||
x += icon_size.width + theme_cache.h_separation;
|
||||
}
|
||||
|
||||
if (!tabs[p_idx].text.is_empty()) {
|
||||
|
@ -1305,6 +1336,27 @@ int TabBar::get_tab_width(int p_idx) const {
|
|||
return x;
|
||||
}
|
||||
|
||||
Size2 TabBar::_get_tab_icon_size(int p_index) const {
|
||||
ERR_FAIL_INDEX_V(p_index, tabs.size(), Size2());
|
||||
const TabBar::Tab &tab = tabs[p_index];
|
||||
Size2 icon_size = tab.icon->get_size();
|
||||
|
||||
int icon_max_width = 0;
|
||||
if (theme_cache.icon_max_width > 0) {
|
||||
icon_max_width = theme_cache.icon_max_width;
|
||||
}
|
||||
if (tab.icon_max_width > 0 && (icon_max_width == 0 || tab.icon_max_width < icon_max_width)) {
|
||||
icon_max_width = tab.icon_max_width;
|
||||
}
|
||||
|
||||
if (icon_max_width > 0 && icon_size.width > icon_max_width) {
|
||||
icon_size.height = icon_size.height * icon_max_width / icon_size.width;
|
||||
icon_size.width = icon_max_width;
|
||||
}
|
||||
|
||||
return icon_size;
|
||||
}
|
||||
|
||||
void TabBar::_ensure_no_over_offset() {
|
||||
if (!is_inside_tree() || !buttons_visible) {
|
||||
return;
|
||||
|
@ -1547,6 +1599,8 @@ void TabBar::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_tab_language", "tab_idx"), &TabBar::get_tab_language);
|
||||
ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabBar::set_tab_icon);
|
||||
ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabBar::get_tab_icon);
|
||||
ClassDB::bind_method(D_METHOD("set_tab_icon_max_width", "tab_idx", "width"), &TabBar::set_tab_icon_max_width);
|
||||
ClassDB::bind_method(D_METHOD("get_tab_icon_max_width", "tab_idx"), &TabBar::get_tab_icon_max_width);
|
||||
ClassDB::bind_method(D_METHOD("set_tab_button_icon", "tab_idx", "icon"), &TabBar::set_tab_button_icon);
|
||||
ClassDB::bind_method(D_METHOD("get_tab_button_icon", "tab_idx"), &TabBar::get_tab_button_icon);
|
||||
ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabBar::set_tab_disabled);
|
||||
|
|
|
@ -62,6 +62,8 @@ private:
|
|||
|
||||
Ref<TextLine> text_buf;
|
||||
Ref<Texture2D> icon;
|
||||
int icon_max_width = 0;
|
||||
|
||||
bool disabled = false;
|
||||
bool hidden = false;
|
||||
int ofs_cache = 0;
|
||||
|
@ -106,6 +108,7 @@ private:
|
|||
|
||||
struct ThemeCache {
|
||||
int h_separation = 0;
|
||||
int icon_max_width = 0;
|
||||
|
||||
Ref<StyleBox> tab_unselected_style;
|
||||
Ref<StyleBox> tab_selected_style;
|
||||
|
@ -133,6 +136,7 @@ private:
|
|||
} theme_cache;
|
||||
|
||||
int get_tab_width(int p_idx) const;
|
||||
Size2 _get_tab_icon_size(int p_idx) const;
|
||||
void _ensure_no_over_offset();
|
||||
|
||||
void _update_hover();
|
||||
|
@ -171,6 +175,9 @@ public:
|
|||
void set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon);
|
||||
Ref<Texture2D> get_tab_icon(int p_tab) const;
|
||||
|
||||
void set_tab_icon_max_width(int p_tab, int p_width);
|
||||
int get_tab_icon_max_width(int p_tab) const;
|
||||
|
||||
void set_tab_disabled(int p_tab, bool p_disabled);
|
||||
bool is_tab_disabled(int p_tab) const;
|
||||
|
||||
|
|
|
@ -146,6 +146,7 @@ void TabContainer::_update_theme_item_cache() {
|
|||
|
||||
// TabBar overrides.
|
||||
theme_cache.icon_separation = get_theme_constant(SNAME("icon_separation"));
|
||||
theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
|
||||
theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
|
||||
|
||||
theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
|
||||
|
@ -245,6 +246,7 @@ void TabContainer::_on_theme_changed() {
|
|||
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("icon_max_width"), theme_cache.icon_max_width);
|
||||
tab_bar->add_theme_constant_override(SNAME("outline_size"), theme_cache.outline_size);
|
||||
|
||||
_update_margins();
|
||||
|
|
|
@ -59,6 +59,7 @@ class TabContainer : public Container {
|
|||
|
||||
// TabBar overrides.
|
||||
int icon_separation = 0;
|
||||
int icon_max_width = 0;
|
||||
int outline_size = 0;
|
||||
|
||||
Ref<StyleBox> tab_unselected_style;
|
||||
|
|
|
@ -1340,10 +1340,7 @@ Size2 TreeItem::get_minimum_size(int p_column) {
|
|||
size.width += parent_tree->theme_cache.checked->get_width() + parent_tree->theme_cache.h_separation;
|
||||
}
|
||||
if (cell.icon.is_valid()) {
|
||||
Size2i icon_size = cell.get_icon_size();
|
||||
if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) {
|
||||
icon_size.width = cell.icon_max_w;
|
||||
}
|
||||
Size2i icon_size = parent_tree->_get_cell_icon_size(cell);
|
||||
size.width += icon_size.width + parent_tree->theme_cache.h_separation;
|
||||
size.height = MAX(size.height, icon_size.height);
|
||||
}
|
||||
|
@ -1628,6 +1625,7 @@ void Tree::_update_theme_item_cache() {
|
|||
theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
|
||||
theme_cache.item_margin = get_theme_constant(SNAME("item_margin"));
|
||||
theme_cache.button_margin = get_theme_constant(SNAME("button_margin"));
|
||||
theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
|
||||
|
||||
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
|
||||
theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
|
||||
|
@ -1654,6 +1652,25 @@ void Tree::_update_theme_item_cache() {
|
|||
theme_cache.base_scale = get_theme_default_base_scale();
|
||||
}
|
||||
|
||||
Size2 Tree::_get_cell_icon_size(const TreeItem::Cell &p_cell) const {
|
||||
Size2i icon_size = p_cell.get_icon_size();
|
||||
|
||||
int max_width = 0;
|
||||
if (theme_cache.icon_max_width > 0) {
|
||||
max_width = theme_cache.icon_max_width;
|
||||
}
|
||||
if (p_cell.icon_max_w > 0 && (max_width == 0 || p_cell.icon_max_w < max_width)) {
|
||||
max_width = p_cell.icon_max_w;
|
||||
}
|
||||
|
||||
if (max_width > 0 && icon_size.width > max_width) {
|
||||
icon_size.height = icon_size.height * max_width / icon_size.width;
|
||||
icon_size.width = max_width;
|
||||
}
|
||||
|
||||
return icon_size;
|
||||
}
|
||||
|
||||
int Tree::compute_item_height(TreeItem *p_item) const {
|
||||
if ((p_item == root && hide_root) || !p_item->is_visible()) {
|
||||
return 0;
|
||||
|
@ -1688,10 +1705,7 @@ int Tree::compute_item_height(TreeItem *p_item) const {
|
|||
case TreeItem::CELL_MODE_ICON: {
|
||||
Ref<Texture2D> icon = p_item->cells[i].icon;
|
||||
if (!icon.is_null()) {
|
||||
Size2i s = p_item->cells[i].get_icon_size();
|
||||
if (p_item->cells[i].icon_max_w > 0 && s.width > p_item->cells[i].icon_max_w) {
|
||||
s.height = s.height * p_item->cells[i].icon_max_w / s.width;
|
||||
}
|
||||
Size2i s = _get_cell_icon_size(p_item->cells[i]);
|
||||
if (s.height > height) {
|
||||
height = s.height;
|
||||
}
|
||||
|
@ -1745,10 +1759,7 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
|
|||
|
||||
int w = 0;
|
||||
if (!p_cell.icon.is_null()) {
|
||||
Size2i bmsize = p_cell.get_icon_size();
|
||||
if (p_cell.icon_max_w > 0 && bmsize.width > p_cell.icon_max_w) {
|
||||
bmsize.width = p_cell.icon_max_w;
|
||||
}
|
||||
Size2i bmsize = _get_cell_icon_size(p_cell);
|
||||
w += bmsize.width + theme_cache.h_separation;
|
||||
if (rect.size.width > 0 && (w + ts.width) > rect.size.width) {
|
||||
ts.width = rect.size.width - w;
|
||||
|
@ -1788,12 +1799,7 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co
|
|||
}
|
||||
|
||||
if (!p_cell.icon.is_null()) {
|
||||
Size2i bmsize = p_cell.get_icon_size();
|
||||
|
||||
if (p_cell.icon_max_w > 0 && bmsize.width > p_cell.icon_max_w) {
|
||||
bmsize.height = bmsize.height * p_cell.icon_max_w / bmsize.width;
|
||||
bmsize.width = p_cell.icon_max_w;
|
||||
}
|
||||
Size2i bmsize = _get_cell_icon_size(p_cell);
|
||||
|
||||
p_cell.draw_icon(ci, rect.position + Size2i(0, Math::floor((real_t)(rect.size.y - bmsize.y) / 2)), bmsize, p_icon_color);
|
||||
rect.position.x += bmsize.x + theme_cache.h_separation;
|
||||
|
@ -2206,12 +2212,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
|
|||
if (p_item->cells[i].icon.is_null()) {
|
||||
break;
|
||||
}
|
||||
Size2i icon_size = p_item->cells[i].get_icon_size();
|
||||
if (p_item->cells[i].icon_max_w > 0 && icon_size.width > p_item->cells[i].icon_max_w) {
|
||||
icon_size.height = icon_size.height * p_item->cells[i].icon_max_w / icon_size.width;
|
||||
icon_size.width = p_item->cells[i].icon_max_w;
|
||||
}
|
||||
|
||||
Size2i icon_size = _get_cell_icon_size(p_item->cells[i]);
|
||||
Point2i icon_ofs = (item_rect.size - icon_size) / 2;
|
||||
icon_ofs += item_rect.position;
|
||||
|
||||
|
@ -3795,8 +3796,9 @@ bool Tree::edit_selected() {
|
|||
popup_rect.size = rect.size;
|
||||
|
||||
// Account for icon.
|
||||
popup_rect.position.x += c.get_icon_size().x;
|
||||
popup_rect.size.x -= c.get_icon_size().x;
|
||||
Size2 icon_size = _get_cell_icon_size(c);
|
||||
popup_rect.position.x += icon_size.x;
|
||||
popup_rect.size.x -= icon_size.x;
|
||||
|
||||
text_editor->clear();
|
||||
text_editor->set_text(c.mode == TreeItem::CELL_MODE_STRING ? c.text : String::num(c.val, Math::range_step_decimals(c.step)));
|
||||
|
|
|
@ -530,21 +530,24 @@ private:
|
|||
Color font_outline_color;
|
||||
|
||||
float base_scale = 1.0;
|
||||
int font_outline_size = 0;
|
||||
|
||||
int h_separation = 0;
|
||||
int v_separation = 0;
|
||||
int item_margin = 0;
|
||||
int button_margin = 0;
|
||||
int icon_max_width = 0;
|
||||
Point2 offset;
|
||||
|
||||
int draw_relationship_lines = 0;
|
||||
int relationship_line_width = 0;
|
||||
int parent_hl_line_width = 0;
|
||||
int children_hl_line_width = 0;
|
||||
int parent_hl_line_margin = 0;
|
||||
int draw_guides = 0;
|
||||
|
||||
int scroll_border = 0;
|
||||
int scroll_speed = 0;
|
||||
int font_outline_size = 0;
|
||||
} theme_cache;
|
||||
|
||||
struct Cache {
|
||||
|
@ -573,6 +576,7 @@ private:
|
|||
} cache;
|
||||
|
||||
int _get_title_button_height() const;
|
||||
Size2 _get_cell_icon_size(const TreeItem::Cell &p_cell) const;
|
||||
|
||||
void _scroll_moved(float p_value);
|
||||
HScrollBar *h_scroll = nullptr;
|
||||
|
|
|
@ -180,6 +180,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
|||
theme->set_color("icon_disabled_color", "Button", Color(1, 1, 1, 0.4));
|
||||
|
||||
theme->set_constant("h_separation", "Button", 2 * scale);
|
||||
theme->set_constant("icon_max_width", "Button", 0);
|
||||
|
||||
// MenuBar
|
||||
theme->set_stylebox("normal", "MenuBar", button_normal);
|
||||
|
@ -688,6 +689,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
|||
theme->set_constant("separator_outline_size", "PopupMenu", 0);
|
||||
theme->set_constant("item_start_padding", "PopupMenu", 2 * scale);
|
||||
theme->set_constant("item_end_padding", "PopupMenu", 2 * scale);
|
||||
theme->set_constant("icon_max_width", "PopupMenu", 0);
|
||||
|
||||
// GraphNode
|
||||
Ref<StyleBoxFlat> graphnode_normal = make_flat_stylebox(style_normal_color, 18, 42, 18, 12);
|
||||
|
@ -780,6 +782,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
|||
theme->set_constant("scroll_border", "Tree", 4);
|
||||
theme->set_constant("scroll_speed", "Tree", 12);
|
||||
theme->set_constant("outline_size", "Tree", 0);
|
||||
theme->set_constant("icon_max_width", "Tree", 0);
|
||||
|
||||
// ItemList
|
||||
|
||||
|
@ -842,6 +845,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
|||
|
||||
theme->set_constant("side_margin", "TabContainer", 8 * scale);
|
||||
theme->set_constant("icon_separation", "TabContainer", 4 * scale);
|
||||
theme->set_constant("icon_max_width", "TabContainer", 0);
|
||||
theme->set_constant("outline_size", "TabContainer", 0);
|
||||
|
||||
// TabBar
|
||||
|
@ -869,6 +873,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
|||
theme->set_color("drop_mark_color", "TabBar", Color(1, 1, 1));
|
||||
|
||||
theme->set_constant("h_separation", "TabBar", 4 * scale);
|
||||
theme->set_constant("icon_max_width", "TabBar", 0);
|
||||
theme->set_constant("outline_size", "TabBar", 0);
|
||||
|
||||
// Separators
|
||||
|
|
Loading…
Reference in a new issue