Browse Source

Merge pull request #53341 from pycbouh/gui-editor-scale-encapsulation

Rémi Verschelde 3 years ago
parent
commit
865b62b1cd

+ 21 - 0
doc/classes/Control.xml

@@ -458,6 +458,27 @@
 				See [method get_theme_color] for details.
 				See [method get_theme_color] for details.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_theme_default_base_scale" qualifiers="const">
+			<return type="float" />
+			<description>
+				Returns the default base scale value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_base_scale] value.
+				See [method get_theme_color] for details.
+			</description>
+		</method>
+		<method name="get_theme_default_font" qualifiers="const">
+			<return type="Font" />
+			<description>
+				Returns the default font from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font] value.
+				See [method get_theme_color] for details.
+			</description>
+		</method>
+		<method name="get_theme_default_font_size" qualifiers="const">
+			<return type="int" />
+			<description>
+				Returns the default font size value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font_size] value.
+				See [method get_theme_color] for details.
+			</description>
+		</method>
 		<method name="get_theme_font" qualifiers="const">
 		<method name="get_theme_font" qualifiers="const">
 			<return type="Font" />
 			<return type="Font" />
 			<argument index="0" name="name" type="StringName" />
 			<argument index="0" name="name" type="StringName" />

+ 26 - 2
doc/classes/Theme.xml

@@ -273,6 +273,24 @@
 				Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
 				Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="has_default_base_scale" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if this theme has a valid [member default_base_scale] value.
+			</description>
+		</method>
+		<method name="has_default_font" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if this theme has a valid [member default_font] value.
+			</description>
+		</method>
+		<method name="has_default_font_size" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if this theme has a valid [member default_font_size] value.
+			</description>
+		</method>
 		<method name="has_font" qualifiers="const">
 		<method name="has_font" qualifiers="const">
 			<return type="bool" />
 			<return type="bool" />
 			<argument index="0" name="name" type="StringName" />
 			<argument index="0" name="name" type="StringName" />
@@ -484,11 +502,17 @@
 		</method>
 		</method>
 	</methods>
 	</methods>
 	<members>
 	<members>
+		<member name="default_base_scale" type="float" setter="set_default_base_scale" getter="get_default_base_scale" default="0.0">
+			The default base scale factor of this [Theme] resource. Used by some controls to scale their visual properties based on a global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used.
+			Use [method has_default_base_scale] to check if this value is valid.
+		</member>
 		<member name="default_font" type="Font" setter="set_default_font" getter="get_default_font">
 		<member name="default_font" type="Font" setter="set_default_font" getter="get_default_font">
-			The theme's default font.
+			The default font of this [Theme] resource. Used as a fallback value for font items defined in this theme, but having invalid values. If this value is also invalid, the global default value is used.
+			Use [method has_default_font] to check if this value is valid.
 		</member>
 		</member>
 		<member name="default_font_size" type="int" setter="set_default_font_size" getter="get_default_font_size" default="-1">
 		<member name="default_font_size" type="int" setter="set_default_font_size" getter="get_default_font_size" default="-1">
-			The theme's default font size. Set to [code]-1[/code] to ignore and use global default.
+			The default font size of this [Theme] resource. Used as a fallback value for font size items defined in this theme, but having invalid values. If this value is set to [code]-1[/code], the global default value is used.
+			Use [method has_default_font_size] to check if this value is valid.
 		</member>
 		</member>
 	</members>
 	</members>
 	<constants>
 	<constants>

+ 15 - 0
doc/classes/Window.xml

@@ -59,6 +59,21 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_theme_default_base_scale" qualifiers="const">
+			<return type="float" />
+			<description>
+			</description>
+		</method>
+		<method name="get_theme_default_font" qualifiers="const">
+			<return type="Font" />
+			<description>
+			</description>
+		</method>
+		<method name="get_theme_default_font_size" qualifiers="const">
+			<return type="int" />
+			<description>
+			</description>
+		</method>
 		<method name="get_theme_font" qualifiers="const">
 		<method name="get_theme_font" qualifiers="const">
 			<return type="Font" />
 			<return type="Font" />
 			<argument index="0" name="name" type="StringName" />
 			<argument index="0" name="name" type="StringName" />

+ 4 - 1
editor/editor_themes.cpp

@@ -292,7 +292,8 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
 Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	Ref<Theme> theme = Ref<Theme>(memnew(Theme));
 	Ref<Theme> theme = Ref<Theme>(memnew(Theme));
 
 
-	const float default_contrast = 0.3;
+	// Controls may rely on the scale for their internal drawing logic.
+	theme->set_default_theme_base_scale(EDSCALE);
 
 
 	// Theme settings
 	// Theme settings
 	Color accent_color = EDITOR_GET("interface/theme/accent_color");
 	Color accent_color = EDITOR_GET("interface/theme/accent_color");
@@ -310,6 +311,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	Color preset_base_color;
 	Color preset_base_color;
 	float preset_contrast = 0;
 	float preset_contrast = 0;
 
 
+	const float default_contrast = 0.3;
+
 	// Please use alphabetical order if you're adding a new theme here
 	// Please use alphabetical order if you're adding a new theme here
 	// (after "Custom")
 	// (after "Custom")
 
 

+ 24 - 29
scene/gui/color_picker.cpp

@@ -35,7 +35,6 @@
 #include "core/os/os.h"
 #include "core/os/os.h"
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"
 #endif
 #endif
 #include "scene/main/window.h"
 #include "scene/main/window.h"
