|
@@ -31,6 +31,7 @@
|
|
|
#include "graph_edit.h"
|
|
|
|
|
|
#include "core/input/input.h"
|
|
|
+#include "core/math/math_funcs.h"
|
|
|
#include "core/os/keyboard.h"
|
|
|
#include "scene/gui/box_container.h"
|
|
|
#include "scene/gui/button.h"
|
|
@@ -44,6 +45,9 @@
|
|
|
#define MIN_ZOOM (((1 / ZOOM_SCALE) / ZOOM_SCALE) / ZOOM_SCALE)
|
|
|
#define MAX_ZOOM (1 * ZOOM_SCALE * ZOOM_SCALE * ZOOM_SCALE)
|
|
|
|
|
|
+#define MINIMAP_OFFSET 12
|
|
|
+#define MINIMAP_PADDING 5
|
|
|
+
|
|
|
bool GraphEditFilter::has_point(const Point2 &p_point) const {
|
|
|
return ge->_filter_input(p_point);
|
|
|
}
|
|
@@ -52,6 +56,141 @@ GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) {
|
|
|
ge = p_edit;
|
|
|
}
|
|
|
|
|
|
+void GraphEditMinimap::_bind_methods() {
|
|
|
+ ClassDB::bind_method(D_METHOD("_gui_input"), &GraphEditMinimap::_gui_input);
|
|
|
+}
|
|
|
+
|
|
|
+GraphEditMinimap::GraphEditMinimap(GraphEdit *p_edit) {
|
|
|
+ ge = p_edit;
|
|
|
+
|
|
|
+ graph_proportions = Vector2(1, 1);
|
|
|
+ graph_padding = Vector2(0, 0);
|
|
|
+ camera_position = Vector2(100, 50);
|
|
|
+ camera_size = Vector2(200, 200);
|
|
|
+ minimap_padding = Vector2(MINIMAP_PADDING, MINIMAP_PADDING);
|
|
|
+ minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
|
|
|
+
|
|
|
+ is_pressing = false;
|
|
|
+ is_resizing = false;
|
|
|
+}
|
|
|
+
|
|
|
+void GraphEditMinimap::update_minimap() {
|
|
|
+ Vector2 graph_offset = _get_graph_offset();
|
|
|
+ Vector2 graph_size = _get_graph_size();
|
|
|
+
|
|
|
+ camera_position = ge->get_scroll_ofs() - graph_offset;
|
|
|
+ camera_size = ge->get_size();
|
|
|
+
|
|
|
+ Vector2 render_size = _get_render_size();
|
|
|
+ float target_ratio = render_size.x / render_size.y;
|
|
|
+ float graph_ratio = graph_size.x / graph_size.y;
|
|
|
+
|
|
|
+ graph_proportions = graph_size;
|
|
|
+ graph_padding = Vector2(0, 0);
|
|
|
+ if (graph_ratio > target_ratio) {
|
|
|
+ graph_proportions.x = graph_size.x;
|
|
|
+ graph_proportions.y = graph_size.x / target_ratio;
|
|
|
+ graph_padding.y = Math::abs(graph_size.y - graph_proportions.y) / 2;
|
|
|
+ } else {
|
|
|
+ graph_proportions.x = graph_size.y * target_ratio;
|
|
|
+ graph_proportions.y = graph_size.y;
|
|
|
+ graph_padding.x = Math::abs(graph_size.x - graph_proportions.x) / 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ // This centers minimap inside the minimap rectangle.
|
|
|
+ minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
|
|
|
+}
|
|
|
+
|
|
|
+Rect2 GraphEditMinimap::get_camera_rect() {
|
|
|
+ Vector2 camera_center = _convert_from_graph_position(camera_position + camera_size / 2) + minimap_offset;
|
|
|
+ Vector2 camera_viewport = _convert_from_graph_position(camera_size);
|
|
|
+ Vector2 camera_position = (camera_center - camera_viewport / 2);
|
|
|
+ return Rect2(camera_position, camera_viewport);
|
|
|
+}
|
|
|
+
|
|
|
+Vector2 GraphEditMinimap::_get_render_size() {
|
|
|
+ if (!is_inside_tree()) {
|
|
|
+ return Vector2(0, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ return get_size() - 2 * minimap_padding;
|
|
|
+}
|
|
|
+
|
|
|
+Vector2 GraphEditMinimap::_get_graph_offset() {
|
|
|
+ return Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
|
|
|
+}
|
|
|
+
|
|
|
+Vector2 GraphEditMinimap::_get_graph_size() {
|
|
|
+ Vector2 graph_size = Vector2(ge->h_scroll->get_max(), ge->v_scroll->get_max()) - Vector2(ge->h_scroll->get_min(), ge->v_scroll->get_min());
|
|
|
+
|
|
|
+ if (graph_size.x == 0) {
|
|
|
+ graph_size.x = 1;
|
|
|
+ }
|
|
|
+ if (graph_size.y == 0) {
|
|
|
+ graph_size.y = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return graph_size;
|
|
|
+}
|
|
|
+
|
|
|
+Vector2 GraphEditMinimap::_convert_from_graph_position(const Vector2 &p_position) {
|
|
|
+ Vector2 map_position = Vector2(0, 0);
|
|
|
+ Vector2 render_size = _get_render_size();
|
|
|
+
|
|
|
+ map_position.x = p_position.x * render_size.x / graph_proportions.x;
|
|
|
+ map_position.y = p_position.y * render_size.y / graph_proportions.y;
|
|
|
+
|
|
|
+ return map_position;
|
|
|
+}
|
|
|
+
|
|
|
+Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position) {
|
|
|
+ Vector2 graph_position = Vector2(0, 0);
|
|
|
+ Vector2 render_size = _get_render_size();
|
|
|
+
|
|
|
+ graph_position.x = p_position.x * graph_proportions.x / render_size.x;
|
|
|
+ graph_position.y = p_position.y * graph_proportions.y / render_size.y;
|
|
|
+
|
|
|
+ return graph_position;
|
|
|
+}
|
|
|
+
|
|
|
+void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
|
|
|
+ Ref<InputEventMouseButton> mb = p_ev;
|
|
|
+ Ref<InputEventMouseMotion> mm = p_ev;
|
|
|
+
|
|
|
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
|
|
|
+ if (mb->is_pressed()) {
|
|
|
+ is_pressing = true;
|
|
|
+
|
|
|
+ Ref<Texture2D> resizer = get_theme_icon("resizer");
|
|
|
+ Rect2 resizer_hitbox = Rect2(Point2(), resizer->get_size());
|
|
|
+ if (resizer_hitbox.has_point(mb->get_position())) {
|
|
|
+ is_resizing = true;
|
|
|
+ } else {
|
|
|
+ Vector2 click_position = _convert_to_graph_position(mb->get_position() - minimap_padding) - graph_padding;
|
|
|
+ _adjust_graph_scroll(click_position);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ is_pressing = false;
|
|
|
+ is_resizing = false;
|
|
|
+ }
|
|
|
+ accept_event();
|
|
|
+ } else if (mm.is_valid() && is_pressing) {
|
|
|
+ if (is_resizing) {
|
|
|
+ ge->set_minimap_size(ge->get_minimap_size() - mm->get_relative());
|
|
|
+ update();
|
|
|
+ } else {
|
|
|
+ Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding;
|
|
|
+ _adjust_graph_scroll(click_position);
|
|
|
+ }
|
|
|
+ accept_event();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
|
|
|
+ Vector2 graph_offset = _get_graph_offset();
|
|
|
+ ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2);
|
|
|
+}
|
|
|
+
|
|
|
Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) {
|
|
|
if (is_node_connected(p_from, p_from_port, p_to, p_to_port)) {
|
|
|
return OK;
|
|
@@ -64,6 +203,7 @@ Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const S
|
|
|
c.activity = 0;
|
|
|
connections.push_back(c);
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
update();
|
|
|
connections_layer->update();
|
|
|
|
|
@@ -85,6 +225,7 @@ void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const
|
|
|
if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) {
|
|
|
connections.erase(E);
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
update();
|
|
|
connections_layer->update();
|
|
|
return;
|
|
@@ -118,6 +259,7 @@ void GraphEdit::_scroll_moved(double) {
|
|
|
awaiting_scroll_offset_update = true;
|
|
|
}
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
update();
|
|
|
|
|
|
if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention
|
|
@@ -234,6 +376,7 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
|
|
|
GraphNode *gn = Object::cast_to<GraphNode>(p_gn);
|
|
|
ERR_FAIL_COND(!gn);
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
update();
|
|
|
connections_layer->update();
|
|
|
}
|
|
@@ -241,7 +384,8 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
|
|
|
void GraphEdit::add_child_notify(Node *p_child) {
|
|
|
Control::add_child_notify(p_child);
|
|
|
|
|
|
- top_layer->call_deferred("raise"); //top layer always on top!
|
|
|
+ top_layer->call_deferred("raise"); // Top layer always on top!
|
|
|
+
|
|
|
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
|
|
|
if (gn) {
|
|
|
gn->set_scale(Vector2(zoom, zoom));
|
|
@@ -255,9 +399,11 @@ void GraphEdit::add_child_notify(Node *p_child) {
|
|
|
|
|
|
void GraphEdit::remove_child_notify(Node *p_child) {
|
|
|
Control::remove_child_notify(p_child);
|
|
|
+
|
|
|
if (is_inside_tree()) {
|
|
|
- top_layer->call_deferred("raise"); //top layer always on top!
|
|
|
+ top_layer->call_deferred("raise"); // Top layer always on top!
|
|
|
}
|
|
|
+
|
|
|
GraphNode *gn = Object::cast_to<GraphNode>(p_child);
|
|
|
if (gn) {
|
|
|
gn->disconnect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved));
|
|
@@ -275,6 +421,7 @@ void GraphEdit::_notification(int p_what) {
|
|
|
zoom_reset->set_icon(get_theme_icon("reset"));
|
|
|
zoom_plus->set_icon(get_theme_icon("more"));
|
|
|
snap_button->set_icon(get_theme_icon("snap"));
|
|
|
+ minimap_button->set_icon(get_theme_icon("minimap"));
|
|
|
}
|
|
|
if (p_what == NOTIFICATION_READY) {
|
|
|
Size2 hmin = h_scroll->get_combined_minimum_size();
|
|
@@ -338,6 +485,7 @@ void GraphEdit::_notification(int p_what) {
|
|
|
if (p_what == NOTIFICATION_RESIZED) {
|
|
|
_update_scroll();
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -472,6 +620,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
|
|
|
connecting_to = mm->get_position();
|
|
|
connecting_target = false;
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
connecting_valid = just_disconnected || click_pos.distance_to(connecting_to) > 20.0 * zoom;
|
|
|
|
|
|
if (connecting_valid) {
|
|
@@ -541,6 +690,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
|
|
|
|
|
|
connecting = false;
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
update();
|
|
|
connections_layer->update();
|
|
|
}
|
|
@@ -632,12 +782,12 @@ void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color) {
|
|
|
+void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_bezier_ratio) {
|
|
|
//cubic bezier code
|
|
|
float diff = p_to.x - p_from.x;
|
|
|
float cp_offset;
|
|
|
- int cp_len = get_theme_constant("bezier_len_pos");
|
|
|
- int cp_neg_len = get_theme_constant("bezier_len_neg");
|
|
|
+ int cp_len = get_theme_constant("bezier_len_pos") * p_bezier_ratio;
|
|
|
+ int cp_neg_len = get_theme_constant("bezier_len_neg") * p_bezier_ratio;
|
|
|
|
|
|
if (diff > 0) {
|
|
|
cp_offset = MIN(cp_len, diff * 0.5);
|
|
@@ -708,7 +858,7 @@ void GraphEdit::_connections_layer_draw() {
|
|
|
color = color.lerp(activity_color, E->get().activity);
|
|
|
tocolor = tocolor.lerp(activity_color, E->get().activity);
|
|
|
}
|
|
|
- _draw_cos_line(connections_layer, frompos, topos, color, tocolor);
|
|
|
+ _draw_cos_line(connections_layer, frompos, topos, color, tocolor, 1.0);
|
|
|
}
|
|
|
|
|
|
while (to_erase.size()) {
|
|
@@ -747,7 +897,7 @@ void GraphEdit::_top_layer_draw() {
|
|
|
if (!connecting_out) {
|
|
|
SWAP(pos, topos);
|
|
|
}
|
|
|
- _draw_cos_line(top_layer, pos, topos, col, col);
|
|
|
+ _draw_cos_line(top_layer, pos, topos, col, col, 1.0);
|
|
|
}
|
|
|
|
|
|
if (box_selecting) {
|
|
@@ -756,6 +906,114 @@ void GraphEdit::_top_layer_draw() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void GraphEdit::_minimap_draw() {
|
|
|
+ if (!is_minimap_enabled()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ minimap->update_minimap();
|
|
|
+
|
|
|
+ // Draw the minimap background.
|
|
|
+ Rect2 minimap_rect = Rect2(Point2(), minimap->get_size());
|
|
|
+ minimap->draw_style_box(minimap->get_theme_stylebox("bg"), minimap_rect);
|
|
|
+
|
|
|
+ Vector2 graph_offset = minimap->_get_graph_offset();
|
|
|
+ Vector2 minimap_offset = minimap->minimap_offset;
|
|
|
+
|
|
|
+ // Draw comment graph nodes.
|
|
|
+ for (int i = get_child_count() - 1; i >= 0; i--) {
|
|
|
+ GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
|
|
|
+ if (!gn || !gn->is_comment()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset;
|
|
|
+ Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
|
|
|
+ Rect2 node_rect = Rect2(node_position, node_size);
|
|
|
+
|
|
|
+ Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox("node")->duplicate();
|
|
|
+
|
|
|
+ // Override default values with colors provided by the GraphNode's stylebox, if possible.
|
|
|
+ Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "commentfocus" : "comment");
|
|
|
+ if (sbf.is_valid()) {
|
|
|
+ Color node_color = sbf->get_bg_color();
|
|
|
+ sb_minimap->set_bg_color(node_color);
|
|
|
+ }
|
|
|
+
|
|
|
+ minimap->draw_style_box(sb_minimap, node_rect);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Draw regular graph nodes.
|
|
|
+ for (int i = get_child_count() - 1; i >= 0; i--) {
|
|
|
+ GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
|
|
|
+ if (!gn || gn->is_comment()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset;
|
|
|
+ Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom);
|
|
|
+ Rect2 node_rect = Rect2(node_position, node_size);
|
|
|
+
|
|
|
+ Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox("node")->duplicate();
|
|
|
+
|
|
|
+ // Override default values with colors provided by the GraphNode's stylebox, if possible.
|
|
|
+ Ref<StyleBoxFlat> sbf = gn->get_theme_stylebox(gn->is_selected() ? "selectedframe" : "frame");
|
|
|
+ if (sbf.is_valid()) {
|
|
|
+ Color node_color = sbf->get_border_color();
|
|
|
+ sb_minimap->set_bg_color(node_color);
|
|
|
+ }
|
|
|
+
|
|
|
+ minimap->draw_style_box(sb_minimap, node_rect);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Draw node connections.
|
|
|
+ Color activity_color = get_theme_color("activity");
|
|
|
+ for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
|
|
|
+ NodePath fromnp(E->get().from);
|
|
|
+
|
|
|
+ Node *from = get_node(fromnp);
|
|
|
+ if (!from) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ GraphNode *gfrom = Object::cast_to<GraphNode>(from);
|
|
|
+ if (!gfrom) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ NodePath tonp(E->get().to);
|
|
|
+ Node *to = get_node(tonp);
|
|
|
+ if (!to) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ GraphNode *gto = Object::cast_to<GraphNode>(to);
|
|
|
+ if (!gto) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector2 from_slot_position = gfrom->get_offset() + gfrom->get_connection_output_position(E->get().from_port);
|
|
|
+ Vector2 from_position = minimap->_convert_from_graph_position(from_slot_position * zoom - graph_offset) + minimap_offset;
|
|
|
+ Color from_color = gfrom->get_connection_output_color(E->get().from_port);
|
|
|
+ Vector2 to_slot_position = gto->get_offset() + gto->get_connection_input_position(E->get().to_port);
|
|
|
+ Vector2 to_position = minimap->_convert_from_graph_position(to_slot_position * zoom - graph_offset) + minimap_offset;
|
|
|
+ Color to_color = gto->get_connection_input_color(E->get().to_port);
|
|
|
+
|
|
|
+ if (E->get().activity > 0) {
|
|
|
+ from_color = from_color.lerp(activity_color, E->get().activity);
|
|
|
+ to_color = to_color.lerp(activity_color, E->get().activity);
|
|
|
+ }
|
|
|
+ _draw_cos_line(minimap, from_position, to_position, from_color, to_color, 0.5);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Draw the "camera" viewport.
|
|
|
+ Rect2 camera_rect = minimap->get_camera_rect();
|
|
|
+ minimap->draw_style_box(minimap->get_theme_stylebox("camera"), camera_rect);
|
|
|
+
|
|
|
+ // Draw the resizer control.
|
|
|
+ Ref<Texture2D> resizer = minimap->get_theme_icon("resizer");
|
|
|
+ Color resizer_color = minimap->get_theme_color("resizer_color");
|
|
|
+ minimap->draw_texture(resizer, Point2(), resizer_color);
|
|
|
+}
|
|
|
+
|
|
|
void GraphEdit::set_selected(Node *p_child) {
|
|
|
for (int i = get_child_count() - 1; i >= 0; i--) {
|
|
|
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
|
|
@@ -836,6 +1094,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
|
|
}
|
|
|
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
}
|
|
|
|
|
|
Ref<InputEventMouseButton> b = p_ev;
|
|
@@ -858,10 +1117,12 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
|
|
gn->set_selected(select);
|
|
|
}
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
} else {
|
|
|
if (connecting) {
|
|
|
connecting = false;
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
} else {
|
|
|
emit_signal("popup_request", b->get_global_position());
|
|
|
}
|
|
@@ -902,6 +1163,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
|
|
dragging = false;
|
|
|
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
update();
|
|
|
connections_layer->update();
|
|
|
}
|
|
@@ -1012,6 +1274,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
|
|
|
box_selecting = false;
|
|
|
previus_selected.clear();
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
}
|
|
|
|
|
|
if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
|
|
@@ -1079,6 +1342,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
|
|
|
if (Math::is_equal_approx(E->get().activity, p_activity)) {
|
|
|
//update only if changed
|
|
|
top_layer->update();
|
|
|
+ minimap->update();
|
|
|
connections_layer->update();
|
|
|
}
|
|
|
E->get().activity = p_activity;
|
|
@@ -1089,6 +1353,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
|
|
|
|
|
|
void GraphEdit::clear_connections() {
|
|
|
connections.clear();
|
|
|
+ minimap->update();
|
|
|
update();
|
|
|
connections_layer->update();
|
|
|
}
|
|
@@ -1112,6 +1377,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) {
|
|
|
top_layer->update();
|
|
|
|
|
|
_update_scroll();
|
|
|
+ minimap->update();
|
|
|
connections_layer->update();
|
|
|
|
|
|
if (is_visible_in_tree()) {
|
|
@@ -1229,6 +1495,47 @@ void GraphEdit::_snap_value_changed(double) {
|
|
|
update();
|
|
|
}
|
|
|
|
|
|
+// _minimap_toggled
|
|
|
+
|
|
|
+void GraphEdit::set_minimap_size(Vector2 p_size) {
|
|
|
+ minimap->set_size(p_size);
|
|
|
+ Vector2 minimap_size = minimap->get_size(); // The size might've been adjusted by the minimum size.
|
|
|
+
|
|
|
+ minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
|
|
|
+ minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET);
|
|
|
+ minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET);
|
|
|
+ minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET);
|
|
|
+ minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET);
|
|
|
+ minimap->update();
|
|
|
+}
|
|
|
+
|
|
|
+Vector2 GraphEdit::get_minimap_size() const {
|
|
|
+ return minimap->get_size();
|
|
|
+}
|
|
|
+
|
|
|
+void GraphEdit::set_minimap_opacity(float p_opacity) {
|
|
|
+ minimap->set_modulate(Color(1, 1, 1, p_opacity));
|
|
|
+ minimap->update();
|
|
|
+}
|
|
|
+
|
|
|
+float GraphEdit::get_minimap_opacity() const {
|
|
|
+ Color minimap_modulate = minimap->get_modulate();
|
|
|
+ return minimap_modulate.a;
|
|
|
+}
|
|
|
+
|
|
|
+void GraphEdit::set_minimap_enabled(bool p_enable) {
|
|
|
+ minimap_button->set_pressed(p_enable);
|
|
|
+ minimap->update();
|
|
|
+}
|
|
|
+
|
|
|
+bool GraphEdit::is_minimap_enabled() const {
|
|
|
+ return minimap_button->is_pressed();
|
|
|
+}
|
|
|
+
|
|
|
+void GraphEdit::_minimap_toggled() {
|
|
|
+ minimap->update();
|
|
|
+}
|
|
|
+
|
|
|
HBoxContainer *GraphEdit::get_zoom_hbox() {
|
|
|
return zoom_hb;
|
|
|
}
|
|
@@ -1260,6 +1567,14 @@ void GraphEdit::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("set_use_snap", "enable"), &GraphEdit::set_use_snap);
|
|
|
ClassDB::bind_method(D_METHOD("is_using_snap"), &GraphEdit::is_using_snap);
|
|
|
|
|
|
+ ClassDB::bind_method(D_METHOD("set_minimap_size", "p_size"), &GraphEdit::set_minimap_size);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_minimap_size"), &GraphEdit::get_minimap_size);
|
|
|
+ ClassDB::bind_method(D_METHOD("set_minimap_opacity", "p_opacity"), &GraphEdit::set_minimap_opacity);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_minimap_opacity"), &GraphEdit::get_minimap_opacity);
|
|
|
+
|
|
|
+ ClassDB::bind_method(D_METHOD("set_minimap_enabled", "enable"), &GraphEdit::set_minimap_enabled);
|
|
|
+ ClassDB::bind_method(D_METHOD("is_minimap_enabled"), &GraphEdit::is_minimap_enabled);
|
|
|
+
|
|
|
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
|
|
|
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
|
|
|
|
|
@@ -1275,6 +1590,10 @@ void GraphEdit::_bind_methods() {
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom"), "set_zoom", "get_zoom");
|
|
|
+ ADD_GROUP("Minimap", "minimap");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "minimap_enabled"), "set_minimap_enabled", "is_minimap_enabled");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size"), "set_minimap_size", "get_minimap_size");
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "minimap_opacity"), "set_minimap_opacity", "get_minimap_opacity");
|
|
|
|
|
|
ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
|
|
|
ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
|
|
@@ -1380,6 +1699,32 @@ GraphEdit::GraphEdit() {
|
|
|
snap_amount->connect("value_changed", callable_mp(this, &GraphEdit::_snap_value_changed));
|
|
|
zoom_hb->add_child(snap_amount);
|
|
|
|
|
|
+ minimap_button = memnew(Button);
|
|
|
+ minimap_button->set_flat(true);
|
|
|
+ minimap_button->set_toggle_mode(true);
|
|
|
+ minimap_button->set_tooltip(RTR("Enable grid minimap."));
|
|
|
+ minimap_button->connect("pressed", callable_mp(this, &GraphEdit::_minimap_toggled));
|
|
|
+ minimap_button->set_pressed(true);
|
|
|
+ minimap_button->set_focus_mode(FOCUS_NONE);
|
|
|
+ zoom_hb->add_child(minimap_button);
|
|
|
+
|
|
|
+ Vector2 minimap_size = Vector2(240, 160);
|
|
|
+ float minimap_opacity = 0.45;
|
|
|
+
|
|
|
+ minimap = memnew(GraphEditMinimap(this));
|
|
|
+ top_layer->add_child(minimap);
|
|
|
+ minimap->set_name("_minimap");
|
|
|
+ minimap->set_modulate(Color(1, 1, 1, minimap_opacity));
|
|
|
+ minimap->set_mouse_filter(MOUSE_FILTER_STOP);
|
|
|
+ minimap->set_custom_minimum_size(Vector2(50, 50));
|
|
|
+ minimap->set_size(minimap_size);
|
|
|
+ minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT);
|
|
|
+ minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET);
|
|
|
+ minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET);
|
|
|
+ minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET);
|
|
|
+ minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET);
|
|
|
+ minimap->connect("draw", callable_mp(this, &GraphEdit::_minimap_draw));
|
|
|
+
|
|
|
setting_scroll_ofs = false;
|
|
|
just_disconnected = false;
|
|
|
set_clip_contents(true);
|