Automatic arrangement of nodes in VisualScript/VisualShaders editors

This PR and commit adds the functionality to arrange nodes in VisualScript/VisualShader editor. The layout generated by this 
feature is compact, with minimum crossings between connections
& uniform horizontal & vertical gaps between the nodes. 

This work has been sponsored by GSoC '21.

Full list of additions/changes:
• Added arrange_nodes() method in GraphEdit module.
    • This method computes new positions for all the selected
      nodes by forming blocks and compressing them.
      The nodes are moved to these new positions. 
    • Adding this method to GraphEdit makes it available for 
      use in VisualScript/VisualShaders editors and its other
      subclasses. 
• Button with an icon has been added to call arrange_nodes() in GraphEdit. 
    • This button is inherited by VisualScript/VisualShaders editors
       to invoke the method.
• Undo/redo is functional with this method.
    • By using signals in arrange_nodes(), position changes are registered 
       in undo/redo stack of the subclass that is using the method. 
• Metadata of the method has been updated in ClassDB
• Method description has been added to class reference of GraphEdit
This commit is contained in:
Umang Kalra 2021-08-11 00:44:19 +05:30
parent da339f8ffc
commit 12fc3f1eef
9 changed files with 542 additions and 1 deletions

View file

@ -116,6 +116,8 @@ private:
Button *minimap_button;
Button *layout_button;
HScrollBar *h_scroll;
VScrollBar *v_scroll;
@ -230,6 +232,24 @@ private:
bool _check_clickable_control(Control *p_control, const Vector2 &pos);
bool arranging_graph = false;
enum SET_OPERATIONS {
IS_EQUAL,
IS_SUBSET,
DIFFERENCE,
UNION,
};
int _set_operations(SET_OPERATIONS p_operation, Set<StringName> &r_u, const Set<StringName> &r_v);
HashMap<int, Vector<StringName>> _layering(const Set<StringName> &r_selected_nodes, const HashMap<StringName, Set<StringName>> &r_upper_neighbours);
Vector<StringName> _split(const Vector<StringName> &r_layer, const HashMap<StringName, Dictionary> &r_crossings);
void _horizontal_alignment(Dictionary &r_root, Dictionary &r_align, const HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, Set<StringName>> &r_upper_neighbours, const Set<StringName> &r_selected_nodes);
void _crossing_minimisation(HashMap<int, Vector<StringName>> &r_layers, const HashMap<StringName, Set<StringName>> &r_upper_neighbours);
void _calculate_inner_shifts(Dictionary &r_inner_shifts, const Dictionary &r_root, const Dictionary &r_node_names, const Dictionary &r_align, const Set<StringName> &r_block_heads, const HashMap<StringName, Pair<int, int>> &r_port_info);
float _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);
void _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);
protected:
static void _bind_methods();
virtual void add_child_notify(Node *p_child) override;
@ -304,6 +324,8 @@ public:
HBoxContainer *get_zoom_hbox();
void arrange_nodes();
GraphEdit();
};