@@ -44,17 +43,7 @@ List<Color> ColorPicker::preset_cache;
 
 
 void ColorPicker::_notification(int p_what) {
 void ColorPicker::_notification(int p_what) {
 	switch (p_what) {
 	switch (p_what) {
-		case NOTIFICATION_THEME_CHANGED: {
-			btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
-			btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
-			_update_presets();
-			_update_controls();
-		} break;
 		case NOTIFICATION_ENTER_TREE: {
 		case NOTIFICATION_ENTER_TREE: {
-			btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
-			btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
-
-			_update_controls();
 			_update_color();
 			_update_color();
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
@@ -71,18 +60,39 @@ void ColorPicker::_notification(int p_what) {
 				}
 				}
 			}
 			}
 #endif
 #endif
-		} break;
-		case NOTIFICATION_PARENTED: {
+			[[fallthrough]];
+		}
+		case NOTIFICATION_THEME_CHANGED: {
+			btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
+			btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
+
+			uv_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
+			w_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("h_width")), 0));
+
+			wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
+			wheel_margin->add_theme_constant_override("margin_bottom", 8 * get_theme_default_base_scale());
+
 			for (int i = 0; i < 4; i++) {
 			for (int i = 0; i < 4; i++) {
+				labels[i]->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0));
 				set_offset((Side)i, get_offset((Side)i) + get_theme_constant(SNAME("margin")));
 				set_offset((Side)i, get_offset((Side)i) + get_theme_constant(SNAME("margin")));
 			}
 			}
+
+			if (Engine::get_singleton()->is_editor_hint()) {
+				// Adjust for the width of the "Script" icon.
+				text_type->set_custom_minimum_size(Size2(28 * get_theme_default_base_scale(), 0));
+			}
+
+			_update_presets();
+			_update_controls();
 		} break;
 		} break;
+
 		case NOTIFICATION_VISIBILITY_CHANGED: {
 		case NOTIFICATION_VISIBILITY_CHANGED: {
 			Popup *p = Object::cast_to<Popup>(get_parent());
 			Popup *p = Object::cast_to<Popup>(get_parent());
 			if (p) {
 			if (p) {
 				p->set_size(Size2(get_combined_minimum_size().width + get_theme_constant(SNAME("margin")) * 2, get_combined_minimum_size().height + get_theme_constant(SNAME("margin")) * 2));
 				p->set_size(Size2(get_combined_minimum_size().width + get_theme_constant(SNAME("margin")) * 2, get_combined_minimum_size().height + get_theme_constant(SNAME("margin")) * 2));
 			}
 			}
 		} break;
 		} break;
+
 		case NOTIFICATION_WM_CLOSE_REQUEST: {
 		case NOTIFICATION_WM_CLOSE_REQUEST: {
 			if (screen != nullptr && screen->is_visible()) {
 			if (screen != nullptr && screen->is_visible()) {
 				screen->hide();
 				screen->hide();
@@ -762,11 +772,7 @@ void ColorPicker::_slider_draw(int p_which) {
 	Size2 size = scroll[p_which]->get_size();
 	Size2 size = scroll[p_which]->get_size();
 	Color left_color;
 	Color left_color;
 	Color right_color;
 	Color right_color;
-#ifdef TOOLS_ENABLED
-	const real_t margin = 4 * EDSCALE;
-#else
-	const real_t margin = 4;
-#endif
+	const real_t margin = 4 * get_theme_default_base_scale();
 
 
 	if (p_which == 3) {
 	if (p_which == 3) {
 		scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
 		scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
@@ -1147,7 +1153,6 @@ ColorPicker::ColorPicker() :
 	uv_edit->set_mouse_filter(MOUSE_FILTER_PASS);
 	uv_edit->set_mouse_filter(MOUSE_FILTER_PASS);
 	uv_edit->set_h_size_flags(SIZE_EXPAND_FILL);
 	uv_edit->set_h_size_flags(SIZE_EXPAND_FILL);
 	uv_edit->set_v_size_flags(SIZE_EXPAND_FILL);
 	uv_edit->set_v_size_flags(SIZE_EXPAND_FILL);
-	uv_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
 	uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit));
 	uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit));
 
 
 	HBoxContainer *hb_smpl = memnew(HBoxContainer);
 	HBoxContainer *hb_smpl = memnew(HBoxContainer);
@@ -1219,9 +1224,6 @@ ColorPicker::ColorPicker() :
 	text_type->set_text("#");
 	text_type->set_text("#");
 	text_type->set_tooltip(TTR("Switch between hexadecimal and code values."));
 	text_type->set_tooltip(TTR("Switch between hexadecimal and code values."));
 	if (Engine::get_singleton()->is_editor_hint()) {
 	if (Engine::get_singleton()->is_editor_hint()) {
-#ifdef TOOLS_ENABLED
-		text_type->set_custom_minimum_size(Size2(28 * EDSCALE, 0)); // Adjust for the width of the "Script" icon.
-#endif
 		text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled));
 		text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled));
 	} else {
 	} else {
 		text_type->set_flat(true);
 		text_type->set_flat(true);
@@ -1236,7 +1238,6 @@ ColorPicker::ColorPicker() :
 
 
 	wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL);
 	wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL);
 	wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL);
 	wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL);
-	wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
 	hb_edit->add_child(wheel_edit);
 	hb_edit->add_child(wheel_edit);
 
 
 	wheel_mat.instantiate();
 	wheel_mat.instantiate();
