Add type variations to Theme

This commit is contained in:
Yuri Sizov 2022-02-11 00:26:09 +03:00
parent 47e34dc4e2
commit df13466139
14 changed files with 897 additions and 422 deletions

View file

@ -584,6 +584,7 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_RANGE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_EXP_RANGE);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_ENUM);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LENGTH);
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL);

View file

@ -93,6 +93,7 @@ enum PropertyHint {
PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send
PROPERTY_HINT_NODE_PATH_VALID_TYPES,
PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};

View file

@ -1420,6 +1420,10 @@
<constant name="PROPERTY_HINT_ENUM" value="3" enum="PropertyHint">
Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
</constant>
<constant name="PROPERTY_HINT_ENUM_SUGGESTION" value="37" enum="PropertyHint">
Hints that a string property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
</constant>
<constant name="PROPERTY_HINT_EXP_EASING" value="4" enum="PropertyHint">
Hints that a float property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"inout"[/code] to also include in/out easing.
</constant>

View file

@ -231,7 +231,7 @@
<argument index="0" name="name" type="String" />
<argument index="1" name="theme_type" type="String" default="&quot;&quot;" />
<description>
Returns a [Color] from the first matching [Theme] in the tree if that [Theme] has a color item with the specified [code]name[/code] and [code]theme_type[/code]. If [code]theme_type[/code] is omitted the class name of the current control is used as the type. If the type is a class name its parent classes are also checked, in order of inheritance.
Returns a [Color] from the first matching [Theme] in the tree if that [Theme] has a color item with the specified [code]name[/code] and [code]theme_type[/code]. If [code]theme_type[/code] is omitted the class name of the current control is used as the type, or [member theme_type_variation] if it is defined. If the type is a class name its parent classes are also checked, in order of inheritance.
For the current control its local overrides are considered first (see [method add_color_override]), then its assigned [member theme]. After the current control, each parent control and its assigned [member theme] are considered; controls without a [member theme] assigned are skipped. If no matching [Theme] is found in the tree, a custom project [Theme] (see [member ProjectSettings.gui/theme/custom]) and the default [Theme] are used.
[codeblock]
func _ready():
@ -855,6 +855,12 @@
<member name="theme" type="Theme" setter="set_theme" getter="get_theme">
Changing this property replaces the current [Theme] resource this node and all its [Control] children use.
</member>
<member name="theme_type_variation" type="String" setter="set_theme_type_variation" getter="get_theme_type_variation" default="&quot;&quot;">
The name of a theme type variation used by this [Control] to look up its own theme items. When empty, the class name of the node is used (e.g. [code]Button[/code] for the [Button] control), as well as the class names of all parent classes (in order of inheritance).
When set, this property gives the highest priority to the type of the specified name. This type can in turn extend another type, forming a dependency chain. See [method Theme.set_type_variation]. If the theme item cannot be found using this type or its base types, lookup falls back on the class names.
[b]Note:[/b] To look up [Control]'s own items use various [code]get_*[/code] methods without specifying [code]theme_type[/code].
[b]Note:[/b] Theme items are looked for in the tree order, from branch to root, where each [Control] node is checked for its [member theme] property. The earliest match against any type/class name is returned. The project-level Theme and the default Theme are checked last.
</member>
</members>
<signals>
<signal name="focus_entered">

View file

