Browse Source

Improve the VisualShader/VisualScript editor UI

Hendrik Brucker 3 years ago
parent
commit
6d876baf60

+ 21 - 0
doc/classes/GraphNode.xml

@@ -119,6 +119,13 @@
 				Returns the right (output) type of the slot [code]idx[/code].
 			</description>
 		</method>
+		<method name="is_slot_draw_stylebox" qualifiers="const">
+			<return type="bool" />
+			<argument index="0" name="idx" type="int" />
+			<description>
+				Returns true if the background [StyleBox] of the slot [code]idx[/code] is drawn.
+			</description>
+		</method>
 		<method name="is_slot_enabled_left" qualifiers="const">
 			<return type="bool" />
 			<argument index="0" name="idx" type="int" />
@@ -152,6 +159,7 @@
 			<argument index="6" name="color_right" type="Color" />
 			<argument index="7" name="custom_left" type="Texture2D" default="null" />
 			<argument index="8" name="custom_right" type="Texture2D" default="null" />
+			<argument index="9" name="enable" type="bool" default="true" />
 			<description>
 				Sets properties of the slot with ID [code]idx[/code].
 				If [code]enable_left[/code]/[code]right[/code], a port will appear and the slot will be able to be connected from this side.
@@ -178,6 +186,14 @@
 				Sets the [Color] of the right (output) side of the slot [code]idx[/code] to [code]color_right[/code].
 			</description>
 		</method>
+		<method name="set_slot_draw_stylebox">
+			<return type="void" />
+			<argument index="0" name="idx" type="int" />
+			<argument index="1" name="draw_stylebox" type="bool" />
+			<description>
+				Toggles the background [StyleBox] of the slot [code]idx[/code].
+			</description>
+		</method>
 		<method name="set_slot_enabled_left">
 			<return type="void" />
 			<argument index="0" name="idx" type="int" />
@@ -301,6 +317,8 @@
 		<theme_item name="title_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)">
 			Color of the title text.
 		</theme_item>
+		<theme_item name="close_h_offset" data_type="constant" type="int" default="22">
+		</theme_item>
 		<theme_item name="close_offset" data_type="constant" type="int" default="22">
 			The vertical offset of the close button.
 		</theme_item>
@@ -343,5 +361,8 @@
 		<theme_item name="selected_frame" data_type="style" type="StyleBox">
 			The background used when the [GraphNode] is selected.
 		</theme_item>
+		<theme_item name="slot" data_type="style" type="StyleBox">
+			The [StyleBox] used for each slot of the [GraphNode].
+		</theme_item>
 	</theme_items>
 </class>

+ 78 - 2
editor/editor_fonts.cpp

@@ -110,6 +110,32 @@
 	m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE);        \
 	MAKE_FALLBACKS(m_name);
 
+#define MAKE_DEFAULT_FONT_MSDF(m_name, m_variations)                  \
+	Ref<Font> m_name;                                                 \
+	m_name.instantiate();                                             \
+	if (CustomFont.is_valid()) {                                      \
+		m_name->add_data(CustomFontMSDF);                             \
+		m_name->add_data(DefaultFontMSDF);                            \
+	} else {                                                          \
+		m_name->add_data(DefaultFontMSDF);                            \
+	}                                                                 \
+	{                                                                 \
+		Dictionary variations;                                        \
+		if (!m_variations.is_empty()) {                               \
+			Vector<String> variation_tags = m_variations.split(",");  \
+			for (int i = 0; i < variation_tags.size(); i++) {         \
+				Vector<String> tokens = variation_tags[i].split("="); \
+				if (tokens.size() == 2) {                             \
+					variations[tokens[0]] = tokens[1].to_float();     \
+				}                                                     \
+			}                                                         \
+		}                                                             \
+		m_name->set_variation_coordinates(variations);                \
+	}                                                                 \
+	m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE);           \
+	m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE);        \
+	MAKE_FALLBACKS(m_name);
+
 #define MAKE_SLANTED_FONT(m_name, m_variations)                       \
 	Ref<Font> m_name;                                                 \
 	m_name.instantiate();                                             \
@@ -163,6 +189,32 @@
 	m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE);        \
 	MAKE_FALLBACKS_BOLD(m_name);
 