@@ -1244,12 +1245,7 @@ ColorPicker::ColorPicker() :
 	circle_mat.instantiate();
 	circle_mat.instantiate();
 	circle_mat->set_shader(circle_shader);
 	circle_mat->set_shader(circle_shader);
 
 
-	MarginContainer *wheel_margin(memnew(MarginContainer));
-#ifdef TOOLS_ENABLED
-	wheel_margin->add_theme_constant_override("margin_bottom", 8 * EDSCALE);
-#else
 	wheel_margin->add_theme_constant_override("margin_bottom", 8);
 	wheel_margin->add_theme_constant_override("margin_bottom", 8);
-#endif
 	wheel_edit->add_child(wheel_margin);
 	wheel_edit->add_child(wheel_margin);
 
 
 	wheel_margin->add_child(wheel);
 	wheel_margin->add_child(wheel);
@@ -1261,7 +1257,6 @@ ColorPicker::ColorPicker() :
 	wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv));
 	wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv));
 
 
 	hb_edit->add_child(w_edit);
 	hb_edit->add_child(w_edit);
-	w_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("h_width")), 0));
 	w_edit->set_h_size_flags(SIZE_FILL);
 	w_edit->set_h_size_flags(SIZE_FILL);
 	w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
 	w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
 	w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input));
 	w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input));

+ 1 - 0
scene/gui/color_picker.h

@@ -81,6 +81,7 @@ private:
 	Control *uv_edit = memnew(Control);
 	Control *uv_edit = memnew(Control);
 	Control *w_edit = memnew(Control);
 	Control *w_edit = memnew(Control);
 	AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer);
 	AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer);
+	MarginContainer *wheel_margin = memnew(MarginContainer);
 	Ref<ShaderMaterial> wheel_mat;
 	Ref<ShaderMaterial> wheel_mat;
 	Ref<ShaderMaterial> circle_mat;
 	Ref<ShaderMaterial> circle_mat;
 	Control *wheel = memnew(Control);
 	Control *wheel = memnew(Control);

+ 152 - 2
scene/gui/control.cpp

@@ -833,11 +833,12 @@ T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner
 	ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
 	ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
 
 
 	// First, look through each control or window node in the branch, until no valid parent can be found.
 	// First, look through each control or window node in the branch, until no valid parent can be found.
