mirror of
https://github.com/godotengine/godot.git
synced 2025-02-17 00:01:03 +00:00
Improve and fix the GraphNode port hotzones
Co-authored-by: Ansraer <jacky2611@gmail.com>
This commit is contained in:
parent
1f690f197a
commit
771cb1261a
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,16 +1086,18 @@ 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_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_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("set_show_close_button", "show"), &GraphNode::set_show_close_button);
|
||||
ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user