2
0
Эх сурвалжийг харах

Merge pull request #61515 from Geometror/improve-graphedit-hotzones

Yuri Rubinsky 3 жил өмнө
parent
commit
3ed2a0428c

+ 4 - 4
doc/classes/GraphEdit.xml

@@ -376,11 +376,11 @@
 		</theme_item>
 		<theme_item name="bezier_len_pos" data_type="constant" type="int" default="80">
 		</theme_item>
-		<theme_item name="port_grab_distance_horizontal" data_type="constant" type="int" default="24">
-			The horizontal range within which a port can be grabbed (on both sides).
+		<theme_item name="port_hotzone_inner_extent" data_type="constant" type="int" default="22">
+			The horizontal range within which a port can be grabbed (inner side).
 		</theme_item>
-		<theme_item name="port_grab_distance_vertical" data_type="constant" type="int" default="26">
-			The vertical range within which a port can be grabbed (on both sides).
+		<theme_item name="port_hotzone_outer_extent" data_type="constant" type="int" default="26">
+			The horizontal range within which a port can be grabbed (outer side).
 		</theme_item>
 		<theme_item name="layout" data_type="icon" type="Texture2D">
 		</theme_item>

+ 14 - 0
doc/classes/GraphNode.xml

@@ -43,6 +43,13 @@
 				Returns the number of enabled input slots (connections) to the GraphNode.
 			</description>
 		</method>
+		<method name="get_connection_input_height">
+			<return type="int" />
+			<argument index="0" name="idx" type="int" />
+			<description>
+				Returns the height of the input connection [code]idx[/code].
+			</description>
+		</method>
 		<method name="get_connection_input_position">
 			<return type="Vector2" />
 			<argument index="0" name="idx" type="int" />
@@ -70,6 +77,13 @@
 				Returns the number of enabled output slots (connections) of the GraphNode.
 			</description>
 		</method>
+		<method name="get_connection_output_height">
+			<return type="int" />
+			<argument index="0" name="idx" type="int" />
+			<description>
+				Returns the height of the output connection [code]idx[/code].
+			</description>
+		</method>
 		<method name="get_connection_output_position">
 			<return type="Vector2" />
 			<argument index="0" name="idx" type="int" />

+ 49 - 31
scene/gui/graph_edit.cpp