-	// For each control iterate through its inheritance chain and see if p_name exists in any of them.
+	// Only nodes with a theme resource attached are considered.
 	Control *theme_owner = p_theme_owner;
 	Control *theme_owner = p_theme_owner;
 	Window *theme_owner_window = p_theme_owner_window;
 	Window *theme_owner_window = p_theme_owner_window;
 
 
 	while (theme_owner || theme_owner_window) {
 	while (theme_owner || theme_owner_window) {
+		// For each theme resource check the theme types provided and see if p_name exists with any of them.
 		for (const StringName &E : p_theme_types) {
 		for (const StringName &E : p_theme_types) {
 			if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
 			if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
 				return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E);
 				return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E);
@@ -888,11 +889,12 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
 	ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
 	ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
 
 
 	// First, look through each control or window node in the branch, until no valid parent can be found.
 	// First, look through each control or window node in the branch, until no valid parent can be found.
-	// For each control iterate through its inheritance chain and see if p_name exists in any of them.
+	// Only nodes with a theme resource attached are considered.
 	Control *theme_owner = p_theme_owner;
 	Control *theme_owner = p_theme_owner;
 	Window *theme_owner_window = p_theme_owner_window;
 	Window *theme_owner_window = p_theme_owner_window;
 
 
 	while (theme_owner || theme_owner_window) {
 	while (theme_owner || theme_owner_window) {
+		// For each theme resource check the theme types provided and see if p_name exists with any of them.
 		for (const StringName &E : p_theme_types) {
 		for (const StringName &E : p_theme_types) {
 			if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
 			if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
 				return true;
 				return true;
@@ -1130,6 +1132,150 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t
 	return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
 	return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
 }
 }
 
 
+float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) {
+	// First, look through each control or window node in the branch, until no valid parent can be found.
+	// Only nodes with a theme resource attached are considered.
+	// For each theme resource see if their assigned theme has the default value defined and valid.
+	Control *theme_owner = p_theme_owner;
+	Window *theme_owner_window = p_theme_owner_window;
+
+	while (theme_owner || theme_owner_window) {
+		if (theme_owner && theme_owner->data.theme->has_default_theme_base_scale()) {
+			return theme_owner->data.theme->get_default_theme_base_scale();
+		}
+
+		if (theme_owner_window && theme_owner_window->theme->has_default_theme_base_scale()) {
+			return theme_owner_window->theme->get_default_theme_base_scale();
+		}
+
+		Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+		Control *parent_c = Object::cast_to<Control>(parent);
+		if (parent_c) {
+			theme_owner = parent_c->data.theme_owner;
+			theme_owner_window = parent_c->data.theme_owner_window;
+		} else {
+			Window *parent_w = Object::cast_to<Window>(parent);
+			if (parent_w) {
+				theme_owner = parent_w->theme_owner;
+				theme_owner_window = parent_w->theme_owner_window;
+			} else {
+				theme_owner = nullptr;
+				theme_owner_window = nullptr;
+			}
+		}
+	}
+
+	// Secondly, check the project-defined Theme resource.
+	if (Theme::get_project_default().is_valid()) {
+		if (Theme::get_project_default()->has_default_theme_base_scale()) {
+			return Theme::get_project_default()->get_default_theme_base_scale();
+		}
+	}
+
+	// Lastly, fall back on the default Theme.
+	return Theme::get_default()->get_default_theme_base_scale();
+}
+
+float Control::get_theme_default_base_scale() const {
+	return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window);
+}
+
+Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) {
+	// First, look through each control or window node in the branch, until no valid parent can be found.
+	// Only nodes with a theme resource attached are considered.
+	// For each theme resource see if their assigned theme has the default value defined and valid.
+	Control *theme_owner = p_theme_owner;
+	Window *theme_owner_window = p_theme_owner_window;
+
+	while (theme_owner || theme_owner_window) {
+		if (theme_owner && theme_owner->data.theme->has_default_theme_font()) {
+			return theme_owner->data.theme->get_default_theme_font();
+		}
+
+		if (theme_owner_window && theme_owner_window->theme->has_default_theme_font()) {
+			return theme_owner_window->theme->get_default_theme_font();
+		}
+
+		Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+		Control *parent_c = Object::cast_to<Control>(parent);
+		if (parent_c) {
+			theme_owner = parent_c->data.theme_owner;
+			theme_owner_window = parent_c->data.theme_owner_window;
+		} else {
+			Window *parent_w = Object::cast_to<Window>(parent);
+			if (parent_w) {
+				theme_owner = parent_w->theme_owner;
+				theme_owner_window = parent_w->theme_owner_window;
+			} else {
+				theme_owner = nullptr;
+				theme_owner_window = nullptr;
+			}
+		}
+	}
+
+	// Secondly, check the project-defined Theme resource.
+	if (Theme::get_project_default().is_valid()) {
+		if (Theme::get_project_default()->has_default_theme_font()) {
+			return Theme::get_project_default()->get_default_theme_font();
+		}
+	}
+
+	// Lastly, fall back on the default Theme.
+	return Theme::get_default()->get_default_theme_font();
+}
+
+Ref<Font> Control::get_theme_default_font() const {
+	return fetch_theme_default_font(data.theme_owner, data.theme_owner_window);
+}
+
+int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) {
+	// First, look through each control or window node in the branch, until no valid parent can be found.
+	// Only nodes with a theme resource attached are considered.
+	// For each theme resource see if their assigned theme has the default value defined and valid.
+	Control *theme_owner = p_theme_owner;
+	Window *theme_owner_window = p_theme_owner_window;
+
+	while (theme_owner || theme_owner_window) {
+		if (theme_owner && theme_owner->data.theme->has_default_theme_font_size()) {
+			return theme_owner->data.theme->get_default_theme_font_size();
+		}
+
+		if (theme_owner_window && theme_owner_window->theme->has_default_theme_font_size()) {
+			return theme_owner_window->theme->get_default_theme_font_size();
+		}
+
+		Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+		Control *parent_c = Object::cast_to<Control>(parent);
+		if (parent_c) {
+			theme_owner = parent_c->data.theme_owner;
+			theme_owner_window = parent_c->data.theme_owner_window;
+		} else {
+			Window *parent_w = Object::cast_to<Window>(parent);
+			if (parent_w) {
+				theme_owner = parent_w->theme_owner;
+				theme_owner_window = parent_w->theme_owner_window;
+			} else {
+				theme_owner = nullptr;
+				theme_owner_window = nullptr;
+			}
+		}
+	}
+
+	// Secondly, check the project-defined Theme resource.
+	if (Theme::get_project_default().is_valid()) {
+		if (Theme::get_project_default()->has_default_theme_font_size()) {
+			return Theme::get_project_default()->get_default_theme_font_size();
+		}
+	}
+
+	// Lastly, fall back on the default Theme.
+	return Theme::get_default()->get_default_theme_font_size();
+}
+
+int Control::get_theme_default_font_size() const {
+	return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window);
+}
+
 Rect2 Control::get_parent_anchorable_rect() const {
 Rect2 Control::get_parent_anchorable_rect() const {
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
 		return Rect2();
 		return Rect2();
@@ -2789,6 +2935,10 @@ void Control::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Control::has_theme_color, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Control::has_theme_color, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Control::has_theme_constant, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Control::has_theme_constant, DEFVAL(""));
 
 
+	ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Control::get_theme_default_base_scale);
+	ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Control::get_theme_default_font);
+	ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Control::get_theme_default_font_size);
+
 	ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control);
 	ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control);
 
 
 	ClassDB::bind_method(D_METHOD("set_h_grow_direction", "direction"), &Control::set_h_grow_direction);
 	ClassDB::bind_method(D_METHOD("set_h_grow_direction", "direction"), &Control::set_h_grow_direction);

+ 8 - 0
scene/gui/control.h

@@ -509,6 +509,14 @@ public:
 	bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 	bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 	bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 	bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 
 
+	static float fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window);
+	static Ref<Font> fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window);
+	static int fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window);
+
+	float get_theme_default_base_scale() const;
+	Ref<Font> get_theme_default_font() const;
+	int get_theme_default_font_size() const;
+
 	/* TOOLTIP */
 	/* TOOLTIP */
 
 
 	void set_tooltip(const String &p_tooltip);
 	void set_tooltip(const String &p_tooltip);

+ 2 - 4
scene/gui/dialogs.cpp

@@ -37,7 +37,6 @@
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 #include "editor/editor_node.h"
 #include "editor/editor_node.h"
-#include "editor/editor_scale.h"
 #include "scene/main/window.h" // Only used to check for more modals when dimming the editor.
 #include "scene/main/window.h" // Only used to check for more modals when dimming the editor.
 #endif
 #endif
 
 
