Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Enable zooming in graph_edit with Ctrl + scrollwheel + relevant cherry-picks #47173

Merged
merged 6 commits into from
Apr 29, 2021
165 changes: 73 additions & 92 deletions scene/gui/graph_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,15 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {

Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
if (is_in_hot_zone(pos, p_point))
if (is_in_hot_zone(pos / zoom, p_point / zoom)) {
return true;
}
}

for (int j = 0; j < gn->get_connection_input_count(); j++) {

Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
if (is_in_hot_zone(pos, p_point)) {
if (is_in_hot_zone(pos / zoom, p_point / zoom)) {
return true;
}
}
Expand All @@ -567,9 +568,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {

Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {

connecting_valid = false;
Ref<Texture> port = get_icon("port", "GraphNode");
Vector2 mpos(mb->get_position().x, mb->get_position().y);
click_pos = mb->get_position() / zoom;
for (int i = get_child_count() - 1; i >= 0; i--) {

GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
Expand All @@ -579,8 +580,7 @@ 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();
if (is_in_hot_zone(pos, mpos)) {

if (is_in_hot_zone(pos / zoom, click_pos)) {
if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
//check disconnect
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
Expand Down Expand Up @@ -626,8 +626,7 @@ 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();
if (is_in_hot_zone(pos, mpos)) {

if (is_in_hot_zone(pos / zoom, click_pos)) {
if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
Expand Down Expand Up @@ -680,72 +679,70 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_target = false;
top_layer->update();
minimap->update();
connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0 * zoom;

Ref<Texture> port = get_icon("port", "GraphNode");
Vector2 mpos = mm->get_position();
for (int i = get_child_count() - 1; i >= 0; i--) {

GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
if (!gn)
continue;

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();
int type = gn->get_connection_output_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {

connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
connecting_target_index = j;
return;
}
if (connecting_valid) {
Ref<Texture> port = get_icon("port", "GraphNode");
Vector2 mpos = mm->get_position() / zoom;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
if (!gn) {
continue;
}
} else {

for (int j = 0; j < gn->get_connection_input_count(); j++) {

Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
int type = gn->get_connection_input_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
connecting_target_index = j;
return;
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();
int type = gn->get_connection_output_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
connecting_target_index = j;
return;
}
}
} else {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
int type = gn->get_connection_input_type(j);
if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
connecting_target_index = j;
return;
}
}
}
}
}
}

if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
if (connecting_valid) {
if (connecting && connecting_target) {
String from = connecting_from;
int from_slot = connecting_index;
String to = connecting_target_to;
int to_slot = connecting_target_index;

if (!connecting_out) {
SWAP(from, to);
SWAP(from_slot, to_slot);
}
emit_signal("connection_request", from, from_slot, to, to_slot);

if (connecting && connecting_target) {

String from = connecting_from;
int from_slot = connecting_index;
String to = connecting_target_to;
int to_slot = connecting_target_index;

if (!connecting_out) {
SWAP(from, to);
SWAP(from_slot, to_slot);
}
emit_signal("connection_request", from, from_slot, to, to_slot);

} else if (!just_disconnected) {

String from = connecting_from;
int from_slot = connecting_index;
Vector2 ofs = Vector2(mb->get_position().x, mb->get_position().y);
} else if (!just_disconnected) {
String from = connecting_from;
int from_slot = connecting_index;
Vector2 ofs = Vector2(mb->get_position().x, mb->get_position().y);

if (!connecting_out) {
emit_signal("connection_from_empty", from, from_slot, ofs);
} else {
emit_signal("connection_to_empty", from, from_slot, ofs);
if (!connecting_out) {
emit_signal("connection_from_empty", from, from_slot, ofs);
} else {
emit_signal("connection_to_empty", from, from_slot, ofs);
}
}
}

Expand Down Expand Up @@ -788,6 +785,11 @@ bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) {
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
Expand Down Expand Up @@ -1247,7 +1249,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
if (gn_selected->is_resizing())
continue;

if (gn_selected->has_point(b->get_position() - gn_selected->get_position())) {
if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) {
gn = gn_selected;
break;
}
Expand Down Expand Up @@ -1341,25 +1343,17 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
minimap->update();
}

if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
//too difficult to get right
//set_zoom(zoom*ZOOM_SCALE);
}

if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) {
//too difficult to get right
//set_zoom(zoom/ZOOM_SCALE);
}
if (b->get_button_index() == BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
if (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
set_zoom_custom(zoom * ZOOM_SCALE, b->get_position());
} else if (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
set_zoom_custom(zoom / ZOOM_SCALE, b->get_position());
} else if (b->get_button_index() == BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
}
if (b->get_button_index() == BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
} else if (b->get_button_index() == BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8);
}
if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
} else if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * b->get_factor() / 8);
}
if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
} else if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * b->get_factor() / 8);
}
}
Expand Down Expand Up @@ -1723,8 +1717,6 @@ void GraphEdit::_bind_methods() {
GraphEdit::GraphEdit() {
set_focus_mode(FOCUS_ALL);

awaiting_scroll_offset_update = false;
top_layer = NULL;
top_layer = memnew(GraphEditFilter(this));
add_child(top_layer);
top_layer->set_mouse_filter(MOUSE_FILTER_PASS);
Expand All @@ -1747,13 +1739,6 @@ GraphEdit::GraphEdit() {
v_scroll->set_name("_v_scroll");
top_layer->add_child(v_scroll);

updating = false;
connecting = false;
right_disconnects = false;

box_selecting = false;
dragging = false;

//set large minmax so it can scroll even if not resized yet
h_scroll->set_min(-10000);
h_scroll->set_max(10000);
Expand All @@ -1764,8 +1749,6 @@ GraphEdit::GraphEdit() {
h_scroll->connect("value_changed", this, "_scroll_moved");
v_scroll->connect("value_changed", this, "_scroll_moved");

zoom = 1;

zoom_hb = memnew(HBoxContainer);
top_layer->add_child(zoom_hb);
zoom_hb->set_position(Vector2(10, 10));
Expand Down Expand Up @@ -1830,7 +1813,5 @@ GraphEdit::GraphEdit() {
minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET);
minimap->connect("draw", this, "_minimap_draw");

setting_scroll_ofs = false;
just_disconnected = false;
set_clip_contents(true);
}
30 changes: 16 additions & 14 deletions scene/gui/graph_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,36 +126,38 @@ class GraphEdit : public Control {
float port_grab_distance_horizontal;
float port_grab_distance_vertical;

bool connecting;
bool connecting = false;
String connecting_from;
bool connecting_out;
bool connecting_out = false;
int connecting_index;
int connecting_type;
Color connecting_color;
bool connecting_target;
bool connecting_target = false;
Vector2 connecting_to;
String connecting_target_to;
int connecting_target_index;
bool just_disconnected;
bool just_disconnected = false;
bool connecting_valid = false;
Vector2 click_pos;

bool dragging;
bool just_selected;
bool moving_selection;
bool dragging = false;
bool just_selected = false;
bool moving_selection = false;
Vector2 drag_accum;

float zoom;
float zoom = 1.0f;

bool box_selecting;
bool box_selection_mode_additive;
bool box_selecting = false;
bool box_selection_mode_additive = false;
Point2 box_selecting_from;
Point2 box_selecting_to;
Rect2 box_selecting_rect;
List<GraphNode *> previus_selected;

bool setting_scroll_ofs;
bool right_disconnects;
bool updating;
bool awaiting_scroll_offset_update;
bool setting_scroll_ofs = false;
bool right_disconnects = false;
bool updating = false;
bool awaiting_scroll_offset_update = false;
List<Connection> connections;

void _bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const;
Expand Down