feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -31,6 +31,7 @@
#include "graph_node.h"
#include "scene/gui/box_container.h"
#include "scene/gui/graph_edit.h"
#include "scene/gui/label.h"
#include "scene/theme/theme_db.h"
@ -41,8 +42,8 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
int idx = str.get_slice("/", 1).to_int();
String slot_property_name = str.get_slice("/", 2);
int idx = str.get_slicec('/', 1).to_int();
String slot_property_name = str.get_slicec('/', 2);
Slot slot;
if (slot_table.has(idx)) {
@ -93,8 +94,8 @@ bool GraphNode::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
int idx = str.get_slice("/", 1).to_int();
StringName slot_property_name = str.get_slice("/", 2);
int idx = str.get_slicec('/', 1).to_int();
StringName slot_property_name = str.get_slicec('/', 2);
Slot slot;
if (slot_table.has(idx)) {
@ -196,6 +197,10 @@ void GraphNode::_resort() {
children_count++;
}
slot_count = children_count;
if (selected_slot >= slot_count) {
selected_slot = -1;
}
if (children_count == 0) {
return;
@ -279,12 +284,13 @@ void GraphNode::_resort() {
Rect2 rect(margin, from_y_pos, final_width, height);
fit_child_in_rect(child, rect);
slot_y_cache.push_back(from_y_pos - sb_panel->get_margin(SIDE_TOP) + height * 0.5);
slot_y_cache.push_back(child->get_rect().position.y + child->get_rect().size.height * 0.5);
ofs_y = to_y_pos;
valid_children_idx++;
}
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
}
@ -306,8 +312,311 @@ void GraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Co
port_icon->draw(get_canvas_item(), p_pos + icon_offset, p_color);
}
void GraphNode::_accessibility_action_slot(const Variant &p_data) {
CustomAccessibilityAction action = (CustomAccessibilityAction)p_data.operator int();
switch (action) {
case ACTION_CONNECT_INPUT: {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_left) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < left_port_cache.size(); i++) {
if (left_port_cache[i].slot_index == selected_slot) {
if (graph->is_keyboard_connecting()) {
graph->end_keyboard_connecting(this, i, -1);
} else {
graph->start_keyboard_connecting(this, i, -1);
}
queue_accessibility_update();
queue_redraw();
break;
}
}
}
}
}
} break;
case ACTION_CONNECT_OUTPUT: {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_right) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < right_port_cache.size(); i++) {
if (right_port_cache[i].slot_index == selected_slot) {
if (graph->is_keyboard_connecting()) {
graph->end_keyboard_connecting(this, -1, i);
} else {
graph->start_keyboard_connecting(this, -1, i);
}
queue_accessibility_update();
queue_redraw();
break;
}
}
}
}
}
} break;
case ACTION_FOLLOW_INPUT: {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_left) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < left_port_cache.size(); i++) {
if (left_port_cache[i].slot_index == selected_slot) {
GraphNode *target = graph->get_input_connection_target(get_name(), i);
if (target) {
target->grab_focus();
break;
}
}
}
}
}
}
} break;
case ACTION_FOLLOW_OUTPUT: {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_right) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < right_port_cache.size(); i++) {
if (right_port_cache[i].slot_index == selected_slot) {
GraphNode *target = graph->get_output_connection_target(get_name(), i);
if (target) {
target->grab_focus();
break;
}
}
}
}
}
}
} break;
}
}
void GraphNode::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (port_pos_dirty) {
_port_pos_update();
}
if (p_event->is_pressed() && slot_count > 0) {
if (p_event->is_action("ui_up", true)) {
selected_slot--;
if (selected_slot < 0) {
selected_slot = -1;
} else {
accept_event();
}
} else if (p_event->is_action("ui_down", true)) {
selected_slot++;
if (selected_slot >= slot_count) {
selected_slot = -1;
} else {
accept_event();
}
} else if (p_event->is_action("ui_cancel", true)) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph && graph->is_keyboard_connecting()) {
graph->force_connection_drag_end();
accept_event();
}
} else if (p_event->is_action("ui_graph_delete", true)) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph && graph->is_keyboard_connecting()) {
graph->end_keyboard_connecting(this, -1, -1);
accept_event();
}
} else if (p_event->is_action("ui_graph_follow_left", true)) {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_left) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < left_port_cache.size(); i++) {
if (left_port_cache[i].slot_index == selected_slot) {
GraphNode *target = graph->get_input_connection_target(get_name(), i);
if (target) {
target->grab_focus();
accept_event();
break;
}
}
}
}
}
}
} else if (p_event->is_action("ui_graph_follow_right", true)) {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_right) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < right_port_cache.size(); i++) {
if (right_port_cache[i].slot_index == selected_slot) {
GraphNode *target = graph->get_output_connection_target(get_name(), i);
if (target) {
target->grab_focus();
accept_event();
break;
}
}
}
}
}
}
} else if (p_event->is_action("ui_left", true)) {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_left) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < left_port_cache.size(); i++) {
if (left_port_cache[i].slot_index == selected_slot) {
if (graph->is_keyboard_connecting()) {
graph->end_keyboard_connecting(this, i, -1);
} else {
graph->start_keyboard_connecting(this, i, -1);
}
accept_event();
break;
}
}
}
}
}
} else if (p_event->is_action("ui_right", true)) {
if (slot_table.has(selected_slot)) {
const Slot &slot = slot_table[selected_slot];
if (slot.enable_right) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
for (int i = 0; i < right_port_cache.size(); i++) {
if (right_port_cache[i].slot_index == selected_slot) {
if (graph->is_keyboard_connecting()) {
graph->end_keyboard_connecting(this, -1, i);
} else {
graph->start_keyboard_connecting(this, -1, i);
}
accept_event();
break;
}
}
}
}
}
} else if (p_event->is_action("ui_accept", true)) {
if (slot_table.has(selected_slot)) {
int idx = 0;
for (int i = 0; i < get_child_count(false); i++) {
Control *child = as_sortable_control(get_child(i, false), SortableVisibilityMode::IGNORE);
if (!child) {
continue;
}
if (idx == selected_slot) {
selected_slot = -1;
child->grab_focus();
break;
}
idx++;
}
accept_event();
}
}
queue_accessibility_update();
queue_redraw();
}
GraphElement::gui_input(p_event);
}
void GraphNode::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
RID ae = get_accessibility_element();
ERR_FAIL_COND(ae.is_null());
String name = get_accessibility_name();
if (name.is_empty()) {
name = get_name();
}
name = vformat(ETR("graph node %s (%s)"), name, get_title());
if (slot_table.has(selected_slot)) {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
Dictionary type_info;
if (graph) {
type_info = graph->get_type_names();
}
const Slot &slot = slot_table[selected_slot];
name += ", " + vformat(ETR("slot %d of %d"), selected_slot + 1, slot_count);
if (slot.enable_left) {
if (type_info.has(slot.type_left)) {
name += "," + vformat(ETR("input port, type: %s"), type_info[slot.type_left]);
} else {
name += "," + vformat(ETR("input port, type: %d"), slot.type_left);
}
if (graph) {
for (int i = 0; i < left_port_cache.size(); i++) {
if (left_port_cache[i].slot_index == selected_slot) {
String cd = graph->get_connections_description(get_name(), i);
if (cd.is_empty()) {
name += " " + ETR("no connections");
} else {
name += " " + cd;
}
break;
}
}
}
}
if (slot.enable_left) {
if (type_info.has(slot.type_right)) {
name += "," + vformat(ETR("output port, type: %s"), type_info[slot.type_right]);
} else {
name += "," + vformat(ETR("output port, type: %d"), slot.type_right);
}
if (graph) {
for (int i = 0; i < right_port_cache.size(); i++) {
if (right_port_cache[i].slot_index == selected_slot) {
String cd = graph->get_connections_description(get_name(), i);
if (cd.is_empty()) {
name += " " + ETR("no connections");
} else {
name += " " + cd;
}
break;
}
}
}
}
if (graph && graph->is_keyboard_connecting()) {
name += ", " + ETR("currently selecting target port");
}
} else {
name += ", " + vformat(ETR("has %d slots"), slot_count);
}
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_LIST);
DisplayServer::get_singleton()->accessibility_update_set_name(ae, name);
DisplayServer::get_singleton()->accessibility_update_add_custom_action(ae, CustomAccessibilityAction::ACTION_CONNECT_INPUT, ETR("Edit Input Port Connection"));
DisplayServer::get_singleton()->accessibility_update_add_custom_action(ae, CustomAccessibilityAction::ACTION_CONNECT_OUTPUT, ETR("Edit Output Port Connection"));
DisplayServer::get_singleton()->accessibility_update_add_custom_action(ae, CustomAccessibilityAction::ACTION_FOLLOW_INPUT, ETR("Follow Input Port Connection"));
DisplayServer::get_singleton()->accessibility_update_add_custom_action(ae, CustomAccessibilityAction::ACTION_FOLLOW_OUTPUT, ETR("Follow Output Port Connection"));
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_CUSTOM, callable_mp(this, &GraphNode::_accessibility_action_slot));
} break;
case NOTIFICATION_FOCUS_EXIT: {
selected_slot = -1;
queue_redraw();
} break;
case NOTIFICATION_DRAW: {
// Used for layout calculations.
Ref<StyleBox> sb_panel = theme_cache.panel;
@ -317,6 +626,7 @@ void GraphNode::_notification(int p_what) {
Ref<StyleBox> sb_to_draw_titlebar = selected ? theme_cache.titlebar_selected : theme_cache.titlebar;
Ref<StyleBox> sb_slot = theme_cache.slot;
Ref<StyleBox> sb_slot_selected = theme_cache.slot_selected;
int port_h_offset = theme_cache.port_h_offset;
@ -329,6 +639,10 @@ void GraphNode::_notification(int p_what) {
// Draw body (slots area) stylebox.
draw_style_box(sb_to_draw_panel, body_rect);
if (has_focus()) {
draw_style_box(theme_cache.panel_focus, body_rect);
}
// Draw title bar stylebox above.
draw_style_box(sb_to_draw_titlebar, titlebar_rect);
@ -348,12 +662,18 @@ void GraphNode::_notification(int p_what) {
// Left port.
if (slot.enable_left) {
draw_port(slot_index, Point2i(port_h_offset, slot_y_cache[E.key] + sb_panel->get_margin(SIDE_TOP)), true, slot.color_left);
draw_port(slot_index, Point2i(port_h_offset, slot_y_cache[E.key]), true, slot.color_left);
}
// Right port.
if (slot.enable_right) {
draw_port(slot_index, Point2i(get_size().x - port_h_offset, slot_y_cache[E.key] + sb_panel->get_margin(SIDE_TOP)), false, slot.color_right);
draw_port(slot_index, Point2i(get_size().x - port_h_offset, slot_y_cache[E.key]), false, slot.color_right);
}
if (slot_index == selected_slot) {
Size2i port_sz = theme_cache.port->get_size();
draw_style_box(sb_slot_selected, Rect2i(port_h_offset - port_sz.x, slot_y_cache[E.key] + sb_panel->get_margin(SIDE_TOP) - port_sz.y, port_sz.x * 2, port_sz.y * 2));
draw_style_box(sb_slot_selected, Rect2i(get_size().x - port_h_offset - port_sz.x, slot_y_cache[E.key] + sb_panel->get_margin(SIDE_TOP) - port_sz.y, port_sz.x * 2, port_sz.y * 2));
}
// Draw slot stylebox.
@ -400,6 +720,8 @@ void GraphNode::set_slot(int p_slot_index, bool p_enable_left, int p_type_left,
slot.custom_port_icon_right = p_custom_right;
slot.draw_stylebox = p_draw_stylebox;
slot_table[p_slot_index] = slot;
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
@ -408,12 +730,16 @@ void GraphNode::set_slot(int p_slot_index, bool p_enable_left, int p_type_left,
void GraphNode::clear_slot(int p_slot_index) {
slot_table.erase(p_slot_index);
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
}
void GraphNode::clear_all_slots() {
slot_table.clear();
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
}
@ -433,6 +759,8 @@ void GraphNode::set_slot_enabled_left(int p_slot_index, bool p_enable) {
}
slot_table[p_slot_index].enable_left = p_enable;
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
@ -447,6 +775,8 @@ void GraphNode::set_slot_type_left(int p_slot_index, int p_type) {
}
slot_table[p_slot_index].type_left = p_type;
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
@ -517,6 +847,8 @@ void GraphNode::set_slot_enabled_right(int p_slot_index, bool p_enable) {
}
slot_table[p_slot_index].enable_right = p_enable;
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
@ -531,6 +863,8 @@ void GraphNode::set_slot_type_right(int p_slot_index, int p_type) {
}
slot_table[p_slot_index].type_right = p_type;
queue_accessibility_update();
queue_redraw();
port_pos_dirty = true;
@ -646,14 +980,9 @@ Size2 GraphNode::get_minimum_size() const {
void GraphNode::_port_pos_update() {
int edgeofs = theme_cache.port_h_offset;
int separation = theme_cache.separation;
Ref<StyleBox> sb_panel = theme_cache.panel;
Ref<StyleBox> sb_titlebar = theme_cache.titlebar;
left_port_cache.clear();
right_port_cache.clear();
int vertical_ofs = titlebar_hbox->get_size().height + sb_titlebar->get_minimum_size().height + sb_panel->get_margin(SIDE_TOP);
int slot_index = 0;
for (int i = 0; i < get_child_count(false); i++) {
@ -663,11 +992,12 @@ void GraphNode::_port_pos_update() {
}
Size2i size = child->get_rect().size;
Point2 pos = child->get_position();
if (slot_table.has(slot_index)) {
if (slot_table[slot_index].enable_left) {
PortCache port_cache;
port_cache.pos = Point2i(edgeofs, vertical_ofs + size.height / 2);
port_cache.pos = Point2i(edgeofs, pos.y + size.height / 2);
port_cache.type = slot_table[slot_index].type_left;
port_cache.color = slot_table[slot_index].color_left;
port_cache.slot_index = slot_index;
@ -675,7 +1005,7 @@ void GraphNode::_port_pos_update() {
}
if (slot_table[slot_index].enable_right) {
PortCache port_cache;
port_cache.pos = Point2i(get_size().width - edgeofs, vertical_ofs + size.height / 2);
port_cache.pos = Point2i(get_size().width - edgeofs, pos.y + size.height / 2);
port_cache.type = slot_table[slot_index].type_right;
port_cache.color = slot_table[slot_index].color_right;
port_cache.slot_index = slot_index;
@ -683,10 +1013,12 @@ void GraphNode::_port_pos_update() {
}
}
vertical_ofs += separation;
vertical_ofs += size.height;
slot_index++;
}
slot_count = slot_index;
if (selected_slot >= slot_count) {
selected_slot = -1;
}
port_pos_dirty = false;
}
@ -781,6 +1113,25 @@ int GraphNode::get_output_port_slot(int p_port_idx) {
return right_port_cache[p_port_idx].slot_index;
}
String GraphNode::get_accessibility_container_name(const Node *p_node) const {
int idx = 0;
for (int i = 0; i < get_child_count(false); i++) {
Control *child = as_sortable_control(get_child(i, false), SortableVisibilityMode::IGNORE);
if (!child) {
continue;
}
if (child == p_node) {
String name = get_accessibility_name();
if (name.is_empty()) {
name = get_name();
}
return vformat(ETR(", in slot %d of graph node %s (%s)"), idx + 1, name, get_title());
}
idx++;
}
return String();
}
void GraphNode::set_title(const String &p_title) {
if (title == p_title) {
return;
@ -890,9 +1241,11 @@ void GraphNode::_bind_methods() {
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, panel);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, panel_selected);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, panel_focus);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, titlebar);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, titlebar_selected);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, slot);
BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, slot_selected);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphNode, separation);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphNode, port_h_offset);
@ -910,7 +1263,9 @@ GraphNode::GraphNode() {
title_label = memnew(Label);
title_label->set_theme_type_variation("GraphNodeTitleLabel");
title_label->set_h_size_flags(SIZE_EXPAND_FILL);
title_label->set_focus_mode(Control::FOCUS_NONE);
titlebar_hbox->add_child(title_label);
set_mouse_filter(MOUSE_FILTER_STOP);
set_focus_mode(FOCUS_ACCESSIBILITY);
}