@@ -363,8 +362,7 @@ Button *ConfirmationDialog::get_cancel_button() {
 
 
 ConfirmationDialog::ConfirmationDialog() {
 ConfirmationDialog::ConfirmationDialog() {
 	set_title(TTRC("Please Confirm..."));
 	set_title(TTRC("Please Confirm..."));
-#ifdef TOOLS_ENABLED
-	set_min_size(Size2(200, 70) * EDSCALE);
-#endif
+	set_min_size(Size2(200, 70));
+
 	cancel = add_cancel_button();
 	cancel = add_cancel_button();
 }
 }

+ 19 - 22
scene/gui/gradient_edit.cpp

@@ -32,15 +32,6 @@
 
 
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 
 
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#define SPACING (3 * EDSCALE)
-#define POINT_WIDTH (8 * EDSCALE)
-#else
-#define SPACING 3
-#define POINT_WIDTH 8
-#endif
-
 GradientEdit::GradientEdit() {
 GradientEdit::GradientEdit() {
 	set_focus_mode(FOCUS_ALL);
 	set_focus_mode(FOCUS_ALL);
 
 
@@ -53,12 +44,12 @@ GradientEdit::GradientEdit() {
 
 
 int GradientEdit::_get_point_from_pos(int x) {
 int GradientEdit::_get_point_from_pos(int x) {
 	int result = -1;
 	int result = -1;
-	int total_w = get_size().width - get_size().height - SPACING;
+	int total_w = get_size().width - get_size().height - draw_spacing;
 	float min_distance = 1e20;
 	float min_distance = 1e20;
 	for (int i = 0; i < points.size(); i++) {
 	for (int i = 0; i < points.size(); i++) {
 		//Check if we clicked at point
 		//Check if we clicked at point
 		float distance = ABS(x - points[i].offset * total_w);
 		float distance = ABS(x - points[i].offset * total_w);
-		float min = (POINT_WIDTH / 2 * 1.7); //make it easier to grab
+		float min = (draw_point_width / 2 * 1.7); //make it easier to grab
 		if (distance <= min && distance < min_distance) {
 		if (distance <= min && distance < min_distance) {
 			result = i;
 			result = i;
 			min_distance = distance;
 			min_distance = distance;
@@ -129,7 +120,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
 		grabbed = _get_point_from_pos(x);
 		grabbed = _get_point_from_pos(x);
 
 
 		if (grabbed != -1) {
 		if (grabbed != -1) {
-			int total_w = get_size().width - get_size().height - SPACING;
+			int total_w = get_size().width - get_size().height - draw_spacing;
 			Gradient::Point newPoint = points[grabbed];
 			Gradient::Point newPoint = points[grabbed];
 			newPoint.offset = CLAMP(x / float(total_w), 0, 1);
 			newPoint.offset = CLAMP(x / float(total_w), 0, 1);
 
 
@@ -151,10 +142,10 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
 	if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
 	if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
 		update();
 		update();
 		int x = mb->get_position().x;
 		int x = mb->get_position().x;
-		int total_w = get_size().width - get_size().height - SPACING;
+		int total_w = get_size().width - get_size().height - draw_spacing;
 
 
 		//Check if color selector was clicked.
 		//Check if color selector was clicked.
-		if (x > total_w + SPACING) {
+		if (x > total_w + draw_spacing) {
 			_show_color_picker();
 			_show_color_picker();
 			return;
 			return;
 		}
 		}
@@ -225,7 +216,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
 	Ref<InputEventMouseMotion> mm = p_event;
 	Ref<InputEventMouseMotion> mm = p_event;
 
 
 	if (mm.is_valid() && grabbing) {
 	if (mm.is_valid() && grabbing) {
-		int total_w = get_size().width - get_size().height - SPACING;
+		int total_w = get_size().width - get_size().height - draw_spacing;
 
 
 		int x = mm->get_position().x;
 		int x = mm->get_position().x;
 
 
@@ -297,6 +288,12 @@ void GradientEdit::_notification(int p_what) {
 			picker->connect("color_changed", callable_mp(this, &GradientEdit::_color_changed));
 			picker->connect("color_changed", callable_mp(this, &GradientEdit::_color_changed));
 		}
 		}
 	}
 	}
+
+	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+		draw_spacing = BASE_SPACING * get_theme_default_base_scale();
+		draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale();
+	}
+
 	if (p_what == NOTIFICATION_DRAW) {
 	if (p_what == NOTIFICATION_DRAW) {
 		int w = get_size().x;
 		int w = get_size().x;
 		int h = get_size().y;
 		int h = get_size().y;
@@ -305,7 +302,7 @@ void GradientEdit::_notification(int p_what) {
 			return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size
 			return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size
 		}
 		}
 
 
-		int total_w = get_size().width - get_size().height - SPACING;
+		int total_w = get_size().width - get_size().height - draw_spacing;
 
 
 		//Draw checker pattern for ramp
 		//Draw checker pattern for ramp
 		draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true);
 		draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true);
@@ -358,7 +355,7 @@ void GradientEdit::_notification(int p_what) {
 			col.a = 0.9;
 			col.a = 0.9;
 
 
 			draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col);
 			draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col);
-			Rect2 rect = Rect2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2, POINT_WIDTH, h / 2);
+			Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2);
 			draw_rect(rect, points[i].color, true);
 			draw_rect(rect, points[i].color, true);
 			draw_rect(rect, col, false);
 			draw_rect(rect, col, false);
 			if (grabbed == i) {
 			if (grabbed == i) {
@@ -375,15 +372,15 @@ void GradientEdit::_notification(int p_what) {
 		}
 		}
 
 
 		//Draw "button" for color selector
 		//Draw "button" for color selector
-		draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + SPACING, 0, h, h), true);
+		draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true);
 		if (grabbed != -1) {
 		if (grabbed != -1) {
 			//Draw with selection color
 			//Draw with selection color
-			draw_rect(Rect2(total_w + SPACING, 0, h, h), points[grabbed].color);
+			draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color);
 		} else {
 		} else {
 			//if no color selected draw grey color with 'X' on top.
 			//if no color selected draw grey color with 'X' on top.
-			draw_rect(Rect2(total_w + SPACING, 0, h, h), Color(0.5, 0.5, 0.5, 1));
-			draw_line(Vector2(total_w + SPACING, 0), Vector2(total_w + SPACING + h, h), Color(1, 1, 1, 0.6));
-			draw_line(Vector2(total_w + SPACING, h), Vector2(total_w + SPACING + h, 0), Color(1, 1, 1, 0.6));
+			draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1));
+			draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6));
+			draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6));
 		}
 		}
 
 
 		//Draw borders around color ramp if in focus
 		//Draw borders around color ramp if in focus