@@ -426,8 +426,8 @@ void GraphEdit::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE:
 		case NOTIFICATION_THEME_CHANGED: {
-			port_grab_distance_horizontal = get_theme_constant(SNAME("port_grab_distance_horizontal"));
-			port_grab_distance_vertical = get_theme_constant(SNAME("port_grab_distance_vertical"));
+			port_hotzone_inner_extent = get_theme_constant("port_hotzone_inner_extent");
+			port_hotzone_outer_extent = get_theme_constant("port_hotzone_outer_extent");
 
 			zoom_minus->set_icon(get_theme_icon(SNAME("minus")));
 			zoom_reset->set_icon(get_theme_icon(SNAME("reset")));
@@ -544,8 +544,7 @@ void GraphEdit::_set_position_of_comment_enclosed_nodes(GraphNode *p_node, HashM
 }
 
 bool GraphEdit::_filter_input(const Point2 &p_point) {
-	Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
-	Vector2i port_size = Vector2i(port->get_width(), port->get_height());
+	Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
 
 	for (int i = get_child_count() - 1; i >= 0; i--) {
 		GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -553,14 +552,18 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
 			continue;
 		}
 
-		for (int j = 0; j < gn->get_connection_output_count(); j++) {
-			if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) {
+		for (int j = 0; j < gn->get_connection_input_count(); j++) {
+			Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+			port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
+			if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) {
 				return true;
 			}
 		}
 
-		for (int j = 0; j < gn->get_connection_input_count(); j++) {
-			if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) {
+		for (int j = 0; j < gn->get_connection_output_count(); j++) {
+			Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+			port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
+			if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) {
 				return true;
 			}
 		}
@@ -572,8 +575,7 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
 void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
 	Ref<InputEventMouseButton> mb = p_ev;
 	if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
-		Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
-		Vector2i port_size = Vector2i(port->get_width(), port->get_height());
+		Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
 
 		connecting_valid = false;
 		click_pos = mb->get_position() / zoom;
@@ -585,6 +587,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
 
 			for (int j = 0; j < gn->get_connection_output_count(); j++) {
 				Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
+				Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+				port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
+
 				if (is_in_output_hotzone(gn, j, click_pos, port_size)) {
 					if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
 						//check disconnect
@@ -629,6 +634,10 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
 
 			for (int j = 0; j < gn->get_connection_input_count(); j++) {
 				Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
+
+				Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+				port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
+
 				if (is_in_input_hotzone(gn, j, click_pos, port_size)) {
 					if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
 						//check disconnect
@@ -682,11 +691,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
 		connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0;
 
 		if (connecting_valid) {
-			Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
-			Vector2i port_size = Vector2i(port->get_width(), port->get_height());
-
 			Vector2 mpos = mm->get_position() / zoom;
 			for (int i = get_child_count() - 1; i >= 0; i--) {
+				Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
 				GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
 				if (!gn) {
 					continue;
@@ -695,6 +702,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
 				if (!connecting_out) {
 					for (int j = 0; j < gn->get_connection_output_count(); j++) {
 						Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
+						Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+						port_size.height = MAX(port_size.height, gn->get_connection_output_height(j));
+
 						int type = gn->get_connection_output_type(j);
 						if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_output_hotzone(gn, j, mpos, port_size)) {
 							connecting_target = true;
@@ -707,6 +717,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
 				} else {
 					for (int j = 0; j < gn->get_connection_input_count(); j++) {
 						Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
+						Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
+						port_size.height = MAX(port_size.height, gn->get_connection_input_height(j));
+
 						int type = gn->get_connection_input_type(j);
 						if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_input_hotzone(gn, j, mpos, port_size)) {
 							connecting_target = true;
@@ -754,19 +767,24 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
 	}
 }
 
-bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) {
-	if (p_control->is_set_as_top_level() || !p_control->is_visible()) {
+bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos, const Vector2 &p_offset) {
+	if (p_control->is_set_as_top_level() || !p_control->is_visible() || !p_control->is_inside_tree()) {
 		return false;
 	}
 
-	if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) {
-		//test children
+	Rect2 control_rect = p_control->get_rect();
+	control_rect.size *= zoom;
+	control_rect.position *= zoom;
+	control_rect.position += p_offset;
+
+	if (!control_rect.has_point(mpos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) {
+		// Test children.
 		for (int i = 0; i < p_control->get_child_count(); i++) {
-			Control *subchild = Object::cast_to<Control>(p_control->get_child(i));
-			if (!subchild) {
+			Control *child_rect = Object::cast_to<Control>(p_control->get_child(i));
+			if (!child_rect) {
 				continue;
 			}
-			if (_check_clickable_control(subchild, pos - subchild->get_position())) {
+			if (_check_clickable_control(child_rect, mpos, control_rect.position)) {
 				return true;
 			}
 		}
@@ -798,7 +816,13 @@ bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index,
 }
 
 bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left) {
-	if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos)) {
+	Rect2 hotzone = Rect2(
+			pos.x - (p_left ? port_hotzone_outer_extent : port_hotzone_inner_extent),
+			pos.y - p_port_size.height / 2.0,
+			port_hotzone_inner_extent + port_hotzone_outer_extent,
+			p_port_size.height);
+
+	if (!hotzone.has_point(p_mouse_pos)) {
 		return false;
 	}
 
@@ -807,23 +831,17 @@ bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_po
 		if (!child) {
 			continue;
 		}
-		Rect2 rect = child->get_rect();
-
-		// To prevent intersections with other nodes.
-		rect.position *= zoom;
-		rect.size *= zoom;
-
-		if (rect.has_point(p_mouse_pos)) {
-			//check sub-controls
-			Vector2 subpos = p_mouse_pos - rect.position;
+		Rect2 child_rect = child->get_rect();
+		child_rect.size *= zoom;
 
+		if (child_rect.has_point(p_mouse_pos * zoom)) {
 			for (int j = 0; j < child->get_child_count(); j++) {
 				Control *subchild = Object::cast_to<Control>(child->get_child(j));
 				if (!subchild) {
 					continue;
 				}
 
-				if (_check_clickable_control(subchild, subpos - subchild->get_position())) {
+				if (_check_clickable_control(subchild, p_mouse_pos * zoom, child_rect.position)) {
 					return false;
 				}
 			}

+ 3 - 3
scene/gui/graph_edit.h

@@ -124,8 +124,8 @@ private:
 	HScrollBar *h_scroll = nullptr;
 	VScrollBar *v_scroll = nullptr;
 
-	float port_grab_distance_horizontal = 0.0;
-	float port_grab_distance_vertical = 0.0;
+	float port_hotzone_inner_extent = 0.0;
+	float port_hotzone_outer_extent = 0.0;
 
 	Ref<ViewPanner> panner;
 	bool warped_panning = true;
@@ -250,7 +250,7 @@ private:
 	friend class GraphEditMinimap;
 	void _minimap_toggled();
 
-	bool _check_clickable_control(Control *p_control, const Vector2 &pos);
+	bool _check_clickable_control(Control *p_control, const Vector2 &r_mouse_pos, const Vector2 &p_offset);
 
 	bool arranging_graph = false;
 

+ 28 - 6
scene/gui/graph_node.cpp

@@ -832,6 +832,7 @@ void GraphNode::_connpos_update() {
 				cc.pos = Point2i(edgeofs, y + h / 2);
 				cc.type = slot_info[idx].type_left;
 				cc.color = slot_info[idx].color_left;
+				cc.height = size.height;
 				conn_input_cache.push_back(cc);
 			}
 			if (slot_info[idx].enable_right) {
@@ -839,6 +840,7 @@ void GraphNode::_connpos_update() {
 				cc.pos = Point2i(get_size().width - edgeofs, y + h / 2);
 				cc.type = slot_info[idx].type_right;
 				cc.color = slot_info[idx].color_right;
+				cc.height = size.height;
 				conn_output_cache.push_back(cc);
 			}
 		}
@@ -859,12 +861,13 @@ int GraphNode::get_connection_input_count() {
 	return conn_input_cache.size();
 }
 
-int GraphNode::get_connection_output_count() {
+int GraphNode::get_connection_input_height(int p_idx) {
 	if (connpos_dirty) {
 		_connpos_update();
 	}
 
-	return conn_output_cache.size();
+	ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0);
+	return conn_input_cache[p_idx].height;
 }
 
 Vector2 GraphNode::get_connection_input_position(int p_idx) {
@@ -897,6 +900,23 @@ Color GraphNode::get_connection_input_color(int p_idx) {
 	return conn_input_cache[p_idx].color;
 }
 
+int GraphNode::get_connection_output_count() {
+	if (connpos_dirty) {
+		_connpos_update();
+	}
+
+	return conn_output_cache.size();
+}
+
+int GraphNode::get_connection_output_height(int p_idx) {
+	if (connpos_dirty) {
+		_connpos_update();
+	}
+
+	ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0);
+	return conn_output_cache[p_idx].height;
+}
+
 Vector2 GraphNode::get_connection_output_position(int p_idx) {
 	if (connpos_dirty) {
 		_connpos_update();
@@ -1066,15 +1086,17 @@ void GraphNode::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected);
 	ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
 
-	ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count);
 	ClassDB::bind_method(D_METHOD("get_connection_input_count"), &GraphNode::get_connection_input_count);
+	ClassDB::bind_method(D_METHOD("get_connection_input_height", "idx"), &GraphNode::get_connection_input_height);
+	ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position);
+	ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type);
+	ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color);
 
+	ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count);
+	ClassDB::bind_method(D_METHOD("get_connection_output_height", "idx"), &GraphNode::get_connection_output_height);
 	ClassDB::bind_method(D_METHOD("get_connection_output_position", "idx"), &GraphNode::get_connection_output_position);
 	ClassDB::bind_method(D_METHOD("get_connection_output_type", "idx"), &GraphNode::get_connection_output_type);
 	ClassDB::bind_method(D_METHOD("get_connection_output_color", "idx"), &GraphNode::get_connection_output_color);
-	ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position);
-	ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type);
-	ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color);
 
 	ClassDB::bind_method(D_METHOD("set_show_close_button", "show"), &GraphNode::set_show_close_button);
 	ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible);

+ 5 - 1
scene/gui/graph_node.h

@@ -81,6 +81,7 @@ private:
 		Vector2 pos;
 		int type = 0;
 		Color color;
+		int height;
 	};
 
 	Vector<ConnCache> conn_input_cache;
@@ -167,10 +168,13 @@ public:
 	bool is_close_button_visible() const;
 
 	int get_connection_input_count();
-	int get_connection_output_count();
+	int get_connection_input_height(int p_idx);
 	Vector2 get_connection_input_position(int p_idx);
 	int get_connection_input_type(int p_idx);
 	Color get_connection_input_color(int p_idx);
+
+	int get_connection_output_count();
+	int get_connection_output_height(int p_idx);
 	Vector2 get_connection_output_position(int p_idx);
 	int get_connection_output_type(int p_idx);
 	Color get_connection_output_color(int p_idx);

+ 2 - 2
scene/resources/default_theme/default_theme.cpp

@@ -1009,8 +1009,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 
 	// Visual Node Ports
 
-	theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale);
-	theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale);
+	theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale);
+	theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale);
 
 	theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0));
 	Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0);