@ -20,7 +20,7 @@
<method name="clear_color">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Clears the [Color] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
@ -28,7 +28,7 @@
<method name="clear_constant">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Clears the constant at [code]name[/code] if the theme has [code]node_type[/code].
</description>
@ -36,7 +36,7 @@
<method name="clear_font">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Clears the [Font] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
@ -44,7 +44,7 @@
<method name="clear_icon">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Clears the icon at [code]name[/code] if the theme has [code]node_type[/code].
</description>
@ -52,7 +52,7 @@
<method name="clear_stylebox">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Clears [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
@ -61,11 +61,18 @@
<return type="void" />
<argument index="0" name="data_type" type="int" enum="Theme.DataType" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Clears the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
</method>
<method name="clear_type_variation">
<return type="void" />
<argument index="0" name="theme_type" type="String" />
<description>
Unmarks [code]theme_type[/code] as being a variation of another theme type. See [method set_type_variation].
</description>
</method>
<method name="copy_default_theme">
<return type="void" />
<description>
@ -82,14 +89,14 @@
<method name="get_color" qualifiers="const">
<return type="Color" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns the [Color] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
</method>
<method name="get_color_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="node_type" type="String" />
<argument index="0" name="theme_type" type="String" />
<description>
Returns all the [Color]s as a [PoolStringArray] filled with each [Color]'s name, for use in [method get_color], if the theme has [code]node_type[/code].
</description>
@ -103,14 +110,14 @@
<method name="get_constant" qualifiers="const">
<return type="int" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns the constant at [code]name[/code] if the theme has [code]node_type[/code].
</description>
</method>
<method name="get_constant_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="node_type" type="String" />
<argument index="0" name="theme_type" type="String" />
<description>
Returns all the constants as a [PoolStringArray] filled with each constant's name, for use in [method get_constant], if the theme has [code]node_type[/code].
</description>
@ -124,14 +131,14 @@
<method name="get_font" qualifiers="const">
<return type="Font" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns the [Font] at [code]name[/code] if the theme has [code]node_type[/code]. If such item does not exist and [member default_font] is set on the theme, the default font will be returned.
</description>
</method>
<method name="get_font_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="node_type" type="String" />
<argument index="0" name="theme_type" type="String" />
<description>
Returns all the [Font]s as a [PoolStringArray] filled with each [Font]'s name, for use in [method get_font], if the theme has [code]node_type[/code].
</description>
@ -145,14 +152,14 @@
<method name="get_icon" qualifiers="const">
<return type="Texture" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns the icon [Texture] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
</method>
<method name="get_icon_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="node_type" type="String" />
<argument index="0" name="theme_type" type="String" />
<description>
Returns all the icons as a [PoolStringArray] filled with each [Texture]'s name, for use in [method get_icon], if the theme has [code]node_type[/code].
</description>
@ -166,7 +173,7 @@
<method name="get_stylebox" qualifiers="const">
<return type="StyleBox" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns the [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
Valid [code]name[/code]s may be found using [method get_stylebox_list]. Valid [code]node_type[/code]s may be found using [method get_stylebox_types].
@ -174,7 +181,7 @@
</method>
<method name="get_stylebox_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="node_type" type="String" />
<argument index="0" name="theme_type" type="String" />
<description>
Returns all the [StyleBox]s as a [PoolStringArray] filled with each [StyleBox]'s name, for use in [method get_stylebox], if the theme has [code]node_type[/code].
Valid [code]node_type[/code]s may be found using [method get_stylebox_types].
@ -190,7 +197,7 @@
<return type="Variant" />
<argument index="0" name="data_type" type="int" enum="Theme.DataType" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Returns the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
Valid [code]name[/code]s may be found using [method get_theme_item_list] or a data type specific method. Valid [code]node_type[/code]s may be found using [method get_theme_item_types] or a data type specific method.
@ -199,7 +206,7 @@
<method name="get_theme_item_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="data_type" type="int" enum="Theme.DataType" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns all the theme items of [code]data_type[/code] as a [PoolStringArray] filled with each theme items's name, for use in [method get_theme_item] or a data type specific method, if the theme has [code]node_type[/code].
Valid [code]node_type[/code]s may be found using [method get_theme_item_types] or a data type specific method.
@ -214,16 +221,30 @@
</method>
<method name="get_type_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="node_type" type="String" />
<argument index="0" name="theme_type" type="String" />
<description>
Returns all the theme types as a [PoolStringArray] filled with unique type names, for use in other [code]get_*[/code] functions of this theme.
[b]Note:[/b] [code]node_type[/code] has no effect and will be removed in future version.
</description>
</method>
<method name="get_type_variation_base" qualifiers="const">
<return type="String" />
<argument index="0" name="theme_type" type="String" />
<description>
Returns the name of the base theme type if [code]theme_type[/code] is a valid variation type. Returns an empty string otherwise.
</description>
</method>
<method name="get_type_variation_list" qualifiers="const">
<return type="PoolStringArray" />
<argument index="0" name="base_type" type="String" />
<description>
Returns a list of all type variations for the given [code]base_type[/code].
</description>
</method>
<method name="has_color" qualifiers="const">
<return type="bool" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns [code]true[/code] if [Color] with [code]name[/code] is in [code]node_type[/code].
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
@ -232,7 +253,7 @@
<method name="has_constant" qualifiers="const">
<return type="bool" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns [code]true[/code] if constant with [code]name[/code] is in [code]node_type[/code].
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
@ -247,7 +268,7 @@
<method name="has_font" qualifiers="const">
<return type="bool" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]node_type[/code].
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
@ -256,7 +277,7 @@
<method name="has_icon" qualifiers="const">
<return type="bool" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns [code]true[/code] if icon [Texture] with [code]name[/code] is in [code]node_type[/code].
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
@ -265,7 +286,7 @@
<method name="has_stylebox" qualifiers="const">
<return type="bool" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<description>
Returns [code]true[/code] if [StyleBox] with [code]name[/code] is in [code]node_type[/code].
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
@ -275,12 +296,20 @@
<return type="bool" />
<argument index="0" name="data_type" type="int" enum="Theme.DataType" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Returns [code]true[/code] if a theme item of [code]data_type[/code] with [code]name[/code] is in [code]node_type[/code].
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
</description>
</method>
<method name="is_type_variation" qualifiers="const">
<return type="bool" />
<argument index="0" name="theme_type" type="String" />
<argument index="1" name="base_type" type="String" />
<description>
Returns [code]true[/code] if [code]theme_type[/code] is marked as a variation of [code]base_type[/code].
</description>
</method>
<method name="merge_with">
<return type="void" />
<argument index="0" name="other" type="Theme" />
@ -293,7 +322,7 @@
<return type="void" />
<argument index="0" name="old_name" type="String" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Renames the [Color] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
@ -302,7 +331,7 @@
<return type="void" />
<argument index="0" name="old_name" type="String" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Renames the constant at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
@ -311,7 +340,7 @@
<return type="void" />
<argument index="0" name="old_name" type="String" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Renames the [Font] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
@ -320,7 +349,7 @@
<return type="void" />
<argument index="0" name="old_name" type="String" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Renames the icon at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
@ -329,7 +358,7 @@
<return type="void" />
<argument index="0" name="old_name" type="String" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<description>
Renames [StyleBox] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
@ -339,7 +368,7 @@
<argument index="0" name="data_type" type="int" enum="Theme.DataType" />
<argument index="1" name="old_name" type="String" />
<argument index="2" name="name" type="String" />
<argument index="3" name="node_type" type="String" />
<argument index="3" name="theme_type" type="String" />
<description>
Renames the theme item of [code]data_type[/code] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
</description>
@ -347,7 +376,7 @@
<method name="set_color">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<argument index="2" name="color" type="Color" />
<description>
Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in [code]node_type[/code].
@ -357,7 +386,7 @@
<method name="set_constant">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<argument index="2" name="constant" type="int" />
<description>
Sets the theme's constant to [code]constant[/code] at [code]name[/code] in [code]node_type[/code].
@ -367,7 +396,7 @@
<method name="set_font">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<argument index="2" name="font" type="Font" />
<description>
Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in [code]node_type[/code].
@ -377,7 +406,7 @@
<method name="set_icon">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<argument index="2" name="texture" type="Texture" />
<description>
Sets the theme's icon [Texture] to [code]texture[/code] at [code]name[/code] in [code]node_type[/code].
@ -387,7 +416,7 @@
<method name="set_stylebox">
<return type="void" />
<argument index="0" name="name" type="String" />
<argument index="1" name="node_type" type="String" />
<argument index="1" name="theme_type" type="String" />
<argument index="2" name="texture" type="StyleBox" />
<description>
Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in [code]node_type[/code].
@ -398,7 +427,7 @@
<return type="void" />
<argument index="0" name="data_type" type="int" enum="Theme.DataType" />
<argument index="1" name="name" type="String" />
<argument index="2" name="node_type" type="String" />
<argument index="2" name="theme_type" type="String" />
<argument index="3" name="value" type="Variant" />
<description>
Sets the theme item of [code]data_type[/code] to [code]value[/code] at [code]name[/code] in [code]node_type[/code].
@ -406,6 +435,17 @@
Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_type_variation">
<return type="void" />
<argument index="0" name="theme_type" type="String" />
<argument index="1" name="base_type" type="String" />
<description>
Marks [code]theme_type[/code] as a variation of [code]base_type[/code].
This adds [code]theme_type[/code] as a suggested option for [member Control.theme_type_variation] on a [Control] that is of the [code]base_type[/code] class.
Variations can also be nested, i.e. [code]base_type[/code] can be another variation. If a chain of variations ends with a [code]base_type[/code] matching the class of the [Control], the whole chain is going to be suggested as options.
[b]Note:[/b] Suggestions only show up if this theme resource is set as the project default theme. See [member ProjectSettings.gui/theme/custom].
</description>
</method>
</methods>
<members>
<member name="default_font" type="Font" setter="set_default_font" getter="get_default_font">

View file

@ -173,40 +173,152 @@ EditorPropertyMultilineText::EditorPropertyMultilineText() {
///////////////////// TEXT ENUM /////////////////////////
void EditorPropertyTextEnum::_emit_changed_value(String p_string) {
emit_changed(get_edited_property(), p_string);
}
void EditorPropertyTextEnum::_option_selected(int p_which) {
emit_changed(get_edited_property(), options->get_item_text(p_which));
_emit_changed_value(option_button->get_item_text(p_which));
}
void EditorPropertyTextEnum::_edit_custom_value() {
default_layout->hide();
edit_custom_layout->show();
custom_value_edit->grab_focus();
}
void EditorPropertyTextEnum::_custom_value_submitted(String p_value) {
edit_custom_layout->hide();
default_layout->show();
_emit_changed_value(p_value.strip_edges());
}
void EditorPropertyTextEnum::_custom_value_accepted() {
String new_value = custom_value_edit->get_text().strip_edges();
_custom_value_submitted(new_value);
}
void EditorPropertyTextEnum::_custom_value_cancelled() {
custom_value_edit->set_text(get_edited_object()->get(get_edited_property()));
edit_custom_layout->hide();
default_layout->show();
}
void EditorPropertyTextEnum::update_property() {
String which = get_edited_object()->get(get_edited_property());
for (int i = 0; i < options->get_item_count(); i++) {
String t = options->get_item_text(i);
if (t == which) {
options->select(i);
return;
String current_value = get_edited_object()->get(get_edited_property());
int default_option = options.find(current_value);
// The list can change in the loose mode.
if (loose_mode) {
custom_value_edit->set_text(current_value);
option_button->clear();
// Manually entered value.
if (default_option < 0 && !current_value.empty()) {
option_button->add_item(current_value, options.size() + 1001);
option_button->select(0);
option_button->add_separator();
}
// Add an explicit empty value for clearing the property.
option_button->add_item("", options.size() + 1000);
for (int i = 0; i < options.size(); i++) {
option_button->add_item(options[i], i);
if (options[i] == current_value) {
option_button->select(option_button->get_item_count() - 1);
}
}
} else {
option_button->select(default_option);
}
}
void EditorPropertyTextEnum::setup(const Vector<String> &p_options) {
void EditorPropertyTextEnum::setup(const Vector<String> &p_options, bool p_loose_mode) {
loose_mode = p_loose_mode;
options.clear();
if (loose_mode) {
// Add an explicit empty value for clearing the property in the loose mode.
option_button->add_item("", options.size() + 1000);
}
for (int i = 0; i < p_options.size(); i++) {
options->add_item(p_options[i], i);
options.push_back(p_options[i]);
option_button->add_item(p_options[i], i);
}
if (loose_mode) {
edit_button->show();
}
}
void EditorPropertyTextEnum::_bind_methods() {
ClassDB::bind_method(D_METHOD("_option_selected"), &EditorPropertyTextEnum::_option_selected);
ClassDB::bind_method(D_METHOD("_edit_custom_value"), &EditorPropertyTextEnum::_edit_custom_value);
ClassDB::bind_method(D_METHOD("_custom_value_submitted"), &EditorPropertyTextEnum::_custom_value_submitted);
ClassDB::bind_method(D_METHOD("_custom_value_accepted"), &EditorPropertyTextEnum::_custom_value_accepted);
ClassDB::bind_method(D_METHOD("_custom_value_cancelled"), &EditorPropertyTextEnum::_custom_value_cancelled);
}
void EditorPropertyTextEnum::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED:
edit_button->set_icon(get_icon("Edit", "EditorIcons"));
accept_button->set_icon(get_icon("ImportCheck", "EditorIcons"));
cancel_button->set_icon(get_icon("ImportFail", "EditorIcons"));
break;
}
}
EditorPropertyTextEnum::EditorPropertyTextEnum() {
options = memnew(OptionButton);
options->set_clip_text(true);
options->set_flat(true);
default_layout = memnew(HBoxContainer);
add_child(default_layout);
add_child(options);
add_focusable(options);
options->connect("item_selected", this, "_option_selected");
edit_custom_layout = memnew(HBoxContainer);
edit_custom_layout->hide();
add_child(edit_custom_layout);
option_button = memnew(OptionButton);
option_button->set_h_size_flags(SIZE_EXPAND_FILL);
option_button->set_clip_text(true);
option_button->set_flat(true);
default_layout->add_child(option_button);
option_button->connect("item_selected", this, "_option_selected");
edit_button = memnew(Button);
edit_button->set_flat(true);
edit_button->hide();
default_layout->add_child(edit_button);
edit_button->connect("pressed", this, "_edit_custom_value");
custom_value_edit = memnew(LineEdit);
custom_value_edit->set_h_size_flags(SIZE_EXPAND_FILL);
edit_custom_layout->add_child(custom_value_edit);
custom_value_edit->connect("text_entered", this, "_custom_value_submitted");
accept_button = memnew(Button);
accept_button->set_flat(true);
edit_custom_layout->add_child(accept_button);
accept_button->connect("pressed", this, "_custom_value_accepted");
cancel_button = memnew(Button);
cancel_button->set_flat(true);
edit_custom_layout->add_child(cancel_button);
cancel_button->connect("pressed", this, "_custom_value_cancelled");
add_focusable(option_button);
add_focusable(edit_button);
add_focusable(custom_value_edit);
add_focusable(accept_button);
add_focusable(cancel_button);
}
///////////////////// PATH /////////////////////////
void EditorPropertyPath::_path_selected(const String &p_path) {
@ -2728,10 +2840,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
}
} break;
case Variant::STRING: {
if (p_hint == PROPERTY_HINT_ENUM) {
if (p_hint == PROPERTY_HINT_ENUM || p_hint == PROPERTY_HINT_ENUM_SUGGESTION) {
EditorPropertyTextEnum *editor = memnew(EditorPropertyTextEnum);
Vector<String> options = p_hint_text.split(",");
editor->setup(options);
Vector<String> options = p_hint_text.split(",", false);
editor->setup(options, (p_hint == PROPERTY_HINT_ENUM_SUGGESTION));
add_property_editor(p_path, editor);
} else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) {
EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText);

View file

@ -89,15 +89,34 @@ public:
class EditorPropertyTextEnum : public EditorProperty {
GDCLASS(EditorPropertyTextEnum, EditorProperty);
OptionButton *options;
HBoxContainer *default_layout;
HBoxContainer *edit_custom_layout;
OptionButton *option_button;
Button *edit_button;
LineEdit *custom_value_edit;
Button *accept_button;
Button *cancel_button;
Vector<String> options;
bool loose_mode = false;
void _emit_changed_value(String p_string);
void _option_selected(int p_which);
void _edit_custom_value();
void _custom_value_submitted(String p_value);
void _custom_value_accepted();
void _custom_value_cancelled();
protected:
static void _bind_methods();
void _notification(int p_what);
public:
void setup(const Vector<String> &p_options);
void setup(const Vector<String> &p_options, bool p_loose_mode = false);
virtual void update_property();
EditorPropertyTextEnum();
};

View file

@ -2158,7 +2158,12 @@ OrderedHashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_
if (include_default) {
names.clear();
(Theme::get_default().operator->()->*get_list_func)(p_type_name, &names);
String default_type = p_type_name;
if (edited_theme->get_type_variation_base(p_type_name) != StringName()) {
default_type = edited_theme->get_type_variation_base(p_type_name);
}
(Theme::get_default().operator->()->*get_list_func)(default_type, &names);
names.sort_custom<StringName::AlphCompare>();
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
items[E->get()] = false;
@ -2483,6 +2488,20 @@ void ThemeTypeEditor::_update_type_items() {
stylebox_items_list->add_child(item_control);
}
}
// Various type settings.
if (edited_type.empty() || ClassDB::class_exists(edited_type)) {
type_variation_edit->set_editable(false);
type_variation_edit->set_text("");
type_variation_button->hide();
type_variation_locked->set_visible(!edited_type.empty());
} else {
type_variation_edit->set_editable(true);
type_variation_edit->set_text(edited_theme->get_type_variation_base(edited_type));
_add_focusable(type_variation_edit);
type_variation_button->show();
type_variation_locked->hide();
}
}
void ThemeTypeEditor::_list_type_selected(int p_index) {
@ -2491,11 +2510,19 @@ void ThemeTypeEditor::_list_type_selected(int p_index) {
}
void ThemeTypeEditor::_add_type_button_cbk() {
add_type_mode = ADD_THEME_TYPE;
add_type_dialog->set_title(TTR("Add Item Type"));
add_type_dialog->get_ok()->set_text(TTR("Add Type"));
add_type_dialog->set_include_own_types(false);
add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);
}
void ThemeTypeEditor::_add_default_type_items() {
List<StringName> names;
String default_type = edited_type;
if (edited_theme->get_type_variation_base(edited_type) != StringName()) {
default_type = edited_theme->get_type_variation_base(edited_type);
}
updating = true;
// Prevent changes from immediately being reported while the operation is still ongoing.
@ -2503,7 +2530,7 @@ void ThemeTypeEditor::_add_default_type_items() {
{
names.clear();
Theme::get_default()->get_icon_list(edited_type, &names);
Theme::get_default()->get_icon_list(default_type, &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (!edited_theme->has_icon(E->get(), edited_type)) {
edited_theme->set_icon(E->get(), edited_type, Ref<Texture>());
@ -2512,7 +2539,7 @@ void ThemeTypeEditor::_add_default_type_items() {
}
{
names.clear();
Theme::get_default()->get_stylebox_list(edited_type, &names);
Theme::get_default()->get_stylebox_list(default_type, &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (!edited_theme->has_stylebox(E->get(), edited_type)) {
edited_theme->set_stylebox(E->get(), edited_type, Ref<StyleBox>());
@ -2521,7 +2548,7 @@ void ThemeTypeEditor::_add_default_type_items() {
}
{
names.clear();
Theme::get_default()->get_font_list(edited_type, &names);
Theme::get_default()->get_font_list(default_type, &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (!edited_theme->has_font(E->get(), edited_type)) {
edited_theme->set_font(E->get(), edited_type, Ref<Font>());
@ -2530,7 +2557,7 @@ void ThemeTypeEditor::_add_default_type_items() {
}
{
names.clear();
Theme::get_default()->get_color_list(edited_type, &names);
Theme::get_default()->get_color_list(default_type, &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (!edited_theme->has_color(E->get(), edited_type)) {
edited_theme->set_color(E->get(), edited_type, Theme::get_default()->get_color(E->get(), edited_type));
@ -2539,7 +2566,7 @@ void ThemeTypeEditor::_add_default_type_items() {
}
{
names.clear();
Theme::get_default()->get_constant_list(edited_type, &names);
Theme::get_default()->get_constant_list(default_type, &names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (!edited_theme->has_constant(E->get(), edited_type)) {
edited_theme->set_constant(E->get(), edited_type, Theme::get_default()->get_constant(E->get(), edited_type));
@ -2817,8 +2844,28 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
edited_theme->_unfreeze_and_propagate_changes();
}
void ThemeTypeEditor::_type_variation_changed(const String p_value) {
if (p_value.empty()) {
edited_theme->clear_type_variation(edited_type);
} else {
edited_theme->set_type_variation(edited_type, StringName(p_value));
}
}
void ThemeTypeEditor::_add_type_variation_cbk() {
add_type_mode = ADD_VARIATION_BASE;
add_type_dialog->set_title(TTR("Set Variation Base Type"));
add_type_dialog->get_ok()->set_text(TTR("Set Base Type"));
add_type_dialog->set_include_own_types(true);
add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);
}
void ThemeTypeEditor::_add_type_dialog_selected(const String p_type_name) {
if (add_type_mode == ADD_THEME_TYPE) {
select_type(p_type_name);
} else if (add_type_mode == ADD_VARIATION_BASE) {
_type_variation_changed(p_type_name);
}
}
void ThemeTypeEditor::_notification(int p_what) {
@ -2832,9 +2879,12 @@ void ThemeTypeEditor::_notification(int p_what) {
data_type_tabs->set_tab_icon(2, get_icon("Font", "EditorIcons"));
data_type_tabs->set_tab_icon(3, get_icon("ImageTexture", "EditorIcons"));
data_type_tabs->set_tab_icon(4, get_icon("StyleBoxFlat", "EditorIcons"));
data_type_tabs->set_tab_icon(5, get_icon("Tools", "EditorIcons"));
data_type_tabs->add_style_override("tab_selected", get_stylebox("tab_selected_odd", "TabContainer"));
data_type_tabs->add_style_override("panel", get_stylebox("panel_odd", "TabContainer"));
type_variation_button->set_icon(get_icon("Add", "EditorIcons"));
} break;
}
}
@ -2847,6 +2897,7 @@ void ThemeTypeEditor::_bind_methods() {
ClassDB::bind_method("_list_type_selected", &ThemeTypeEditor::_list_type_selected);
ClassDB::bind_method("_add_type_button_cbk", &ThemeTypeEditor::_add_type_button_cbk);
ClassDB::bind_method("_add_type_variation_cbk", &ThemeTypeEditor::_add_type_variation_cbk);
ClassDB::bind_method("_add_type_dialog_selected", &ThemeTypeEditor::_add_type_dialog_selected);
ClassDB::bind_method("_add_default_type_items", &ThemeTypeEditor::_add_default_type_items);
@ -2868,6 +2919,7 @@ void ThemeTypeEditor::_bind_methods() {
ClassDB::bind_method("_pin_leading_stylebox", &ThemeTypeEditor::_pin_leading_stylebox);
ClassDB::bind_method("_unpin_leading_stylebox", &ThemeTypeEditor::_unpin_leading_stylebox);
ClassDB::bind_method("_update_stylebox_from_leading", &ThemeTypeEditor::_update_stylebox_from_leading);
ClassDB::bind_method("_type_variation_changed", &ThemeTypeEditor::_type_variation_changed);
}
void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
@ -2878,6 +2930,8 @@ void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
edited_theme = p_theme;
edited_theme->connect("changed", this, "_update_type_list_debounced");
_update_type_list();
add_type_dialog->set_edited_theme(edited_theme);
}
void ThemeTypeEditor::select_type(String p_type_name) {
@ -2956,6 +3010,45 @@ ThemeTypeEditor::ThemeTypeEditor() {
icon_items_list = _create_item_list(Theme::DATA_TYPE_ICON);
stylebox_items_list = _create_item_list(Theme::DATA_TYPE_STYLEBOX);
VBoxContainer *type_settings_tab = memnew(VBoxContainer);
type_settings_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);
data_type_tabs->add_child(type_settings_tab);
data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");
ScrollContainer *type_settings_sc = memnew(ScrollContainer);
type_settings_sc->set_v_size_flags(SIZE_EXPAND_FILL);
type_settings_sc->set_enable_h_scroll(false);
type_settings_tab->add_child(type_settings_sc);
VBoxContainer *type_settings_list = memnew(VBoxContainer);
type_settings_list->set_h_size_flags(SIZE_EXPAND_FILL);
type_settings_sc->add_child(type_settings_list);
VBoxContainer *type_variation_vb = memnew(VBoxContainer);
type_settings_list->add_child(type_variation_vb);
HBoxContainer *type_variation_hb = memnew(HBoxContainer);
type_variation_vb->add_child(type_variation_hb);
Label *type_variation_label = memnew(Label);
type_variation_hb->add_child(type_variation_label);
type_variation_label->set_text(TTR("Base Type"));
type_variation_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
type_variation_edit = memnew(LineEdit);
type_variation_hb->add_child(type_variation_edit);
type_variation_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
type_variation_edit->connect("text_changed", this, "_type_variation_changed");
type_variation_edit->connect("focus_exited", this, "_update_type_items");
type_variation_button = memnew(Button);
type_variation_hb->add_child(type_variation_button);
type_variation_button->set_tooltip(TTR("Select the variation base type from a list of available types."));
type_variation_button->connect("pressed", this, "_add_type_variation_cbk");
type_variation_locked = memnew(Label);
type_variation_vb->add_child(type_variation_locked);
type_variation_locked->set_align(Label::ALIGN_CENTER);
type_variation_locked->set_autowrap(true);
type_variation_locked->set_text(TTR("A type associated with a built-in class cannot be marked as a variation of another type."));
type_variation_locked->hide();
add_type_dialog = memnew(ThemeTypeDialog);
add_type_dialog->set_title(TTR("Add Item Type"));
add_child(add_type_dialog);

View file

@ -321,6 +321,16 @@ class ThemeTypeEditor : public MarginContainer {
VBoxContainer *icon_items_list;
VBoxContainer *stylebox_items_list;
LineEdit *type_variation_edit;
Button *type_variation_button;
Label *type_variation_locked;
enum TypeDialogMode {
ADD_THEME_TYPE,
ADD_VARIATION_BASE,
};
TypeDialogMode add_type_mode = ADD_THEME_TYPE;
ThemeTypeDialog *add_type_dialog;
Vector<Control *> focusables;
@ -357,6 +367,9 @@ class ThemeTypeEditor : public MarginContainer {
void _unpin_leading_stylebox();
void _update_stylebox_from_leading();
void _type_variation_changed(const String p_value);
void _add_type_variation_cbk();
void _add_type_dialog_selected(const String p_type_name);
protected:

View file

@ -116,7 +116,11 @@ void ThemeEditorPreview::_draw_picker_overlay() {
highlight_rect.position = picker_overlay->get_global_transform().affine_inverse().xform(highlight_rect.position);
picker_overlay->draw_style_box(theme_cache.preview_picker_overlay, highlight_rect);
String highlight_name = hovered_control->get_class_name();
String highlight_name = hovered_control->get_theme_type_variation();
if (highlight_name == StringName()) {
highlight_name = hovered_control->get_class_name();
}
Rect2 highlight_label_rect = highlight_rect;
highlight_label_rect.size = theme_cache.preview_picker_font->get_string_size(highlight_name);
@ -147,7 +151,10 @@ void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_even
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
if (hovered_control) {
StringName theme_type = hovered_control->get_class_name();
StringName theme_type = hovered_control->get_theme_type_variation();
if (theme_type == StringName()) {
theme_type = hovered_control->get_class_name();
}
emit_signal("control_picked", theme_type);
picker_button->set_pressed(false);

View file

@ -400,6 +400,34 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
void Control::_validate_property(PropertyInfo &property) const {
if (property.name == "theme_type_variation") {
List<StringName> names;
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
Theme::get_default()->get_type_variation_list(get_class_name(), &names);
if (Theme::get_project_default().is_valid()) {
Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
}
names.sort_custom<StringName::AlphCompare>();
Vector<StringName> unique_names;
String hint_string;
for (const List<StringName>::Element *E = names.front(); E; E = E->next()) {
// Skip duplicate values.
if (unique_names.find(E->get()) != -1) {
continue;
}
hint_string += String(E->get()) + ",";
unique_names.push_back(E->get());
}
property.hint_string = hint_string;
}
}
Control *Control::get_parent_control() const {
return data.parent;
}
@ -850,15 +878,19 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Theme::DataType p_
}
void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
Theme::get_default()->get_type_dependencies(get_class_name(), p_list);
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(data.theme_type_variation) != StringName()) {
Theme::get_project_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
} else {
Theme::get_default()->get_type_dependencies(p_theme_type, p_list);
Theme::get_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
}
} else {
Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
}
}
Ref<Texture> Control::get_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Texture> *tex = data.icon_override.getptr(p_name);
if (tex) {
return *tex;
@ -913,7 +945,7 @@ Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_th
}
Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
if (style) {
return *style;
@ -926,7 +958,7 @@ Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &
}
Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Font> *font = data.font_override.getptr(p_name);
if (font) {
return *font;
@ -939,7 +971,7 @@ Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_theme_
}
Color Control::get_color(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Color *color = data.color_override.getptr(p_name);
if (color) {
return *color;
@ -952,7 +984,7 @@ Color Control::get_color(const StringName &p_name, const StringName &p_theme_typ
}
int Control::get_constant(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const int *constant = data.constant_override.getptr(p_name);
if (constant) {
return *constant;
@ -995,7 +1027,7 @@ bool Control::has_constant_override(const StringName &p_name) const {
}
bool Control::has_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_icon_override(p_name)) {
return true;
}
@ -1046,7 +1078,7 @@ bool Control::has_shader(const StringName &p_name, const StringName &p_theme_typ
}
bool Control::has_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_stylebox_override(p_name)) {
return true;
}
@ -1058,7 +1090,7 @@ bool Control::has_stylebox(const StringName &p_name, const StringName &p_theme_t
}
bool Control::has_font(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_font_override(p_name)) {
return true;
}
@ -1070,7 +1102,7 @@ bool Control::has_font(const StringName &p_name, const StringName &p_theme_type)
}
bool Control::has_color(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_color_override(p_name)) {
return true;
}
@ -1082,7 +1114,7 @@ bool Control::has_color(const StringName &p_name, const StringName &p_theme_type
}
bool Control::has_constant(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name()) {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
if (has_constant_override(p_name)) {
return true;
}
@ -2086,16 +2118,25 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
}
}
Ref<Theme> Control::get_theme() const {
return data.theme;
}
void Control::set_theme_type_variation(const StringName &p_theme_type) {
data.theme_type_variation = p_theme_type;
_propagate_theme_changed(this, data.theme_owner);
}
StringName Control::get_theme_type_variation() const {
return data.theme_type_variation;
}
void Control::accept_event() {
if (is_inside_tree()) {
get_viewport()->_gui_accept_event();
}
}
Ref<Theme> Control::get_theme() const {
return data.theme;
}
void Control::set_tooltip(const String &p_tooltip) {
data.tooltip = p_tooltip;
update_configuration_warning();
@ -2637,6 +2678,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_theme", "theme"), &Control::set_theme);
ClassDB::bind_method(D_METHOD("get_theme"), &Control::get_theme);
ClassDB::bind_method(D_METHOD("set_theme_type_variation", "theme_type"), &Control::set_theme_type_variation);
ClassDB::bind_method(D_METHOD("get_theme_type_variation"), &Control::get_theme_type_variation);
ClassDB::bind_method(D_METHOD("add_icon_override", "name", "texture"), &Control::add_icon_override);
ClassDB::bind_method(D_METHOD("add_shader_override", "name", "shader"), &Control::add_shader_override);
ClassDB::bind_method(D_METHOD("add_stylebox_override", "name", "stylebox"), &Control::add_style_override);
@ -2786,6 +2830,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,20,0.01,or_greater"), "set_stretch_ratio", "get_stretch_ratio");
ADD_GROUP("Theme", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
BIND_ENUM_CONSTANT(FOCUS_NONE);
BIND_ENUM_CONSTANT(FOCUS_CLICK);

View file

@ -181,6 +181,7 @@ private:
uint64_t modal_frame; //frame used to put something as modal
Ref<Theme> theme;
Control *theme_owner;
StringName theme_type_variation;
String tooltip;
CursorShape default_cursor;
@ -255,8 +256,8 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_notification);
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const;
//bind helpers
@ -379,6 +380,9 @@ public:
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
void set_theme_type_variation(const StringName &p_theme_type);
StringName get_theme_type_variation() const;
void set_h_size_flags(int p_flags);
int get_h_size_flags() const;

File diff suppressed because it is too large Load diff

View file

@ -69,21 +69,25 @@ private:
HashMap<StringName, HashMap<StringName, Ref<Shader>>> shader_map;
HashMap<StringName, HashMap<StringName, Color>> color_map;
HashMap<StringName, HashMap<StringName, int>> constant_map;
HashMap<StringName, StringName> variation_map;
HashMap<StringName, List<StringName>> variation_base_map;
PoolVector<String> _get_icon_list(const String &p_node_type) const;
PoolVector<String> _get_icon_list(const String &p_theme_type) const;
PoolVector<String> _get_icon_types() const;
PoolVector<String> _get_stylebox_list(const String &p_node_type) const;
PoolVector<String> _get_stylebox_list(const String &p_theme_type) const;
PoolVector<String> _get_stylebox_types() const;
PoolVector<String> _get_font_list(const String &p_node_type) const;
PoolVector<String> _get_font_list(const String &p_theme_type) const;
PoolVector<String> _get_font_types() const;
PoolVector<String> _get_color_list(const String &p_node_type) const;
PoolVector<String> _get_color_list(const String &p_theme_type) const;
PoolVector<String> _get_color_types() const;
PoolVector<String> _get_constant_list(const String &p_node_type) const;
PoolVector<String> _get_constant_list(const String &p_theme_type) const;
PoolVector<String> _get_constant_types() const;
PoolVector<String> _get_theme_item_list(DataType p_data_type, const String &p_node_type) const;
PoolVector<String> _get_theme_item_list(DataType p_data_type, const String &p_theme_type) const;
PoolVector<String> _get_theme_item_types(DataType p_data_type) const;
PoolVector<String> _get_type_list(const String &p_node_type) const;
Vector<String> _get_type_variation_list(const StringName &p_theme_type) const;
PoolVector<String> _get_type_list(const String &p_theme_type) const;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@ -122,74 +126,80 @@ public:
Ref<Font> get_default_theme_font() const;
bool has_default_theme_font() const;
void set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture> &p_icon);
Ref<Texture> get_icon(const StringName &p_name, const StringName &p_node_type) const;
bool has_icon(const StringName &p_name, const StringName &p_node_type) const;
bool has_icon_nocheck(const StringName &p_name, const StringName &p_node_type) const;
void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_icon(const StringName &p_name, const StringName &p_node_type);
void get_icon_list(StringName p_node_type, List<StringName> *p_list) const;
void add_icon_type(const StringName &p_node_type);
void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture> &p_icon);
Ref<Texture> get_icon(const StringName &p_name, const StringName &p_theme_type) const;
bool has_icon(const StringName &p_name, const StringName &p_theme_type) const;
bool has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_icon(const StringName &p_name, const StringName &p_theme_type);
void get_icon_list(StringName p_theme_type, List<StringName> *p_list) const;
void add_icon_type(const StringName &p_theme_type);
void get_icon_types(List<StringName> *p_list) const;
void set_shader(const StringName &p_name, const StringName &p_node_type, const Ref<Shader> &p_shader);
Ref<Shader> get_shader(const StringName &p_name, const StringName &p_node_type) const;
bool has_shader(const StringName &p_name, const StringName &p_node_type) const;
void clear_shader(const StringName &p_name, const StringName &p_node_type);
void get_shader_list(const StringName &p_node_type, List<StringName> *p_list) const;
void set_shader(const StringName &p_name, const StringName &p_theme_type, const Ref<Shader> &p_shader);
Ref<Shader> get_shader(const StringName &p_name, const StringName &p_theme_type) const;
bool has_shader(const StringName &p_name, const StringName &p_theme_type) const;
void clear_shader(const StringName &p_name, const StringName &p_theme_type);
void get_shader_list(const StringName &p_theme_type, List<StringName> *p_list) const;
void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style);
Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const;
bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const;
bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_node_type) const;
void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_stylebox(const StringName &p_name, const StringName &p_node_type);
void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const;
void add_stylebox_type(const StringName &p_node_type);
void set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style);
Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_theme_type) const;
bool has_stylebox(const StringName &p_name, const StringName &p_theme_type) const;
bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_stylebox(const StringName &p_name, const StringName &p_theme_type);
void get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const;
void add_stylebox_type(const StringName &p_theme_type);
void get_stylebox_types(List<StringName> *p_list) const;
void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font);
Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const;
bool has_font(const StringName &p_name, const StringName &p_node_type) const;
bool has_font_nocheck(const StringName &p_name, const StringName &p_node_type) const;
void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_font(const StringName &p_name, const StringName &p_node_type);
void get_font_list(StringName p_node_type, List<StringName> *p_list) const;
void add_font_type(const StringName &p_node_type);
void set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font);
Ref<Font> get_font(const StringName &p_name, const StringName &p_theme_type) const;
bool has_font(const StringName &p_name, const StringName &p_theme_type) const;
bool has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_font(const StringName &p_name, const StringName &p_theme_type);
void get_font_list(StringName p_theme_type, List<StringName> *p_list) const;
void add_font_type(const StringName &p_theme_type);
void get_font_types(List<StringName> *p_list) const;
void set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color);
Color get_color(const StringName &p_name, const StringName &p_node_type) const;
bool has_color(const StringName &p_name, const StringName &p_node_type) const;
bool has_color_nocheck(const StringName &p_name, const StringName &p_node_type) const;
void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_color(const StringName &p_name, const StringName &p_node_type);
void get_color_list(StringName p_node_type, List<StringName> *p_list) const;
void add_color_type(const StringName &p_node_type);
void set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color);
Color get_color(const StringName &p_name, const StringName &p_theme_type) const;
bool has_color(const StringName &p_name, const StringName &p_theme_type) const;
bool has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_color(const StringName &p_name, const StringName &p_theme_type);
void get_color_list(StringName p_theme_type, List<StringName> *p_list) const;
void add_color_type(const StringName &p_theme_type);
void get_color_types(List<StringName> *p_list) const;
void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant);
int get_constant(const StringName &p_name, const StringName &p_node_type) const;
bool has_constant(const StringName &p_name, const StringName &p_node_type) const;
bool has_constant_nocheck(const StringName &p_name, const StringName &p_node_type) const;
void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_constant(const StringName &p_name, const StringName &p_node_type);
void get_constant_list(StringName p_node_type, List<StringName> *p_list) const;
void add_constant_type(const StringName &p_node_type);
void set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant);
int get_constant(const StringName &p_name, const StringName &p_theme_type) const;
bool has_constant(const StringName &p_name, const StringName &p_theme_type) const;
bool has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_constant(const StringName &p_name, const StringName &p_theme_type);
void get_constant_list(StringName p_theme_type, List<StringName> *p_list) const;
void add_constant_type(const StringName &p_theme_type);
void get_constant_types(List<StringName> *p_list) const;
void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value);
Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
bool has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type);
void get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const;
void add_theme_item_type(DataType p_data_type, const StringName &p_node_type);
void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type, const Variant &p_value);
Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const;
bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const;
bool has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const;
void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type);
void get_theme_item_list(DataType p_data_type, StringName p_theme_type, List<StringName> *p_list) const;
void add_theme_item_type(DataType p_data_type, const StringName &p_theme_type);
void get_theme_item_types(DataType p_data_type, List<StringName> *p_list) const;
void set_type_variation(const StringName &p_theme_type, const StringName &p_base_type);
bool is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const;
void clear_type_variation(const StringName &p_theme_type);
StringName get_type_variation_base(const StringName &p_theme_type) const;
void get_type_variation_list(const StringName &p_base_type, List<StringName> *p_list) const;
void get_type_list(List<StringName> *p_list) const;
void get_type_dependencies(const StringName &p_base_type, List<StringName> *p_list);
void get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variant, List<StringName> *p_list);
void copy_default_theme();
void copy_theme(const Ref<Theme> &p_other);