+ 7 - 0
scene/gui/gradient_edit.h

@@ -46,6 +46,13 @@ class GradientEdit : public Control {
 	int grabbed = -1;
 	int grabbed = -1;
 	Vector<Gradient::Point> points;
 	Vector<Gradient::Point> points;
 
 
+	// Make sure to use the scaled value below.
+	const int BASE_SPACING = 3;
+	const int BASE_POINT_WIDTH = 8;
+
+	int draw_spacing = BASE_SPACING;
+	int draw_point_width = BASE_POINT_WIDTH;
+
 	void _draw_checker(int x, int y, int w, int h);
 	void _draw_checker(int x, int y, int w, int h);
 	void _color_changed(const Color &p_color);
 	void _color_changed(const Color &p_color);
 	int _get_point_from_pos(int x);
 	int _get_point_from_pos(int x);

+ 3 - 13
scene/gui/graph_edit.cpp

@@ -36,10 +36,6 @@
 #include "scene/gui/box_container.h"
 #include "scene/gui/box_container.h"
 #include "scene/gui/button.h"
 #include "scene/gui/button.h"
 
 
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
 constexpr int MINIMAP_OFFSET = 12;
 constexpr int MINIMAP_OFFSET = 12;
 constexpr int MINIMAP_PADDING = 5;
 constexpr int MINIMAP_PADDING = 5;
 
 
@@ -436,6 +432,8 @@ void GraphEdit::_notification(int p_what) {
 		snap_button->set_icon(get_theme_icon(SNAME("snap")));
 		snap_button->set_icon(get_theme_icon(SNAME("snap")));
 		minimap_button->set_icon(get_theme_icon(SNAME("minimap")));
 		minimap_button->set_icon(get_theme_icon(SNAME("minimap")));
 		layout_button->set_icon(get_theme_icon(SNAME("layout")));
 		layout_button->set_icon(get_theme_icon(SNAME("layout")));
+
+		zoom_label->set_custom_minimum_size(Size2(48, 0) * get_theme_default_base_scale());
 	}
 	}
 	if (p_what == NOTIFICATION_READY) {
 	if (p_what == NOTIFICATION_READY) {
 		Size2 hmin = h_scroll->get_combined_minimum_size();
 		Size2 hmin = h_scroll->get_combined_minimum_size();
@@ -816,11 +814,7 @@ void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from
 		scaled_points.push_back(points[i] * p_zoom);
 		scaled_points.push_back(points[i] * p_zoom);
 	}
 	}
 
 