+#define MAKE_BOLD_FONT_MSDF(m_name, m_variations)                     \
+	Ref<Font> m_name;                                                 \
+	m_name.instantiate();                                             \
+	if (CustomFontBold.is_valid()) {                                  \
+		m_name->add_data(CustomFontBoldMSDF);                         \
+		m_name->add_data(DefaultFontBoldMSDF);                        \
+	} else {                                                          \
+		m_name->add_data(DefaultFontBoldMSDF);                        \
+	}                                                                 \
+	{                                                                 \
+		Dictionary variations;                                        \
+		if (!m_variations.is_empty()) {                               \
+			Vector<String> variation_tags = m_variations.split(",");  \
+			for (int i = 0; i < variation_tags.size(); i++) {         \
+				Vector<String> tokens = variation_tags[i].split("="); \
+				if (tokens.size() == 2) {                             \
+					variations[tokens[0]] = tokens[1].to_float();     \
+				}                                                     \
+			}                                                         \
+		}                                                             \
+		m_name->set_variation_coordinates(variations);                \
+	}                                                                 \
+	m_name->set_spacing(TextServer::SPACING_TOP, -EDSCALE);           \
+	m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE);        \
+	MAKE_FALLBACKS_BOLD(m_name);
+
 #define MAKE_SOURCE_FONT(m_name, m_variations)                        \
 	Ref<Font> m_name;                                                 \
 	m_name.instantiate();                                             \
@@ -189,13 +241,14 @@
 	m_name->set_spacing(TextServer::SPACING_BOTTOM, -EDSCALE);        \
 	MAKE_FALLBACKS(m_name);
 
-Ref<FontData> load_cached_external_font(const String &p_path, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning) {
+Ref<FontData> load_cached_external_font(const String &p_path, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false) {
 	Ref<FontData> font;
 	font.instantiate();
 
 	Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
 
 	font->set_data(data);
+	font->set_multichannel_signed_distance_field(p_msdf);
 	font->set_antialiased(p_aa);
 	font->set_hinting(p_hinting);
 	font->set_force_autohinter(p_autohint);
@@ -204,11 +257,12 @@ Ref<FontData> load_cached_external_font(const String &p_path, TextServer::Hintin
 	return font;
 }
 
-Ref<FontData> load_cached_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning) {
+Ref<FontData> load_cached_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false) {
 	Ref<FontData> font;
 	font.instantiate();
 
 	font->set_data_ptr(p_data, p_size);
+	font->set_multichannel_signed_distance_field(p_msdf);
 	font->set_antialiased(p_aa);
 	font->set_hinting(p_hinting);
 	font->set_force_autohinter(p_autohint);
@@ -261,6 +315,13 @@ void editor_register_fonts(Ref<Theme> p_theme) {
 		EditorSettings::get_singleton()->set_manually("interface/editor/main_font", "");
 	}
 
+	Ref<FontData> CustomFontMSDF;
+	if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
+		CustomFontMSDF = load_cached_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
+	} else {
+		EditorSettings::get_singleton()->set_manually("interface/editor/main_font", "");
+	}
+
 	Ref<FontData> CustomFontSlanted;
 	if (CustomFont.is_valid()) {
 		CustomFontSlanted = CustomFont->duplicate();
@@ -282,6 +343,13 @@ void editor_register_fonts(Ref<Theme> p_theme) {
 		CustomFontBold->set_embolden(embolden_strength);
 	}
 
+	Ref<FontData> CustomFontBoldMSDF;
+	if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
+		CustomFontBoldMSDF = load_cached_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
+	} else {
+		EditorSettings::get_singleton()->set_manually("interface/editor/main_font_bold", "");
+	}
+
 	/* Custom source code font */
 
 	String custom_font_path_source = EditorSettings::get_singleton()->get("interface/editor/code_font");
@@ -295,7 +363,9 @@ void editor_register_fonts(Ref<Theme> p_theme) {
 	/* Noto Sans */
 
 	Ref<FontData> DefaultFont = load_cached_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning);
+	Ref<FontData> DefaultFontMSDF = load_cached_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
 	Ref<FontData> DefaultFontBold = load_cached_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning);
+	Ref<FontData> DefaultFontBoldMSDF = load_cached_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
 	Ref<FontData> FontArabic = load_cached_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning);
 	Ref<FontData> FontArabicBold = load_cached_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning);
 	Ref<FontData> FontBengali = load_cached_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning);
