2016-06-18 14:46:12 +02:00
/*************************************************************************/
/* graph_edit.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2016-06-18 14:46:12 +02:00
/*************************************************************************/
2022-01-03 21:27:34 +01:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2016-06-18 14:46:12 +02:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2015-01-03 20:52:37 +01:00
# include "graph_edit.h"
2017-08-27 21:07:15 +02:00
2020-04-28 15:19:37 +02:00
# include "core/input/input.h"
2020-11-06 20:16:45 +01:00
# include "core/math/math_funcs.h"
2018-09-11 18:13:45 +02:00
# include "core/os/keyboard.h"
2016-01-19 02:10:44 +01:00
# include "scene/gui/box_container.h"
2020-06-19 20:49:04 +02:00
# include "scene/gui/button.h"
2021-09-28 18:00:16 +02:00
# include "scene/gui/view_panner.h"
2016-01-23 22:49:26 +01:00
2021-04-17 20:02:04 +02:00
constexpr int MINIMAP_OFFSET = 12 ;
constexpr int MINIMAP_PADDING = 5 ;
2020-11-06 20:16:45 +01:00
2017-03-05 16:44:50 +01:00
bool GraphEditFilter : : has_point ( const Point2 & p_point ) const {
2015-07-21 03:15:06 +02:00
return ge - > _filter_input ( p_point ) ;
2015-01-03 20:52:37 +01:00
}
GraphEditFilter : : GraphEditFilter ( GraphEdit * p_edit ) {
2017-03-05 16:44:50 +01:00
ge = p_edit ;
2015-01-03 20:52:37 +01:00
}
2020-11-06 20:16:45 +01:00
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 ;
}
2021-08-22 17:37:22 +02:00
void GraphEditMinimap : : gui_input ( const Ref < InputEvent > & p_ev ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_ev . is_null ( ) ) ;
2021-01-25 15:37:05 +01:00
if ( ! ge - > is_minimap_enabled ( ) ) {
return ;
}
2020-11-06 20:16:45 +01:00
Ref < InputEventMouseButton > mb = p_ev ;
Ref < InputEventMouseMotion > mm = p_ev ;
2021-08-13 23:31:57 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = MouseButton : : LEFT ) {
2020-11-06 20:16:45 +01:00
if ( mb - > is_pressed ( ) ) {
is_pressing = true ;
2021-07-17 23:22:52 +02:00
Ref < Texture2D > resizer = get_theme_icon ( SNAME ( " resizer " ) ) ;
2020-11-06 20:16:45 +01:00
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 ) {
2021-03-20 15:04:23 +01:00
// Prevent setting minimap wider than GraphEdit
Vector2 new_minimap_size ;
new_minimap_size . x = MIN ( get_size ( ) . x - mm - > get_relative ( ) . x , ge - > get_size ( ) . x - 2.0 * minimap_padding . x ) ;
new_minimap_size . y = MIN ( get_size ( ) . y - mm - > get_relative ( ) . y , ge - > get_size ( ) . y - 2.0 * minimap_padding . y ) ;
ge - > set_minimap_size ( new_minimap_size ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-11-06 20:16:45 +01:00
} 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 ) ;
}
2022-09-19 17:43:15 +02:00
PackedStringArray GraphEdit : : get_configuration_warnings ( ) const {
PackedStringArray warnings = Control : : get_configuration_warnings ( ) ;
2022-09-14 18:09:21 +02:00
warnings . push_back ( RTR ( " Please be aware that GraphEdit and GraphNode will undergo extensive refactoring in a future beta version involving compatibility-breaking API changes. " ) ) ;
return warnings ;
}
2017-03-05 16:44:50 +01:00
Error GraphEdit : : connect_node ( const StringName & p_from , int p_from_port , const StringName & p_to , int p_to_port ) {
2020-05-14 16:41:43 +02:00
if ( is_node_connected ( p_from , p_from_port , p_to , p_to_port ) ) {
2015-07-21 03:15:06 +02:00
return OK ;
2020-05-14 16:41:43 +02:00
}
2015-07-21 03:15:06 +02:00
Connection c ;
2017-03-05 16:44:50 +01:00
c . from = p_from ;
c . from_port = p_from_port ;
c . to = p_to ;
c . to_port = p_to_port ;
2018-06-19 03:10:48 +02:00
c . activity = 0 ;
2015-07-21 03:15:06 +02:00
connections . push_back ( c ) ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2015-07-21 03:15:06 +02:00
return OK ;
2015-01-03 20:52:37 +01:00
}
2017-03-05 16:44:50 +01:00
bool GraphEdit : : is_node_connected ( const StringName & p_from , int p_from_port , const StringName & p_to , int p_to_port ) {
2021-07-24 15:46:25 +02:00
for ( const Connection & E : connections ) {
2021-07-16 05:45:57 +02:00
if ( E . from = = p_from & & E . from_port = = p_from_port & & E . to = = p_to & & E . to_port = = p_to_port ) {
2015-07-21 03:15:06 +02:00
return true ;
2020-05-14 16:41:43 +02:00
}
2015-07-21 03:15:06 +02:00
}
2015-01-03 20:52:37 +01:00
2015-07-21 03:15:06 +02:00
return false ;
2015-01-03 20:52:37 +01:00
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : disconnect_node ( const StringName & p_from , int p_from_port , const StringName & p_to , int p_to_port ) {
2021-07-16 05:45:57 +02:00
for ( const List < Connection > : : Element * E = connections . front ( ) ; E ; E = E - > next ( ) ) {
2017-03-05 16:44:50 +01:00
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 ) {
2015-07-21 03:15:06 +02:00
connections . erase ( E ) ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2015-07-21 03:15:06 +02:00
return ;
}
}
2015-01-03 20:52:37 +01:00
}
2015-01-08 04:41:34 +01:00
void GraphEdit : : get_connection_list ( List < Connection > * r_connections ) const {
2017-03-05 16:44:50 +01:00
* r_connections = connections ;
2015-01-03 20:52:37 +01:00
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : set_scroll_ofs ( const Vector2 & p_ofs ) {
setting_scroll_ofs = true ;
2017-01-04 05:16:14 +01:00
h_scroll - > set_value ( p_ofs . x ) ;
v_scroll - > set_value ( p_ofs . y ) ;
2016-08-07 00:00:54 +02:00
_update_scroll ( ) ;
2017-03-05 16:44:50 +01:00
setting_scroll_ofs = false ;
2016-08-07 00:00:54 +02:00
}
2017-03-05 16:44:50 +01:00
Vector2 GraphEdit : : get_scroll_ofs ( ) const {
return Vector2 ( h_scroll - > get_value ( ) , v_scroll - > get_value ( ) ) ;
2016-01-17 22:26:32 +01:00
}
2015-01-03 20:52:37 +01:00
2016-01-17 22:26:32 +01:00
void GraphEdit : : _scroll_moved ( double ) {
2016-08-31 04:44:14 +02:00
if ( ! awaiting_scroll_offset_update ) {
2021-07-17 23:22:52 +02:00
call_deferred ( SNAME ( " _update_scroll_offset " ) ) ;
2017-03-05 16:44:50 +01:00
awaiting_scroll_offset_update = true ;
2016-08-31 04:44:14 +02:00
}
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
2016-08-07 00:00:54 +02:00
2017-03-05 16:44:50 +01:00
if ( ! setting_scroll_ofs ) { //in godot, signals on change value are avoided as a convention
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " scroll_offset_changed " ) , get_scroll_ofs ( ) ) ;
2016-08-07 00:00:54 +02:00
}
2015-01-03 20:52:37 +01:00
}
void GraphEdit : : _update_scroll_offset ( ) {
2016-08-31 04:44:14 +02:00
set_block_minimum_size_adjust ( true ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn ) {
2015-07-21 03:15:06 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-01-03 20:52:37 +01:00
2020-12-22 17:24:29 +01:00
Point2 pos = gn - > get_position_offset ( ) * zoom ;
2017-03-05 16:44:50 +01:00
pos - = Point2 ( h_scroll - > get_value ( ) , v_scroll - > get_value ( ) ) ;
2017-03-29 17:29:38 +02:00
gn - > set_position ( pos ) ;
2017-03-05 16:44:50 +01:00
if ( gn - > get_scale ( ) ! = Vector2 ( zoom , zoom ) ) {
gn - > set_scale ( Vector2 ( zoom , zoom ) ) ;
2016-08-31 04:44:14 +02:00
}
2015-07-21 03:15:06 +02:00
}
2015-01-03 20:52:37 +01:00
2017-03-29 17:29:38 +02:00
connections_layer - > set_position ( - Point2 ( h_scroll - > get_value ( ) , v_scroll - > get_value ( ) ) ) ;
2016-08-31 04:44:14 +02:00
set_block_minimum_size_adjust ( false ) ;
2017-03-05 16:44:50 +01:00
awaiting_scroll_offset_update = false ;
2015-01-03 20:52:37 +01:00
}
void GraphEdit : : _update_scroll ( ) {
2020-05-14 16:41:43 +02:00
if ( updating ) {
2015-07-21 03:15:06 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-01-03 20:52:37 +01:00
2017-03-05 16:44:50 +01:00
updating = true ;
2016-08-31 04:44:14 +02:00
set_block_minimum_size_adjust ( true ) ;
2015-07-21 03:15:06 +02:00
Rect2 screen ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn ) {
2015-07-21 03:15:06 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-01-03 20:52:37 +01:00
2015-07-21 03:15:06 +02:00
Rect2 r ;
2020-12-22 17:24:29 +01:00
r . position = gn - > get_position_offset ( ) * zoom ;
2017-03-05 16:44:50 +01:00
r . size = gn - > get_size ( ) * zoom ;
2015-07-21 03:15:06 +02:00
screen = screen . merge ( r ) ;
}
2015-01-03 20:52:37 +01:00
2017-06-04 00:25:13 +02:00
screen . position - = get_size ( ) ;
2017-03-05 16:44:50 +01:00
screen . size + = get_size ( ) * 2.0 ;
2015-01-08 04:41:34 +01:00
2017-06-04 00:25:13 +02:00
h_scroll - > set_min ( screen . position . x ) ;
h_scroll - > set_max ( screen . position . x + screen . size . x ) ;
2015-07-21 03:15:06 +02:00
h_scroll - > set_page ( get_size ( ) . x ) ;
2020-05-14 16:41:43 +02:00
if ( h_scroll - > get_max ( ) - h_scroll - > get_min ( ) < = h_scroll - > get_page ( ) ) {
2015-07-21 03:15:06 +02:00
h_scroll - > hide ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2015-07-21 03:15:06 +02:00
h_scroll - > show ( ) ;
2020-05-14 16:41:43 +02:00
}
2015-01-03 20:52:37 +01:00
2017-06-04 00:25:13 +02:00
v_scroll - > set_min ( screen . position . y ) ;
v_scroll - > set_max ( screen . position . y + screen . size . y ) ;
2015-07-21 03:15:06 +02:00
v_scroll - > set_page ( get_size ( ) . y ) ;
2015-01-03 20:52:37 +01:00
2020-05-14 16:41:43 +02:00
if ( v_scroll - > get_max ( ) - v_scroll - > get_min ( ) < = v_scroll - > get_page ( ) ) {
2015-07-21 03:15:06 +02:00
v_scroll - > hide ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2015-07-21 03:15:06 +02:00
v_scroll - > show ( ) ;
2020-05-14 16:41:43 +02:00
}
2015-01-03 20:52:37 +01:00
2020-01-14 02:49:17 +01:00
Size2 hmin = h_scroll - > get_combined_minimum_size ( ) ;
Size2 vmin = v_scroll - > get_combined_minimum_size ( ) ;
// Avoid scrollbar overlapping.
2020-12-22 17:24:29 +01:00
h_scroll - > set_anchor_and_offset ( SIDE_RIGHT , ANCHOR_END , v_scroll - > is_visible ( ) ? - vmin . width : 0 ) ;
v_scroll - > set_anchor_and_offset ( SIDE_BOTTOM , ANCHOR_END , h_scroll - > is_visible ( ) ? - hmin . height : 0 ) ;
2020-01-14 02:49:17 +01:00
2016-08-31 04:44:14 +02:00
set_block_minimum_size_adjust ( false ) ;
if ( ! awaiting_scroll_offset_update ) {
2021-07-17 23:22:52 +02:00
call_deferred ( SNAME ( " _update_scroll_offset " ) ) ;
2017-03-05 16:44:50 +01:00
awaiting_scroll_offset_update = true ;
2016-08-31 04:44:14 +02:00
}
2017-03-05 16:44:50 +01:00
updating = false ;
2015-01-03 20:52:37 +01:00
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : _graph_node_raised ( Node * p_gn ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( p_gn ) ;
2015-07-21 03:15:06 +02:00
ERR_FAIL_COND ( ! gn ) ;
2016-08-25 22:45:20 +02:00
if ( gn - > is_comment ( ) ) {
2017-03-05 16:44:50 +01:00
move_child ( gn , 0 ) ;
2017-08-08 15:57:33 +02:00
} else {
2022-04-10 20:52:55 +02:00
gn - > move_to_front ( ) ;
2016-08-25 22:45:20 +02:00
}
2022-08-24 16:57:17 +02:00
}
void GraphEdit : : _graph_node_selected ( Node * p_gn ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( p_gn ) ;
ERR_FAIL_COND ( ! gn ) ;
emit_signal ( SNAME ( " node_selected " ) , gn ) ;
}
void GraphEdit : : _graph_node_deselected ( Node * p_gn ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( p_gn ) ;
ERR_FAIL_COND ( ! gn ) ;
emit_signal ( SNAME ( " node_deselected " ) , gn ) ;
2015-01-03 20:52:37 +01:00
}
void GraphEdit : : _graph_node_moved ( Node * p_gn ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( p_gn ) ;
2015-07-21 03:15:06 +02:00
ERR_FAIL_COND ( ! gn ) ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2015-01-03 20:52:37 +01:00
}
2021-02-10 15:18:34 +01:00
void GraphEdit : : _graph_node_slot_updated ( int p_index , Node * p_gn ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( p_gn ) ;
ERR_FAIL_COND ( ! gn ) ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2021-02-10 15:18:34 +01:00
}
2015-01-03 20:52:37 +01:00
void GraphEdit : : add_child_notify ( Node * p_child ) {
2016-08-06 03:46:45 +02:00
Control : : add_child_notify ( p_child ) ;
2021-07-17 23:22:52 +02:00
top_layer - > call_deferred ( SNAME ( " raise " ) ) ; // Top layer always on top!
2020-11-06 20:16:45 +01:00
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( p_child ) ;
2015-07-21 03:15:06 +02:00
if ( gn ) {
2017-03-05 16:44:50 +01:00
gn - > set_scale ( Vector2 ( zoom , zoom ) ) ;
2022-07-28 22:56:41 +02:00
gn - > connect ( " position_offset_changed " , callable_mp ( this , & GraphEdit : : _graph_node_moved ) . bind ( gn ) ) ;
2022-08-24 16:57:17 +02:00
gn - > connect ( " selected " , callable_mp ( this , & GraphEdit : : _graph_node_selected ) . bind ( gn ) ) ;
gn - > connect ( " deselected " , callable_mp ( this , & GraphEdit : : _graph_node_deselected ) . bind ( gn ) ) ;
2022-07-28 22:56:41 +02:00
gn - > connect ( " slot_updated " , callable_mp ( this , & GraphEdit : : _graph_node_slot_updated ) . bind ( gn ) ) ;
gn - > connect ( " raise_request " , callable_mp ( this , & GraphEdit : : _graph_node_raised ) . bind ( gn ) ) ;
2022-08-13 23:21:24 +02:00
gn - > connect ( " item_rect_changed " , callable_mp ( ( CanvasItem * ) connections_layer , & CanvasItem : : queue_redraw ) ) ;
gn - > connect ( " item_rect_changed " , callable_mp ( ( CanvasItem * ) minimap , & GraphEditMinimap : : queue_redraw ) ) ;
2015-07-21 03:15:06 +02:00
_graph_node_moved ( gn ) ;
2020-02-07 10:09:39 +01:00
gn - > set_mouse_filter ( MOUSE_FILTER_PASS ) ;
2015-07-21 03:15:06 +02:00
}
2015-01-03 20:52:37 +01:00
}
void GraphEdit : : remove_child_notify ( Node * p_child ) {
2016-08-06 03:46:45 +02:00
Control : : remove_child_notify ( p_child ) ;
2020-11-06 20:16:45 +01:00
2021-01-13 01:49:49 +01:00
if ( p_child = = top_layer ) {
top_layer = nullptr ;
minimap = nullptr ;
} else if ( p_child = = connections_layer ) {
connections_layer = nullptr ;
}
if ( top_layer ! = nullptr & & is_inside_tree ( ) ) {
2021-07-17 23:22:52 +02:00
top_layer - > call_deferred ( SNAME ( " raise " ) ) ; // Top layer always on top!
2019-03-01 21:24:57 +01:00
}
2020-11-06 20:16:45 +01:00
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( p_child ) ;
2015-07-21 03:15:06 +02:00
if ( gn ) {
2020-12-26 10:48:40 +01:00
gn - > disconnect ( " position_offset_changed " , callable_mp ( this , & GraphEdit : : _graph_node_moved ) ) ;
2022-08-24 16:57:17 +02:00
gn - > disconnect ( " selected " , callable_mp ( this , & GraphEdit : : _graph_node_selected ) ) ;
gn - > disconnect ( " deselected " , callable_mp ( this , & GraphEdit : : _graph_node_deselected ) ) ;
2021-02-10 15:18:34 +01:00
gn - > disconnect ( " slot_updated " , callable_mp ( this , & GraphEdit : : _graph_node_slot_updated ) ) ;
2020-02-21 18:28:45 +01:00
gn - > disconnect ( " raise_request " , callable_mp ( this , & GraphEdit : : _graph_node_raised ) ) ;
2021-01-13 01:49:49 +01:00
// In case of the whole GraphEdit being destroyed these references can already be freed.
if ( connections_layer ! = nullptr & & connections_layer - > is_inside_tree ( ) ) {
2022-08-13 23:21:24 +02:00
gn - > disconnect ( " item_rect_changed " , callable_mp ( ( CanvasItem * ) connections_layer , & CanvasItem : : queue_redraw ) ) ;
2021-01-13 01:49:49 +01:00
}
if ( minimap ! = nullptr & & minimap - > is_inside_tree ( ) ) {
2022-08-13 23:21:24 +02:00
gn - > disconnect ( " item_rect_changed " , callable_mp ( ( CanvasItem * ) minimap , & GraphEditMinimap : : queue_redraw ) ) ;
2021-01-13 01:49:49 +01:00
}
2015-07-21 03:15:06 +02:00
}
2015-01-03 20:52:37 +01:00
}
void GraphEdit : : _notification ( int p_what ) {
2022-02-15 18:06:48 +01:00
switch ( p_what ) {
2022-08-29 11:04:31 +02:00
case NOTIFICATION_ENTER_TREE :
2022-02-15 18:06:48 +01:00
case NOTIFICATION_THEME_CHANGED : {
2022-05-30 15:48:58 +02:00
port_hotzone_inner_extent = get_theme_constant ( " port_hotzone_inner_extent " ) ;
port_hotzone_outer_extent = get_theme_constant ( " port_hotzone_outer_extent " ) ;
2022-02-15 18:06:48 +01:00
zoom_minus - > set_icon ( get_theme_icon ( SNAME ( " minus " ) ) ) ;
zoom_reset - > set_icon ( get_theme_icon ( SNAME ( " reset " ) ) ) ;
zoom_plus - > set_icon ( get_theme_icon ( SNAME ( " more " ) ) ) ;
snap_button - > set_icon ( get_theme_icon ( SNAME ( " snap " ) ) ) ;
minimap_button - > set_icon ( get_theme_icon ( SNAME ( " minimap " ) ) ) ;
layout_button - > set_icon ( get_theme_icon ( SNAME ( " layout " ) ) ) ;
zoom_label - > set_custom_minimum_size ( Size2 ( 48 , 0 ) * get_theme_default_base_scale ( ) ) ;
} break ;
case NOTIFICATION_READY : {
Size2 hmin = h_scroll - > get_combined_minimum_size ( ) ;
Size2 vmin = v_scroll - > get_combined_minimum_size ( ) ;
h_scroll - > set_anchor_and_offset ( SIDE_LEFT , ANCHOR_BEGIN , 0 ) ;
h_scroll - > set_anchor_and_offset ( SIDE_RIGHT , ANCHOR_END , 0 ) ;
h_scroll - > set_anchor_and_offset ( SIDE_TOP , ANCHOR_END , - hmin . height ) ;
h_scroll - > set_anchor_and_offset ( SIDE_BOTTOM , ANCHOR_END , 0 ) ;
v_scroll - > set_anchor_and_offset ( SIDE_LEFT , ANCHOR_END , - vmin . width ) ;
v_scroll - > set_anchor_and_offset ( SIDE_RIGHT , ANCHOR_END , 0 ) ;
v_scroll - > set_anchor_and_offset ( SIDE_TOP , ANCHOR_BEGIN , 0 ) ;
v_scroll - > set_anchor_and_offset ( SIDE_BOTTOM , ANCHOR_END , 0 ) ;
} break ;
case NOTIFICATION_DRAW : {
draw_style_box ( get_theme_stylebox ( SNAME ( " bg " ) ) , Rect2 ( Point2 ( ) , get_size ( ) ) ) ;
if ( is_using_snap ( ) ) {
// Draw grid.
int snap = get_snap ( ) ;
Vector2 offset = get_scroll_ofs ( ) / zoom ;
Size2 size = get_size ( ) / zoom ;
Point2i from = ( offset / float ( snap ) ) . floor ( ) ;
Point2i len = ( size / float ( snap ) ) . floor ( ) + Vector2 ( 1 , 1 ) ;
Color grid_minor = get_theme_color ( SNAME ( " grid_minor " ) ) ;
Color grid_major = get_theme_color ( SNAME ( " grid_major " ) ) ;
for ( int i = from . x ; i < from . x + len . x ; i + + ) {
Color color ;
if ( ABS ( i ) % 10 = = 0 ) {
color = grid_major ;
} else {
color = grid_minor ;
}
float base_ofs = i * snap * zoom - offset . x * zoom ;
draw_line ( Vector2 ( base_ofs , 0 ) , Vector2 ( base_ofs , get_size ( ) . height ) , color ) ;
2020-05-14 16:41:43 +02:00
}
2016-08-04 05:05:35 +02:00
2022-02-15 18:06:48 +01:00
for ( int i = from . y ; i < from . y + len . y ; i + + ) {
Color color ;
2016-08-04 05:05:35 +02:00
2022-02-15 18:06:48 +01:00
if ( ABS ( i ) % 10 = = 0 ) {
color = grid_major ;
} else {
color = grid_minor ;
}
2016-08-04 05:05:35 +02:00
2022-02-15 18:06:48 +01:00
float base_ofs = i * snap * zoom - offset . y * zoom ;
draw_line ( Vector2 ( 0 , base_ofs ) , Vector2 ( get_size ( ) . width , base_ofs ) , color ) ;
2020-05-14 16:41:43 +02:00
}
2016-08-04 05:05:35 +02:00
}
2022-02-15 18:06:48 +01:00
} break ;
2015-01-03 20:52:37 +01:00
2022-02-15 18:06:48 +01:00
case NOTIFICATION_RESIZED : {
_update_scroll ( ) ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
2022-02-15 18:06:48 +01:00
} break ;
2015-07-21 03:15:06 +02:00
}
2015-01-03 20:52:37 +01:00
}
2021-11-15 06:28:57 +01:00
void GraphEdit : : _update_comment_enclosed_nodes_list ( GraphNode * p_node , HashMap < StringName , Vector < GraphNode * > > & p_comment_enclosed_nodes ) {
Rect2 comment_node_rect = p_node - > get_rect ( ) ;
2022-06-02 13:14:46 +02:00
comment_node_rect . size * = zoom ;
2021-11-15 06:28:57 +01:00
2022-06-02 13:14:46 +02:00
Vector < GraphNode * > enclosed_nodes ;
2021-11-15 06:28:57 +01:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
if ( ! gn | | gn - > is_selected ( ) ) {
continue ;
}
Rect2 node_rect = gn - > get_rect ( ) ;
2022-06-02 13:14:46 +02:00
node_rect . size * = zoom ;
2021-11-15 06:28:57 +01:00
bool included = comment_node_rect . encloses ( node_rect ) ;
if ( included ) {
enclosed_nodes . push_back ( gn ) ;
}
}
2022-05-08 10:09:19 +02:00
p_comment_enclosed_nodes . insert ( p_node - > get_name ( ) , enclosed_nodes ) ;
2021-11-15 06:28:57 +01:00
}
void GraphEdit : : _set_drag_comment_enclosed_nodes ( GraphNode * p_node , HashMap < StringName , Vector < GraphNode * > > & p_comment_enclosed_nodes , bool p_drag ) {
for ( int i = 0 ; i < p_comment_enclosed_nodes [ p_node - > get_name ( ) ] . size ( ) ; i + + ) {
p_comment_enclosed_nodes [ p_node - > get_name ( ) ] [ i ] - > set_drag ( p_drag ) ;
}
}
void GraphEdit : : _set_position_of_comment_enclosed_nodes ( GraphNode * p_node , HashMap < StringName , Vector < GraphNode * > > & p_comment_enclosed_nodes , Vector2 p_drag_accum ) {
for ( int i = 0 ; i < p_comment_enclosed_nodes [ p_node - > get_name ( ) ] . size ( ) ; i + + ) {
Vector2 pos = ( p_comment_enclosed_nodes [ p_node - > get_name ( ) ] [ i ] - > get_drag_from ( ) * zoom + drag_accum ) / zoom ;
if ( is_using_snap ( ) ^ Input : : get_singleton ( ) - > is_key_pressed ( Key : : CTRL ) ) {
const int snap = get_snap ( ) ;
pos = pos . snapped ( Vector2 ( snap , snap ) ) ;
}
p_comment_enclosed_nodes [ p_node - > get_name ( ) ] [ i ] - > set_position_offset ( pos ) ;
}
}
2017-03-05 16:44:50 +01:00
bool GraphEdit : : _filter_input ( const Point2 & p_point ) {
2022-05-30 15:48:58 +02:00
Ref < Texture2D > port_icon = get_theme_icon ( SNAME ( " port " ) , SNAME ( " GraphNode " ) ) ;
2015-01-03 20:52:37 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn ) {
2015-07-21 03:15:06 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-01-03 20:52:37 +01:00
2022-05-30 15:48:58 +02:00
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 ) ) {
2015-07-21 03:15:06 +02:00
return true ;
2020-05-14 16:41:43 +02:00
}
2015-07-21 03:15:06 +02:00
}
2015-01-03 20:52:37 +01:00
2022-05-30 15:48:58 +02:00
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 ) ) {
2015-07-21 03:15:06 +02:00
return true ;
2016-09-07 00:55:22 +02:00
}
2015-07-21 03:15:06 +02:00
}
}
2015-01-03 20:52:37 +01:00
2015-07-21 03:15:06 +02:00
return false ;
2015-01-03 20:52:37 +01:00
}
2017-05-20 17:38:03 +02:00
void GraphEdit : : _top_layer_input ( const Ref < InputEvent > & p_ev ) {
Ref < InputEventMouseButton > mb = p_ev ;
2021-08-13 23:31:57 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = MouseButton : : LEFT & & mb - > is_pressed ( ) ) {
2022-05-30 15:48:58 +02:00
Ref < Texture2D > port_icon = get_theme_icon ( SNAME ( " port " ) , SNAME ( " GraphNode " ) ) ;
2021-08-11 16:43:05 +02:00
connecting_valid = false ;
2021-02-26 08:31:39 +01:00
click_pos = mb - > get_position ( ) / zoom ;
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn ) {
2015-07-21 03:15:06 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-01-03 20:52:37 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < gn - > get_connection_output_count ( ) ; j + + ) {
2017-09-10 15:37:49 +02:00
Vector2 pos = gn - > get_connection_output_position ( j ) + gn - > get_position ( ) ;
2022-05-30 15:48:58 +02:00
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 ) ) ;
2021-08-23 14:04:18 +02:00
if ( is_in_output_hotzone ( gn , j , click_pos , port_size ) ) {
2016-08-03 00:11:05 +02:00
if ( valid_left_disconnect_types . has ( gn - > get_connection_output_type ( j ) ) ) {
//check disconnect
2021-07-24 15:46:25 +02:00
for ( const Connection & E : connections ) {
2021-07-16 05:45:57 +02:00
if ( E . from = = gn - > get_name ( ) & & E . from_port = = j ) {
Node * to = get_node ( String ( E . to ) ) ;
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < GraphNode > ( to ) ) {
2021-07-16 05:45:57 +02:00
connecting_from = E . to ;
connecting_index = E . to_port ;
2017-03-05 16:44:50 +01:00
connecting_out = false ;
2021-07-16 05:45:57 +02:00
connecting_type = Object : : cast_to < GraphNode > ( to ) - > get_connection_input_type ( E . to_port ) ;
connecting_color = Object : : cast_to < GraphNode > ( to ) - > get_connection_input_color ( E . to_port ) ;
2017-03-05 16:44:50 +01:00
connecting_target = false ;
connecting_to = pos ;
2016-08-03 00:11:05 +02:00
2022-05-04 07:31:53 +02:00
if ( connecting_type > = 0 ) {
just_disconnected = true ;
emit_signal ( SNAME ( " disconnection_request " ) , E . from , E . from_port , E . to , E . to_port ) ;
to = get_node ( String ( connecting_from ) ) ; //maybe it was erased
if ( Object : : cast_to < GraphNode > ( to ) ) {
connecting = true ;
emit_signal ( SNAME ( " connection_drag_started " ) , connecting_from , connecting_index , false ) ;
}
2016-08-03 00:11:05 +02:00
}
return ;
}
}
}
}
2017-03-05 16:44:50 +01:00
connecting_from = gn - > get_name ( ) ;
connecting_index = j ;
connecting_out = true ;
connecting_type = gn - > get_connection_output_type ( j ) ;
connecting_color = gn - > get_connection_output_color ( j ) ;
connecting_target = false ;
connecting_to = pos ;
2022-05-04 07:31:53 +02:00
if ( connecting_type > = 0 ) {
connecting = true ;
just_disconnected = false ;
emit_signal ( SNAME ( " connection_drag_started " ) , connecting_from , connecting_index , true ) ;
}
2015-07-21 03:15:06 +02:00
return ;
}
}
2015-01-03 20:52:37 +01:00
2017-03-05 16:44:50 +01:00
for ( int j = 0 ; j < gn - > get_connection_input_count ( ) ; j + + ) {
2017-09-10 15:37:49 +02:00
Vector2 pos = gn - > get_connection_input_position ( j ) + gn - > get_position ( ) ;
2022-05-30 15:48:58 +02:00
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 ) ) ;
2021-08-23 14:04:18 +02:00
if ( is_in_input_hotzone ( gn , j , click_pos , port_size ) ) {
2016-08-03 00:11:05 +02:00
if ( right_disconnects | | valid_right_disconnect_types . has ( gn - > get_connection_input_type ( j ) ) ) {
2015-07-21 03:15:06 +02:00
//check disconnect
2021-07-24 15:46:25 +02:00
for ( const Connection & E : connections ) {
2021-07-16 05:45:57 +02:00
if ( E . to = = gn - > get_name ( ) & & E . to_port = = j ) {
Node * fr = get_node ( String ( E . from ) ) ;
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < GraphNode > ( fr ) ) {
2021-07-16 05:45:57 +02:00
connecting_from = E . from ;
connecting_index = E . from_port ;
2017-03-05 16:44:50 +01:00
connecting_out = true ;
2021-07-16 05:45:57 +02:00
connecting_type = Object : : cast_to < GraphNode > ( fr ) - > get_connection_output_type ( E . from_port ) ;
connecting_color = Object : : cast_to < GraphNode > ( fr ) - > get_connection_output_color ( E . from_port ) ;
2017-03-05 16:44:50 +01:00
connecting_target = false ;
connecting_to = pos ;
2018-10-19 13:31:35 +02:00
just_disconnected = true ;
2015-01-07 05:45:46 +01:00
2022-05-04 07:31:53 +02:00
if ( connecting_type > = 0 ) {
emit_signal ( SNAME ( " disconnection_request " ) , E . from , E . from_port , E . to , E . to_port ) ;
fr = get_node ( String ( connecting_from ) ) ; //maybe it was erased
if ( Object : : cast_to < GraphNode > ( fr ) ) {
connecting = true ;
emit_signal ( SNAME ( " connection_drag_started " ) , connecting_from , connecting_index , true ) ;
}
2015-07-21 03:15:06 +02:00
}
return ;
}
}
}
}
2015-01-07 05:45:46 +01:00
2017-03-05 16:44:50 +01:00
connecting_from = gn - > get_name ( ) ;
connecting_index = j ;
connecting_out = false ;
connecting_type = gn - > get_connection_input_type ( j ) ;
connecting_color = gn - > get_connection_input_color ( j ) ;
connecting_target = false ;
connecting_to = pos ;
2022-05-04 07:31:53 +02:00
if ( connecting_type > = 0 ) {
connecting = true ;
just_disconnected = false ;
emit_signal ( SNAME ( " connection_drag_started " ) , connecting_from , connecting_index , false ) ;
}
2015-07-21 03:15:06 +02:00
return ;
}
}
}
}
2015-01-03 20:52:37 +01:00
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseMotion > mm = p_ev ;
if ( mm . is_valid ( ) & & connecting ) {
2017-06-03 10:54:24 +02:00
connecting_to = mm - > get_position ( ) ;
2017-03-05 16:44:50 +01:00
connecting_target = false ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
2021-08-11 16:43:05 +02:00
connecting_valid = just_disconnected | | click_pos . distance_to ( connecting_to / zoom ) > 20.0 ;
2020-07-04 07:00:17 +02:00
if ( connecting_valid ) {
2021-02-26 08:31:39 +01:00
Vector2 mpos = mm - > get_position ( ) / zoom ;
2020-07-04 07:00:17 +02:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2022-05-30 15:48:58 +02:00
Ref < Texture2D > port_icon = get_theme_icon ( SNAME ( " port " ) , SNAME ( " GraphNode " ) ) ;
2020-07-04 07:00:17 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
if ( ! gn ) {
continue ;
}
2015-01-03 20:52:37 +01:00
2020-07-04 07:00:17 +02:00
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 ( ) ;
2022-05-30 15:48:58 +02:00
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 ) ) ;
2020-07-04 07:00:17 +02:00
int type = gn - > get_connection_output_type ( j ) ;
2022-04-11 00:34:59 +02:00
if ( ( type = = connecting_type | | valid_connection_types . has ( ConnType ( connecting_type , type ) ) ) & & is_in_output_hotzone ( gn , j , mpos , port_size ) ) {
2021-08-01 03:19:55 +02:00
if ( ! is_node_hover_valid ( gn - > get_name ( ) , j , connecting_from , connecting_index ) ) {
continue ;
}
2020-07-04 07:00:17 +02:00
connecting_target = true ;
connecting_to = pos ;
connecting_target_to = gn - > get_name ( ) ;
connecting_target_index = j ;
return ;
}
2015-07-21 03:15:06 +02:00
}
2020-07-04 07:00:17 +02:00
} else {
for ( int j = 0 ; j < gn - > get_connection_input_count ( ) ; j + + ) {
Vector2 pos = gn - > get_connection_input_position ( j ) + gn - > get_position ( ) ;
2022-05-30 15:48:58 +02:00
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 ) ) ;
2020-07-04 07:00:17 +02:00
int type = gn - > get_connection_input_type ( j ) ;
2022-04-11 00:34:59 +02:00
if ( ( type = = connecting_type | | valid_connection_types . has ( ConnType ( connecting_type , type ) ) ) & & is_in_input_hotzone ( gn , j , mpos , port_size ) ) {
2021-08-01 03:19:55 +02:00
if ( ! is_node_hover_valid ( connecting_from , connecting_index , gn - > get_name ( ) , j ) ) {
continue ;
}
2020-07-04 07:00:17 +02:00
connecting_target = true ;
connecting_to = pos ;
connecting_target_to = gn - > get_name ( ) ;
connecting_target_index = j ;
return ;
}
2015-07-21 03:15:06 +02:00
}
}
}
}
}
2015-01-03 20:52:37 +01:00
2021-08-13 23:31:57 +02:00
if ( mb . is_valid ( ) & & mb - > get_button_index ( ) = = MouseButton : : LEFT & & ! mb - > is_pressed ( ) ) {
2020-07-04 07:00:17 +02:00
if ( connecting_valid ) {
if ( connecting & & connecting_target ) {
String from = connecting_from ;
2022-09-09 15:29:51 +02:00
int from_port = connecting_index ;
2020-07-04 07:00:17 +02:00
String to = connecting_target_to ;
2022-09-09 15:29:51 +02:00
int to_port = connecting_target_index ;
2020-07-04 07:00:17 +02:00
if ( ! connecting_out ) {
SWAP ( from , to ) ;
2022-09-09 15:29:51 +02:00
SWAP ( from_port , to_port ) ;
2020-07-04 07:00:17 +02:00
}
2022-09-09 15:29:51 +02:00
emit_signal ( SNAME ( " connection_request " ) , from , from_port , to , to_port ) ;
2015-07-21 03:15:06 +02:00
2020-07-04 07:00:17 +02:00
} else if ( ! just_disconnected ) {
String from = connecting_from ;
2022-09-09 15:29:51 +02:00
int from_port = connecting_index ;
2021-09-23 16:58:43 +02:00
Vector2 ofs = mb - > get_position ( ) ;
2019-06-26 20:50:38 +02:00
2020-07-04 07:00:17 +02:00
if ( ! connecting_out ) {
2022-09-09 15:29:51 +02:00
emit_signal ( SNAME ( " connection_from_empty " ) , from , from_port , ofs ) ;
2020-07-04 07:00:17 +02:00
} else {
2022-09-09 15:29:51 +02:00
emit_signal ( SNAME ( " connection_to_empty " ) , from , from_port , ofs ) ;
2020-07-04 07:00:17 +02:00
}
2019-06-26 20:50:38 +02:00
}
2015-07-21 03:15:06 +02:00
}
2019-06-26 20:50:38 +02:00
2021-07-26 16:31:31 +02:00
if ( connecting ) {
force_connection_drag_end ( ) ;
}
2015-07-21 03:15:06 +02:00
}
2015-01-03 20:52:37 +01:00
}
2022-05-30 15:48:58 +02:00
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 ( ) ) {
2018-08-20 18:38:18 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-08-20 18:38:18 +02:00
2022-05-30 15:48:58 +02:00
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.
2018-08-20 18:38:18 +02:00
for ( int i = 0 ; i < p_control - > get_child_count ( ) ; i + + ) {
2022-05-30 15:48:58 +02:00
Control * child_rect = Object : : cast_to < Control > ( p_control - > get_child ( i ) ) ;
if ( ! child_rect ) {
2018-08-20 18:38:18 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2022-05-30 15:48:58 +02:00
if ( _check_clickable_control ( child_rect , mpos , control_rect . position ) ) {
2018-08-20 18:38:18 +02:00
return true ;
}
}
return false ;
} else {
return true ;
}
}
2022-09-09 15:29:51 +02:00
bool GraphEdit : : is_in_input_hotzone ( GraphNode * p_node , int p_port , const Vector2 & p_mouse_pos , const Vector2i & p_port_size ) {
2021-12-29 18:27:44 +01:00
bool success ;
2022-09-09 15:29:51 +02:00
if ( GDVIRTUAL_CALL ( _is_in_input_hotzone , p_node , p_port , p_mouse_pos , success ) ) {
2021-12-29 18:27:44 +01:00
return success ;
2021-08-11 16:43:05 +02:00
} else {
2022-09-09 15:29:51 +02:00
Vector2 pos = p_node - > get_connection_input_position ( p_port ) + p_node - > get_position ( ) ;
2021-08-23 14:04:18 +02:00
return is_in_port_hotzone ( pos / zoom , p_mouse_pos , p_port_size , true ) ;
}
}
2022-09-09 15:29:51 +02:00
bool GraphEdit : : is_in_output_hotzone ( GraphNode * p_node , int p_port , const Vector2 & p_mouse_pos , const Vector2i & p_port_size ) {
2021-12-29 18:27:44 +01:00
bool success ;
2022-09-09 15:29:51 +02:00
if ( GDVIRTUAL_CALL ( _is_in_output_hotzone , p_node , p_port , p_mouse_pos , success ) ) {
2021-12-29 18:27:44 +01:00
return success ;
2021-08-23 14:04:18 +02:00
} else {
2022-09-09 15:29:51 +02:00
Vector2 pos = p_node - > get_connection_output_position ( p_port ) + p_node - > get_position ( ) ;
2021-08-23 14:04:18 +02:00
return is_in_port_hotzone ( pos / zoom , p_mouse_pos , p_port_size , false ) ;
}
}
bool GraphEdit : : is_in_port_hotzone ( const Vector2 & pos , const Vector2 & p_mouse_pos , const Vector2i & p_port_size , bool p_left ) {
2022-05-30 15:48:58 +02:00
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 ) ) {
2021-08-23 14:04:18 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-08-20 18:38:18 +02:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
Control * child = Object : : cast_to < Control > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! child ) {
2018-08-20 18:38:18 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2022-05-30 15:48:58 +02:00
Rect2 child_rect = child - > get_rect ( ) ;
child_rect . size * = zoom ;
2018-08-20 18:38:18 +02:00
2022-05-30 15:48:58 +02:00
if ( child_rect . has_point ( p_mouse_pos * zoom ) ) {
2018-08-20 18:38:18 +02:00
for ( int j = 0 ; j < child - > get_child_count ( ) ; j + + ) {
Control * subchild = Object : : cast_to < Control > ( child - > get_child ( j ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! subchild ) {
2018-08-20 18:38:18 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-08-20 18:38:18 +02:00
2022-05-30 15:48:58 +02:00
if ( _check_clickable_control ( subchild , p_mouse_pos * zoom , child_rect . position ) ) {
2018-08-20 18:38:18 +02:00
return false ;
}
}
}
}
return true ;
2018-05-13 05:34:35 +02:00
}
2020-07-19 19:11:02 +02:00
PackedVector2Array GraphEdit : : get_connection_line ( const Vector2 & p_from , const Vector2 & p_to ) {
2021-08-22 17:37:22 +02:00
Vector < Vector2 > ret ;
if ( GDVIRTUAL_CALL ( _get_connection_line , p_from , p_to , ret ) ) {
return ret ;
2016-08-23 15:15:47 +02:00
}
2022-05-30 15:38:13 +02:00
float x_diff = ( p_to . x - p_from . x ) ;
float cp_offset = x_diff * lines_curvature ;
if ( x_diff < 0 ) {
cp_offset * = - 1 ;
}
2020-07-19 19:11:02 +02:00
Curve2D curve ;
curve . add_point ( p_from ) ;
2022-05-30 15:38:13 +02:00
curve . set_point_out ( 0 , Vector2 ( cp_offset , 0 ) ) ;
2020-07-19 19:11:02 +02:00
curve . add_point ( p_to ) ;
2022-05-30 15:38:13 +02:00
curve . set_point_in ( 1 , Vector2 ( - cp_offset , 0 ) ) ;
if ( lines_curvature > 0 ) {
return curve . tessellate ( 5 , 2.0 ) ;
} else {
return curve . tessellate ( 1 ) ;
}
2020-07-19 19:11:02 +02:00
}
2017-07-01 02:30:17 +02:00
2021-08-22 11:08:37 +02:00
void GraphEdit : : _draw_connection_line ( CanvasItem * p_where , const Vector2 & p_from , const Vector2 & p_to , const Color & p_color , const Color & p_to_color , float p_width , float p_zoom ) {
Vector < Vector2 > points = get_connection_line ( p_from / p_zoom , p_to / p_zoom ) ;
Vector < Vector2 > scaled_points ;
2017-07-01 02:30:17 +02:00
Vector < Color > colors ;
2021-08-22 21:09:16 +02:00
float length = ( p_from / p_zoom ) . distance_to ( p_to / p_zoom ) ;
2020-07-19 19:11:02 +02:00
for ( int i = 0 ; i < points . size ( ) ; i + + ) {
2021-08-22 21:09:16 +02:00
float d = ( p_from / p_zoom ) . distance_to ( points [ i ] ) / length ;
2020-07-19 19:11:02 +02:00
colors . push_back ( p_color . lerp ( p_to_color , d ) ) ;
2021-08-22 11:08:37 +02:00
scaled_points . push_back ( points [ i ] * p_zoom ) ;
2020-07-19 19:11:02 +02:00
}
2017-07-01 02:30:17 +02:00
2021-10-02 22:07:42 +02:00
p_where - > draw_polyline_colors ( scaled_points , colors , Math : : floor ( p_width * get_theme_default_base_scale ( ) ) , lines_antialiased ) ;
2015-01-03 20:52:37 +01:00
}
2016-08-31 04:44:14 +02:00
void GraphEdit : : _connections_layer_draw ( ) {
2021-07-17 23:22:52 +02:00
Color activity_color = get_theme_color ( SNAME ( " activity " ) ) ;
2017-08-27 21:07:15 +02:00
//draw connections
List < List < Connection > : : Element * > to_erase ;
for ( List < Connection > : : Element * E = connections . front ( ) ; E ; E = E - > next ( ) ) {
NodePath fromnp ( E - > get ( ) . from ) ;
2016-08-31 04:44:14 +02:00
2017-08-27 21:07:15 +02:00
Node * from = get_node ( fromnp ) ;
if ( ! from ) {
to_erase . push_back ( E ) ;
continue ;
}
2016-08-31 04:44:14 +02:00
2017-08-27 21:07:15 +02:00
GraphNode * gfrom = Object : : cast_to < GraphNode > ( from ) ;
2016-08-31 04:44:14 +02:00
2017-08-27 21:07:15 +02:00
if ( ! gfrom ) {
to_erase . push_back ( E ) ;
continue ;
}
2016-08-31 04:44:14 +02:00
2017-08-27 21:07:15 +02:00
NodePath tonp ( E - > get ( ) . to ) ;
Node * to = get_node ( tonp ) ;
if ( ! to ) {
to_erase . push_back ( E ) ;
continue ;
}
2016-08-31 04:44:14 +02:00
2017-08-27 21:07:15 +02:00
GraphNode * gto = Object : : cast_to < GraphNode > ( to ) ;
2016-08-31 04:44:14 +02:00
2017-08-27 21:07:15 +02:00
if ( ! gto ) {
to_erase . push_back ( E ) ;
continue ;
2016-08-31 04:44:14 +02:00
}
2020-12-22 17:24:29 +01:00
Vector2 frompos = gfrom - > get_connection_output_position ( E - > get ( ) . from_port ) + gfrom - > get_position_offset ( ) * zoom ;
2017-08-27 21:07:15 +02:00
Color color = gfrom - > get_connection_output_color ( E - > get ( ) . from_port ) ;
2020-12-22 17:24:29 +01:00
Vector2 topos = gto - > get_connection_input_position ( E - > get ( ) . to_port ) + gto - > get_position_offset ( ) * zoom ;
2017-08-27 21:07:15 +02:00
Color tocolor = gto - > get_connection_input_color ( E - > get ( ) . to_port ) ;
2018-06-19 03:10:48 +02:00
if ( E - > get ( ) . activity > 0 ) {
2020-03-16 10:07:33 +01:00
color = color . lerp ( activity_color , E - > get ( ) . activity ) ;
tocolor = tocolor . lerp ( activity_color , E - > get ( ) . activity ) ;
2018-06-19 03:10:48 +02:00
}
2021-08-22 11:08:37 +02:00
_draw_connection_line ( connections_layer , frompos , topos , color , tocolor , lines_thickness , zoom ) ;
2017-08-27 21:07:15 +02:00
}
while ( to_erase . size ( ) ) {
connections . erase ( to_erase . front ( ) - > get ( ) ) ;
to_erase . pop_front ( ) ;
2016-08-31 04:44:14 +02:00
}
}
2015-01-03 20:52:37 +01:00
void GraphEdit : : _top_layer_draw ( ) {
2015-07-21 03:15:06 +02:00
_update_scroll ( ) ;
if ( connecting ) {
Node * fromn = get_node ( connecting_from ) ;
ERR_FAIL_COND ( ! fromn ) ;
2017-08-24 22:58:51 +02:00
GraphNode * from = Object : : cast_to < GraphNode > ( fromn ) ;
2015-07-21 03:15:06 +02:00
ERR_FAIL_COND ( ! from ) ;
Vector2 pos ;
2020-05-14 16:41:43 +02:00
if ( connecting_out ) {
2017-09-10 15:37:49 +02:00
pos = from - > get_connection_output_position ( connecting_index ) ;
2020-05-14 16:41:43 +02:00
} else {
2017-09-10 15:37:49 +02:00
pos = from - > get_connection_input_position ( connecting_index ) ;
2020-05-14 16:41:43 +02:00
}
2017-03-29 17:29:38 +02:00
pos + = from - > get_position ( ) ;
2015-07-21 03:15:06 +02:00
Vector2 topos ;
2017-03-05 16:44:50 +01:00
topos = connecting_to ;
2015-07-21 03:15:06 +02:00
2017-03-05 16:44:50 +01:00
Color col = connecting_color ;
2015-07-21 03:15:06 +02:00
if ( connecting_target ) {
2017-03-05 16:44:50 +01:00
col . r + = 0.4 ;
col . g + = 0.4 ;
col . b + = 0.4 ;
2015-07-21 03:15:06 +02:00
}
2016-08-25 22:45:20 +02:00
if ( ! connecting_out ) {
2017-03-05 16:44:50 +01:00
SWAP ( pos , topos ) ;
2016-08-25 22:45:20 +02:00
}
2021-08-22 11:08:37 +02:00
_draw_connection_line ( top_layer , pos , topos , col , col , lines_thickness , zoom ) ;
2015-07-21 03:15:06 +02:00
}
2019-08-15 22:17:08 +02:00
if ( box_selecting ) {
2021-07-17 23:22:52 +02:00
top_layer - > draw_rect ( box_selecting_rect , get_theme_color ( SNAME ( " selection_fill " ) ) ) ;
top_layer - > draw_rect ( box_selecting_rect , get_theme_color ( SNAME ( " selection_stroke " ) ) , false ) ;
2019-08-15 22:17:08 +02:00
}
2015-01-03 20:52:37 +01:00
}
2020-11-06 20:16:45 +01:00
void GraphEdit : : _minimap_draw ( ) {
if ( ! is_minimap_enabled ( ) ) {
return ;
}
minimap - > update_minimap ( ) ;
// Draw the minimap background.
Rect2 minimap_rect = Rect2 ( Point2 ( ) , minimap - > get_size ( ) ) ;
2021-07-17 23:22:52 +02:00
minimap - > draw_style_box ( minimap - > get_theme_stylebox ( SNAME ( " bg " ) ) , minimap_rect ) ;
2020-11-06 20:16:45 +01:00
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 ;
}
2020-12-22 17:24:29 +01:00
Vector2 node_position = minimap - > _convert_from_graph_position ( gn - > get_position_offset ( ) * zoom - graph_offset ) + minimap_offset ;
2020-11-06 20:16:45 +01:00
Vector2 node_size = minimap - > _convert_from_graph_position ( gn - > get_size ( ) * zoom ) ;
Rect2 node_rect = Rect2 ( node_position , node_size ) ;
2021-07-17 23:22:52 +02:00
Ref < StyleBoxFlat > sb_minimap = minimap - > get_theme_stylebox ( SNAME ( " node " ) ) - > duplicate ( ) ;
2020-11-06 20:16:45 +01:00
// Override default values with colors provided by the GraphNode's stylebox, if possible.
2022-04-14 23:20:28 +02:00
Ref < StyleBoxFlat > sbf = gn - > get_theme_stylebox ( gn - > is_selected ( ) ? " comment_focus " : " comment " ) ;
2020-11-06 20:16:45 +01:00
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 ;
}
2020-12-22 17:24:29 +01:00
Vector2 node_position = minimap - > _convert_from_graph_position ( gn - > get_position_offset ( ) * zoom - graph_offset ) + minimap_offset ;
2020-11-06 20:16:45 +01:00
Vector2 node_size = minimap - > _convert_from_graph_position ( gn - > get_size ( ) * zoom ) ;
Rect2 node_rect = Rect2 ( node_position , node_size ) ;
2021-07-17 23:22:52 +02:00
Ref < StyleBoxFlat > sb_minimap = minimap - > get_theme_stylebox ( SNAME ( " node " ) ) - > duplicate ( ) ;
2020-11-06 20:16:45 +01:00
// Override default values with colors provided by the GraphNode's stylebox, if possible.
2022-04-14 23:20:28 +02:00
Ref < StyleBoxFlat > sbf = gn - > get_theme_stylebox ( gn - > is_selected ( ) ? " selected_frame " : " frame " ) ;
2020-11-06 20:16:45 +01:00
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.
2021-07-17 23:22:52 +02:00
Color activity_color = get_theme_color ( SNAME ( " activity " ) ) ;
2021-07-24 15:46:25 +02:00
for ( const Connection & E : connections ) {
2021-07-16 05:45:57 +02:00
NodePath fromnp ( E . from ) ;
2020-11-06 20:16:45 +01:00
Node * from = get_node ( fromnp ) ;
if ( ! from ) {
continue ;
}
GraphNode * gfrom = Object : : cast_to < GraphNode > ( from ) ;
if ( ! gfrom ) {
continue ;
}
2021-07-16 05:45:57 +02:00
NodePath tonp ( E . to ) ;
2020-11-06 20:16:45 +01:00
Node * to = get_node ( tonp ) ;
if ( ! to ) {
continue ;
}
GraphNode * gto = Object : : cast_to < GraphNode > ( to ) ;
if ( ! gto ) {
continue ;
}
2022-09-09 15:29:51 +02:00
Vector2 from_port_position = gfrom - > get_position_offset ( ) * zoom + gfrom - > get_connection_output_position ( E . from_port ) ;
Vector2 from_position = minimap - > _convert_from_graph_position ( from_port_position - graph_offset ) + minimap_offset ;
2021-07-16 05:45:57 +02:00
Color from_color = gfrom - > get_connection_output_color ( E . from_port ) ;
2022-09-09 15:29:51 +02:00
Vector2 to_port_position = gto - > get_position_offset ( ) * zoom + gto - > get_connection_input_position ( E . to_port ) ;
Vector2 to_position = minimap - > _convert_from_graph_position ( to_port_position - graph_offset ) + minimap_offset ;
2021-07-16 05:45:57 +02:00
Color to_color = gto - > get_connection_input_color ( E . to_port ) ;
2020-11-06 20:16:45 +01:00
2021-07-16 05:45:57 +02:00
if ( E . activity > 0 ) {
from_color = from_color . lerp ( activity_color , E . activity ) ;
to_color = to_color . lerp ( activity_color , E . activity ) ;
2020-11-06 20:16:45 +01:00
}
2021-08-22 11:08:37 +02:00
_draw_connection_line ( minimap , from_position , to_position , from_color , to_color , 0.1 , minimap - > _convert_from_graph_position ( Vector2 ( zoom , zoom ) ) . length ( ) ) ;
2020-11-06 20:16:45 +01:00
}
// Draw the "camera" viewport.
Rect2 camera_rect = minimap - > get_camera_rect ( ) ;
2021-07-17 23:22:52 +02:00
minimap - > draw_style_box ( minimap - > get_theme_stylebox ( SNAME ( " camera " ) ) , camera_rect ) ;
2020-11-06 20:16:45 +01:00
// Draw the resizer control.
2021-07-17 23:22:52 +02:00
Ref < Texture2D > resizer = minimap - > get_theme_icon ( SNAME ( " resizer " ) ) ;
Color resizer_color = minimap - > get_theme_color ( SNAME ( " resizer_color " ) ) ;
2020-11-06 20:16:45 +01:00
minimap - > draw_texture ( resizer , Point2 ( ) , resizer_color ) ;
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : set_selected ( Node * p_child ) {
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn ) {
2016-08-03 00:11:05 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-08-03 00:11:05 +02:00
2017-03-05 16:44:50 +01:00
gn - > set_selected ( gn = = p_child ) ;
2016-08-03 00:11:05 +02:00
}
}
2021-08-22 17:37:22 +02:00
void GraphEdit : : gui_input ( const Ref < InputEvent > & p_ev ) {
2021-04-05 08:52:21 +02:00
ERR_FAIL_COND ( p_ev . is_null ( ) ) ;
2022-01-19 19:59:12 +01:00
if ( panner - > gui_input ( p_ev , warped_panning ? get_global_rect ( ) : Rect2 ( ) ) ) {
return ;
}
2021-04-05 08:52:21 +02:00
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseMotion > mm = p_ev ;
2015-07-19 06:48:46 +02:00
2017-05-20 17:38:03 +02:00
if ( mm . is_valid ( ) & & dragging ) {
2020-10-20 03:25:07 +02:00
if ( ! moving_selection ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " begin_node_move " ) ) ;
2020-10-20 03:25:07 +02:00
moving_selection = true ;
}
2017-03-05 16:44:50 +01:00
just_selected = true ;
2020-05-04 20:36:52 +02:00
drag_accum + = mm - > get_relative ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2022-05-04 07:31:53 +02:00
if ( gn & & gn - > is_selected ( ) & & gn - > is_draggable ( ) ) {
2017-03-05 16:44:50 +01:00
Vector2 pos = ( gn - > get_drag_from ( ) * zoom + drag_accum ) / zoom ;
2019-11-15 19:34:44 +01:00
// Snapping can be toggled temporarily by holding down Ctrl.
// This is done here as to not toggle the grid when holding down Ctrl.
2021-08-13 23:31:57 +02:00
if ( is_using_snap ( ) ^ Input : : get_singleton ( ) - > is_key_pressed ( Key : : CTRL ) ) {
2019-11-15 19:34:44 +01:00
const int snap = get_snap ( ) ;
2017-03-05 16:44:50 +01:00
pos = pos . snapped ( Vector2 ( snap , snap ) ) ;
2016-08-04 05:05:35 +02:00
}
2020-12-22 17:24:29 +01:00
gn - > set_position_offset ( pos ) ;
2021-11-15 06:28:57 +01:00
if ( gn - > is_comment ( ) ) {
_set_position_of_comment_enclosed_nodes ( gn , comment_enclosed_nodes , drag_accum ) ;
}
2016-08-04 05:05:35 +02:00
}
2015-07-21 03:15:06 +02:00
}
}
2015-07-19 06:48:46 +02:00
2017-05-20 17:38:03 +02:00
if ( mm . is_valid ( ) & & box_selecting ) {
2020-05-04 20:36:52 +02:00
box_selecting_to = mm - > get_position ( ) ;
2015-07-25 02:59:48 +02:00
2021-09-29 05:51:34 +02:00
box_selecting_rect = Rect2 ( box_selecting_from . min ( box_selecting_to ) , ( box_selecting_from - box_selecting_to ) . abs ( ) ) ;
2015-07-25 02:59:48 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn ) {
2015-07-25 02:59:48 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-07-25 02:59:48 +02:00
2016-01-19 00:32:37 +01:00
Rect2 r = gn - > get_rect ( ) ;
2017-03-05 16:44:50 +01:00
r . size * = zoom ;
2016-01-19 00:32:37 +01:00
bool in_box = r . intersects ( box_selecting_rect ) ;
2015-07-25 02:59:48 +02:00
2020-05-14 16:41:43 +02:00
if ( in_box ) {
2022-08-24 16:57:17 +02:00
gn - > set_selected ( box_selection_mode_additive ) ;
2020-05-14 16:41:43 +02:00
} else {
2022-08-24 16:57:17 +02:00
gn - > set_selected ( previous_selected . find ( gn ) ! = nullptr ) ;
2020-05-14 16:41:43 +02:00
}
2015-07-25 02:59:48 +02:00
}
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
2015-07-25 02:59:48 +02:00
}
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseButton > b = p_ev ;
if ( b . is_valid ( ) ) {
2021-08-13 23:31:57 +02:00
if ( b - > get_button_index ( ) = = MouseButton : : RIGHT & & b - > is_pressed ( ) ) {
2015-07-25 02:59:48 +02:00
if ( box_selecting ) {
box_selecting = false ;
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn ) {
2015-07-25 02:59:48 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-07-25 02:59:48 +02:00
2022-08-24 16:57:17 +02:00
gn - > set_selected ( previous_selected . find ( gn ) ! = nullptr ) ;
2015-07-25 02:59:48 +02:00
}
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
2015-07-25 02:59:48 +02:00
} else {
2016-01-19 00:32:37 +01:00
if ( connecting ) {
2021-07-26 16:31:31 +02:00
force_connection_drag_end ( ) ;
2016-01-19 00:32:37 +01:00
} else {
2022-03-12 09:28:32 +01:00
emit_signal ( SNAME ( " popup_request " ) , b - > get_position ( ) ) ;
2016-01-19 00:32:37 +01:00
}
2015-07-25 02:59:48 +02:00
}
2015-07-21 03:15:06 +02:00
}
2015-07-19 06:48:46 +02:00
2021-08-13 23:31:57 +02:00
if ( b - > get_button_index ( ) = = MouseButton : : LEFT & & ! b - > is_pressed ( ) & & dragging ) {
if ( ! just_selected & & drag_accum = = Vector2 ( ) & & Input : : get_singleton ( ) - > is_key_pressed ( Key : : CTRL ) ) {
2015-07-21 03:15:06 +02:00
//deselect current node
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2015-07-19 06:48:46 +02:00
2016-01-19 00:32:37 +01:00
if ( gn ) {
Rect2 r = gn - > get_rect ( ) ;
2017-03-05 16:44:50 +01:00
r . size * = zoom ;
2020-05-04 20:36:52 +02:00
if ( r . has_point ( b - > get_position ( ) ) ) {
2016-01-19 00:32:37 +01:00
gn - > set_selected ( false ) ;
2020-05-14 16:41:43 +02:00
}
2016-01-19 00:32:37 +01:00
}
2015-07-21 03:15:06 +02:00
}
}
2015-07-19 06:48:46 +02:00
2017-03-05 16:44:50 +01:00
if ( drag_accum ! = Vector2 ( ) ) {
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( gn & & gn - > is_selected ( ) ) {
2015-07-21 03:15:06 +02:00
gn - > set_drag ( false ) ;
2021-11-15 06:28:57 +01:00
if ( gn - > is_comment ( ) ) {
_set_drag_comment_enclosed_nodes ( gn , comment_enclosed_nodes , false ) ;
}
2020-05-14 16:41:43 +02:00
}
2015-07-21 03:15:06 +02:00
}
2020-10-20 03:25:07 +02:00
}
2015-07-19 06:48:46 +02:00
2020-10-20 03:25:07 +02:00
if ( moving_selection ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " end_node_move " ) ) ;
2020-10-20 03:25:07 +02:00
moving_selection = false ;
2015-07-21 03:15:06 +02:00
}
2015-07-19 06:48:46 +02:00
2015-07-21 03:15:06 +02:00
dragging = false ;
2015-07-19 06:48:46 +02:00
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2015-07-21 03:15:06 +02:00
}
2015-07-19 06:48:46 +02:00
2021-08-13 23:31:57 +02:00
if ( b - > get_button_index ( ) = = MouseButton : : LEFT & & b - > is_pressed ( ) ) {
2020-04-02 01:20:12 +02:00
GraphNode * gn = nullptr ;
2017-08-08 15:57:33 +02:00
2022-08-24 16:57:17 +02:00
// Find node which was clicked on.
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2017-08-24 22:58:51 +02:00
GraphNode * gn_selected = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2015-07-19 06:48:46 +02:00
2022-08-24 16:57:17 +02:00
if ( ! gn_selected ) {
continue ;
}
2016-08-25 22:45:20 +02:00
2022-08-24 16:57:17 +02:00
if ( gn_selected - > is_resizing ( ) ) {
continue ;
}
if ( gn_selected - > has_point ( ( b - > get_position ( ) - gn_selected - > get_position ( ) ) / zoom ) ) {
gn = gn_selected ;
break ;
2016-01-19 00:32:37 +01:00
}
2015-07-21 03:15:06 +02:00
}
2015-07-19 06:48:46 +02:00
2015-07-21 03:15:06 +02:00
if ( gn ) {
2020-05-14 16:41:43 +02:00
if ( _filter_input ( b - > get_position ( ) ) ) {
2015-07-21 03:15:06 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-07-19 06:48:46 +02:00
2022-08-24 16:57:17 +02:00
// Left-clicked on a node, select it.
2015-07-21 03:15:06 +02:00
dragging = true ;
drag_accum = Vector2 ( ) ;
just_selected = ! gn - > is_selected ( ) ;
2021-08-13 23:31:57 +02:00
if ( ! gn - > is_selected ( ) & & ! Input : : get_singleton ( ) - > is_key_pressed ( Key : : CTRL ) ) {
2015-07-21 03:15:06 +02:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-08-24 22:58:51 +02:00
GraphNode * o_gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2022-08-24 16:57:17 +02:00
if ( ! o_gn ) {
continue ;
2020-04-10 22:00:50 +02:00
}
2022-08-24 16:57:17 +02:00
o_gn - > set_selected ( o_gn = = gn ) ;
2015-07-21 03:15:06 +02:00
}
}
2015-07-19 06:48:46 +02:00
2022-08-24 16:57:17 +02:00
gn - > set_selected ( true ) ;
2015-07-21 03:15:06 +02:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-08-24 22:58:51 +02:00
GraphNode * o_gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! o_gn ) {
2015-07-21 03:15:06 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
if ( o_gn - > is_selected ( ) ) {
2015-07-21 03:15:06 +02:00
o_gn - > set_drag ( true ) ;
2021-11-15 06:28:57 +01:00
if ( o_gn - > is_comment ( ) ) {
_update_comment_enclosed_nodes_list ( o_gn , comment_enclosed_nodes ) ;
_set_drag_comment_enclosed_nodes ( o_gn , comment_enclosed_nodes , true ) ;
}
2020-05-14 16:41:43 +02:00
}
2015-07-21 03:15:06 +02:00
}
2015-07-19 06:48:46 +02:00
2015-07-21 03:15:06 +02:00
} else {
2020-05-14 16:41:43 +02:00
if ( _filter_input ( b - > get_position ( ) ) ) {
2016-01-19 00:32:37 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-01-19 19:59:12 +01:00
if ( panner - > is_panning ( ) ) {
2016-02-08 20:28:12 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-01-19 00:32:37 +01:00
2022-08-24 16:57:17 +02:00
// Left-clicked on empty space, start box select.
2015-07-25 02:59:48 +02:00
box_selecting = true ;
2020-05-04 20:36:52 +02:00
box_selecting_from = b - > get_position ( ) ;
2021-04-24 22:33:50 +02:00
if ( b - > is_ctrl_pressed ( ) ) {
2020-04-10 22:00:50 +02:00
box_selection_mode_additive = true ;
2021-03-25 12:08:38 +01:00
previous_selected . clear ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2019-02-12 21:10:08 +01:00
GraphNode * gn2 = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn2 | | ! gn2 - > is_selected ( ) ) {
2015-07-25 02:59:48 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-07-25 02:59:48 +02:00
2021-03-25 12:08:38 +01:00
previous_selected . push_back ( gn2 ) ;
2015-07-25 02:59:48 +02:00
}
2021-04-24 22:33:50 +02:00
} else if ( b - > is_shift_pressed ( ) ) {
2020-04-10 22:00:50 +02:00
box_selection_mode_additive = false ;
2021-03-25 12:08:38 +01:00
previous_selected . clear ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2019-02-12 21:10:08 +01:00
GraphNode * gn2 = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn2 | | ! gn2 - > is_selected ( ) ) {
2015-07-25 02:59:48 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-07-19 06:48:46 +02:00
2021-03-25 12:08:38 +01:00
previous_selected . push_back ( gn2 ) ;
2015-07-25 02:59:48 +02:00
}
} else {
2020-04-10 22:00:50 +02:00
box_selection_mode_additive = true ;
2021-03-25 12:08:38 +01:00
previous_selected . clear ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2019-02-12 21:10:08 +01:00
GraphNode * gn2 = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
2020-05-14 16:41:43 +02:00
if ( ! gn2 ) {
2015-07-25 02:59:48 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2022-08-24 16:57:17 +02:00
2019-02-12 21:10:08 +01:00
gn2 - > set_selected ( false ) ;
2015-07-25 02:59:48 +02:00
}
2015-07-21 03:15:06 +02:00
}
}
}
2015-07-25 02:59:48 +02:00
2021-08-13 23:31:57 +02:00
if ( b - > get_button_index ( ) = = MouseButton : : LEFT & & ! b - > is_pressed ( ) & & box_selecting ) {
2022-08-24 16:57:17 +02:00
// Box selection ended. Nodes were selected during mouse movement.
2015-07-25 02:59:48 +02:00
box_selecting = false ;
2021-03-25 05:21:34 +01:00
box_selecting_rect = Rect2 ( ) ;
2021-03-25 12:08:38 +01:00
previous_selected . clear ( ) ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
2015-07-25 02:59:48 +02:00
}
2015-07-21 03:15:06 +02:00
}
2015-07-26 02:16:07 +02:00
2020-12-07 12:32:00 +01:00
if ( p_ev - > is_pressed ( ) ) {
if ( p_ev - > is_action ( " ui_graph_duplicate " ) ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " duplicate_nodes_request " ) ) ;
2019-07-12 19:36:33 +02:00
accept_event ( ) ;
2020-12-07 12:32:00 +01:00
} else if ( p_ev - > is_action ( " ui_copy " ) ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " copy_nodes_request " ) ) ;
2019-07-12 19:36:33 +02:00
accept_event ( ) ;
2020-12-07 12:32:00 +01:00
} else if ( p_ev - > is_action ( " ui_paste " ) ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " paste_nodes_request " ) ) ;
2019-07-12 19:36:33 +02:00
accept_event ( ) ;
2020-12-07 12:32:00 +01:00
} else if ( p_ev - > is_action ( " ui_graph_delete " ) ) {
2022-05-17 12:13:35 +02:00
TypedArray < StringName > nodes ;
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
if ( ! gn ) {
continue ;
}
if ( gn - > is_selected ( ) & & gn - > is_close_button_visible ( ) ) {
nodes . push_back ( gn - > get_name ( ) ) ;
}
}
emit_signal ( SNAME ( " delete_nodes_request " ) , nodes ) ;
2019-07-12 19:36:33 +02:00
accept_event ( ) ;
}
2015-07-27 02:57:27 +02:00
}
2017-11-01 21:49:39 +01:00
Ref < InputEventMagnifyGesture > magnify_gesture = p_ev ;
if ( magnify_gesture . is_valid ( ) ) {
set_zoom_custom ( zoom * magnify_gesture - > get_factor ( ) , magnify_gesture - > get_position ( ) ) ;
}
Ref < InputEventPanGesture > pan_gesture = p_ev ;
if ( pan_gesture . is_valid ( ) ) {
h_scroll - > set_value ( h_scroll - > get_value ( ) + h_scroll - > get_page ( ) * pan_gesture - > get_delta ( ) . x / 8 ) ;
v_scroll - > set_value ( v_scroll - > get_value ( ) + v_scroll - > get_page ( ) * pan_gesture - > get_delta ( ) . y / 8 ) ;
}
2015-01-03 20:52:37 +01:00
}
2022-01-23 13:49:53 +01:00
void GraphEdit : : _scroll_callback ( Vector2 p_scroll_vec , bool p_alt ) {
2021-09-28 18:00:16 +02:00
if ( p_scroll_vec . x ! = 0 ) {
h_scroll - > set_value ( h_scroll - > get_value ( ) + ( h_scroll - > get_page ( ) * Math : : abs ( p_scroll_vec . x ) / 8 ) * SIGN ( p_scroll_vec . x ) ) ;
} else {
v_scroll - > set_value ( v_scroll - > get_value ( ) + ( v_scroll - > get_page ( ) * Math : : abs ( p_scroll_vec . y ) / 8 ) * SIGN ( p_scroll_vec . y ) ) ;
}
}
void GraphEdit : : _pan_callback ( Vector2 p_scroll_vec ) {
h_scroll - > set_value ( h_scroll - > get_value ( ) - p_scroll_vec . x ) ;
v_scroll - > set_value ( v_scroll - > get_value ( ) - p_scroll_vec . y ) ;
}
2022-01-19 19:59:12 +01:00
void GraphEdit : : _zoom_callback ( Vector2 p_scroll_vec , Vector2 p_origin , bool p_alt ) {
2021-09-28 18:00:16 +02:00
set_zoom_custom ( p_scroll_vec . y < 0 ? zoom * zoom_step : zoom / zoom_step , p_origin ) ;
}
2018-06-19 03:10:48 +02:00
void GraphEdit : : set_connection_activity ( const StringName & p_from , int p_from_port , const StringName & p_to , int p_to_port , float p_activity ) {
2021-07-16 05:45:57 +02:00
for ( Connection & E : connections ) {
if ( E . from = = p_from & & E . from_port = = p_from_port & & E . to = = p_to & & E . to_port = = p_to_port ) {
if ( Math : : is_equal_approx ( E . activity , p_activity ) ) {
2018-06-19 03:10:48 +02:00
//update only if changed
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2018-06-19 03:10:48 +02:00
}
2021-07-16 05:45:57 +02:00
E . activity = p_activity ;
2018-06-19 03:10:48 +02:00
return ;
}
}
}
2015-01-03 20:52:37 +01:00
void GraphEdit : : clear_connections ( ) {
2015-07-21 03:15:06 +02:00
connections . clear ( ) ;
2022-08-13 23:21:24 +02:00
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2015-01-03 20:52:37 +01:00
}
2021-07-26 16:31:31 +02:00
void GraphEdit : : force_connection_drag_end ( ) {
ERR_FAIL_COND_MSG ( ! connecting , " Drag end requested without active drag! " ) ;
connecting = false ;
connecting_valid = false ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
minimap - > queue_redraw ( ) ;
queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2021-07-26 16:31:31 +02:00
emit_signal ( SNAME ( " connection_drag_ended " ) ) ;
}
2021-08-01 03:19:55 +02:00
bool GraphEdit : : is_node_hover_valid ( const StringName & p_from , const int p_from_port , const StringName & p_to , const int p_to_port ) {
bool valid ;
if ( GDVIRTUAL_CALL ( _is_node_hover_valid , p_from , p_from_port , p_to , p_to_port , valid ) ) {
return valid ;
}
return true ;
}
2021-09-28 18:00:16 +02:00
void GraphEdit : : set_panning_scheme ( PanningScheme p_scheme ) {
panning_scheme = p_scheme ;
panner - > set_control_scheme ( ( ViewPanner : : ControlScheme ) p_scheme ) ;
}
GraphEdit : : PanningScheme GraphEdit : : get_panning_scheme ( ) const {
return panning_scheme ;
}
2016-01-19 00:32:37 +01:00
void GraphEdit : : set_zoom ( float p_zoom ) {
2017-11-01 21:49:39 +01:00
set_zoom_custom ( p_zoom , get_size ( ) / 2 ) ;
}
void GraphEdit : : set_zoom_custom ( float p_zoom , const Vector2 & p_center ) {
2021-06-16 15:14:25 +02:00
p_zoom = CLAMP ( p_zoom , zoom_min , zoom_max ) ;
2020-05-14 16:41:43 +02:00
if ( zoom = = p_zoom ) {
2016-01-19 00:32:37 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-01-19 00:32:37 +01:00
2017-11-01 21:49:39 +01:00
Vector2 sbofs = ( Vector2 ( h_scroll - > get_value ( ) , v_scroll - > get_value ( ) ) + p_center ) / zoom ;
2016-02-08 20:28:12 +01:00
2016-01-19 00:32:37 +01:00
zoom = p_zoom ;
2022-08-13 23:21:24 +02:00
top_layer - > queue_redraw ( ) ;
2016-02-08 20:28:12 +01:00
2021-06-16 15:14:25 +02:00
zoom_minus - > set_disabled ( zoom = = zoom_min ) ;
zoom_plus - > set_disabled ( zoom = = zoom_max ) ;
2016-02-08 20:28:12 +01:00
_update_scroll ( ) ;
2022-08-13 23:21:24 +02:00
minimap - > queue_redraw ( ) ;
connections_layer - > queue_redraw ( ) ;
2016-02-08 20:28:12 +01:00
2017-01-13 14:45:50 +01:00
if ( is_visible_in_tree ( ) ) {
2017-11-01 21:49:39 +01:00
Vector2 ofs = sbofs * zoom - p_center ;
2017-03-05 16:44:50 +01:00
h_scroll - > set_value ( ofs . x ) ;
v_scroll - > set_value ( ofs . y ) ;
2016-01-19 00:32:37 +01:00
}
2016-02-08 20:28:12 +01:00
2021-06-16 15:14:25 +02:00
_update_zoom_label ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-01-19 00:32:37 +01:00
}
float GraphEdit : : get_zoom ( ) const {
return zoom ;
}
2015-01-03 20:52:37 +01:00
2021-06-16 15:14:25 +02:00
void GraphEdit : : set_zoom_step ( float p_zoom_step ) {
p_zoom_step = abs ( p_zoom_step ) ;
if ( zoom_step = = p_zoom_step ) {
return ;
}
zoom_step = p_zoom_step ;
}
float GraphEdit : : get_zoom_step ( ) const {
return zoom_step ;
}
void GraphEdit : : set_zoom_min ( float p_zoom_min ) {
ERR_FAIL_COND_MSG ( p_zoom_min > zoom_max , " Cannot set min zoom level greater than max zoom level. " ) ;
if ( zoom_min = = p_zoom_min ) {
return ;
}
zoom_min = p_zoom_min ;
set_zoom ( zoom ) ;
}
float GraphEdit : : get_zoom_min ( ) const {
return zoom_min ;
}
void GraphEdit : : set_zoom_max ( float p_zoom_max ) {
ERR_FAIL_COND_MSG ( p_zoom_max < zoom_min , " Cannot set max zoom level lesser than min zoom level. " ) ;
if ( zoom_max = = p_zoom_max ) {
return ;
}
zoom_max = p_zoom_max ;
set_zoom ( zoom ) ;
}
float GraphEdit : : get_zoom_max ( ) const {
return zoom_max ;
}
void GraphEdit : : set_show_zoom_label ( bool p_enable ) {
if ( zoom_label - > is_visible ( ) = = p_enable ) {
return ;
}
zoom_label - > set_visible ( p_enable ) ;
}
bool GraphEdit : : is_showing_zoom_label ( ) const {
return zoom_label - > is_visible ( ) ;
}
2015-01-07 05:45:46 +01:00
void GraphEdit : : set_right_disconnects ( bool p_enable ) {
2017-03-05 16:44:50 +01:00
right_disconnects = p_enable ;
2015-01-07 05:45:46 +01:00
}
2017-03-05 16:44:50 +01:00
bool GraphEdit : : is_right_disconnects_enabled ( ) const {
2015-07-21 03:15:06 +02:00
return right_disconnects ;
2015-01-07 05:45:46 +01:00
}
2016-08-03 00:11:05 +02:00
void GraphEdit : : add_valid_right_disconnect_type ( int p_type ) {
valid_right_disconnect_types . insert ( p_type ) ;
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : remove_valid_right_disconnect_type ( int p_type ) {
2016-08-03 00:11:05 +02:00
valid_right_disconnect_types . erase ( p_type ) ;
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : add_valid_left_disconnect_type ( int p_type ) {
2016-08-03 00:11:05 +02:00
valid_left_disconnect_types . insert ( p_type ) ;
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : remove_valid_left_disconnect_type ( int p_type ) {
2016-08-03 00:11:05 +02:00
valid_left_disconnect_types . erase ( p_type ) ;
}
2022-08-05 20:35:08 +02:00
TypedArray < Dictionary > GraphEdit : : _get_connection_list ( ) const {
2015-07-21 03:15:06 +02:00
List < Connection > conns ;
get_connection_list ( & conns ) ;
2022-08-05 20:35:08 +02:00
TypedArray < Dictionary > arr ;
2021-07-24 15:46:25 +02:00
for ( const Connection & E : conns ) {
2015-07-21 03:15:06 +02:00
Dictionary d ;
2021-07-16 05:45:57 +02:00
d [ " from " ] = E . from ;
d [ " from_port " ] = E . from_port ;
d [ " to " ] = E . to ;
d [ " to_port " ] = E . to_port ;
2015-07-21 03:15:06 +02:00
arr . push_back ( d ) ;
}
return arr ;
2015-01-08 04:41:34 +01:00
}
2016-02-08 20:28:12 +01:00
void GraphEdit : : _zoom_minus ( ) {
2021-06-16 15:14:25 +02:00
set_zoom ( zoom / zoom_step ) ;
2016-02-08 20:28:12 +01:00
}
2020-05-14 14:29:06 +02:00
2016-02-08 20:28:12 +01:00
void GraphEdit : : _zoom_reset ( ) {
set_zoom ( 1 ) ;
}
void GraphEdit : : _zoom_plus ( ) {
2021-06-16 15:14:25 +02:00
set_zoom ( zoom * zoom_step ) ;
}
void GraphEdit : : _update_zoom_label ( ) {
int zoom_percent = static_cast < int > ( Math : : round ( zoom * 100 ) ) ;
String zoom_text = itos ( zoom_percent ) + " % " ;
zoom_label - > set_text ( zoom_text ) ;
2016-02-08 20:28:12 +01:00
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : add_valid_connection_type ( int p_type , int p_with_type ) {
2022-04-11 00:34:59 +02:00
ConnType ct ( p_type , p_with_type ) ;
2016-08-03 00:11:05 +02:00
valid_connection_types . insert ( ct ) ;
}
2017-03-05 16:44:50 +01:00
void GraphEdit : : remove_valid_connection_type ( int p_type , int p_with_type ) {
2022-04-11 00:34:59 +02:00
ConnType ct ( p_type , p_with_type ) ;
2016-08-03 00:11:05 +02:00
valid_connection_types . erase ( ct ) ;
}
2017-03-05 16:44:50 +01:00
bool GraphEdit : : is_valid_connection_type ( int p_type , int p_with_type ) const {
2022-04-11 00:34:59 +02:00
ConnType ct ( p_type , p_with_type ) ;
2016-08-03 00:11:05 +02:00
return valid_connection_types . has ( ct ) ;
}
2016-08-04 05:05:35 +02:00
void GraphEdit : : set_use_snap ( bool p_enable ) {
2022-03-16 08:50:48 +01:00
if ( snap_button - > is_pressed ( ) = = p_enable ) {
return ;
}
2016-08-04 05:05:35 +02:00
snap_button - > set_pressed ( p_enable ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-08-04 05:05:35 +02:00
}
2017-03-05 16:44:50 +01:00
bool GraphEdit : : is_using_snap ( ) const {
2016-08-04 05:05:35 +02:00
return snap_button - > is_pressed ( ) ;
}
2017-03-05 16:44:50 +01:00
int GraphEdit : : get_snap ( ) const {
2017-01-04 05:16:14 +01:00
return snap_amount - > get_value ( ) ;
2016-08-04 05:05:35 +02:00
}
void GraphEdit : : set_snap ( int p_snap ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_snap < 5 ) ;
2017-01-04 05:16:14 +01:00
snap_amount - > set_value ( p_snap ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-08-04 05:05:35 +02:00
}
2020-05-14 14:29:06 +02:00
2016-08-04 05:05:35 +02:00
void GraphEdit : : _snap_toggled ( ) {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-08-04 05:05:35 +02:00
}
void GraphEdit : : _snap_value_changed ( double ) {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2016-08-04 05:05:35 +02:00
}
2020-11-06 20:16:45 +01:00
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 ) ;
2020-12-22 17:24:29 +01:00
minimap - > set_offset ( Side : : SIDE_LEFT , - minimap_size . x - MINIMAP_OFFSET ) ;
minimap - > set_offset ( Side : : SIDE_TOP , - minimap_size . y - MINIMAP_OFFSET ) ;
minimap - > set_offset ( Side : : SIDE_RIGHT , - MINIMAP_OFFSET ) ;
minimap - > set_offset ( Side : : SIDE_BOTTOM , - MINIMAP_OFFSET ) ;
2022-08-13 23:21:24 +02:00
minimap - > queue_redraw ( ) ;
2020-11-06 20:16:45 +01:00
}
Vector2 GraphEdit : : get_minimap_size ( ) const {
return minimap - > get_size ( ) ;
}
void GraphEdit : : set_minimap_opacity ( float p_opacity ) {
2022-03-16 08:50:48 +01:00
if ( minimap - > get_modulate ( ) . a = = p_opacity ) {
return ;
}
2020-11-06 20:16:45 +01:00
minimap - > set_modulate ( Color ( 1 , 1 , 1 , p_opacity ) ) ;
2022-08-13 23:21:24 +02:00
minimap - > queue_redraw ( ) ;
2020-11-06 20:16:45 +01:00
}
float GraphEdit : : get_minimap_opacity ( ) const {
Color minimap_modulate = minimap - > get_modulate ( ) ;
return minimap_modulate . a ;
}
void GraphEdit : : set_minimap_enabled ( bool p_enable ) {
2022-03-16 08:50:48 +01:00
if ( minimap_button - > is_pressed ( ) = = p_enable ) {
return ;
}
2020-11-06 20:16:45 +01:00
minimap_button - > set_pressed ( p_enable ) ;
2022-01-26 03:04:02 +01:00
_minimap_toggled ( ) ;
2022-08-13 23:21:24 +02:00
minimap - > queue_redraw ( ) ;
2020-11-06 20:16:45 +01:00
}
bool GraphEdit : : is_minimap_enabled ( ) const {
return minimap_button - > is_pressed ( ) ;
}
2022-05-04 07:31:53 +02:00
void GraphEdit : : set_arrange_nodes_button_hidden ( bool p_enable ) {
arrange_nodes_button_hidden = p_enable ;
if ( arrange_nodes_button_hidden ) {
layout_button - > hide ( ) ;
} else {
layout_button - > show ( ) ;
}
}
bool GraphEdit : : is_arrange_nodes_button_hidden ( ) const {
return arrange_nodes_button_hidden ;
}
2020-11-06 20:16:45 +01:00
void GraphEdit : : _minimap_toggled ( ) {
2021-03-01 16:19:48 +01:00
if ( is_minimap_enabled ( ) ) {
minimap - > set_visible ( true ) ;
2022-08-13 23:21:24 +02:00
minimap - > queue_redraw ( ) ;
2021-03-01 16:19:48 +01:00
} else {
minimap - > set_visible ( false ) ;
}
2020-11-06 20:16:45 +01:00
}
2022-05-30 15:38:13 +02:00
void GraphEdit : : set_connection_lines_curvature ( float p_curvature ) {
lines_curvature = p_curvature ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-05-30 15:38:13 +02:00
}
float GraphEdit : : get_connection_lines_curvature ( ) const {
return lines_curvature ;
}
2020-12-18 14:13:28 +01:00
void GraphEdit : : set_connection_lines_thickness ( float p_thickness ) {
2022-03-16 08:50:48 +01:00
if ( lines_thickness = = p_thickness ) {
return ;
}
2020-12-18 14:13:28 +01:00
lines_thickness = p_thickness ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-12-18 14:13:28 +01:00
}
float GraphEdit : : get_connection_lines_thickness ( ) const {
return lines_thickness ;
}
void GraphEdit : : set_connection_lines_antialiased ( bool p_antialiased ) {
2022-03-16 08:50:48 +01:00
if ( lines_antialiased = = p_antialiased ) {
return ;
}
2020-12-18 14:13:28 +01:00
lines_antialiased = p_antialiased ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-12-18 14:13:28 +01:00
}
bool GraphEdit : : is_connection_lines_antialiased ( ) const {
return lines_antialiased ;
}
2018-06-19 03:10:48 +02:00
HBoxContainer * GraphEdit : : get_zoom_hbox ( ) {
return zoom_hb ;
}
2022-01-19 19:59:12 +01:00
Ref < ViewPanner > GraphEdit : : get_panner ( ) {
return panner ;
}
void GraphEdit : : set_warped_panning ( bool p_warped ) {
warped_panning = p_warped ;
}
2022-05-19 17:00:06 +02:00
int GraphEdit : : _set_operations ( SET_OPERATIONS p_operation , HashSet < StringName > & r_u , const HashSet < StringName > & r_v ) {
2021-08-10 21:14:19 +02:00
switch ( p_operation ) {
case GraphEdit : : IS_EQUAL : {
2022-05-19 01:43:40 +02:00
for ( const StringName & E : r_u ) {
if ( ! r_v . has ( E ) ) {
2021-08-10 21:14:19 +02:00
return 0 ;
2022-01-27 17:34:33 +01:00
}
2021-08-10 21:14:19 +02:00
}
return r_u . size ( ) = = r_v . size ( ) ;
} break ;
case GraphEdit : : IS_SUBSET : {
if ( r_u . size ( ) = = r_v . size ( ) & & ! r_u . size ( ) ) {
return 1 ;
}
2022-05-19 01:43:40 +02:00
for ( const StringName & E : r_u ) {
if ( ! r_v . has ( E ) ) {
2021-08-10 21:14:19 +02:00
return 0 ;
2022-01-27 17:34:33 +01:00
}
2021-08-10 21:14:19 +02:00
}
return 1 ;
} break ;
case GraphEdit : : DIFFERENCE : {
2022-05-19 17:00:06 +02:00
for ( HashSet < StringName > : : Iterator E = r_u . begin ( ) ; E ; ) {
HashSet < StringName > : : Iterator N = E ;
+ + N ;
if ( r_v . has ( * E ) ) {
r_u . remove ( E ) ;
2021-08-10 21:14:19 +02:00
}
2022-05-19 17:00:06 +02:00
E = N ;
2021-08-10 21:14:19 +02:00
}
return r_u . size ( ) ;
} break ;
case GraphEdit : : UNION : {
2022-05-19 01:43:40 +02:00
for ( const StringName & E : r_v ) {
if ( ! r_u . has ( E ) ) {
r_u . insert ( E ) ;
2021-08-10 21:14:19 +02:00
}
}
2021-12-30 18:31:59 +01:00
return r_u . size ( ) ;
2021-08-10 21:14:19 +02:00
} break ;
default :
break ;
}
return - 1 ;
}
2022-05-19 17:00:06 +02:00
HashMap < int , Vector < StringName > > GraphEdit : : _layering ( const HashSet < StringName > & r_selected_nodes , const HashMap < StringName , HashSet < StringName > > & r_upper_neighbours ) {
2021-08-10 21:14:19 +02:00
HashMap < int , Vector < StringName > > l ;
2022-05-19 17:00:06 +02:00
HashSet < StringName > p = r_selected_nodes , q = r_selected_nodes , u , z ;
2021-08-10 21:14:19 +02:00
int current_layer = 0 ;
bool selected = false ;
while ( ! _set_operations ( GraphEdit : : IS_EQUAL , q , u ) ) {
_set_operations ( GraphEdit : : DIFFERENCE , p , u ) ;
2022-05-19 01:43:40 +02:00
for ( const StringName & E : p ) {
2022-05-19 17:00:06 +02:00
HashSet < StringName > n = r_upper_neighbours [ E ] ;
2021-08-10 21:14:19 +02:00
if ( _set_operations ( GraphEdit : : IS_SUBSET , n , z ) ) {
Vector < StringName > t ;
2022-05-19 01:43:40 +02:00
t . push_back ( E ) ;
2021-08-10 21:14:19 +02:00
if ( ! l . has ( current_layer ) ) {
2022-05-08 10:09:19 +02:00
l . insert ( current_layer , Vector < StringName > { } ) ;
2021-08-10 21:14:19 +02:00
}
selected = true ;
t . append_array ( l [ current_layer ] ) ;
2022-05-08 10:09:19 +02:00
l . insert ( current_layer , t ) ;
2022-05-19 17:00:06 +02:00
HashSet < StringName > V ;
2022-05-19 01:43:40 +02:00
V . insert ( E ) ;
2021-08-10 21:14:19 +02:00
_set_operations ( GraphEdit : : UNION , u , V ) ;
}
}
if ( ! selected ) {
current_layer + + ;
2022-08-02 21:11:19 +02:00
uint32_t previous_size_z = z . size ( ) ;
2021-08-10 21:14:19 +02:00
_set_operations ( GraphEdit : : UNION , z , u ) ;
2022-08-02 21:11:19 +02:00
if ( z . size ( ) = = previous_size_z ) {
WARN_PRINT ( " Graph contains cycle(s). The cycle(s) will not be rearranged accurately. " ) ;
Vector < StringName > t ;
if ( l . has ( 0 ) ) {
t . append_array ( l [ 0 ] ) ;
}
for ( const StringName & E : p ) {
t . push_back ( E ) ;
}
l . insert ( 0 , t ) ;
break ;
}
2021-08-10 21:14:19 +02:00
}
selected = false ;
}
return l ;
}
Vector < StringName > GraphEdit : : _split ( const Vector < StringName > & r_layer , const HashMap < StringName , Dictionary > & r_crossings ) {
if ( ! r_layer . size ( ) ) {
return Vector < StringName > ( ) ;
}
StringName p = r_layer [ Math : : random ( 0 , r_layer . size ( ) - 1 ) ] ;
Vector < StringName > left ;
Vector < StringName > right ;
for ( int i = 0 ; i < r_layer . size ( ) ; i + + ) {
if ( p ! = r_layer [ i ] ) {
StringName q = r_layer [ i ] ;
int cross_pq = r_crossings [ p ] [ q ] ;
int cross_qp = r_crossings [ q ] [ p ] ;
if ( cross_pq > cross_qp ) {
left . push_back ( q ) ;
} else {
right . push_back ( q ) ;
}
}
}
left . push_back ( p ) ;
left . append_array ( right ) ;
return left ;
}
2022-05-19 17:00:06 +02:00
void GraphEdit : : _horizontal_alignment ( Dictionary & r_root , Dictionary & r_align , const HashMap < int , Vector < StringName > > & r_layers , const HashMap < StringName , HashSet < StringName > > & r_upper_neighbours , const HashSet < StringName > & r_selected_nodes ) {
2022-05-19 01:43:40 +02:00
for ( const StringName & E : r_selected_nodes ) {
r_root [ E ] = E ;
r_align [ E ] = E ;
2021-08-10 21:14:19 +02:00
}
if ( r_layers . size ( ) = = 1 ) {
return ;
}
for ( unsigned int i = 1 ; i < r_layers . size ( ) ; i + + ) {
Vector < StringName > lower_layer = r_layers [ i ] ;
Vector < StringName > upper_layer = r_layers [ i - 1 ] ;
int r = - 1 ;
for ( int j = 0 ; j < lower_layer . size ( ) ; j + + ) {
Vector < Pair < int , StringName > > up ;
StringName current_node = lower_layer [ j ] ;
for ( int k = 0 ; k < upper_layer . size ( ) ; k + + ) {
StringName adjacent_neighbour = upper_layer [ k ] ;
if ( r_upper_neighbours [ current_node ] . has ( adjacent_neighbour ) ) {
up . push_back ( Pair < int , StringName > ( k , adjacent_neighbour ) ) ;
}
}
2021-12-30 18:31:59 +01:00
int start = ( up . size ( ) - 1 ) / 2 ;
int end = ( up . size ( ) - 1 ) % 2 ? start + 1 : start ;
2021-08-10 21:14:19 +02:00
for ( int p = start ; p < = end ; p + + ) {
StringName Align = r_align [ current_node ] ;
if ( Align = = current_node & & r < up [ p ] . first ) {
r_align [ up [ p ] . second ] = lower_layer [ j ] ;
r_root [ current_node ] = r_root [ up [ p ] . second ] ;
r_align [ current_node ] = r_root [ up [ p ] . second ] ;
r = up [ p ] . first ;
}
}
}
}
}
2022-05-19 17:00:06 +02:00
void GraphEdit : : _crossing_minimisation ( HashMap < int , Vector < StringName > > & r_layers , const HashMap < StringName , HashSet < StringName > > & r_upper_neighbours ) {
2021-08-10 21:14:19 +02:00
if ( r_layers . size ( ) = = 1 ) {
return ;
}
for ( unsigned int i = 1 ; i < r_layers . size ( ) ; i + + ) {
Vector < StringName > upper_layer = r_layers [ i - 1 ] ;
Vector < StringName > lower_layer = r_layers [ i ] ;
HashMap < StringName , Dictionary > c ;
for ( int j = 0 ; j < lower_layer . size ( ) ; j + + ) {
StringName p = lower_layer [ j ] ;
Dictionary d ;
for ( int k = 0 ; k < lower_layer . size ( ) ; k + + ) {
unsigned int crossings = 0 ;
StringName q = lower_layer [ k ] ;
if ( j ! = k ) {
for ( int h = 1 ; h < upper_layer . size ( ) ; h + + ) {
if ( r_upper_neighbours [ p ] . has ( upper_layer [ h ] ) ) {
for ( int g = 0 ; g < h ; g + + ) {
if ( r_upper_neighbours [ q ] . has ( upper_layer [ g ] ) ) {
crossings + + ;
}
}
}
}
}
d [ q ] = crossings ;
}
2022-05-08 10:09:19 +02:00
c . insert ( p , d ) ;
2021-08-10 21:14:19 +02:00
}
2022-05-08 10:09:19 +02:00
r_layers . insert ( i , _split ( lower_layer , c ) ) ;
2021-08-10 21:14:19 +02:00
}
}
2022-05-19 17:00:06 +02:00
void GraphEdit : : _calculate_inner_shifts ( Dictionary & r_inner_shifts , const Dictionary & r_root , const Dictionary & r_node_names , const Dictionary & r_align , const HashSet < StringName > & r_block_heads , const HashMap < StringName , Pair < int , int > > & r_port_info ) {
2022-05-19 01:43:40 +02:00
for ( const StringName & E : r_block_heads ) {
2021-08-10 21:14:19 +02:00
real_t left = 0 ;
2022-05-19 01:43:40 +02:00
StringName u = E ;
2021-08-10 21:14:19 +02:00
StringName v = r_align [ u ] ;
while ( u ! = v & & ( StringName ) r_root [ u ] ! = v ) {
String _connection = String ( u ) + " " + String ( v ) ;
GraphNode * gfrom = Object : : cast_to < GraphNode > ( r_node_names [ u ] ) ;
GraphNode * gto = Object : : cast_to < GraphNode > ( r_node_names [ v ] ) ;
Pair < int , int > ports = r_port_info [ _connection ] ;
int pfrom = ports . first ;
int pto = ports . second ;
Vector2 frompos = gfrom - > get_connection_output_position ( pfrom ) ;
Vector2 topos = gto - > get_connection_input_position ( pto ) ;
real_t s = ( real_t ) r_inner_shifts [ u ] + ( frompos . y - topos . y ) / zoom ;
r_inner_shifts [ v ] = s ;
left = MIN ( left , s ) ;
u = v ;
v = ( StringName ) r_align [ v ] ;
}
2022-05-19 01:43:40 +02:00
u = E ;
2021-08-10 21:14:19 +02:00
do {
r_inner_shifts [ u ] = ( real_t ) r_inner_shifts [ u ] - left ;
u = ( StringName ) r_align [ u ] ;
2022-05-19 01:43:40 +02:00
} while ( u ! = E ) ;
2021-08-10 21:14:19 +02:00
}
}
float GraphEdit : : _calculate_threshold ( StringName p_v , StringName p_w , const Dictionary & r_node_names , const HashMap < int , Vector < StringName > > & r_layers , const Dictionary & r_root , const Dictionary & r_align , const Dictionary & r_inner_shift , real_t p_current_threshold , const HashMap < StringName , Vector2 > & r_node_positions ) {
# define MAX_ORDER 2147483647
# define ORDER(node, layers) \
for ( unsigned int i = 0 ; i < layers . size ( ) ; i + + ) { \
int index = layers [ i ] . find ( node ) ; \
if ( index > 0 ) { \
order = index ; \
break ; \
} \
order = MAX_ORDER ; \
}
int order = MAX_ORDER ;
float threshold = p_current_threshold ;
if ( p_v = = p_w ) {
int min_order = MAX_ORDER ;
Connection incoming ;
for ( List < Connection > : : Element * E = connections . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) . to = = p_w ) {
ORDER ( E - > get ( ) . from , r_layers ) ;
if ( min_order > order ) {
min_order = order ;
incoming = E - > get ( ) ;
}
}
}
if ( incoming . from ! = StringName ( ) ) {
GraphNode * gfrom = Object : : cast_to < GraphNode > ( r_node_names [ incoming . from ] ) ;
GraphNode * gto = Object : : cast_to < GraphNode > ( r_node_names [ p_w ] ) ;
Vector2 frompos = gfrom - > get_connection_output_position ( incoming . from_port ) ;
Vector2 topos = gto - > get_connection_input_position ( incoming . to_port ) ;
//If connected block node is selected, calculate thershold or add current block to list
if ( gfrom - > is_selected ( ) ) {
Vector2 connected_block_pos = r_node_positions [ r_root [ incoming . from ] ] ;
if ( connected_block_pos . y ! = FLT_MAX ) {
//Connected block is placed. Calculate threshold
threshold = connected_block_pos . y + ( real_t ) r_inner_shift [ incoming . from ] - ( real_t ) r_inner_shift [ p_w ] + frompos . y - topos . y ;
}
}
}
}
if ( threshold = = FLT_MIN & & ( StringName ) r_align [ p_w ] = = p_v ) {
//This time, pick an outgoing edge and repeat as above!
int min_order = MAX_ORDER ;
Connection outgoing ;
for ( List < Connection > : : Element * E = connections . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) . from = = p_w ) {
ORDER ( E - > get ( ) . to , r_layers ) ;
if ( min_order > order ) {
min_order = order ;
outgoing = E - > get ( ) ;
}
}
}
if ( outgoing . to ! = StringName ( ) ) {
GraphNode * gfrom = Object : : cast_to < GraphNode > ( r_node_names [ p_w ] ) ;
GraphNode * gto = Object : : cast_to < GraphNode > ( r_node_names [ outgoing . to ] ) ;
Vector2 frompos = gfrom - > get_connection_output_position ( outgoing . from_port ) ;
Vector2 topos = gto - > get_connection_input_position ( outgoing . to_port ) ;
//If connected block node is selected, calculate thershold or add current block to list
if ( gto - > is_selected ( ) ) {
Vector2 connected_block_pos = r_node_positions [ r_root [ outgoing . to ] ] ;
if ( connected_block_pos . y ! = FLT_MAX ) {
//Connected block is placed. Calculate threshold
threshold = connected_block_pos . y + ( real_t ) r_inner_shift [ outgoing . to ] - ( real_t ) r_inner_shift [ p_w ] + frompos . y - topos . y ;
}
}
}
}
# undef MAX_ORDER
# undef ORDER
return threshold ;
}
void GraphEdit : : _place_block ( StringName p_v , float p_delta , const HashMap < int , Vector < StringName > > & r_layers , const Dictionary & r_root , const Dictionary & r_align , const Dictionary & r_node_name , const Dictionary & r_inner_shift , Dictionary & r_sink , Dictionary & r_shift , HashMap < StringName , Vector2 > & r_node_positions ) {
# define PRED(node, layers) \
for ( unsigned int i = 0 ; i < layers . size ( ) ; i + + ) { \
int index = layers [ i ] . find ( node ) ; \
if ( index > 0 ) { \
predecessor = layers [ i ] [ index - 1 ] ; \
break ; \
} \
predecessor = StringName ( ) ; \
}
StringName predecessor ;
StringName successor ;
Vector2 pos = r_node_positions [ p_v ] ;
if ( pos . y = = FLT_MAX ) {
pos . y = 0 ;
bool initial = false ;
StringName w = p_v ;
real_t threshold = FLT_MIN ;
do {
PRED ( w , r_layers ) ;
if ( predecessor ! = StringName ( ) ) {
StringName u = r_root [ predecessor ] ;
_place_block ( u , p_delta , r_layers , r_root , r_align , r_node_name , r_inner_shift , r_sink , r_shift , r_node_positions ) ;
threshold = _calculate_threshold ( p_v , w , r_node_name , r_layers , r_root , r_align , r_inner_shift , threshold , r_node_positions ) ;
if ( ( StringName ) r_sink [ p_v ] = = p_v ) {
r_sink [ p_v ] = r_sink [ u ] ;
}
Vector2 predecessor_root_pos = r_node_positions [ u ] ;
Vector2 predecessor_node_size = Object : : cast_to < GraphNode > ( r_node_name [ predecessor ] ) - > get_size ( ) ;
if ( r_sink [ p_v ] ! = r_sink [ u ] ) {
real_t sc = pos . y + ( real_t ) r_inner_shift [ w ] - predecessor_root_pos . y - ( real_t ) r_inner_shift [ predecessor ] - predecessor_node_size . y - p_delta ;
r_shift [ r_sink [ u ] ] = MIN ( sc , ( real_t ) r_shift [ r_sink [ u ] ] ) ;
} else {
real_t sb = predecessor_root_pos . y + ( real_t ) r_inner_shift [ predecessor ] + predecessor_node_size . y - ( real_t ) r_inner_shift [ w ] + p_delta ;
sb = MAX ( sb , threshold ) ;
if ( initial ) {
pos . y = sb ;
} else {
pos . y = MAX ( pos . y , sb ) ;
}
initial = false ;
}
}
threshold = _calculate_threshold ( p_v , w , r_node_name , r_layers , r_root , r_align , r_inner_shift , threshold , r_node_positions ) ;
w = r_align [ w ] ;
} while ( w ! = p_v ) ;
2022-05-08 10:09:19 +02:00
r_node_positions . insert ( p_v , pos ) ;
2021-08-10 21:14:19 +02:00
}
# undef PRED
}
void GraphEdit : : arrange_nodes ( ) {
if ( ! arranging_graph ) {
arranging_graph = true ;
} else {
return ;
}
Dictionary node_names ;
2022-05-19 17:00:06 +02:00
HashSet < StringName > selected_nodes ;
2021-08-10 21:14:19 +02:00
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
if ( ! gn ) {
continue ;
}
node_names [ gn - > get_name ( ) ] = gn ;
}
2022-05-19 17:00:06 +02:00
HashMap < StringName , HashSet < StringName > > upper_neighbours ;
2021-08-10 21:14:19 +02:00
HashMap < StringName , Pair < int , int > > port_info ;
Vector2 origin ( FLT_MAX , FLT_MAX ) ;
float gap_v = 100.0f ;
float gap_h = 100.0f ;
for ( int i = get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( get_child ( i ) ) ;
if ( ! gn ) {
continue ;
}
if ( gn - > is_selected ( ) ) {
selected_nodes . insert ( gn - > get_name ( ) ) ;
2022-05-19 17:00:06 +02:00
HashSet < StringName > s ;
2021-08-10 21:14:19 +02:00
for ( List < Connection > : : Element * E = connections . front ( ) ; E ; E = E - > next ( ) ) {
GraphNode * p_from = Object : : cast_to < GraphNode > ( node_names [ E - > get ( ) . from ] ) ;
2022-08-02 21:11:19 +02:00
if ( E - > get ( ) . to = = gn - > get_name ( ) & & p_from - > is_selected ( ) & & E - > get ( ) . to ! = E - > get ( ) . from ) {
2021-08-10 21:14:19 +02:00
if ( ! s . has ( p_from - > get_name ( ) ) ) {
s . insert ( p_from - > get_name ( ) ) ;
}
String s_connection = String ( p_from - > get_name ( ) ) + " " + String ( E - > get ( ) . to ) ;
StringName _connection ( s_connection ) ;
Pair < int , int > ports ( E - > get ( ) . from_port , E - > get ( ) . to_port ) ;
if ( port_info . has ( _connection ) ) {
Pair < int , int > p_ports = port_info [ _connection ] ;
if ( p_ports . first < ports . first ) {
ports = p_ports ;
}
}
2022-05-08 10:09:19 +02:00
port_info . insert ( _connection , ports ) ;
2021-08-10 21:14:19 +02:00
}
}
2022-05-08 10:09:19 +02:00
upper_neighbours . insert ( gn - > get_name ( ) , s ) ;
2021-08-10 21:14:19 +02:00
}
}
2021-08-22 00:27:48 +02:00
if ( ! selected_nodes . size ( ) ) {
arranging_graph = false ;
return ;
}
2021-08-10 21:14:19 +02:00
HashMap < int , Vector < StringName > > layers = _layering ( selected_nodes , upper_neighbours ) ;
_crossing_minimisation ( layers , upper_neighbours ) ;
Dictionary root , align , sink , shift ;
_horizontal_alignment ( root , align , layers , upper_neighbours , selected_nodes ) ;
HashMap < StringName , Vector2 > new_positions ;
Vector2 default_position ( FLT_MAX , FLT_MAX ) ;
Dictionary inner_shift ;
2022-05-19 17:00:06 +02:00
HashSet < StringName > block_heads ;
2021-08-10 21:14:19 +02:00
2022-05-19 01:43:40 +02:00
for ( const StringName & E : selected_nodes ) {
inner_shift [ E ] = 0.0f ;
sink [ E ] = E ;
shift [ E ] = FLT_MAX ;
new_positions . insert ( E , default_position ) ;
if ( ( StringName ) root [ E ] = = E ) {
block_heads . insert ( E ) ;
2021-08-10 21:14:19 +02:00
}
}
_calculate_inner_shifts ( inner_shift , root , node_names , align , block_heads , port_info ) ;
2022-05-19 01:43:40 +02:00
for ( const StringName & E : block_heads ) {
_place_block ( E , gap_v , layers , root , align , node_names , inner_shift , sink , shift , new_positions ) ;
2021-08-10 21:14:19 +02:00
}
2021-08-22 00:27:48 +02:00
origin . y = Object : : cast_to < GraphNode > ( node_names [ layers [ 0 ] [ 0 ] ] ) - > get_position_offset ( ) . y - ( new_positions [ layers [ 0 ] [ 0 ] ] . y + ( float ) inner_shift [ layers [ 0 ] [ 0 ] ] ) ;
origin . x = Object : : cast_to < GraphNode > ( node_names [ layers [ 0 ] [ 0 ] ] ) - > get_position_offset ( ) . x ;
2021-08-10 21:14:19 +02:00
2022-05-19 01:43:40 +02:00
for ( const StringName & E : block_heads ) {
StringName u = E ;
float start_from = origin . y + new_positions [ E ] . y ;
2021-08-10 21:14:19 +02:00
do {
Vector2 cal_pos ;
cal_pos . y = start_from + ( real_t ) inner_shift [ u ] ;
2022-05-08 10:09:19 +02:00
new_positions . insert ( u , cal_pos ) ;
2021-08-10 21:14:19 +02:00
u = align [ u ] ;
2022-05-19 01:43:40 +02:00
} while ( u ! = E ) ;
2021-08-10 21:14:19 +02:00
}
Fix various typos
Found via ` codespell -q 3 -S ./thirdparty,*.po,./DONORS.md -L ackward,ang,ans,ba,beng,cas,childs,childrens,dof,doubleclick,expct,fave,findn,gird,hist,inout,leapyear,lod,nd,numer,ois,ony,paket,seeked,sinc,switchs,te,uint,varn`
Update editor/import/resource_importer_layered_texture.cpp
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Update doc/classes/TileSetScenesCollectionSource.xml
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Update scene/gui/graph_edit.cpp
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Update scene/resources/animation.cpp
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Update scene/resources/animation.cpp
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Update scene/resources/animation.cpp
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Update scene/gui/rich_text_label.cpp
Co-authored-by: Raul Santos <raulsntos@gmail.com>
Revert previously committed change
2022-01-02 07:03:58 +01:00
// Compute horizontal coordinates individually for layers to get uniform gap.
2021-08-10 21:14:19 +02:00
float start_from = origin . x ;
float largest_node_size = 0.0f ;
for ( unsigned int i = 0 ; i < layers . size ( ) ; i + + ) {
Vector < StringName > layer = layers [ i ] ;
for ( int j = 0 ; j < layer . size ( ) ; j + + ) {
float current_node_size = Object : : cast_to < GraphNode > ( node_names [ layer [ j ] ] ) - > get_size ( ) . x ;
largest_node_size = MAX ( largest_node_size , current_node_size ) ;
}
for ( int j = 0 ; j < layer . size ( ) ; j + + ) {
float current_node_size = Object : : cast_to < GraphNode > ( node_names [ layer [ j ] ] ) - > get_size ( ) . x ;
Vector2 cal_pos = new_positions [ layer [ j ] ] ;
if ( current_node_size = = largest_node_size ) {
cal_pos . x = start_from ;
} else {
2021-08-22 00:27:48 +02:00
float current_node_start_pos = start_from ;
if ( current_node_size < largest_node_size / 2 ) {
if ( ! ( i | | j ) ) {
start_from - = ( largest_node_size - current_node_size ) ;
}
2021-08-10 21:14:19 +02:00
current_node_start_pos = start_from + largest_node_size - current_node_size ;
}
cal_pos . x = current_node_start_pos ;
}
2022-05-08 10:09:19 +02:00
new_positions . insert ( layer [ j ] , cal_pos ) ;
2021-08-10 21:14:19 +02:00
}
start_from + = largest_node_size + gap_h ;
largest_node_size = 0.0f ;
}
2021-08-20 14:48:34 +02:00
emit_signal ( SNAME ( " begin_node_move " ) ) ;
2022-05-19 01:43:40 +02:00
for ( const StringName & E : selected_nodes ) {
GraphNode * gn = Object : : cast_to < GraphNode > ( node_names [ E ] ) ;
2021-08-10 21:14:19 +02:00
gn - > set_drag ( true ) ;
2022-05-19 01:43:40 +02:00
Vector2 pos = ( new_positions [ E ] ) ;
2021-08-10 21:14:19 +02:00
if ( is_using_snap ( ) ) {
const int snap = get_snap ( ) ;
pos = pos . snapped ( Vector2 ( snap , snap ) ) ;
}
gn - > set_position_offset ( pos ) ;
gn - > set_drag ( false ) ;
}
2021-08-20 14:48:34 +02:00
emit_signal ( SNAME ( " end_node_move " ) ) ;
2021-08-10 21:14:19 +02:00
arranging_graph = false ;
}
2015-01-03 20:52:37 +01:00
void GraphEdit : : _bind_methods ( ) {
2022-09-09 15:29:51 +02:00
ClassDB : : bind_method ( D_METHOD ( " connect_node " , " from_node " , " from_port " , " to_node " , " to_port " ) , & GraphEdit : : connect_node ) ;
ClassDB : : bind_method ( D_METHOD ( " is_node_connected " , " from_node " , " from_port " , " to_node " , " to_port " ) , & GraphEdit : : is_node_connected ) ;
ClassDB : : bind_method ( D_METHOD ( " disconnect_node " , " from_node " , " from_port " , " to_node " , " to_port " ) , & GraphEdit : : disconnect_node ) ;
ClassDB : : bind_method ( D_METHOD ( " set_connection_activity " , " from_node " , " from_port " , " to_node " , " to_port " , " amount " ) , & GraphEdit : : set_connection_activity ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_connection_list " ) , & GraphEdit : : _get_connection_list ) ;
2018-01-31 01:09:41 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear_connections " ) , & GraphEdit : : clear_connections ) ;
2021-07-26 16:31:31 +02:00
ClassDB : : bind_method ( D_METHOD ( " force_connection_drag_end " ) , & GraphEdit : : force_connection_drag_end ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_scroll_ofs " ) , & GraphEdit : : get_scroll_ofs ) ;
2022-04-14 23:20:28 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_scroll_ofs " , " offset " ) , & GraphEdit : : set_scroll_ofs ) ;
2016-01-19 00:32:37 +01:00
2018-01-31 01:09:41 +01:00
ClassDB : : bind_method ( D_METHOD ( " add_valid_right_disconnect_type " , " type " ) , & GraphEdit : : add_valid_right_disconnect_type ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_valid_right_disconnect_type " , " type " ) , & GraphEdit : : remove_valid_right_disconnect_type ) ;
ClassDB : : bind_method ( D_METHOD ( " add_valid_left_disconnect_type " , " type " ) , & GraphEdit : : add_valid_left_disconnect_type ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_valid_left_disconnect_type " , " type " ) , & GraphEdit : : remove_valid_left_disconnect_type ) ;
ClassDB : : bind_method ( D_METHOD ( " add_valid_connection_type " , " from_type " , " to_type " ) , & GraphEdit : : add_valid_connection_type ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_valid_connection_type " , " from_type " , " to_type " ) , & GraphEdit : : remove_valid_connection_type ) ;
ClassDB : : bind_method ( D_METHOD ( " is_valid_connection_type " , " from_type " , " to_type " ) , & GraphEdit : : is_valid_connection_type ) ;
2022-09-09 15:29:51 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_connection_line " , " from_node " , " to_node " ) , & GraphEdit : : get_connection_line ) ;
2018-01-31 01:09:41 +01:00
2021-09-28 18:00:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_panning_scheme " , " scheme " ) , & GraphEdit : : set_panning_scheme ) ;
ClassDB : : bind_method ( D_METHOD ( " get_panning_scheme " ) , & GraphEdit : : get_panning_scheme ) ;
2021-02-04 14:38:51 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_zoom " , " zoom " ) , & GraphEdit : : set_zoom ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_zoom " ) , & GraphEdit : : get_zoom ) ;
2016-08-04 05:05:35 +02:00
2021-06-16 15:14:25 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_zoom_min " , " zoom_min " ) , & GraphEdit : : set_zoom_min ) ;
ClassDB : : bind_method ( D_METHOD ( " get_zoom_min " ) , & GraphEdit : : get_zoom_min ) ;
ClassDB : : bind_method ( D_METHOD ( " set_zoom_max " , " zoom_max " ) , & GraphEdit : : set_zoom_max ) ;
ClassDB : : bind_method ( D_METHOD ( " get_zoom_max " ) , & GraphEdit : : get_zoom_max ) ;
ClassDB : : bind_method ( D_METHOD ( " set_zoom_step " , " zoom_step " ) , & GraphEdit : : set_zoom_step ) ;
ClassDB : : bind_method ( D_METHOD ( " get_zoom_step " ) , & GraphEdit : : get_zoom_step ) ;
ClassDB : : bind_method ( D_METHOD ( " set_show_zoom_label " , " enable " ) , & GraphEdit : : set_show_zoom_label ) ;
ClassDB : : bind_method ( D_METHOD ( " is_showing_zoom_label " ) , & GraphEdit : : is_showing_zoom_label ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_snap " , " pixels " ) , & GraphEdit : : set_snap ) ;
ClassDB : : bind_method ( D_METHOD ( " get_snap " ) , & GraphEdit : : get_snap ) ;
2016-08-04 05:05:35 +02:00
2017-03-05 16:44:50 +01:00
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 ) ;
2015-01-07 05:45:46 +01:00
2022-05-30 15:38:13 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_connection_lines_curvature " , " curvature " ) , & GraphEdit : : set_connection_lines_curvature ) ;
ClassDB : : bind_method ( D_METHOD ( " get_connection_lines_curvature " ) , & GraphEdit : : get_connection_lines_curvature ) ;
2020-12-18 14:13:28 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_connection_lines_thickness " , " pixels " ) , & GraphEdit : : set_connection_lines_thickness ) ;
ClassDB : : bind_method ( D_METHOD ( " get_connection_lines_thickness " ) , & GraphEdit : : get_connection_lines_thickness ) ;
ClassDB : : bind_method ( D_METHOD ( " set_connection_lines_antialiased " , " pixels " ) , & GraphEdit : : set_connection_lines_antialiased ) ;
ClassDB : : bind_method ( D_METHOD ( " is_connection_lines_antialiased " ) , & GraphEdit : : is_connection_lines_antialiased ) ;
2021-02-04 14:38:51 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_minimap_size " , " size " ) , & GraphEdit : : set_minimap_size ) ;
2020-11-06 20:16:45 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_minimap_size " ) , & GraphEdit : : get_minimap_size ) ;
2021-02-04 14:38:51 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_minimap_opacity " , " opacity " ) , & GraphEdit : : set_minimap_opacity ) ;
2020-11-06 20:16:45 +01:00
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 ) ;
2022-05-04 07:31:53 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_arrange_nodes_button_hidden " , " enable " ) , & GraphEdit : : set_arrange_nodes_button_hidden ) ;
ClassDB : : bind_method ( D_METHOD ( " is_arrange_nodes_button_hidden " ) , & GraphEdit : : is_arrange_nodes_button_hidden ) ;
2017-03-05 16:44:50 +01:00
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 ) ;
2015-01-03 20:52:37 +01:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _update_scroll_offset " ) , & GraphEdit : : _update_scroll_offset ) ;
2022-09-09 15:29:51 +02:00
GDVIRTUAL_BIND ( _is_in_input_hotzone , " in_node " , " in_port " , " mouse_position " ) ;
GDVIRTUAL_BIND ( _is_in_output_hotzone , " in_node " , " in_port " , " mouse_position " ) ;
2016-08-31 04:44:14 +02:00
2018-06-19 03:10:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_zoom_hbox " ) , & GraphEdit : : get_zoom_hbox ) ;
2021-08-10 21:14:19 +02:00
ClassDB : : bind_method ( D_METHOD ( " arrange_nodes " ) , & GraphEdit : : arrange_nodes ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_selected " , " node " ) , & GraphEdit : : set_selected ) ;
2015-01-03 20:52:37 +01:00
2022-09-09 15:29:51 +02:00
GDVIRTUAL_BIND ( _get_connection_line , " from_position " , " to_position " )
GDVIRTUAL_BIND ( _is_node_hover_valid , " from_node " , " from_port " , " to_node " , " to_port " ) ;
2020-07-19 19:11:02 +02:00
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " right_disconnects " ) , " set_right_disconnects " , " is_right_disconnects_enabled " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " scroll_offset " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_scroll_ofs " , " get_scroll_ofs " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " snap_distance " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_snap " , " get_snap " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " use_snap " ) , " set_use_snap " , " is_using_snap " ) ;
2021-09-28 18:00:16 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " panning_scheme " , PROPERTY_HINT_ENUM , " Scroll Zooms,Scroll Pans " ) , " set_panning_scheme " , " get_panning_scheme " ) ;
2021-06-16 15:14:25 +02:00
ADD_GROUP ( " Connection Lines " , " connection_lines " ) ;
2022-05-30 15:38:13 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " connection_lines_curvature " ) , " set_connection_lines_curvature " , " get_connection_lines_curvature " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " connection_lines_thickness " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_connection_lines_thickness " , " get_connection_lines_thickness " ) ;
2020-12-18 14:13:28 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " connection_lines_antialiased " ) , " set_connection_lines_antialiased " , " is_connection_lines_antialiased " ) ;
2021-06-16 15:14:25 +02:00
ADD_GROUP ( " Zoom " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " zoom " ) , " set_zoom " , " get_zoom " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " zoom_min " ) , " set_zoom_min " , " get_zoom_min " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " zoom_max " ) , " set_zoom_max " , " get_zoom_max " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " zoom_step " ) , " set_zoom_step " , " get_zoom_step " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " show_zoom_label " ) , " set_show_zoom_label " , " is_showing_zoom_label " ) ;
2020-11-06 20:16:45 +01:00
ADD_GROUP ( " Minimap " , " minimap " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " minimap_enabled " ) , " set_minimap_enabled " , " is_minimap_enabled " ) ;
2022-05-20 07:24:41 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : VECTOR2 , " minimap_size " , PROPERTY_HINT_NONE , " suffix:px " ) , " set_minimap_size " , " get_minimap_size " ) ;
2020-11-06 20:16:45 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " minimap_opacity " ) , " set_minimap_opacity " , " get_minimap_opacity " ) ;
2018-01-11 23:35:12 +01:00
2022-05-04 07:31:53 +02:00
ADD_GROUP ( " UI " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " arrange_nodes_button_hidden " ) , " set_arrange_nodes_button_hidden " , " is_arrange_nodes_button_hidden " ) ;
2022-09-09 15:29:51 +02:00
ADD_SIGNAL ( MethodInfo ( " connection_request " , PropertyInfo ( Variant : : STRING_NAME , " from_node " ) , PropertyInfo ( Variant : : INT , " from_port " ) , PropertyInfo ( Variant : : STRING_NAME , " to_node " ) , PropertyInfo ( Variant : : INT , " to_port " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " disconnection_request " , PropertyInfo ( Variant : : STRING_NAME , " from_node " ) , PropertyInfo ( Variant : : INT , " from_port " ) , PropertyInfo ( Variant : : STRING_NAME , " to_node " ) , PropertyInfo ( Variant : : INT , " to_port " ) ) ) ;
2018-12-27 11:10:09 +01:00
ADD_SIGNAL ( MethodInfo ( " popup_request " , PropertyInfo ( Variant : : VECTOR2 , " position " ) ) ) ;
2015-07-26 02:16:07 +02:00
ADD_SIGNAL ( MethodInfo ( " duplicate_nodes_request " ) ) ;
2019-07-12 19:36:33 +02:00
ADD_SIGNAL ( MethodInfo ( " copy_nodes_request " ) ) ;
ADD_SIGNAL ( MethodInfo ( " paste_nodes_request " ) ) ;
2018-09-01 12:05:51 +02:00
ADD_SIGNAL ( MethodInfo ( " node_selected " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_RESOURCE_TYPE , " Node " ) ) ) ;
2020-12-21 11:26:41 +01:00
ADD_SIGNAL ( MethodInfo ( " node_deselected " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_RESOURCE_TYPE , " Node " ) ) ) ;
2022-09-09 15:29:51 +02:00
ADD_SIGNAL ( MethodInfo ( " connection_to_empty " , PropertyInfo ( Variant : : STRING_NAME , " from_node " ) , PropertyInfo ( Variant : : INT , " from_port " ) , PropertyInfo ( Variant : : VECTOR2 , " release_position " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " connection_from_empty " , PropertyInfo ( Variant : : STRING_NAME , " to_node " ) , PropertyInfo ( Variant : : INT , " to_port " ) , PropertyInfo ( Variant : : VECTOR2 , " release_position " ) ) ) ;
2022-05-17 12:13:35 +02:00
ADD_SIGNAL ( MethodInfo ( " delete_nodes_request " , PropertyInfo ( Variant : : ARRAY , " nodes " , PROPERTY_HINT_ARRAY_TYPE , " StringName " ) ) ) ;
2020-10-20 08:22:40 +02:00
ADD_SIGNAL ( MethodInfo ( " begin_node_move " ) ) ;
ADD_SIGNAL ( MethodInfo ( " end_node_move " ) ) ;
2022-04-14 23:20:28 +02:00
ADD_SIGNAL ( MethodInfo ( " scroll_offset_changed " , PropertyInfo ( Variant : : VECTOR2 , " offset " ) ) ) ;
2022-09-09 15:29:51 +02:00
ADD_SIGNAL ( MethodInfo ( " connection_drag_started " , PropertyInfo ( Variant : : STRING , " from_node " ) , PropertyInfo ( Variant : : INT , " from_port " ) , PropertyInfo ( Variant : : BOOL , " is_output " ) ) ) ;
2021-07-26 16:31:31 +02:00
ADD_SIGNAL ( MethodInfo ( " connection_drag_ended " ) ) ;
2021-09-28 18:00:16 +02:00
BIND_ENUM_CONSTANT ( SCROLL_ZOOMS ) ;
BIND_ENUM_CONSTANT ( SCROLL_PANS ) ;
2015-01-03 20:52:37 +01:00
}
GraphEdit : : GraphEdit ( ) {
2015-07-26 02:16:07 +02:00
set_focus_mode ( FOCUS_ALL ) ;
2021-06-16 15:14:25 +02:00
// Allow dezooming 8 times from the default zoom level.
// At low zoom levels, text is unreadable due to its small size and poor filtering,
2021-04-17 20:02:04 +02:00
// but this is still useful for previewing and navigation.
2021-06-16 15:14:25 +02:00
zoom_min = ( 1 / Math : : pow ( zoom_step , 8 ) ) ;
// Allow zooming 4 times from the default zoom level.
zoom_max = ( 1 * Math : : pow ( zoom_step , 4 ) ) ;
2021-09-28 18:00:16 +02:00
panner . instantiate ( ) ;
panner - > set_callbacks ( callable_mp ( this , & GraphEdit : : _scroll_callback ) , callable_mp ( this , & GraphEdit : : _pan_callback ) , callable_mp ( this , & GraphEdit : : _zoom_callback ) ) ;
2017-03-05 16:44:50 +01:00
top_layer = memnew ( GraphEditFilter ( this ) ) ;
2021-08-25 15:49:30 +02:00
add_child ( top_layer , false , INTERNAL_MODE_BACK ) ;
2017-01-08 23:54:19 +01:00
top_layer - > set_mouse_filter ( MOUSE_FILTER_PASS ) ;
2022-03-19 01:02:57 +01:00
top_layer - > set_anchors_and_offsets_preset ( Control : : PRESET_FULL_RECT ) ;
2020-02-21 18:28:45 +01:00
top_layer - > connect ( " draw " , callable_mp ( this , & GraphEdit : : _top_layer_draw ) ) ;
top_layer - > connect ( " gui_input " , callable_mp ( this , & GraphEdit : : _top_layer_input ) ) ;
2022-01-19 19:59:12 +01:00
top_layer - > connect ( " focus_exited " , callable_mp ( panner . ptr ( ) , & ViewPanner : : release_pan_key ) ) ;
2015-01-03 20:52:37 +01:00
2017-03-05 16:44:50 +01:00
connections_layer = memnew ( Control ) ;
2021-08-25 15:49:30 +02:00
add_child ( connections_layer , false , INTERNAL_MODE_FRONT ) ;
2020-02-21 18:28:45 +01:00
connections_layer - > connect ( " draw " , callable_mp ( this , & GraphEdit : : _connections_layer_draw ) ) ;
2016-08-31 04:44:14 +02:00
connections_layer - > set_name ( " CLAYER " ) ;
2018-09-13 03:38:39 +02:00
connections_layer - > set_disable_visibility_clip ( true ) ; // so it can draw freely and be offset
2017-08-08 15:57:33 +02:00
connections_layer - > set_mouse_filter ( MOUSE_FILTER_IGNORE ) ;
2016-08-31 04:44:14 +02:00
2015-07-21 03:15:06 +02:00
h_scroll = memnew ( HScrollBar ) ;
h_scroll - > set_name ( " _h_scroll " ) ;
top_layer - > add_child ( h_scroll ) ;
2015-01-03 20:52:37 +01:00
2015-07-21 03:15:06 +02:00
v_scroll = memnew ( VScrollBar ) ;
v_scroll - > set_name ( " _v_scroll " ) ;
top_layer - > add_child ( v_scroll ) ;
2020-01-14 22:19:12 +01:00
2016-08-07 00:00:54 +02:00
//set large minmax so it can scroll even if not resized yet
h_scroll - > set_min ( - 10000 ) ;
h_scroll - > set_max ( 10000 ) ;
v_scroll - > set_min ( - 10000 ) ;
v_scroll - > set_max ( 10000 ) ;
2020-02-21 18:28:45 +01:00
h_scroll - > connect ( " value_changed " , callable_mp ( this , & GraphEdit : : _scroll_moved ) ) ;
v_scroll - > connect ( " value_changed " , callable_mp ( this , & GraphEdit : : _scroll_moved ) ) ;
2016-01-19 00:32:37 +01:00
2018-06-19 03:10:48 +02:00
zoom_hb = memnew ( HBoxContainer ) ;
2016-02-08 20:28:12 +01:00
top_layer - > add_child ( zoom_hb ) ;
2017-03-29 17:29:38 +02:00
zoom_hb - > set_position ( Vector2 ( 10 , 10 ) ) ;
2016-02-08 20:28:12 +01:00
2021-06-16 15:14:25 +02:00
zoom_label = memnew ( Label ) ;
zoom_hb - > add_child ( zoom_label ) ;
zoom_label - > set_visible ( false ) ;
zoom_label - > set_v_size_flags ( Control : : SIZE_SHRINK_CENTER ) ;
2021-11-25 03:58:47 +01:00
zoom_label - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2021-06-16 15:14:25 +02:00
zoom_label - > set_custom_minimum_size ( Size2 ( 48 , 0 ) ) ;
_update_zoom_label ( ) ;
2020-06-19 20:49:04 +02:00
zoom_minus = memnew ( Button ) ;
zoom_minus - > set_flat ( true ) ;
2016-02-08 20:28:12 +01:00
zoom_hb - > add_child ( zoom_minus ) ;
2022-08-25 12:42:17 +02:00
zoom_minus - > set_tooltip_text ( RTR ( " Zoom Out " ) ) ;
2020-02-21 18:28:45 +01:00
zoom_minus - > connect ( " pressed " , callable_mp ( this , & GraphEdit : : _zoom_minus ) ) ;
2016-08-04 05:05:35 +02:00
zoom_minus - > set_focus_mode ( FOCUS_NONE ) ;
2016-02-08 20:28:12 +01:00
2020-06-19 20:49:04 +02:00
zoom_reset = memnew ( Button ) ;
zoom_reset - > set_flat ( true ) ;
2016-02-08 20:28:12 +01:00
zoom_hb - > add_child ( zoom_reset ) ;
2022-08-25 12:42:17 +02:00
zoom_reset - > set_tooltip_text ( RTR ( " Zoom Reset " ) ) ;
2020-02-21 18:28:45 +01:00
zoom_reset - > connect ( " pressed " , callable_mp ( this , & GraphEdit : : _zoom_reset ) ) ;
2016-08-04 05:05:35 +02:00
zoom_reset - > set_focus_mode ( FOCUS_NONE ) ;
2016-02-08 20:28:12 +01:00
2020-06-19 20:49:04 +02:00
zoom_plus = memnew ( Button ) ;
zoom_plus - > set_flat ( true ) ;
2016-02-08 20:28:12 +01:00
zoom_hb - > add_child ( zoom_plus ) ;
2022-08-25 12:42:17 +02:00
zoom_plus - > set_tooltip_text ( RTR ( " Zoom In " ) ) ;
2020-02-21 18:28:45 +01:00
zoom_plus - > connect ( " pressed " , callable_mp ( this , & GraphEdit : : _zoom_plus ) ) ;
2016-08-04 05:05:35 +02:00
zoom_plus - > set_focus_mode ( FOCUS_NONE ) ;
2020-06-19 20:49:04 +02:00
snap_button = memnew ( Button ) ;
snap_button - > set_flat ( true ) ;
2016-08-04 05:05:35 +02:00
snap_button - > set_toggle_mode ( true ) ;
2022-08-25 12:42:17 +02:00
snap_button - > set_tooltip_text ( RTR ( " Enable snap and show grid. " ) ) ;
2020-02-21 18:28:45 +01:00
snap_button - > connect ( " pressed " , callable_mp ( this , & GraphEdit : : _snap_toggled ) ) ;
2016-08-04 05:05:35 +02:00
snap_button - > set_pressed ( true ) ;
snap_button - > set_focus_mode ( FOCUS_NONE ) ;
zoom_hb - > add_child ( snap_button ) ;
2017-03-05 16:44:50 +01:00
snap_amount = memnew ( SpinBox ) ;
2016-08-04 05:05:35 +02:00
snap_amount - > set_min ( 5 ) ;
snap_amount - > set_max ( 100 ) ;
snap_amount - > set_step ( 1 ) ;
2017-01-04 05:16:14 +01:00
snap_amount - > set_value ( 20 ) ;
2020-02-21 18:28:45 +01:00
snap_amount - > connect ( " value_changed " , callable_mp ( this , & GraphEdit : : _snap_value_changed ) ) ;
2016-08-04 05:05:35 +02:00
zoom_hb - > add_child ( snap_amount ) ;
2020-11-06 20:16:45 +01:00
minimap_button = memnew ( Button ) ;
minimap_button - > set_flat ( true ) ;
minimap_button - > set_toggle_mode ( true ) ;
2022-08-25 12:42:17 +02:00
minimap_button - > set_tooltip_text ( RTR ( " Enable grid minimap. " ) ) ;
2020-11-06 20:16:45 +01:00
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 ) ;
2021-08-10 21:14:19 +02:00
layout_button = memnew ( Button ) ;
layout_button - > set_flat ( true ) ;
zoom_hb - > add_child ( layout_button ) ;
2022-08-25 12:42:17 +02:00
layout_button - > set_tooltip_text ( RTR ( " Arrange nodes. " ) ) ;
2021-08-10 21:14:19 +02:00
layout_button - > connect ( " pressed " , callable_mp ( this , & GraphEdit : : arrange_nodes ) ) ;
layout_button - > set_focus_mode ( FOCUS_NONE ) ;
2020-11-06 20:16:45 +01:00
Vector2 minimap_size = Vector2 ( 240 , 160 ) ;
2020-12-17 18:40:32 +01:00
float minimap_opacity = 0.65 ;
2020-11-06 20:16:45 +01:00
minimap = memnew ( GraphEditMinimap ( this ) ) ;
top_layer - > add_child ( minimap ) ;
minimap - > set_name ( " _minimap " ) ;
minimap - > set_modulate ( Color ( 1 , 1 , 1 , minimap_opacity ) ) ;
2021-01-25 15:37:05 +01:00
minimap - > set_mouse_filter ( MOUSE_FILTER_PASS ) ;
2020-11-06 20:16:45 +01:00
minimap - > set_custom_minimum_size ( Vector2 ( 50 , 50 ) ) ;
minimap - > set_size ( minimap_size ) ;
minimap - > set_anchors_preset ( Control : : PRESET_BOTTOM_RIGHT ) ;
2020-12-22 17:24:29 +01:00
minimap - > set_offset ( Side : : SIDE_LEFT , - minimap_size . x - MINIMAP_OFFSET ) ;
minimap - > set_offset ( Side : : SIDE_TOP , - minimap_size . y - MINIMAP_OFFSET ) ;
minimap - > set_offset ( Side : : SIDE_RIGHT , - MINIMAP_OFFSET ) ;
minimap - > set_offset ( Side : : SIDE_BOTTOM , - MINIMAP_OFFSET ) ;
2020-11-06 20:16:45 +01:00
minimap - > connect ( " draw " , callable_mp ( this , & GraphEdit : : _minimap_draw ) ) ;
2017-01-09 19:50:08 +01:00
set_clip_contents ( true ) ;
2015-01-03 20:52:37 +01:00
}