-#ifdef TOOLS_ENABLED
-	p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * EDSCALE), lines_antialiased);
-#else
-	p_where->draw_polyline_colors(scaled_points, colors, p_width, lines_antialiased);
-#endif
+	p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * get_theme_default_base_scale()), lines_antialiased);
 }
 }
 
 
 void GraphEdit::_connections_layer_draw() {
 void GraphEdit::_connections_layer_draw() {
@@ -2272,11 +2266,7 @@ GraphEdit::GraphEdit() {
 	zoom_label->set_visible(false);
 	zoom_label->set_visible(false);
 	zoom_label->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
 	zoom_label->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
 	zoom_label->set_align(Label::ALIGN_CENTER);
 	zoom_label->set_align(Label::ALIGN_CENTER);
-#ifdef TOOLS_ENABLED
-	zoom_label->set_custom_minimum_size(Size2(48, 0) * EDSCALE);
-#else
 	zoom_label->set_custom_minimum_size(Size2(48, 0));
 	zoom_label->set_custom_minimum_size(Size2(48, 0));
-#endif
 	_update_zoom_label();
 	_update_zoom_label();
 
 
 	zoom_minus = memnew(Button);
 	zoom_minus = memnew(Button);

+ 1 - 6
scene/gui/line_edit.cpp

@@ -40,7 +40,6 @@
 #include "servers/display_server.h"
 #include "servers/display_server.h"
 #include "servers/text_server.h"
 #include "servers/text_server.h"
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"
 #endif
 #endif
 #include "scene/main/window.h"
 #include "scene/main/window.h"
@@ -713,11 +712,7 @@ void LineEdit::_notification(int p_what) {
 				ofs_max -= r_icon->get_width();
 				ofs_max -= r_icon->get_width();
 			}
 			}
 
 
-#ifdef TOOLS_ENABLED
-			int caret_width = Math::round(EDSCALE);
-#else
-			int caret_width = 1;
-#endif
+			int caret_width = Math::round(1 * get_theme_default_base_scale());
 
 
 			// Draw selections rects.
 			// Draw selections rects.
 			Vector2 ofs = Point2(x_ofs + scroll_offset, y_ofs);
 			Vector2 ofs = Point2(x_ofs + scroll_offset, y_ofs);

+ 2 - 12
scene/gui/rich_text_label.cpp

@@ -41,10 +41,6 @@
 #include "modules/regex/regex.h"
 #include "modules/regex/regex.h"
 #endif
 #endif
 
 
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
 RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const {
 RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const {
 	if (p_free) {
 	if (p_free) {
 		if (p_item->subitems.size()) {
 		if (p_item->subitems.size()) {
@@ -995,19 +991,13 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
 				Color uc = font_color;
 				Color uc = font_color;
 				uc.a *= 0.5;
 				uc.a *= 0.5;
 				float y_off = TS->shaped_text_get_underline_position(rid);
 				float y_off = TS->shaped_text_get_underline_position(rid);
-				float underline_width = TS->shaped_text_get_underline_thickness(rid);
-#ifdef TOOLS_ENABLED
-				underline_width *= EDSCALE;
-#endif
+				float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
 				draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
 				draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
 			} else if (_find_strikethrough(it)) {
 			} else if (_find_strikethrough(it)) {
 				Color uc = font_color;
 				Color uc = font_color;
 				uc.a *= 0.5;
 				uc.a *= 0.5;
 				float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
 				float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
-				float underline_width = TS->shaped_text_get_underline_thickness(rid);
-#ifdef TOOLS_ENABLED
-				underline_width *= EDSCALE;
-#endif
+				float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
 				draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
 				draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
 			}
 			}
 
 

+ 2 - 10
scene/gui/text_edit.cpp

@@ -42,10 +42,6 @@
 
 
 #include "scene/main/window.h"
 #include "scene/main/window.h"
 
 
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
 static bool _is_text_char(char32_t c) {
 static bool _is_text_char(char32_t c) {
 	return !is_symbol(c);
 	return !is_symbol(c);
 }
 }
@@ -1173,12 +1169,8 @@ void TextEdit::_notification(int p_what) {
 						}
 						}
 					}
 					}
 
 
-					// Carets
-#ifdef TOOLS_ENABLED
-					int caret_width = Math::round(EDSCALE);
-#else
-					int caret_width = 1;
-#endif
+					// Carets.
+					int caret_width = Math::round(1 * get_theme_default_base_scale());
 
 
 					if (!clipped && caret.line == line && line_wrap_index == caret_wrap_index) {
 					if (!clipped && caret.line == line && line_wrap_index == caret_wrap_index) {
 						caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
 						caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);

+ 5 - 13
scene/gui/tree.cpp

@@ -41,10 +41,6 @@
 
 
 #include "box_container.h"
 #include "box_container.h"
 
 
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
 #include <limits.h>
 #include <limits.h>
 
 
 Size2 TreeItem::Cell::get_icon_size() const {
 Size2 TreeItem::Cell::get_icon_size() const {
@@ -1377,6 +1373,8 @@ void Tree::update_cache() {
 	cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover"));
 	cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover"));
 	cache.title_button_color = get_theme_color(SNAME("title_button_color"));
 	cache.title_button_color = get_theme_color(SNAME("title_button_color"));
 
 
+	cache.base_scale = get_theme_default_base_scale();
+
 	v_scroll->set_custom_step(cache.font->get_height(cache.font_size));
 	v_scroll->set_custom_step(cache.font->get_height(cache.font_size));
 }
 }
 
 
@@ -2046,15 +2044,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
 						root_pos -= Point2i(cache.arrow->get_width(), 0);
 						root_pos -= Point2i(cache.arrow->get_width(), 0);
 					}
 					}
 
 
-					float line_width = cache.relationship_line_width;
-					float parent_line_width = cache.parent_hl_line_width;
-					float children_line_width = cache.children_hl_line_width;
-
-#ifdef TOOLS_ENABLED
-					line_width *= Math::round(EDSCALE);
-					parent_line_width *= Math::round(EDSCALE);
-					children_line_width *= Math::round(EDSCALE);
-#endif
+					float line_width = cache.relationship_line_width * Math::round(cache.base_scale);
+					float parent_line_width = cache.parent_hl_line_width * Math::round(cache.base_scale);
+					float children_line_width = cache.children_hl_line_width * Math::round(cache.base_scale);
 
 
 					Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
 					Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
 
 

+ 2 - 0
scene/gui/tree.h

@@ -516,6 +516,8 @@ private:
 		Color custom_button_font_highlight;
 		Color custom_button_font_highlight;
 		Color font_outline_color;
 		Color font_outline_color;
 
 
+		float base_scale = 1.0;
+
 		int hseparation = 0;
 		int hseparation = 0;
 		int vseparation = 0;
 		int vseparation = 0;
 		int item_margin = 0;
 		int item_margin = 0;

+ 16 - 0
scene/main/window.cpp

@@ -1266,6 +1266,18 @@ bool Window::has_theme_constant(const StringName &p_name, const StringName &p_th
 	return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
 	return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
 }
 }
 
 
+float Window::get_theme_default_base_scale() const {
+	return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window);
+}
+
+Ref<Font> Window::get_theme_default_font() const {
+	return Control::fetch_theme_default_font(theme_owner, theme_owner_window);
+}
+
+int Window::get_theme_default_font_size() const {
+	return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window);
+}
+
 Rect2i Window::get_parent_rect() const {
 Rect2i Window::get_parent_rect() const {
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
 	if (is_embedded()) {
 	if (is_embedded()) {
@@ -1480,6 +1492,10 @@ void Window::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Window::has_theme_color, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Window::has_theme_color, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Window::has_theme_constant, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Window::has_theme_constant, DEFVAL(""));
 
 
+	ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Window::get_theme_default_base_scale);
+	ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Window::get_theme_default_font);
+	ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Window::get_theme_default_font_size);
+
 	ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction);
 	ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction);
 	ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
 	ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
 	ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl);
 	ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl);