@@ -347,12 +417,18 @@ void editor_register_fonts(Ref<Theme> p_theme) {
 	p_theme->set_font_size("main_size", "EditorFonts", default_font_size);
 	p_theme->set_font("main", "EditorFonts", df);
 
+	MAKE_DEFAULT_FONT_MSDF(df_msdf, String());
+	p_theme->set_font("main_msdf", "EditorFonts", df_msdf);
+
 	// Bold font
 	MAKE_BOLD_FONT(df_bold, String());
 	MAKE_SLANTED_FONT(df_italic, String());
 	p_theme->set_font_size("bold_size", "EditorFonts", default_font_size);
 	p_theme->set_font("bold", "EditorFonts", df_bold);
 
+	MAKE_BOLD_FONT_MSDF(df_bold_msdf, String());
+	p_theme->set_font("main_bold_msdf", "EditorFonts", df_bold_msdf);
+
 	// Title font
 	p_theme->set_font_size("title_size", "EditorFonts", default_font_size + 1 * EDSCALE);
 	p_theme->set_font("title", "EditorFonts", df_bold);

+ 1 - 0
editor/editor_settings.cpp

@@ -682,6 +682,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 
 	// Visual editors
 	EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/minimap_opacity", 0.85, "0.0,1.0,0.01")
+	EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/visual_editors/visualshader/port_preview_size", 160, "100,400,0.01")
 
 	/* Run */
 

+ 48 - 28
editor/editor_themes.cpp

@@ -741,17 +741,28 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_stylebox("pressed", "EditorLogFilterButton", editor_log_button_pressed);
 
 	// OptionButton
-	theme->set_stylebox("focus", "OptionButton", style_widget_focus);
-
+	Ref<StyleBoxFlat> style_option_button_focus = style_widget_focus->duplicate();
+	Ref<StyleBoxFlat> style_option_button_normal = style_widget->duplicate();
+	Ref<StyleBoxFlat> style_option_button_hover = style_widget_hover->duplicate();
+	Ref<StyleBoxFlat> style_option_button_pressed = style_widget_pressed->duplicate();
+	Ref<StyleBoxFlat> style_option_button_disabled = style_widget_disabled->duplicate();
+
+	style_option_button_focus->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+	style_option_button_normal->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+	style_option_button_hover->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+	style_option_button_pressed->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+	style_option_button_disabled->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+
+	theme->set_stylebox("focus", "OptionButton", style_option_button_focus);
 	theme->set_stylebox("normal", "OptionButton", style_widget);
 	theme->set_stylebox("hover", "OptionButton", style_widget_hover);
 	theme->set_stylebox("pressed", "OptionButton", style_widget_pressed);
 	theme->set_stylebox("disabled", "OptionButton", style_widget_disabled);
 
-	theme->set_stylebox("normal_mirrored", "OptionButton", style_widget);
-	theme->set_stylebox("hover_mirrored", "OptionButton", style_widget_hover);
-	theme->set_stylebox("pressed_mirrored", "OptionButton", style_widget_pressed);
-	theme->set_stylebox("disabled_mirrored", "OptionButton", style_widget_disabled);
+	theme->set_stylebox("normal_mirrored", "OptionButton", style_option_button_normal);
+	theme->set_stylebox("hover_mirrored", "OptionButton", style_option_button_hover);
+	theme->set_stylebox("pressed_mirrored", "OptionButton", style_option_button_pressed);
+	theme->set_stylebox("disabled_mirrored", "OptionButton", style_option_button_disabled);
 
 	theme->set_color("font_color", "OptionButton", font_color);
 	theme->set_color("font_hover_color", "OptionButton", font_hover_color);
@@ -1435,7 +1446,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 		style_minimap_node = make_flat_stylebox(Color(0, 0, 0), 0, 0, 0, 0);
 	}
 	style_minimap_camera->set_border_width_all(1);
-	style_minimap_node->set_corner_radius_all(1);
 	theme->set_stylebox("camera", "GraphEditMinimap", style_minimap_camera);
 	theme->set_stylebox("node", "GraphEditMinimap", style_minimap_node);
 
@@ -1450,20 +1460,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_color("resizer_color", "GraphEditMinimap", minimap_resizer_color);
 
 	// GraphNode
-	const int gn_margin_side = 28;
+	const int gn_margin_side = 2;
+	const int gn_margin_bottom = 2;
 