+ 4 - 0
scene/main/window.h

@@ -280,6 +280,10 @@ public:
 	bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 	bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 	bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 	bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
 
 
+	float get_theme_default_base_scale() const;
+	Ref<Font> get_theme_default_font() const;
+	int get_theme_default_font_size() const;
+
 	Rect2i get_parent_rect() const;
 	Rect2i get_parent_rect() const;
 	virtual DisplayServer::WindowID get_window_id() const override;
 	virtual DisplayServer::WindowID get_window_id() const override;
 
 

+ 8 - 1
scene/resources/default_theme/default_theme.cpp

@@ -1036,9 +1036,16 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
 	}
 	}
 
 
 	Ref<Font> large_font = default_font;
 	Ref<Font> large_font = default_font;
-	fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0);
+
+	float default_scale = 1.0;
+	if (p_hidpi) {
+		default_scale = 2.0;
+	}
+
+	fill_default_theme(t, default_font, large_font, default_icon, default_style, default_scale);
 
 
 	Theme::set_default(t);
 	Theme::set_default(t);
+	Theme::set_default_base_scale(default_scale);
 	Theme::set_default_icon(default_icon);
 	Theme::set_default_icon(default_icon);
 	Theme::set_default_style(default_style);
 	Theme::set_default_style(default_style);
 	Theme::set_default_font(default_font);
 	Theme::set_default_font(default_font);

File diff suppressed because it is too large
+ 578 - 454
scene/resources/theme.cpp


+ 14 - 1
scene/resources/theme.h

@@ -96,13 +96,19 @@ protected:
 	bool _get(const StringName &p_name, Variant &r_ret) const;
 	bool _get(const StringName &p_name, Variant &r_ret) const;
 	void _get_property_list(List<PropertyInfo> *p_list) const;
 	void _get_property_list(List<PropertyInfo> *p_list) const;
 
 
-	static Ref<Theme> project_default_theme;
+	// Universal Theme resources used when no other theme has the item.
 	static Ref<Theme> default_theme;
 	static Ref<Theme> default_theme;
+	static Ref<Theme> project_default_theme;
+
+	// Universal default values, final fallback for every theme.
+	static float default_base_scale;
 	static Ref<Texture2D> default_icon;
 	static Ref<Texture2D> default_icon;
 	static Ref<StyleBox> default_style;
 	static Ref<StyleBox> default_style;
 	static Ref<Font> default_font;
 	static Ref<Font> default_font;
 	static int default_font_size;
 	static int default_font_size;
 
 
+	// Default values configurable for each individual theme.
+	float default_theme_base_scale = 0.0;
 	Ref<Font> default_theme_font;
 	Ref<Font> default_theme_font;
 	int default_theme_font_size = -1;
 	int default_theme_font_size = -1;
 
 
@@ -120,16 +126,23 @@ public:
 	static Ref<Theme> get_project_default();
 	static Ref<Theme> get_project_default();
 	static void set_project_default(const Ref<Theme> &p_project_default);
 	static void set_project_default(const Ref<Theme> &p_project_default);
 
 
+	static void set_default_base_scale(float p_base_scale);
 	static void set_default_icon(const Ref<Texture2D> &p_icon);
 	static void set_default_icon(const Ref<Texture2D> &p_icon);
 	static void set_default_style(const Ref<StyleBox> &p_style);
 	static void set_default_style(const Ref<StyleBox> &p_style);
 	static void set_default_font(const Ref<Font> &p_font);
 	static void set_default_font(const Ref<Font> &p_font);
 	static void set_default_font_size(int p_font_size);
 	static void set_default_font_size(int p_font_size);
 
 
+	void set_default_theme_base_scale(float p_base_scale);
+	float get_default_theme_base_scale() const;
+	bool has_default_theme_base_scale() const;
+
 	void set_default_theme_font(const Ref<Font> &p_default_font);
 	void set_default_theme_font(const Ref<Font> &p_default_font);
 	Ref<Font> get_default_theme_font() const;
 	Ref<Font> get_default_theme_font() const;
+	bool has_default_theme_font() const;
 
 
 	void set_default_theme_font_size(int p_font_size);
 	void set_default_theme_font_size(int p_font_size);
 	int get_default_theme_font_size() const;
 	int get_default_theme_font_size() const;
+	bool has_default_theme_font_size() const;
 
 
 	void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon);
 	void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon);
 	Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_theme_type) const;
 	Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_theme_type) const;

Some files were not shown because too many files changed in this diff