-	Ref<StyleBoxFlat> graphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+	Color graphnode_bg = dark_color_3;
+	if (!dark_theme) {
+		graphnode_bg = prop_section_color;
+	}
+
+	Ref<StyleBoxFlat> graphsb = make_flat_stylebox(graphnode_bg.lerp(style_tree_bg->get_bg_color(), 0.3), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
 	graphsb->set_border_width_all(border_width);
-	graphsb->set_border_color(dark_color_3);
-	Ref<StyleBoxFlat> graphsbselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+	graphsb->set_border_color(graphnode_bg);
+	Ref<StyleBoxFlat> graphsbselected = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 1), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
 	graphsbselected->set_border_width_all(2 * EDSCALE + border_width);
-	graphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
-	Ref<StyleBoxFlat> graphsbcomment = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.3), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+	graphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.6));
+	Ref<StyleBoxFlat> graphsbcomment = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.3), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
 	graphsbcomment->set_border_width_all(border_width);
-	graphsbcomment->set_border_color(dark_color_3);
-	Ref<StyleBoxFlat> graphsbcommentselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.4), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+	graphsbcomment->set_border_color(graphnode_bg);
+	Ref<StyleBoxFlat> graphsbcommentselected = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.4), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
 	graphsbcommentselected->set_border_width_all(border_width);
-	graphsbcommentselected->set_border_color(dark_color_3);
+	graphsbcommentselected->set_border_color(graphnode_bg);
 	Ref<StyleBoxFlat> graphsbbreakpoint = graphsbselected->duplicate();
 	graphsbbreakpoint->set_draw_center(false);
 	graphsbbreakpoint->set_border_color(warning_color);
@@ -1472,10 +1488,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	graphsbposition->set_draw_center(false);
 	graphsbposition->set_border_color(error_color);
 	graphsbposition->set_shadow_color(error_color * Color(1.0, 1.0, 1.0, 0.2));
-	Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+	Ref<StyleBoxEmpty> graphsbslot = make_empty_stylebox(12, 0, 12, 0);
+	Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
 	smgraphsb->set_border_width_all(border_width);
-	smgraphsb->set_border_color(dark_color_3);
-	Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+	smgraphsb->set_border_color(graphnode_bg);
+	Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, gn_margin_bottom, corner_width);
 	smgraphsbselected->set_border_width_all(2 * EDSCALE + border_width);
 	smgraphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
 	smgraphsbselected->set_shadow_size(8 * EDSCALE);
@@ -1492,19 +1509,20 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_stylebox("comment_focus", "GraphNode", graphsbcommentselected);
 	theme->set_stylebox("breakpoint", "GraphNode", graphsbbreakpoint);
 	theme->set_stylebox("position", "GraphNode", graphsbposition);
+	theme->set_stylebox("slot", "GraphNode", graphsbslot);
 	theme->set_stylebox("state_machine_frame", "GraphNode", smgraphsb);
 	theme->set_stylebox("state_machine_selected_frame", "GraphNode", smgraphsbselected);
 
-	Color default_node_color = dark_color_1.inverted();
-	theme->set_color("title_color", "GraphNode", default_node_color);
-	default_node_color.a = 0.7;
-	theme->set_color("close_color", "GraphNode", default_node_color);
-	theme->set_color("resizer_color", "GraphNode", default_node_color);
+	Color node_decoration_color = dark_color_1.inverted();
+	theme->set_color("title_color", "GraphNode", node_decoration_color);
+	node_decoration_color.a = 0.7;
+	theme->set_color("close_color", "GraphNode", node_decoration_color);
+	theme->set_color("resizer_color", "GraphNode", node_decoration_color);
 
-	theme->set_constant("port_offset", "GraphNode", 14 * EDSCALE);
-	theme->set_constant("title_h_offset", "GraphNode", -16 * EDSCALE);
-	theme->set_constant("title_offset", "GraphNode", 20 * EDSCALE);
-	theme->set_constant("close_h_offset", "GraphNode", 20 * EDSCALE);
+	theme->set_constant("port_offset", "GraphNode", 0);
+	theme->set_constant("title_h_offset", "GraphNode", 12 * EDSCALE);
+	theme->set_constant("title_offset", "GraphNode", 21 * EDSCALE);
+	theme->set_constant("close_h_offset", "GraphNode", -2 * EDSCALE);
 	theme->set_constant("close_offset", "GraphNode", 20 * EDSCALE);
 	theme->set_constant("separation", "GraphNode", 1 * EDSCALE);
 
@@ -1512,6 +1530,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_icon("resizer", "GraphNode", theme->get_icon(SNAME("GuiResizer"), SNAME("EditorIcons")));
 	theme->set_icon("port", "GraphNode", theme->get_icon(SNAME("GuiGraphNodePort"), SNAME("EditorIcons")));
 
+	theme->set_font("title_font", "GraphNode", theme->get_font(SNAME("main_bold_msdf"), SNAME("EditorFonts")));
+
 	// GridContainer
 	theme->set_constant("v_separation", "GridContainer", Math::round(widget_default_margin.y - 2 * EDSCALE));
 

+ 18 - 5
editor/plugins/visual_shader_editor_plugin.cpp

@@ -148,6 +148,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
 			if (links[p_node_id].preview_pos != -1) {
 				links[p_node_id].graph_node->move_child(vbox, links[p_node_id].preview_pos);
 			}
+			links[p_node_id].graph_node->set_slot_draw_stylebox(vbox->get_index(), false);
 
 			Control *offset = memnew(Control);
 			offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
@@ -386,6 +387,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 		"alpha"
 	};
 
+	// Visual shader specific theme for MSDF font.
+	Ref<Theme> vstheme;
+	vstheme.instantiate();
+	Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", "EditorFonts");
+	vstheme->set_font("font", "Label", label_font);
+	vstheme->set_font("font", "LineEdit", label_font);
+	vstheme->set_font("font", "Button", label_font);
+
 	Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);
 
 	Ref<VisualShaderNodeResizableBase> resizable_node = Object::cast_to<VisualShaderNodeResizableBase>(vsnode.ptr());
@@ -406,8 +415,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 		custom_node->_set_initialized(true);
 	}
 
+	// Create graph node.
 	GraphNode *node = memnew(GraphNode);
 	graph->add_child(node);
+	node->set_theme(vstheme);
 	editor->_update_created_node(node);
 	register_link(p_type, p_id, vsnode.ptr(), node);
 
@@ -942,12 +953,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 
 	if (vsnode->get_output_port_for_preview() >= 0) {
 		show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview());
+	} else {
+		offset = memnew(Control);
+		offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
+		node->add_child(offset);
 	}
 
-	offset = memnew(Control);
-	offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
-	node->add_child(offset);
-
 	String error = vsnode->get_warning(mode, p_type);
 	if (!error.is_empty()) {
 		Label *error_label = memnew(Label);
@@ -4652,6 +4663,7 @@ VisualShaderEditor::VisualShaderEditor() {
 	graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
 	graph->set_v_size_flags(SIZE_EXPAND_FILL);
 	graph->set_h_size_flags(SIZE_EXPAND_FILL);
+	graph->set_show_zoom_label(true);
 	add_child(graph);
 	graph->set_drag_forwarding(this);
 	float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
@@ -6252,7 +6264,8 @@ void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Visua
 }
 
 Size2 VisualShaderNodePortPreview::get_minimum_size() const {
-	return Size2(100, 100) * EDSCALE;
+	int port_preview_size = EditorSettings::get_singleton()->get("editors/visual_editors/visualshader/port_preview_size");
+	return Size2(port_preview_size, port_preview_size) * EDSCALE;
 }
 
 void VisualShaderNodePortPreview::_notification(int p_what) {

+ 10 - 2
modules/visual_script/editor/visual_script_editor.cpp

@@ -647,6 +647,14 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 		Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons"))
 	};
 
+	// Visual script specific theme for MSDF font.
+	Ref<Theme> vstheme;
+	vstheme.instantiate();
+	Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", "EditorFonts");
+	vstheme->set_font("font", "Label", label_font);
+	vstheme->set_font("font", "LineEdit", label_font);
+	vstheme->set_font("font", "Button", label_font);
+
 	Ref<Texture2D> seq_port = Control::get_theme_icon(SNAME("VisualShaderPort"), SNAME("EditorIcons"));
 	List<int> node_ids;
 	script->get_node_list(&node_ids);
@@ -960,9 +968,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 
 			slot_idx++;
 		}
-
 		graph->add_child(gnode);
-
+		gnode->set_theme(vstheme);
 		if (gnode->is_comment()) {
 			graph->move_child(gnode, 0);
 		}
@@ -4577,6 +4584,7 @@ VisualScriptEditor::VisualScriptEditor() {
 	add_child(graph);
 	graph->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	graph->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+	graph->set_show_zoom_label(true);
 	graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected));
 	graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move));
 	graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move));

+ 62 - 19
scene/gui/graph_node.cpp

@@ -93,11 +93,13 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
 		si.color_right = p_value;
 	} else if (what == "right_icon") {
 		si.custom_slot_right = p_value;
+	} else if (what == "draw_stylebox") {
+		si.draw_stylebox = p_value;
 	} else {
 		return false;
 	}
 
-	set_slot(idx, si.enable_left, si.type_left, si.color_left, si.enable_right, si.type_right, si.color_right, si.custom_slot_left, si.custom_slot_right);
+	set_slot(idx, si.enable_left, si.type_left, si.color_left, si.enable_right, si.type_right, si.color_right, si.custom_slot_left, si.custom_slot_right, si.draw_stylebox);
 	update();
 	return true;
 }
@@ -144,6 +146,8 @@ bool GraphNode::_get(const StringName &p_name, Variant &r_ret) const {
 		r_ret = si.color_right;
 	} else if (what == "right_icon") {
 		r_ret = si.custom_slot_right;
+	} else if (what == "draw_stylebox") {
+		r_ret = si.draw_stylebox;
 	} else {
 		return false;
 	}
@@ -175,7 +179,7 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const {
 		p_list->push_back(PropertyInfo(Variant::INT, base + "right_type"));
 		p_list->push_back(PropertyInfo(Variant::COLOR, base + "right_color"));
 		p_list->push_back(PropertyInfo(Variant::OBJECT, base + "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
-
+		p_list->push_back(PropertyInfo(Variant::BOOL, base + "draw_stylebox"));
 		idx++;
 	}
 }
@@ -185,6 +189,7 @@ void GraphNode::_resort() {
 
 	Size2i new_size = get_size();
 	Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame"));
+	Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
 
 	int sep = get_theme_constant(SNAME("separation"));
 
@@ -204,7 +209,7 @@ void GraphNode::_resort() {
 			continue;
 		}
 
-		Size2i size = c->get_combined_minimum_size();
+		Size2i size = c->get_combined_minimum_size() + (slot_info[i].draw_stylebox ? sb_slot->get_minimum_size() : Size2());
 		_MinSizeCache msc;
 
 		stretch_min += size.height;
@@ -312,7 +317,9 @@ void GraphNode::_resort() {
 
 		int size = to - from;
 
-		Rect2 rect(sb->get_margin(SIDE_LEFT), from, w, size);
+		float margin = sb->get_margin(SIDE_LEFT) + (slot_info[i].draw_stylebox ? sb_slot->get_margin(SIDE_LEFT) : 0);
+		float width = w - (slot_info[i].draw_stylebox ? sb_slot->get_minimum_size().x : 0);
+		Rect2 rect(margin, from, width, size);
 
 		fit_child_in_rect(c, rect);
 		cache_y.push_back(from - sb->get_margin(SIDE_TOP) + size * 0.5);
@@ -351,14 +358,14 @@ void GraphNode::_notification(int p_what) {
 			Ref<StyleBox> sb;
 
 			if (comment) {
-				sb = get_theme_stylebox(selected ? "comment_focus" : "comment");
+				sb = get_theme_stylebox(selected ? SNAME("comment_focus") : SNAME("comment"));
 
 			} else {
-				sb = get_theme_stylebox(selected ? "selected_frame" : "frame");
+				sb = get_theme_stylebox(selected ? SNAME("selected_frame") : SNAME("frame"));
 			}
 
-			//sb=sb->duplicate();
-			//sb->call("set_modulate",modulate);
+			Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
+
 			Ref<Texture2D> port = get_theme_icon(SNAME("port"));
 			Ref<Texture2D> close = get_theme_icon(SNAME("close"));
 			Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
@@ -389,13 +396,9 @@ void GraphNode::_notification(int p_what) {
 
 			int w = get_size().width - sb->get_minimum_size().x;
 
-			if (show_close) {
-				w -= close->get_width();
-			}
-
 			title_buf->draw(get_canvas_item(), Point2(sb->get_margin(SIDE_LEFT) + title_h_offset, -title_buf->get_size().y + title_offset), title_color);
 			if (show_close) {
-				Vector2 cpos = Point2(w + sb->get_margin(SIDE_LEFT) + close_h_offset, -close->get_height() + close_offset);
+				Vector2 cpos = Point2(w + sb->get_margin(SIDE_LEFT) + close_h_offset - close->get_width(), -close->get_height() + close_offset);
 				draw_texture(close, cpos, close_color);
 				close_rect.position = cpos;
 				close_rect.size = close->get_size();
@@ -411,7 +414,7 @@ void GraphNode::_notification(int p_what) {
 					continue;
 				}
 				const Slot &s = slot_info[E.key];
-				//left
+				// Left port.
 				if (s.enable_left) {
 					Ref<Texture2D> p = port;
 					if (s.custom_slot_left.is_valid()) {
@@ -419,6 +422,7 @@ void GraphNode::_notification(int p_what) {
 					}
 					p->draw(get_canvas_item(), icofs + Point2(edgeofs, cache_y[E.key]), s.color_left);
 				}
+				// Right port.
 				if (s.enable_right) {
 					Ref<Texture2D> p = port;
 					if (s.custom_slot_right.is_valid()) {
@@ -426,6 +430,15 @@ void GraphNode::_notification(int p_what) {
 					}
 					p->draw(get_canvas_item(), icofs + Point2(get_size().x - edgeofs, cache_y[E.key]), s.color_right);
 				}
+
+				// Draw slot stylebox.
+				if (s.draw_stylebox) {
+					Control *c = Object::cast_to<Control>(get_child(E.key));
+					Rect2 c_rect = c->get_rect();
+					c_rect.position.x = sb->get_margin(SIDE_LEFT);
+					c_rect.size.width = w;
+					draw_style_box(sb_slot, c_rect);
+				}
 			}
 
 			if (resizable) {
@@ -482,7 +495,7 @@ void GraphNode::_validate_property(PropertyInfo &property) const {
 }
 #endif
 
-void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right) {
+void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right, bool p_draw_stylebox) {
 	ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set slot with p_idx (%d) lesser than zero.", p_idx));
 
 	if (!p_enable_left && p_type_left == 0 && p_color_left == Color(1, 1, 1, 1) &&
@@ -501,6 +514,7 @@ void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const C
 	s.color_right = p_color_right;
 	s.custom_slot_left = p_custom_left;
 	s.custom_slot_right = p_custom_right;
+	s.draw_stylebox = p_draw_stylebox;
 	slot_info[p_idx] = s;
 	update();
 	connpos_dirty = true;
@@ -622,16 +636,39 @@ Color GraphNode::get_slot_color_right(int p_idx) const {
 	return slot_info[p_idx].color_right;
 }
 
+bool GraphNode::is_slot_draw_stylebox(int p_idx) const {
+	if (!slot_info.has(p_idx)) {
+		return false;
+	}
+	return slot_info[p_idx].draw_stylebox;
+}
+
+void GraphNode::set_slot_draw_stylebox(int p_idx, bool p_enable) {
+	ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set draw_stylebox for the slot with p_idx (%d) lesser than zero.", p_idx));
+
+	slot_info[p_idx].draw_stylebox = p_enable;
+	update();
+	connpos_dirty = true;
+
+	emit_signal(SNAME("slot_updated"), p_idx);
+}
+
 Size2 GraphNode::get_minimum_size() const {
-	int sep = get_theme_constant(SNAME("separation"));
 	Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame"));
+	Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
+
+	int sep = get_theme_constant(SNAME("separation"));
+	int title_h_offset = get_theme_constant(SNAME("title_h_offset"));
+
 	bool first = true;
 
 	Size2 minsize;
-	minsize.x = title_buf->get_size().x;
+	minsize.x = title_buf->get_size().x + title_h_offset;
 	if (show_close) {
+		int close_h_offset = get_theme_constant(SNAME("close_h_offset"));
 		Ref<Texture2D> close = get_theme_icon(SNAME("close"));
-		minsize.x += sep + close->get_width();
+		//TODO: Remove this magic number after GraphNode rework.
+		minsize.x += 12 + close->get_width() + close_h_offset;
 	}
 
 	for (int i = 0; i < get_child_count(); i++) {
@@ -644,6 +681,9 @@ Size2 GraphNode::get_minimum_size() const {
 		}
 
 		Size2i size = c->get_combined_minimum_size();
+		if (slot_info.has(i)) {
+			size += slot_info[i].draw_stylebox ? sb_slot->get_minimum_size() : Size2();
+		}
 
 		minsize.y += size.y;
 		minsize.x = MAX(minsize.x, size.x);
@@ -989,7 +1029,7 @@ void GraphNode::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_language", "language"), &GraphNode::set_language);
 	ClassDB::bind_method(D_METHOD("get_language"), &GraphNode::get_language);
 
-	ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()));
+	ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right", "enable"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true));
 	ClassDB::bind_method(D_METHOD("clear_slot", "idx"), &GraphNode::clear_slot);
 	ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots);
 
@@ -1011,6 +1051,9 @@ void GraphNode::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_slot_color_right", "idx", "color_right"), &GraphNode::set_slot_color_right);
 	ClassDB::bind_method(D_METHOD("get_slot_color_right", "idx"), &GraphNode::get_slot_color_right);
 
+	ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "idx"), &GraphNode::is_slot_draw_stylebox);
+	ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "idx", "draw_stylebox"), &GraphNode::set_slot_draw_stylebox);
+
 	ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset);
 	ClassDB::bind_method(D_METHOD("get_position_offset"), &GraphNode::get_position_offset);
 

+ 8 - 2
scene/gui/graph_node.h

@@ -54,6 +54,7 @@ private:
 		Color color_right = Color(1, 1, 1, 1);
 		Ref<Texture2D> custom_slot_left;
 		Ref<Texture2D> custom_slot_right;
+		bool draw_stylebox = true;
 	};
 
 	String title;
@@ -115,7 +116,7 @@ protected:
 public:
 	bool has_point(const Point2 &p_point) const override;
 
-	void set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left = Ref<Texture2D>(), const Ref<Texture2D> &p_custom_right = Ref<Texture2D>());
+	void set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left = Ref<Texture2D>(), const Ref<Texture2D> &p_custom_right = Ref<Texture2D>(), bool p_draw_stylebox = true);
 	void clear_slot(int p_idx);
 	void clear_all_slots();
 
@@ -137,6 +138,9 @@ public:
 	void set_slot_color_right(int p_idx, const Color &p_color_right);
 	Color get_slot_color_right(int p_idx) const;
 
+	bool is_slot_draw_stylebox(int p_idx) const;
+	void set_slot_draw_stylebox(int p_idx, bool p_enable);
+
 	void set_title(const String &p_title);
 	String get_title() const;
 
@@ -185,7 +189,9 @@ public:
 	virtual Vector<int> get_allowed_size_flags_horizontal() const override;
 	virtual Vector<int> get_allowed_size_flags_vertical() const override;
 
-	bool is_resizing() const { return resizing; }
+	bool is_resizing() const {
+		return resizing;
+	}
 
 	GraphNode();
 };

+ 3 - 0
scene/resources/default_theme/default_theme.cpp

@@ -686,6 +686,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	graphnode_breakpoint->set_border_color(Color(0.9, 0.29, 0.3));
 	Ref<StyleBoxFlat> graphnode_position = make_flat_stylebox(style_pressed_color, 18, 42, 18, 12, 6, true, 4);
 	graphnode_position->set_border_color(Color(0.98, 0.89, 0.27));
+	Ref<StyleBoxEmpty> graphnode_slot = make_empty_stylebox(0, 0, 0, 0);
 
 	theme->set_stylebox("frame", "GraphNode", graphnode_normal);
 	theme->set_stylebox("selected_frame", "GraphNode", graphnode_selected);
@@ -693,6 +694,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	theme->set_stylebox("comment_focus", "GraphNode", graphnode_comment_selected);
 	theme->set_stylebox("breakpoint", "GraphNode", graphnode_breakpoint);
 	theme->set_stylebox("position", "GraphNode", graphnode_position);
+	theme->set_stylebox("slot", "GraphNode", graphnode_slot);
 
 	theme->set_icon("port", "GraphNode", icons["graph_port"]);
 	theme->set_icon("close", "GraphNode", icons["close"]);
@@ -704,6 +706,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	theme->set_constant("separation", "GraphNode", 2 * scale);
 	theme->set_constant("title_offset", "GraphNode", 26 * scale);
 	theme->set_constant("close_offset", "GraphNode", 22 * scale);
+	theme->set_constant("close_h_offset", "GraphNode", 22 * scale);
 	theme->set_constant("port_offset", "GraphNode", 0);
 
 	// Tree