From 2fc80b006096b6574570c669d0d585ea2fa7b613 Mon Sep 17 00:00:00 2001 From: Tanasart Date: Sun, 21 Apr 2024 20:02:10 +0700 Subject: [PATCH] pin --- .../scripts/node_pin/node_pin.gml.backup0 | 26 +- .../scripts/node_pin/node_pin.gml.backup1 | 105 + .../panel_graph/panel_graph.gml.backup0 | 2331 ++++++++++++++++ .../panel_graph/panel_graph.gml.backup1 | 2332 +++++++++++++++++ scripts/node_pin/node_pin.gml | 24 +- scripts/panel_graph/panel_graph.gml | 7 +- 6 files changed, 4794 insertions(+), 31 deletions(-) create mode 100644 #backups/scripts/node_pin/node_pin.gml.backup1 create mode 100644 #backups/scripts/panel_graph/panel_graph.gml.backup0 create mode 100644 #backups/scripts/panel_graph/panel_graph.gml.backup1 diff --git a/#backups/scripts/node_pin/node_pin.gml.backup0 b/#backups/scripts/node_pin/node_pin.gml.backup0 index a75ceaae0..a4d82933d 100644 --- a/#backups/scripts/node_pin/node_pin.gml.backup0 +++ b/#backups/scripts/node_pin/node_pin.gml.backup0 @@ -1,4 +1,4 @@ -// 2024-04-21 17:06:08 +// 2024-04-21 20:02:06 function Node_Pin(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { name = "Pin"; w = 32; @@ -57,34 +57,32 @@ function Node_Pin(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { static drawJunctionNames = function(_x, _y, _mx, _my, _s) {} static drawJunctions = function(_x, _y, _mx, _my, _s) { #region - isHovering = false; - var hover = noone; + + var _dval = PANEL_GRAPH.value_dragging; + var hover = _dval == noone || _dval.connect_type == JUNCTION_CONNECT.input? outputs[| 0] : inputs[| 0]; var xx = x * _s + _x; var yy = y * _s + _y; - var hov = PANEL_GRAPH.value_dragging; + isHovering = point_in_circle(_mx, _my, xx, yy, _s * 24); - if(hov == noone && point_in_circle(_mx, _my, xx, yy, _s * 24)) { - isHovering = true; - hover_scale_to = 1; - } + hover.drawJunction(_s, _mx, _my); - if(outputs[| 0].drawJunction(_s, _mx, _my)) - hover = outputs[| 0]; + if(!isHovering) return noone; + hover_scale_to = 1; return hover; } #endregion static drawNode = function(_x, _y, _mx, _my, _s) { #region - if(group != PANEL_GRAPH.getCurrentContext()) return; + // if(group != PANEL_GRAPH.getCurrentContext()) return; var xx = x * _s + _x; var yy = y * _s + _y; hover_alpha = 0.5; if(active_draw_index > -1) { - hover_alpha = 1; - hover_scale_to = 1; - active_draw_index = -1; + hover_alpha = 1; + hover_scale_to = 1; + active_draw_index = -1; } if(hover_scale > 0) { diff --git a/#backups/scripts/node_pin/node_pin.gml.backup1 b/#backups/scripts/node_pin/node_pin.gml.backup1 new file mode 100644 index 000000000..3a3bd6834 --- /dev/null +++ b/#backups/scripts/node_pin/node_pin.gml.backup1 @@ -0,0 +1,105 @@ +// 2024-04-21 19:59:15 +function Node_Pin(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { + name = "Pin"; + w = 32; + h = 32; + + auto_height = false; + junction_shift_y = 16; + + isHovering = false; + hover_scale = 0; + hover_scale_to = 0; + hover_alpha = 0; + + bg_spr = THEME.node_pin_bg; + bg_sel_spr = THEME.node_pin_bg_active; + + inputs[| 0] = nodeValue("In", self, JUNCTION_CONNECT.input, VALUE_TYPE.any, 0 ) + .setVisible(true, true); + + outputs[| 0] = nodeValue("Out", self, JUNCTION_CONNECT.output, VALUE_TYPE.any, 0); + + static step = function() { #region + if(inputs[| 0].isLeaf()) return; + + inputs[| 0].setType(inputs[| 0].value_from.type); + outputs[| 0].setType(inputs[| 0].value_from.type); + + inputs[| 0].color_display = inputs[| 0].value_from.color_display; + outputs[| 0].color_display = inputs[| 0].color_display; + } #endregion + + static update = function() { #region + var _val = getInputData(0); + outputs[| 0].setValue(_val); + } #endregion + + static pointIn = function(_x, _y, _mx, _my, _s) { #region + var xx = x * _s + _x; + var yy = y * _s + _y; + + return point_in_circle(_mx, _my, xx, yy, _s * 24); + } #endregion + + static preDraw = function(_x, _y, _s) { #region + var xx = x * _s + _x; + var yy = y * _s + _y; + + inputs[| 0].x = xx; + inputs[| 0].y = yy; + + outputs[| 0].x = xx; + outputs[| 0].y = yy; + } #endregion + + static drawBadge = function(_x, _y, _s) {} + static drawJunctionNames = function(_x, _y, _mx, _my, _s) {} + + static drawJunctions = function(_x, _y, _mx, _my, _s) { #region + + var _dval = PANEL_GRAPH.value_dragging; + var hover = _dval == noone || _dval.connect_type == JUNCTION_CONNECT.input? outputs[| 0] : inputs[| 0]; + var xx = x * _s + _x; + var yy = y * _s + _y; + isHovering = point_in_circle(_mx, _my, xx, yy, _s * 24); + + hover.drawJunction(_s, _mx, _my); + + if(!isHovering) return noone; + + hover_scale_to = 1; + return hover; + } #endregion + + static drawNode = function(_x, _y, _mx, _my, _s) { #region + // if(group != PANEL_GRAPH.getCurrentContext()) return; + + var xx = x * _s + _x; + var yy = y * _s + _y; + + hover_alpha = 0.5; + if(active_draw_index > -1) { + hover_alpha = 1; + hover_scale_to = 1; + active_draw_index = -1; + } + + if(hover_scale > 0) { + draw_set_color(COLORS._main_accent); + draw_set_alpha(hover_alpha); + draw_circle_border(xx, yy, _s * hover_scale * 20, 2); + draw_set_alpha(1); + } + + hover_scale = lerp_float(hover_scale, hover_scale_to, 3); + hover_scale_to = 0; + + if(renamed && display_name != "" && display_name != "Pin") { + draw_set_text(f_p0, fa_center, fa_bottom, COLORS._main_text); + draw_text_transformed(xx, yy - 12, display_name, _s, _s, 0); + } + + return drawJunctions(_x, _y, _mx, _my, _s); + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/panel_graph/panel_graph.gml.backup0 b/#backups/scripts/panel_graph/panel_graph.gml.backup0 new file mode 100644 index 000000000..a49c1930a --- /dev/null +++ b/#backups/scripts/panel_graph/panel_graph.gml.backup0 @@ -0,0 +1,2331 @@ +// 2024-04-21 19:34:00 +#region funtion calls + function __fnInit_Graph() { + __registerFunction("graph_add_node", panel_graph_add_node); + __registerFunction("graph_focus_content", panel_graph_focus_content); + __registerFunction("graph_preview_focus", panel_graph_preview_focus); + __registerFunction("graph_preview_window", panel_graph_preview_window); + + __registerFunction("graph_import_image", panel_graph_import_image); + __registerFunction("graph_import_image_array", panel_graph_import_image_array); + __registerFunction("graph_add_number", panel_graph_add_number); + __registerFunction("graph_add_vec2", panel_graph_add_vec2); + __registerFunction("graph_add_vec3", panel_graph_add_vec3); + __registerFunction("graph_add_vec4", panel_graph_add_vec4); + __registerFunction("graph_add_transform", panel_graph_add_transform); + + __registerFunction("graph_select_all", panel_graph_select_all); + __registerFunction("graph_toggle_grid", panel_graph_toggle_grid); + __registerFunction("graph_toggle_preview", panel_graph_toggle_preview); + __registerFunction("graph_toggle_render", panel_graph_toggle_render); + + __registerFunction("graph_export", panel_graph_export); + + __registerFunction("graph_blend", panel_graph_blend); + __registerFunction("graph_compose", panel_graph_compose); + __registerFunction("graph_array", panel_graph_array); + __registerFunction("graph_group", panel_graph_group); + __registerFunction("graph_ungroup", panel_graph_ungroup); + + __registerFunction("graph_canvas", panel_graph_canvas); + __registerFunction("graph_canvas_blend", panel_graph_canvas_blend); + + __registerFunction("graph_frame", panel_graph_frame); + __registerFunction("graph_delete_break", panel_graph_delete_break); + __registerFunction("graph_delete_merge", panel_graph_delete_merge); + __registerFunction("graph_duplicate", panel_graph_duplicate); + __registerFunction("graph_copy", panel_graph_copy); + __registerFunction("graph_paste", panel_graph_paste); + + __registerFunction("graph_pan", panel_graph_pan); + __registerFunction("graph_zoom", panel_graph_zoom); + } + + function panel_graph_add_node() { CALL("graph_add_node"); PANEL_GRAPH.callAddDialog(); } + function panel_graph_focus_content() { CALL("graph_focus_content"); PANEL_GRAPH.fullView(); } + function panel_graph_preview_focus() { CALL("graph_preview_focus"); PANEL_GRAPH.setCurrentPreview(); } + function panel_graph_preview_window() { CALL("graph_preview_window"); PANEL_GRAPH.create_preview_window(PANEL_GRAPH.getFocusingNode()); } + + function panel_graph_import_image() { CALL("graph_import_image"); nodeBuild("Node_Image", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_import_image_array() { CALL("graph_import_image_array"); nodeBuild("Node_Image_Sequence", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_number() { CALL("graph_add_number"); nodeBuild("Node_Number", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_vec2() { CALL("graph_add_vec2"); nodeBuild("Node_Vector2", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_vec3() { CALL("graph_add_vec3"); nodeBuild("Node_Vector3", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_vec4() { CALL("graph_add_vec4"); nodeBuild("Node_Vector4", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_transform() { CALL("graph_add_transform"); PANEL_GRAPH.doTransform(); } + + function panel_graph_select_all() { CALL("graph_select_all"); PANEL_GRAPH.nodes_selecting = ds_list_to_array(PANEL_GRAPH.nodes_list); } + function panel_graph_toggle_grid() { CALL("graph_toggle_grid"); PANEL_GRAPH.display_parameter.show_grid = !PANEL_GRAPH.display_parameter.show_grid; } + function panel_graph_toggle_preview() { CALL("graph_toggle_preview"); PANEL_GRAPH.setTriggerPreview(); } + function panel_graph_toggle_parameter() { CALL("graph_toggle_parameter"); PANEL_GRAPH.setTriggerParameter(); } + function panel_graph_toggle_render() { CALL("graph_toggle_render"); PANEL_GRAPH.setTriggerRender(); } + + function panel_graph_export() { CALL("graph_export"); PANEL_GRAPH.setCurrentExport(); } + + function panel_graph_blend() { CALL("graph_blend"); PANEL_GRAPH.doBlend(); } + function panel_graph_compose() { CALL("graph_compose"); PANEL_GRAPH.doCompose(); } + function panel_graph_array() { CALL("graph_array"); PANEL_GRAPH.doArray(); } + function panel_graph_group() { CALL("graph_group"); PANEL_GRAPH.doGroup(); } + function panel_graph_ungroup() { CALL("graph_ungroup"); PANEL_GRAPH.doUngroup(); } + + function panel_graph_canvas() { CALL("graph_canvas"); PANEL_GRAPH.setCurrentCanvas(); } + function panel_graph_canvas_blend() { CALL("graph_canvas_blend"); PANEL_GRAPH.setCurrentCanvasBlend(); } + + function panel_graph_frame() { CALL("graph_frame"); PANEL_GRAPH.doFrame(); } + function panel_graph_delete_break() { CALL("graph_delete_break"); PANEL_GRAPH.doDelete(false); } + function panel_graph_delete_merge() { CALL("graph_delete_merge"); PANEL_GRAPH.doDelete(true); } + function panel_graph_duplicate() { CALL("graph_duplicate"); PANEL_GRAPH.doDuplicate(); } + function panel_graph_copy() { CALL("graph_copy"); PANEL_GRAPH.doCopy(); } + function panel_graph_paste() { CALL("graph_paste"); PANEL_GRAPH.doPaste(); } + + function panel_graph_pan() { CALL("graph_pan"); PANEL_GRAPH.graph_dragging_key = true; } + function panel_graph_zoom() { CALL("graph_zoom"); PANEL_GRAPH.graph_zooming_key = true; } +#endregion + +function connectionParameter() constructor { #region + log = false; + active = true; + + x = 0; + y = 0; + s = 0; + mx = 0; + my = 0; + aa = 0; + bg = 0; + + minx = 0; + miny = 0; + maxx = 0; + maxy = 0; + + max_layer = 0; + highlight = 0; + cur_layer = 1; + + static setPos = function(_x, _y, _s, _mx, _my) { + self.x = _x; + self.y = _y; + self.s = _s; + self.mx = _mx; + self.my = _my; + } + + static setBoundary = function(_minx, _miny, _maxx, _maxy) { + self.minx = _minx; + self.miny = _miny; + self.maxx = _maxx; + self.maxy = _maxy; + } + + static setProp = function(_max_layer, _highlight) { + self.max_layer = _max_layer; + self.highlight = _highlight; + } + + static setDraw = function(_aa, _bg = c_black) { + self.aa = _aa; + self.bg = _bg; + } +} #endregion + +function Panel_Graph(project = PROJECT) : PanelContent() constructor { + title = __txt("Graph"); + title_raw = ""; + context_str = "Graph"; + icon = THEME.panel_graph_icon; + + static setProject = function(project) { + self.project = project; + nodes_list = project.nodes; + } + setProject(project); + + #region ---- display ---- + display_parameter = { + show_grid : true, + show_dimension : true, + show_compute : true, + + avoid_label : true, + preview_scale : 100, + highlight : false, + } + + connection_param = new connectionParameter(); + + bg_color = c_black; + #endregion + + #region ---- position ---- + scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0]; + graph_s = 1; + graph_s_to = graph_s; + + graph_dragging_key = false; + graph_zooming_key = false; + + graph_draggable= true; + graph_dragging = false; + graph_drag_mx = 0; + graph_drag_my = 0; + graph_drag_sx = 0; + graph_drag_sy = 0; + + graph_zooming = false; + graph_zoom_mx = 0; + graph_zoom_my = 0; + graph_zoom_m = 0; + graph_zoom_s = 0; + + drag_key = PREFERENCES.pan_mouse_key; + drag_locking = false; + #endregion + + #region ---- mouse ---- + mouse_graph_x = 0; + mouse_graph_y = 0; + mouse_grid_x = 0; + mouse_grid_y = 0; + mouse_on_graph = false; + + node_bg_hovering = false; + #endregion + + #region ---- nodes ---- + node_context = ds_list_create(); + + node_dragging = noone; + node_drag_mx = 0; + node_drag_my = 0; + node_drag_sx = 0; + node_drag_sy = 0; + node_drag_ox = 0; + node_drag_oy = 0; + + selection_block = 0; + nodes_selecting = []; + nodes_selecting_jun = []; + nodes_select_drag = 0; + nodes_select_frame = 0; + nodes_select_mx = 0; + nodes_select_my = 0; + + nodes_junction_d = noone; + nodes_junction_dx = 0; + nodes_junction_dy = 0; + + node_hovering = noone; + node_hover = noone; + + junction_hovering = noone; + junction_hover_direct = noone; + add_node_draw_junc = false; + add_node_draw_x_fix = 0; + add_node_draw_y_fix = 0; + add_node_draw_x = 0; + add_node_draw_y = 0; + + connection_aa = 2; + connection_surface = surface_create(1, 1); + connection_surface_aa = surface_create(1, 1); + + connection_draw_mouse = noone; + connection_draw_target = noone; + + value_focus = noone; + value_dragging = noone; + value_draggings = []; + + frame_hovering = noone; + _frame_hovering = noone; + #endregion + + #region ---- minimap ---- + minimap_show = false; + minimap_w = ui(160); + minimap_h = ui(160); + minimap_surface = -1; + + minimap_panning = false; + minimap_dragging = false; + minimap_drag_sx = 0; + minimap_drag_sy = 0; + minimap_drag_mx = 0; + minimap_drag_my = 0; + #endregion + + #region ---- context frame ---- + context_framing = false; + context_frame_progress = 0; + context_frame_direct = 0; + context_frame_sx = 0; context_frame_ex = 0; + context_frame_sy = 0; context_frame_ey = 0; + #endregion + + toolbar_height = ui(40); + + function toCenterNode(_list = nodes_list) { #region + if(!project.active) return; + + if(ds_list_empty(_list)) { + graph_x = round(w / 2 / graph_s); + graph_y = round(h / 2 / graph_s); + return; + } + + var minx = 99999; + var maxx = -99999; + var miny = 99999; + var maxy = -99999; + + for(var i = 0; i < ds_list_size(_list); i++) { + var _node = _list[| i]; + if(!is_struct(_node) || !is_instanceof(_node, Node) || !_node.active) + continue; + + minx = min(_node.x - 32, minx); + maxx = max(_node.x + _node.w + 32, maxx); + + miny = min(_node.y - 32, miny); + maxy = max(_node.y + _node.h + 32, maxy); + } + + graph_x = w / 2 / graph_s - (minx + maxx) / 2; + graph_y = (h - toolbar_height) / 2 / graph_s - (miny + maxy) / 2; + + graph_x = round(graph_x); + graph_y = round(graph_y); + } #endregion + + function initSize() { toCenterNode(); } initSize(); + + #region ++++ hotkeys ++++ + addHotkey("Graph", "Add node", "A", MOD_KEY.none, panel_graph_add_node); + addHotkey("Graph", "Focus content", "F", MOD_KEY.none, panel_graph_focus_content); + addHotkey("Graph", "Preview focusing node", "P", MOD_KEY.none, panel_graph_preview_focus); + addHotkey("Graph", "Preview window", "P", MOD_KEY.ctrl, panel_graph_preview_window); + + addHotkey("Graph", "Import image", "I", MOD_KEY.none, panel_graph_import_image); + addHotkey("Graph", "Import image array", "I", MOD_KEY.shift, panel_graph_import_image_array); + addHotkey("Graph", "Add number", "1", MOD_KEY.none, panel_graph_add_number); + addHotkey("Graph", "Add vector2", "2", MOD_KEY.none, panel_graph_add_vec2); + addHotkey("Graph", "Add vector3", "3", MOD_KEY.none, panel_graph_add_vec3); + addHotkey("Graph", "Add vector4", "4", MOD_KEY.none, panel_graph_add_vec4); + addHotkey("Graph", "Transform node", "T", MOD_KEY.ctrl, panel_graph_add_transform); + + addHotkey("Graph", "Select all", "A", MOD_KEY.ctrl, panel_graph_select_all); + addHotkey("Graph", "Toggle grid", "G", MOD_KEY.none, panel_graph_toggle_grid); + addHotkey("Graph", "Toggle preview", "H", MOD_KEY.none, panel_graph_toggle_preview); + addHotkey("Graph", "Toggle render", "R", MOD_KEY.none, panel_graph_toggle_render); + addHotkey("Graph", "Toggle parameters", "M", MOD_KEY.none, panel_graph_toggle_parameter); + + if(!DEMO) addHotkey("Graph", "Export", "E", MOD_KEY.ctrl, panel_graph_export); + + addHotkey("Graph", "Blend", "B", MOD_KEY.ctrl, panel_graph_blend); + addHotkey("Graph", "Compose", "B", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_compose); + addHotkey("Graph", "Array", "A", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_array); + addHotkey("Graph", "Group", "G", MOD_KEY.ctrl, panel_graph_group); + addHotkey("Graph", "Ungroup", "G", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_ungroup); + + addHotkey("Graph", "Canvas", "C", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_canvas); + addHotkey("Graph", "Canvas blend", "C", MOD_KEY.ctrl | MOD_KEY.alt, panel_graph_canvas_blend); + + addHotkey("Graph", "Frame", "F", MOD_KEY.ctrl, panel_graph_frame); + + addHotkey("Graph", "Delete (break)", vk_delete, MOD_KEY.shift, panel_graph_delete_break); + addHotkey("Graph", "Delete (merge)", vk_delete, MOD_KEY.none, panel_graph_delete_merge); + + addHotkey("Graph", "Duplicate", "D", MOD_KEY.ctrl, panel_graph_duplicate); + addHotkey("Graph", "Copy", "C", MOD_KEY.ctrl, panel_graph_copy); + addHotkey("Graph", "Paste", "V", MOD_KEY.ctrl, panel_graph_paste); + + addHotkey("Graph", "Pan", "", MOD_KEY.ctrl, panel_graph_pan); + addHotkey("Graph", "Zoom", "", MOD_KEY.alt | MOD_KEY.ctrl, panel_graph_zoom); + #endregion + + #region ++++ toolbars ++++ + tooltip_center = new tooltipHotkey(__txtx("panel_graph_center_to_nodes", "Center to nodes"), "Graph", "Focus content"); + + toolbars = [ + [ + THEME.icon_preview_export, + function() { return 0; }, + function() { return __txtx("panel_graph_export_image", "Export graph as image"); }, + function() { dialogPanelCall(new Panel_Graph_Export_Image(self)); } + ], + [ + THEME.icon_center_canvas, + function() { return 0; }, + function() { return tooltip_center; }, + function() { toCenterNode(); } + ], + [ + THEME.icon_minimap, + function() { return minimap_show; }, + function() { return minimap_show? __txtx("panel_graph_minimap_enabled", "Minimap enabled") : __txtx("panel_graph_minimap_disabled", "Minimap disabled"); }, + function() { minimap_show = !minimap_show; } + ], + [ + THEME.icon_curve_connection, + function() { return PREFERENCES.curve_connection_line; }, + function() { return __txtx("panel_graph_connection_line", "Connection render settings"); }, + function(param) { + dialogPanelCall(new Panel_Graph_Connection_Setting(), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); + } + ], + [ + THEME.icon_grid_setting, + function() { return 0; }, + function() { return __txtx("grid_title", "Grid settings"); }, + function(param) { + dialogPanelCall(new Panel_Graph_Grid_Setting(), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); + } + ], + [ + THEME.icon_visibility, + function() { return 0; }, + function() { return __txtx("graph_visibility_title", "Visibility settings"); }, + function(param) { + dialogPanelCall(new Panel_Graph_View_Setting(display_parameter), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); + } + ], + ]; + #endregion + + #region ++++ node setters ++++ + function setCurrentPreview(_node = getFocusingNode()) { #region + if(!_node) return; + + PANEL_PREVIEW.setNodePreview(_node); + } #endregion + + function setCurrentExport(_node = getFocusingNode()) { #region + if(DEMO) return; + if(!_node) return; + + var _outp = -1; + var _path = -1; + + for( var i = 0; i < ds_list_size(_node.outputs); i++ ) { + if(_node.outputs[| i].type == VALUE_TYPE.path) + _path = _node.outputs[| i]; + if(_node.outputs[| i].type == VALUE_TYPE.surface && _outp == -1) + _outp = _node.outputs[| i]; + } + + if(_outp == -1) return; + + var _export = nodeBuild("Node_Export", _node.x + _node.w + 64, _node.y); + if(_path != -1) + _export.inputs[| 1].setFrom(_path); + + _export.inputs[| 0].setFrom(_outp); + } #endregion + + function setCurrentCanvas(_node = getFocusingNode()) { #region + if(!_node) return; + + var _outp = -1; + var surf = -1; + + for( var i = 0; i < ds_list_size(_node.outputs); i++ ) { + if(_node.outputs[| i].type != VALUE_TYPE.surface) continue; + + _outp = _node.outputs[| i]; + surf = _outp.getValue(); + break; + } + + if(_outp == -1) return; + if(!is_array(surf)) surf = [ surf ]; + + var _canvas = nodeBuild("Node_Canvas", _node.x + _node.w + 64, _node.y); + var _dim = surface_get_dimension(surf[0]); + + _canvas.attributes.dimension = _dim; + _canvas.attributes.frames = array_length(surf); + _canvas.canvas_surface = surface_array_clone(surf); + _canvas.inputs[| 0].setValue(_dim); + + _canvas.apply_surfaces(); + + } #endregion + + function setTriggerPreview() { #region + __temp_show = false; + array_foreach(nodes_selecting, function(node, index) { + if(index == 0) __temp_show = !node.previewable; + node.previewable = __temp_show; + node.refreshNodeDisplay(); + }); + } #endregion + + function setTriggerParameter() { #region + __temp_show = false; + array_foreach(nodes_selecting, function(node, index) { + if(index == 0) __temp_show = !node.show_parameter; + node.show_parameter = __temp_show; + node.refreshNodeDisplay(); + }); + } #endregion + + function setTriggerRender() { #region + __temp_active = false; + array_foreach(nodes_selecting, function(node, index) { + if(index == 0) __temp_active = !node.renderActive; + node.renderActive = __temp_active; + }); + } #endregion + + function setCurrentCanvasBlend(_node = getFocusingNode()) { #region + if(!_node) return; + + var _outp = -1; + var surf = -1; + + for( var i = 0; i < ds_list_size(_node.outputs); i++ ) { + if(_node.outputs[| i].type == VALUE_TYPE.surface) { + _outp = _node.outputs[| i]; + var _val = _node.outputs[| i].getValue(); + if(is_array(_val)) + surf = _val[_node.preview_index]; + else + surf = _val; + break; + } + } + + if(_outp == -1) return; + + var _canvas = nodeBuild("Node_Canvas", _node.x, _node.y + _node.h + 64); + + _canvas.inputs[| 0].setValue([surface_get_width_safe(surf), surface_get_height_safe(surf)]); + _canvas.inputs[| 5].setValue(true); + + var _blend = new Node_Blend(_node.x + _node.w + 64, _node.y, getCurrentContext()); + _blend.inputs[| 0].setFrom(_outp); + _blend.inputs[| 1].setFrom(_canvas.outputs[| 0]); + } #endregion + #endregion + + #region ++++ context menu ++++ + menu_sent_to_preview = menuItem(__txtx("panel_graph_send_to_preview", "Send to preview"), function() { setCurrentPreview(node_hover); }); + menu_send_to_window = menuItem(__txtx("panel_graph_preview_window", "Send to preview window"), function() { create_preview_window(node_hover); }, noone, ["Graph", "Preview window"]); + menu_sent_to_inspector = menuItem(__txtx("panel_graph_inspector_panel", "Send to new inspector"), function() { + var pan = panelAdd("Panel_Inspector", true); + pan.destroy_on_click_out = false; + pan.content.setInspecting(node_hover); + pan.content.locked = true; + }); + menu_send_export = menuItem(__txtx("panel_graph_send_to_export", "Send to export"), function() { setCurrentExport(node_hover); }, noone, ["Graph", "Export"]); + menu_toggle_preview = menuItem(__txtx("panel_graph_toggle_preview", "Toggle node preview"), function() { setTriggerPreview(); }, noone, ["Graph", "Toggle preview"]); + menu_toggle_render = menuItem(__txtx("panel_graph_toggle_render", "Toggle node render"), function() { setTriggerRender(); }, noone, ["Graph", "Toggle render"]); + menu_toggle_param = menuItem(__txtx("panel_graph_toggle_parameter", "Toggle node parameters"),function() { setTriggerParameter(); }, noone, ["Graph", "Toggle parameters"]); + menu_open_group = menuItem(__txtx("panel_graph_enter_group", "Open group"), function() { PANEL_GRAPH.addContext(node_hover); }, THEME.group); + + function openGroupTab(group) { + var graph = new Panel_Graph(project); + panel.setContent(graph, true); + + for( var i = 0; i < ds_list_size(node_context); i++ ) + graph.addContext(node_context[| i]); + graph.addContext(group); + + setFocus(panel); + } + menu_open_group_tab = menuItem(__txtx("panel_graph_enter_group_new_tab", "Open group in new tab"), function() { openGroupTab(node_hover); }, THEME.group); + menu_group_ungroup = menuItem(__txt("Ungroup"), function() { doUngroup(); }, THEME.group, ["Graph", "Ungroup"]); + menu_group_tool = menuItem(__txt("Set as group tool"), function() { node_hover.setTool(!node_hover.isTool); }); + + menu_node_delete_merge = menuItem(__txtx("panel_graph_delete_and_merge_connection", "Delete and merge connection"), function() { doDelete(true); }, THEME.cross, ["Graph", "Delete (merge)"]); + menu_node_delete_cut = menuItem(__txtx("panel_graph_delete_and_cut_connection", "Delete and cut connection"), function() { doDelete(false); }, THEME.cross, ["Graph", "Delete (break)"]); + menu_node_duplicate = menuItem(__txt("Duplicate"), function() { doDuplicate(); }, THEME.duplicate, ["Graph", "Duplicate"]); + menu_node_copy = menuItem(__txt("Copy"), function() { doCopy(); }, THEME.copy, ["Graph", "Copy"]); + + menu_node_transform = menuItem(__txtx("panel_graph_add_transform", "Add transform"), function() { doTransform(); }, noone, ["Graph", "Transform node"]); + menu_node_canvas = menuItem(__txtx("panel_graph_canvas", "Canvas"), + function(_dat) { + return submenuCall(_dat, [ + menuItem(__txtx("panel_graph_copy_to_canvas", "Copy to canvas"), function() { setCurrentCanvas(node_hover); }, noone, ["Graph", "Canvas"]), + menuItem(__txtx("panel_graph_overlay_canvas", "Overlay canvas"), function() { setCurrentCanvasBlend(node_hover); }, noone, ["Graph", "Canvas blend"]) + ]); + }).setIsShelf(); + + menu_nodes_align = menuItem(__txtx("panel_graph_align_nodes", "Align nodes"), function(_dat) { + return submenuCall(_dat, [ + menuItemGroup(__txtx("horizontal", "Horizontal"), [ + [ [THEME.inspector_surface_halign, 0], function() { node_halign(nodes_selecting, fa_left); } ], + [ [THEME.inspector_surface_halign, 1], function() { node_halign(nodes_selecting, fa_center); } ], + [ [THEME.inspector_surface_halign, 2], function() { node_halign(nodes_selecting, fa_right); } ], + ]), + menuItemGroup(__txtx("vertical", "Vertical"), [ + [ [THEME.inspector_surface_valign, 0], function() { node_valign(nodes_selecting, fa_top); } ], + [ [THEME.inspector_surface_valign, 1], function() { node_valign(nodes_selecting, fa_middle); } ], + [ [THEME.inspector_surface_valign, 2], function() { node_valign(nodes_selecting, fa_bottom); } ], + ]), + menuItemGroup(__txtx("distribute", "Distribute"), [ + [ [THEME.obj_distribute_h, 0], function() { node_hdistribute(nodes_selecting); } ], + [ [THEME.obj_distribute_v, 0], function() { node_vdistribute(nodes_selecting); } ], + ]), + ]); + }).setIsShelf(); + menu_nodes_blend = menuItem(__txtx("panel_graph_blend_nodes", "Blend nodes"), function() { doBlend(); }, noone, ["Graph", "Blend"]); + menu_nodes_compose = menuItem(__txtx("panel_graph_compose_nodes", "Compose nodes"), function() { doCompose(); }, noone, ["Graph", "Compose"]); + menu_nodes_array = menuItem(__txtx("panel_graph_array_from_nodes", "Array from nodes"), function() { doArray(); }, noone, ["Graph", "Array"]); + menu_nodes_group = menuItem(__txtx("panel_graph_group_nodes", "Group nodes"), function() { doGroup(); }, THEME.group, ["Graph", "Group"]); + menu_nodes_frame = menuItem(__txtx("panel_graph_frame_nodes", "Frame nodes"), function() { doFrame(); }, noone, ["Graph", "Frame"]); + + menu_node_copy_prop = menuItem(__txtx("panel_graph_copy_prop", "Copy all properties"), function() { doCopyProp(); }); + menu_node_paste_prop = menuItem(__txtx("panel_graph_paste_prop", "Paste all properties"), function() { doPasteProp(); }); + + #region node color + function setSelectingNodeColor(color) { + __temp_color = color; + + if(node_hover) node_hover.attributes.color = __temp_color; + array_foreach(nodes_selecting, function(node) { node.attributes.color = __temp_color; }); + } + + var _clrs = COLORS.labels; + var _item = array_create(array_length(_clrs)); + + for( var i = 0, n = array_length(_clrs); i < n; i++ ) { + _item[i] = [ + [ THEME.timeline_color, i > 0, _clrs[i] ], + function(_data) { + setSelectingNodeColor(_data.color); + }, "", { color: i == 0? -1 : _clrs[i] } + ]; + } + + array_push(_item, [ + [ THEME.timeline_color, 2 ], + function(_data) { + colorSelectorCall(node_hover? node_hover.attributes.color : c_white, setSelectingNodeColor); + } + ]); + + menu_node_color = menuItemGroup(__txt("Node Color"), _item); + menu_node_color.spacing = ui(24); + #endregion + + #region junction color + __junction_hovering = noone; + + function setSelectingJuncColor(color) { + if(__junction_hovering == noone) return; + __junction_hovering.setColor(color); + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _node = nodes_selecting[i]; + + for( var j = 0, m = ds_list_size(_node.inputs); j < m; j++ ) { + var _input = _node.inputs[| j]; + if(_input.isLeaf()) continue; + _input.setColor(color); + } + } + } + + var _clrs = COLORS.labels; + var _item = array_create(array_length(_clrs)); + + for( var i = 0, n = array_length(_clrs); i < n; i++ ) { + _item[i] = [ + [ THEME.timeline_color, i > 0, _clrs[i] ], + function(_data) { + setSelectingJuncColor(_data.color); + }, "", { color: i == 0? -1 : _clrs[i] } + ]; + } + + array_push(_item, [ + [ THEME.timeline_color, 2 ], + function(_data) { + colorSelectorCall(__junction_hovering? __junction_hovering.color : c_white, setSelectingJuncColor); + } + ]); + + menu_junc_color = menuItemGroup(__txt("Connection Color"), _item); + menu_junc_color.spacing = ui(24); + #endregion + #endregion + + function getFocusingNode() { INLINE return array_empty(nodes_selecting)? noone : nodes_selecting[0]; } + + function getCurrentContext() { #region + if(ds_list_empty(node_context)) return noone; + return node_context[| ds_list_size(node_context) - 1]; + } #endregion + + function getNodeList(cont = getCurrentContext()) { #region + return cont == noone? project.nodes : cont.getNodeList(); + } #endregion + + function onFocusBegin() { #region + PANEL_GRAPH = self; + PROJECT = project; + + nodes_select_drag = 0; + } #endregion + + function stepBegin() { #region + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + var m_x = (mx - gr_x) / graph_s; + var m_y = (my - gr_y) / graph_s; + mouse_graph_x = m_x; + mouse_graph_y = m_y; + + mouse_grid_x = round(m_x / project.graphGrid.size) * project.graphGrid.size; + mouse_grid_y = round(m_y / project.graphGrid.size) * project.graphGrid.size; + + setTitle(); + } #endregion + + function focusNode(_node) { #region + if(_node == noone) { + nodes_selecting = []; + return; + } + + nodes_selecting = [ _node ]; + fullView(); + } #endregion + + function fullView() { #region + INLINE + var _l = ds_list_create_from_array(nodes_selecting); + toCenterNode(array_empty(nodes_selecting)? nodes_list : _l); + ds_list_destroy(_l); + + graph_s_to = 1; + } #endregion + + function dragGraph() { #region + if(graph_dragging) { + if(!MOUSE_WRAPPING) { + var dx = mx - graph_drag_mx; + var dy = my - graph_drag_my; + + graph_x += dx / graph_s; + graph_y += dy / graph_s; + } + + graph_drag_mx = mx; + graph_drag_my = my; + setMouseWrap(); + + if(mouse_release(drag_key)) + graph_dragging = false; + } + + if(graph_zooming) { + if(!MOUSE_WRAPPING) { + var dy = -(my - graph_zoom_m) / 200; + + var _s = graph_s; + + graph_s_to = clamp(graph_s_to * (1 + dy), scale[0], scale[array_length(scale) - 1]); + graph_s = graph_s_to; + + if(_s != graph_s) { + var mb_x = (graph_zoom_mx - graph_x * _s) / _s; + var ma_x = (graph_zoom_mx - graph_x * graph_s) / graph_s; + var md_x = ma_x - mb_x; + graph_x += md_x; + + var mb_y = (graph_zoom_my - graph_y * _s) / _s; + var ma_y = (graph_zoom_my - graph_y * graph_s) / graph_s; + var md_y = ma_y - mb_y; + graph_y += md_y; + } + } + + graph_zoom_m = my; + setMouseWrap(); + + if(mouse_release(drag_key)) + graph_zooming = false; + } + + if(mouse_on_graph && pFOCUS && graph_draggable) { + var _doDragging = false; + var _doZooming = false; + + if(mouse_press(PREFERENCES.pan_mouse_key)) { + _doDragging = true; + drag_key = PREFERENCES.pan_mouse_key; + } else if(mouse_press(mb_left) && graph_dragging_key) { + _doDragging = true; + drag_key = mb_left; + } else if(mouse_press(mb_left) && graph_zooming_key) { + _doZooming = true; + drag_key = mb_left; + } + + if(_doDragging) { + graph_dragging = true; + graph_drag_mx = mx; + graph_drag_my = my; + graph_drag_sx = graph_x; + graph_drag_sy = graph_y; + } + + if(_doZooming) { + graph_zooming = true; + graph_zoom_mx = mx; + graph_zoom_my = my; + graph_zoom_m = my; + graph_zoom_s = graph_s; + } + } + + if(mouse_on_graph && pHOVER && graph_draggable) { + var _s = graph_s; + if(mouse_wheel_down() && !key_mod_press_any()) { //zoom out + for( var i = 1, n = array_length(scale); i < n; i++ ) { + if(scale[i - 1] < graph_s_to && graph_s_to <= scale[i]) { + graph_s_to = scale[i - 1]; + break; + } + } + } + if(mouse_wheel_up() && !key_mod_press_any()) { // zoom in + for( var i = 1, n = array_length(scale); i < n; i++ ) { + if(scale[i - 1] <= graph_s_to && graph_s_to < scale[i]) { + graph_s_to = scale[i]; + break; + } + } + } + + graph_s = lerp_float(graph_s, graph_s_to, PREFERENCES.graph_zoom_smoooth); + + if(_s != graph_s) { + var mb_x = (mx - graph_x * _s) / _s; + var ma_x = (mx - graph_x * graph_s) / graph_s; + var md_x = ma_x - mb_x; + graph_x += md_x; + + var mb_y = (my - graph_y * _s) / _s; + var ma_y = (my - graph_y * graph_s) / graph_s; + var md_y = ma_y - mb_y; + graph_y += md_y; + } + } + + graph_draggable = true; + graph_x = round(graph_x); + graph_y = round(graph_y); + } #endregion + + function drawGrid() { #region + if(!display_parameter.show_grid) return; + var gls = project.graphGrid.size; + while(gls * graph_s < 8) gls *= 5; + + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + var gr_ls = gls * graph_s; + var xx = -gr_ls, xs = safe_mod(gr_x, gr_ls); + var yy = -gr_ls, ys = safe_mod(gr_y, gr_ls); + + draw_set_color(project.graphGrid.color); + var aa = 0.5; + if(graph_s < 0.25) + aa = 0.3; + var oa = project.graphGrid.opacity; + var ori = project.graphGrid.show_origin; + var hig = project.graphGrid.highlight; + + while(xx < w + gr_ls) { + draw_set_alpha( oa * aa * (1 + (round((xx + xs - gr_x) / gr_ls) % hig == 0) * 2) ); + draw_line(xx + xs, 0, xx + xs, h); + + if(ori && xx + xs - gr_x == 0) draw_line_width(xx + xs, 0, xx + xs, h, 3); + xx += gr_ls; + } + + while(yy < h + gr_ls) { + draw_set_alpha( oa * aa * (1 + (round((yy + ys - gr_y) / gr_ls) % hig == 0) * 2) ); + draw_line(0, yy + ys, w, yy + ys); + + if(ori && yy + ys - gr_y == 0) draw_line_width(0, yy + ys, w, yy + ys, 3); + yy += gr_ls; + } + draw_set_alpha(1); + } #endregion + + function drawBasePreview() { #region + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + var _hov = false; + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var h = nodes_list[| i].drawPreviewBackground(gr_x, gr_y, mx, my, graph_s); + _hov |= h; + } + + return _hov; + } #endregion + + function drawNodes() { #region + if(selection_block-- > 0) return; + + display_parameter.highlight = + !array_empty(nodes_selecting) && ( + (PREFERENCES.connection_line_highlight == 1 && key_mod_press(ALT)) || + PREFERENCES.connection_line_highlight == 2 + ); + + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + + var log = false; + var t = get_timer(); + printIf(log, "============ Draw start ============"); + + _frame_hovering = frame_hovering; + frame_hovering = noone; + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + nodes_list[| i].cullCheck(gr_x, gr_y, graph_s, -32, -32, w + 32, h + 64); + nodes_list[| i].preDraw(gr_x, gr_y, graph_s, gr_x, gr_y); + } + printIf(log, $"Predraw time: {get_timer() - t}"); t = get_timer(); + + #region draw frame + for(var i = 0; i < ds_list_size(nodes_list); i++) { + if(nodes_list[| i].drawNodeBG(gr_x, gr_y, mx, my, graph_s, display_parameter)) + frame_hovering = nodes_list[| i]; + } + #endregion + printIf(log, $"Frame draw time: {get_timer() - t}"); t = get_timer(); + + #region hover + node_hovering = noone; + if(pHOVER) + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + _node.branch_drawing = false; + if(_node.pointIn(gr_x, gr_y, mx, my, graph_s)) + node_hovering = _node; + } + + if(node_hovering != noone) + _HOVERING_ELEMENT = node_hovering; + + if(node_hovering != noone && pFOCUS && DOUBLE_CLICK && struct_has(node_hovering, "onDoubleClick")) { + + if(node_hovering.onDoubleClick(self)) { + DOUBLE_CLICK = false; + node_hovering = noone; + } + } + + if(node_hovering) node_hovering.onDrawHover(gr_x, gr_y, mx, my, graph_s); + #endregion + printIf(log, $"Hover time: {get_timer() - t}"); t = get_timer(); + + #region ++++++++++++ interaction ++++++++++++ + if(mouse_on_graph && pHOVER) { + #region select + if(NODE_DROPPER_TARGET != noone && node_hovering) { + node_hovering.draw_droppable = true; + if(mouse_press(mb_left, NODE_DROPPER_TARGET_CAN)) { + NODE_DROPPER_TARGET.expression += node_hovering.internalName; + NODE_DROPPER_TARGET.expressionUpdate(); + } + } else if(mouse_press(mb_left, pFOCUS)) { + if(key_mod_press(SHIFT)) { + if(node_hovering) { + if(array_exists(nodes_selecting, node_hovering)) + array_remove(nodes_selecting, node_hovering); + else + array_push(nodes_selecting, node_hovering); + } else + nodes_selecting = []; + } else if(value_focus || node_hovering == noone) { + nodes_selecting = []; + + if(DOUBLE_CLICK && !PANEL_INSPECTOR.locked) + PANEL_INSPECTOR.inspecting = noone; + } else { + if(is_instanceof(node_hovering, Node_Frame)) { + var fx0 = (node_hovering.x + graph_x) * graph_s; + var fy0 = (node_hovering.y + graph_y) * graph_s; + var fx1 = fx0 + node_hovering.w * graph_s; + var fy1 = fy0 + node_hovering.h * graph_s; + + nodes_selecting = [ node_hovering ]; + + if(!key_mod_press(CTRL)) + for(var i = 0; i < ds_list_size(nodes_list); i++) { //select content + var _node = nodes_list[| i]; + if(_node == node_hovering) continue; + + if(!_node.selectable) continue; + + var _x = (_node.x + graph_x) * graph_s; + var _y = (_node.y + graph_y) * graph_s; + var _w = _node.w * graph_s; + var _h = _node.h * graph_s; + + if(_w && _h && rectangle_inside_rectangle(fx0, fy0, fx1, fy1, _x, _y, _x + _w, _y + _h)) + array_push_unique(nodes_selecting, _node); + } + } else if(DOUBLE_CLICK) { + PANEL_PREVIEW.setNodePreview(node_hovering); + if(PREFERENCES.inspector_focus_on_double_click) { + if(PANEL_INSPECTOR.panel && struct_has(PANEL_INSPECTOR.panel, "switchContent")) + PANEL_INSPECTOR.panel.switchContent(PANEL_INSPECTOR); + } + } else { + var hover_selected = false; + for( var i = 0; i < array_length(nodes_selecting); i++ ) { + if(nodes_selecting[i] != node_hovering) continue; + + hover_selected = true; + break; + } + if(!hover_selected) + nodes_selecting = [ node_hovering ]; + } + + if(WIDGET_CURRENT) WIDGET_CURRENT.deactivate(); + array_foreach(nodes_selecting, function(node) { bringNodeToFront(node); }); + } + } + #endregion + + if(mouse_press(mb_right, pFOCUS)) { #region + node_hover = node_hovering; + + if(value_focus) { + __junction_hovering = value_focus; + + var menu = [ menu_junc_color ]; + + if(value_focus.connect_type == JUNCTION_CONNECT.output) { + var sep = false; + + for( var i = 0, n = array_length(value_focus.value_to); i < n; i++ ) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _to = value_focus.value_to[i]; + array_push(menu, menuItem($"[{_to.node.display_name}] {_to.getName()}", function(data) { + data.params.juncTo.removeFrom(); + }, THEME.cross,,, { juncTo: _to })); + } + + for( var i = 0, n = array_length(value_focus.value_to_loop); i < n; i++ ) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _to = value_focus.value_to_loop[i]; + array_push(menu, menuItem($"[{_to.junc_in.node.display_name}] {_to.junc_in.getName()}", function(data) { + data.params.juncTo.destroy(); + }, _to.icon_24,,, { juncTo: _to })); + } + } else { + var sep = false; + + if(value_focus.value_from) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _jun = value_focus.value_from; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.removeFrom(); + }, THEME.cross)); + } + + if(value_focus.value_from_loop) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _jun = value_focus.value_from_loop.junc_out; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.removeFromLoop(); + }, value_focus.value_from_loop.icon_24)); + } + } + + menuCall("graph_node_selected_menu",,, menu); + + } else if(node_hover && node_hover.draggable) { + var menu = []; + array_push(menu, menu_node_color, -1, menu_sent_to_preview, menu_send_to_window, menu_sent_to_inspector); + if(!DEMO) + array_push(menu, menu_send_export); + array_push(menu, -1, menu_toggle_preview, menu_toggle_render, menu_toggle_param); + + if(is_instanceof(node_hover, Node_Collection)) + array_push(menu, -1, menu_open_group, menu_open_group_tab, menu_group_ungroup); + + if(node_hover.group != noone) + array_push(menu, menu_group_tool); + + array_push(menu, -1, menu_node_delete_merge, menu_node_delete_cut, menu_node_duplicate, menu_node_copy); + if(array_empty(nodes_selecting)) array_push(menu, menu_node_copy_prop, menu_node_paste_prop); + + array_push(menu, -1, menu_node_transform, menu_node_canvas); + + if(array_empty(nodes_selecting) >= 2) + array_push(menu, -1, menu_nodes_align, menu_nodes_blend, menu_nodes_compose, menu_nodes_array, menu_nodes_group, menu_nodes_frame); + + menuCall("graph_node_selected_multiple_menu",,, menu ); + } else if(node_hover == noone) { + var menu = []; + + __junction_hovering = junction_hovering; + if(junction_hovering != noone) + array_push(menu, menu_junc_color, -1); + + array_push(menu, menuItem(__txt("Copy"), function() { doCopy(); }, THEME.copy, ["Graph", "Copy"]).setActive(array_length(nodes_selecting))); + array_push(menu, menuItem(__txt("Paste"), function() { doPaste(); }, THEME.paste, ["Graph", "Paste"]).setActive(clipboard_get_text() != "")); + + if(junction_hovering != noone) { + array_push(menu, -1); + + if(is_instanceof(junction_hovering, Node_Feedback_Inline)) { + var _jun = junction_hovering.junc_out; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.destroy(); + }, THEME.feedback)); + } else { + var _jun = junction_hovering.value_from; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.removeFrom(); + }, THEME.cross)); + } + } + + var ctx = is_instanceof(frame_hovering, Node_Collection_Inline)? frame_hovering : getCurrentContext(); + var _diaAdd = callAddDialog(ctx); + + var _dia = menuCall("graph_node_selected_menu", o_dialog_add_node.dialog_x - ui(8), o_dialog_add_node.dialog_y + ui(4), menu, fa_right ); + _dia.passthrough = true; + setFocus(_diaAdd, "Dialog"); + } + } #endregion + + if(is_instanceof(frame_hovering, Node_Collection_Inline) && DOUBLE_CLICK && array_empty(nodes_selecting)) { #region + nodes_selecting = [ frame_hovering ]; + } #endregion + } + #endregion + printIf(log, $"Node selection time: {get_timer() - t}"); t = get_timer(); + + #region draw active + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _node = nodes_selecting[i]; + if(!_node) continue; + _node.drawActive(gr_x, gr_y, graph_s); + } + #endregion + printIf(log, $"Draw active: {get_timer() - t}"); t = get_timer(); + + #region draw connections + var aa = floor(min(8192 / w, 8192 / h, PREFERENCES.connection_line_aa)); + + connection_surface = surface_verify(connection_surface, w * aa, h * aa); + connection_surface_aa = surface_verify(connection_surface_aa, w, h); + surface_set_target(connection_surface); + DRAW_CLEAR + + var hov = noone; + var hoverable = !bool(node_dragging) && pHOVER; + var param = connection_param; + + param.active = hoverable; + param.setPos(gr_x, gr_y, graph_s, mx, my); + param.setBoundary(-64, -64, w + 64, h + 64); + param.setProp(ds_list_size(nodes_list), display_parameter.highlight); + param.setDraw(aa, bg_color); + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + param.cur_layer = i + 1; + + var _hov = nodes_list[| i].drawConnections(param); + if(_hov != noone && is_struct(_hov)) hov = _hov; + } + + if(value_dragging && connection_draw_mouse != noone) { + var _cmx = connection_draw_mouse[0]; + var _cmy = connection_draw_mouse[1]; + var _cmt = connection_draw_target; + + if(array_empty(value_draggings)) + value_dragging.drawConnectionMouse(param, _cmx, _cmy, _cmt); + else { + var _stIndex = array_find(value_draggings, value_dragging); + + for( var i = 0, n = array_length(value_draggings); i < n; i++ ) { + var _dmx = _cmx; + var _dmy = value_draggings[i].connect_type == JUNCTION_CONNECT.output? _cmy + (i - _stIndex) * 24 * graph_s : _cmy; + + value_draggings[i].drawConnectionMouse(param, _dmx, _dmy, _cmt); + } + } + } + + surface_reset_target(); + + gpu_set_texfilter(true); + surface_set_shader(connection_surface_aa, sh_downsample); + shader_set_f("down", aa); + shader_set_dim("dimension", connection_surface); + draw_surface(connection_surface, 0, 0); + surface_reset_shader(); + gpu_set_texfilter(false); + + BLEND_ALPHA_MULP + draw_surface(connection_surface_aa, 0, 0); + BLEND_NORMAL + + junction_hovering = node_hovering == noone? hov : noone; + value_focus = noone; + #endregion + printIf(log, $"Draw connection: {get_timer() - t}"); t = get_timer(); + + #region draw node + var t = get_timer(); + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].onDrawNodeBehind(gr_x, gr_y, mx, my, graph_s); + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + + if(is_instanceof(_node, Node_Frame)) continue; + try { + var val = _node.drawNode(gr_x, gr_y, mx, my, graph_s, display_parameter); + if(val) { + value_focus = val; + if(key_mod_press(SHIFT)) TOOLTIP = [ val.getValue(), val.type ]; + } + } catch(e) { + log_warning("NODE DRAW", exception_print(e)); + } + } + + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].drawBadge(gr_x, gr_y, graph_s); + + if(PANEL_INSPECTOR && PANEL_INSPECTOR.prop_hover != noone) + value_focus = PANEL_INSPECTOR.prop_hover; + #endregion + printIf(log, $"Draw node: {get_timer() - t}"); t = get_timer(); + + #region dragging + if(mouse_press(mb_left)) + node_dragging = noone; + + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].groupCheck(gr_x, gr_y, graph_s, mx, my); + + if(node_dragging && !key_mod_press(ALT)) { + var nx = node_drag_sx + (mouse_graph_x - node_drag_mx); + var ny = node_drag_sy + (mouse_graph_y - node_drag_my); + + if(!key_mod_press(CTRL) && project.graphGrid.snap) { + nx = round(nx / project.graphGrid.size) * project.graphGrid.size; + ny = round(ny / project.graphGrid.size) * project.graphGrid.size; + } + + if(node_drag_ox == -1 || node_drag_oy == -1) { + node_drag_ox = nx; + node_drag_oy = ny; + } else if(nx != node_drag_ox || ny != node_drag_oy) { + var dx = nx - node_drag_ox; + var dy = ny - node_drag_oy; + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _node = nodes_selecting[i]; + var _nx = _node.x + dx; + var _ny = _node.y + dy; + + if(!key_mod_press(CTRL) && project.graphGrid.snap) { + _nx = round(_nx / project.graphGrid.size) * project.graphGrid.size; + _ny = round(_ny / project.graphGrid.size) * project.graphGrid.size; + } + + _node.move(_nx, _ny, graph_s); + } + + node_drag_ox = nx; + node_drag_oy = ny; + } + + if(mouse_release(mb_left) && (nx != node_drag_sx || ny != node_drag_sy)) { + var shfx = node_drag_sx - nx; + var shfy = node_drag_sy - ny; + + UNDO_HOLDING = false; + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _n = nodes_selecting[i]; + if(_n == noone) continue; + recordAction(ACTION_TYPE.var_modify, _n, [ _n.x + shfx, "x", "node x position" ]); + recordAction(ACTION_TYPE.var_modify, _n, [ _n.y + shfy, "y", "node y position" ]); + } + } + } + + if(mouse_release(mb_left)) + node_dragging = noone; + #endregion + printIf(log, $"Drag node time : {get_timer() - t}"); t = get_timer(); + + if(mouse_on_graph && pFOCUS) { #region + var _node = getFocusingNode(); + if(_node && _node.draggable && value_focus == noone) { + if(mouse_press(mb_left) && !key_mod_press(ALT)) { + node_dragging = _node; + node_drag_mx = mouse_graph_x; + node_drag_my = mouse_graph_y; + node_drag_sx = _node.x; + node_drag_sy = _node.y; + + node_drag_ox = -1; + node_drag_oy = -1; + } + } + + if(DOUBLE_CLICK && junction_hovering != noone) { + var _mx = round(mouse_graph_x / project.graphGrid.size) * project.graphGrid.size; + var _my = round(mouse_graph_y / project.graphGrid.size) * project.graphGrid.size; + + var _pin = nodeBuild("Node_Pin", _mx, _my); + _pin.inputs[| 0].setFrom(junction_hovering.value_from); + junction_hovering.setFrom(_pin.outputs[| 0]); + } + } #endregion + + #region draw selection frame + if(nodes_select_drag) { + if(point_distance(nodes_select_mx, nodes_select_my, mx, my) > 16) + nodes_select_drag = 2; + + if(nodes_select_drag == 2) { + draw_sprite_stretched_points_clamp(THEME.ui_selection, 0, nodes_select_mx, nodes_select_my, mx, my, COLORS._main_accent); + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + + if(!_node.selectable) continue; + if(is_instanceof(_node, Node_Frame) && !nodes_select_frame) continue; + + var _x = (_node.x + graph_x) * graph_s; + var _y = (_node.y + graph_y) * graph_s; + var _w = _node.w * graph_s; + var _h = _node.h * graph_s; + + var _sel = _w && _h && rectangle_in_rectangle(_x, _y, _x + _w, _y + _h, nodes_select_mx, nodes_select_my, mx, my); + + if(!array_exists(nodes_selecting, _node) && _sel) + array_push(nodes_selecting, _node); + if(array_exists(nodes_selecting, _node) && !_sel) + array_remove(nodes_selecting, _node); + } + } + + if(mouse_release(mb_left)) + nodes_select_drag = 0; + } + + if(nodes_junction_d != noone) { + var shx = nodes_junction_dx + (mx - nodes_select_mx) / graph_s; + var shy = nodes_junction_dy + (my - nodes_select_my) / graph_s; + + shx = value_snap(shx, key_mod_press(CTRL)? 1 : 4); + shy = value_snap(shy, key_mod_press(CTRL)? 1 : 4); + + nodes_junction_d.draw_line_shift_x = shx; + nodes_junction_d.draw_line_shift_y = shy; + + if(mouse_release(mb_left)) + nodes_junction_d = noone; + } + + if(mouse_on_graph && !node_bg_hovering && mouse_press(mb_left, pFOCUS) && !graph_dragging_key && !graph_zooming_key) { + if(is_instanceof(junction_hovering, NodeValue) && junction_hovering.draw_line_shift_hover) { + nodes_select_mx = mx; + nodes_select_my = my; + nodes_junction_d = junction_hovering; + nodes_junction_dx = junction_hovering.draw_line_shift_x; + nodes_junction_dy = junction_hovering.draw_line_shift_y; + } else if(array_empty(nodes_selecting) && !value_focus && !drag_locking) { + nodes_select_drag = 1; + nodes_select_frame = frame_hovering == noone; + + nodes_select_mx = mx; + nodes_select_my = my; + } + drag_locking = false; + } + #endregion + printIf(log, $"Draw selection frame : {get_timer() - t}"); t = get_timer(); + } #endregion + + function drawJunctionConnect() { #region + if(value_dragging) { + var xx = value_dragging.x; + var yy = value_dragging.y; + var _mx = mx; + var _my = my; + var target = noone; + + if(value_focus && value_focus != value_dragging && value_focus.connect_type != value_dragging.connect_type) + target = value_focus; + + if(key_mod_press(CTRL) && node_hovering != noone) { + if(value_dragging.connect_type == JUNCTION_CONNECT.input) { + target = node_hovering.getOutput(value_dragging); + if(target != noone) + node_hovering.active_draw_index = 1; + } else { + target = node_hovering.getInput(value_dragging); + if(target != noone) + node_hovering.active_draw_index = 1; + } + } + + var _mmx = target != noone? target.x : _mx; + var _mmy = target != noone? target.y : _my; + + connection_draw_mouse = [ _mmx, _mmy ]; + connection_draw_target = target; + + value_dragging.drawJunction(graph_s, value_dragging.x, value_dragging.y); + if(target) target.drawJunction(graph_s, target.x, target.y); + + if(mouse_release(mb_left)) { // CONNECT junction + var _connect = [ 0, noone, noone ]; + + if(PANEL_INSPECTOR && PANEL_INSPECTOR.attribute_hovering != noone) { + PANEL_INSPECTOR.attribute_hovering(value_dragging); + } else if(target != noone) { + var _addInput = false; + if(target.isLeaf() && target.connect_type == JUNCTION_CONNECT.input && target.node.auto_input) + _addInput = true; + + if(value_dragging.connect_type == JUNCTION_CONNECT.input) { + if(array_empty(value_draggings)) { + _connect = [ value_dragging.setFrom(target), value_dragging, target ]; + } else { + for( var i = 0, n = array_length(value_draggings); i < n; i++ ) + value_draggings[i].setFrom(target); + } + } else if(_addInput && !array_empty(value_draggings)) { + for( var i = 0, n = array_length(value_draggings); i < n; i++ ) + target.node.addInput(value_draggings[i]); + } else { + _connect = [ target.setFrom(value_dragging), target, value_dragging ]; + } + } else { + if(value_dragging.connect_type == JUNCTION_CONNECT.input) + value_dragging.removeFrom(); + value_dragging.node.triggerRender(); + + if(value_focus != value_dragging) { + var ctx = is_instanceof(frame_hovering, Node_Collection_Inline)? frame_hovering : getCurrentContext(); + with(dialogCall(o_dialog_add_node, mouse_mx + 8, mouse_my + 8, { context: ctx })) { + node_target_x = other.mouse_grid_x; + node_target_y = other.mouse_grid_y; + node_called = other.value_dragging; + + alarm[0] = 1; + } + } + } + + value_dragging = noone; + connection_draw_mouse = noone; + + if(_connect[0] == -9) { + if(_connect[1].value_from_loop != noone) + _connect[1].value_from_loop.destroy(); + + var menu = [ + menuItem("Feedback", function(data) { + var junc_in = data.params.junc_in; + var junc_out = data.params.junc_out; + + var feed = nodeBuild("Node_Feedback_Inline", 0, 0); + feed.attributes.junc_in = [ junc_in .node.node_id, junc_in .index ]; + feed.attributes.junc_out = [ junc_out.node.node_id, junc_out.index ]; + feed.scanJunc(); + + }, THEME.feedback_24,,, { junc_in : _connect[1], junc_out : _connect[2] }), + + menuItem("Loop", function(data) { + var junc_in = data.params.junc_in; + var junc_out = data.params.junc_out; + + var feed = nodeBuild("Node_Iterate_Inline", 0, 0); + feed.attributes.junc_in = [ junc_in .node.node_id, junc_in .index ]; + feed.attributes.junc_out = [ junc_out.node.node_id, junc_out.index ]; + feed.scanJunc(); + + }, THEME.loop_24,,, { junc_in : _connect[1], junc_out : _connect[2] }), + ]; + + menuCall(,,, menu); + } + } + } else if(value_focus && mouse_press(mb_left, pFOCUS) && !key_mod_press(ALT)) { + value_dragging = value_focus; + value_draggings = []; + + if(value_dragging.connect_type == JUNCTION_CONNECT.output) { + if(key_mod_press(CTRL)) { + var _to = value_dragging.getJunctionTo(); + + if(array_length(_to)) { + value_dragging = _to[0]; + value_draggings = array_create(array_length(_to)); + + for( var i = 0, n = array_length(_to); i < n; i++ ) { + value_draggings[i] = _to[i]; + _to[i].removeFrom(); + } + } + } else if(array_exists(nodes_selecting_jun, value_dragging.node)) { + var _jlist = ds_priority_create(); + + for( var i = 0, n = array_length(nodes_selecting_jun); i < n; i++ ) { + var _node = nodes_selecting_jun[i]; + + if(_node == value_focus.node) { + ds_priority_add(_jlist, value_focus, value_focus.y); + } else { + for( var j = 0, m = ds_list_size(_node.outputs); j < m; j++ ) { + var _junction = _node.outputs[| j]; + if(!_junction.visible) continue; + if(value_bit(_junction.type) & value_bit(value_dragging.type) == 0) continue; + + ds_priority_add(_jlist, _junction, _junction.y); + break; + } + } + } + + while(!ds_priority_empty(_jlist)) + array_push(value_draggings, ds_priority_delete_min(_jlist)); + + ds_priority_destroy(_jlist); + } + } else { + if(key_mod_press(CTRL) && value_dragging.value_from) { + var fr = value_dragging.value_from; + value_dragging.removeFrom(); + value_dragging = fr; + } + } + } + + nodes_selecting_jun = array_clone(nodes_selecting, 1); + + #region draw junction name + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].drawJunctionNames(gr_x, gr_y, mx, my, graph_s); + #endregion + + } #endregion + + function callAddDialog(ctx = getCurrentContext()) { #region + var _dia = dialogCall(o_dialog_add_node, mouse_mx + 8, mouse_my + 8, { context: ctx }); + + with(_dia) { + node_target_x = other.mouse_grid_x; + node_target_y = other.mouse_grid_y; + junction_hovering = other.junction_hovering; + + resetPosition(); + alarm[0] = 1; + } + + return _dia; + } #endregion + + function drawContext() { #region + draw_set_text(f_p0, fa_left, fa_center); + var xx = ui(16), tt, tw, th; + var bh = toolbar_height - ui(12); + var tbh = h - toolbar_height / 2; + + for(var i = -1; i < ds_list_size(node_context); i++) { + if(i == -1) { + tt = __txt("Global"); + } else { + var _cnt = node_context[| i]; + tt = _cnt.renamed? _cnt.display_name : _cnt.name; + } + + tw = string_width(tt); + th = string_height(tt); + + if(i < ds_list_size(node_context) - 1) { + if(buttonInstant(THEME.button_hide_fill, xx - ui(6), tbh - bh / 2, tw + ui(12), bh, [mx, my], pFOCUS, pHOVER) == 2) { + node_hover = noone; + nodes_selecting = []; + PANEL_PREVIEW.resetNodePreview(); + setContextFrame(true, node_context[| i + 1]); + var _nodeFocus = node_context[| i + 1]; + + if(i == -1) + resetContext(); + else { + for(var j = ds_list_size(node_context) - 1; j > i; j--) + ds_list_delete(node_context, j); + nodes_list = node_context[| i].getNodeList(); + } + + nodes_selecting = [ _nodeFocus ]; + var _l = ds_list_create_from_array(nodes_selecting) + toCenterNode(_l); + ds_list_destroy(_l); + break; + } + + draw_sprite_ui_uniform(THEME.arrow, 0, xx + tw + ui(16), tbh, 1, COLORS._main_icon); + } + + draw_set_color(COLORS._main_text); + draw_set_alpha(i < ds_list_size(node_context) - 1? 0.33 : 1); + draw_text(xx, tbh - 2, tt); + draw_set_alpha(1); + xx += tw; + xx += ui(32); + } + } #endregion + + function drawToolBar() { #region + toolbar_height = ui(40); + var ty = h - toolbar_height; + + if(pHOVER && point_in_rectangle(mx, my, 0, ty, w, h)) + mouse_on_graph = false; + + draw_sprite_stretched(THEME.toolbar, 0, 0, ty, w, h); + drawContext(); + + var tbx = w - toolbar_height / 2; + var tby = ty + toolbar_height / 2; + + for( var i = 0, n = array_length(toolbars); i < n; i++ ) { + var tb = toolbars[i]; + var tbSpr = tb[0]; + var tbInd = tb[1](); + var tbTooltip = tb[2](); + + var b = buttonInstant(THEME.button_hide, tbx - ui(14), tby - ui(14), ui(28), ui(28), [mx, my], pFOCUS, pHOVER, tbTooltip, tbSpr, tbInd); + if(b == 2) tb[3]( { x: x + tbx - ui(14), y: y + tby - ui(14) } ); + + tbx -= ui(32); + } + + draw_set_color(COLORS.panel_toolbar_separator); + draw_line_width(tbx + ui(12), tby - toolbar_height / 2 + ui(8), tbx + ui(12), tby + toolbar_height / 2 - ui(8), 2); + } #endregion + + function drawMinimap() { #region + if(!minimap_show) return; + var mx1 = w - ui(8); + var my1 = h - toolbar_height - ui(8); + var mx0 = mx1 - minimap_w; + var my0 = my1 - minimap_h; + + minimap_w = min(minimap_w, w - ui(16)); + minimap_h = min(minimap_h, h - ui(16) - toolbar_height); + + var mini_hover = false; + if(pHOVER && point_in_rectangle(mx, my, mx0, my0, mx1, my1)) { + mouse_on_graph = false; + mini_hover = true; + } + + var hover = mini_hover && !point_in_rectangle(mx, my, mx0, my0, mx0 + ui(16), my0 + ui(16)) && !minimap_dragging; + + if(!is_surface(minimap_surface) || surface_get_width_safe(minimap_surface) != minimap_w || surface_get_height_safe(minimap_surface) != minimap_h) { + minimap_surface = surface_create_valid(minimap_w, minimap_h); + } + + surface_set_target(minimap_surface); + draw_clear_alpha(COLORS.panel_bg_clear_inner, 0.75); + if(!ds_list_empty(nodes_list)) { + var minx = 99999; + var maxx = -99999; + var miny = 99999; + var maxy = -99999; + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + minx = min(_node.x - 32, minx); + maxx = max(_node.x + _node.w + 32, maxx); + + miny = min(_node.y - 32, miny); + maxy = max(_node.y + _node.h + 32, maxy); + } + + var cx = (minx + maxx) / 2; + var cy = (miny + maxy) / 2; + var spw = maxx - minx; + var sph = maxy - miny; + var ss = min(minimap_w / spw, minimap_h / sph); + + draw_set_alpha(0.4); + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + + var nx = minimap_w / 2 + (_node.x - cx) * ss; + var ny = minimap_h / 2 + (_node.y - cy) * ss; + var nw = _node.w * ss; + var nh = _node.h * ss; + + draw_set_color(_node.getColor()); + draw_roundrect_ext(nx, ny, nx + nw, ny + nh, THEME_VALUE.minimap_corner_radius, THEME_VALUE.minimap_corner_radius, false); + } + draw_set_alpha(1); + + var gx = minimap_w / 2 - (graph_x + cx) * ss; + var gy = minimap_h / 2 - (graph_y + cy) * ss; + var gw = w / graph_s * ss; + var gh = h / graph_s * ss; + + draw_set_color(COLORS.panel_graph_minimap_focus); + draw_rectangle(gx, gy, gx + gw, gy + gh, 1); + + if(minimap_panning) { + graph_x = -((mx - mx0 - gw / 2) - minimap_w / 2) / ss - cx; + graph_y = -((my - my0 - gh / 2) - minimap_h / 2) / ss - cy; + + graph_x = round(graph_x); + graph_y = round(graph_y); + + if(mouse_release(mb_left)) + minimap_panning = false; + } + + if(mouse_click(mb_left, hover)) + minimap_panning = true; + } + + surface_reset_target(); + + draw_surface_ext_safe(minimap_surface, mx0, my0, 1, 1, 0, c_white, 0.5 + 0.35 * hover); + draw_set_color(COLORS.panel_graph_minimap_outline); + draw_rectangle(mx0, my0, mx1 - 1, my1 - 1, true); + + if(minimap_dragging) { + mouse_on_graph = false; + var sw = minimap_drag_sx + minimap_drag_mx - mx; + var sh = minimap_drag_sy + minimap_drag_my - my; + + minimap_w = max(ui(64), sw); + minimap_h = max(ui(64), sh); + + if(mouse_release(mb_left)) + minimap_dragging = false; + } + + if(pHOVER && point_in_rectangle(mx, my, mx0, my0, mx0 + ui(16), my0 + ui(16))) { + draw_sprite_ui(THEME.node_resize, 0, mx0 + ui(2), my0 + ui(2), 0.5, 0.5, 180, c_white, 0.75); + if(mouse_press(mb_left, pFOCUS)) { + minimap_dragging = true; + minimap_drag_sx = minimap_w; + minimap_drag_sy = minimap_h; + minimap_drag_mx = mx; + minimap_drag_my = my; + } + } else + draw_sprite_ui(THEME.node_resize, 0, mx0 + ui(2), my0 + ui(2), 0.5, 0.5, 180, c_white, 0.3); + } #endregion + + function drawContextFrame() { #region + if(!context_framing) return; + context_frame_progress = lerp_float(context_frame_progress, 1, 5); + if(context_frame_progress == 1) + context_framing = false; + + var _fr_x0 = 0, _fr_y0 = 0; + var _fr_x1 = w, _fr_y1 = h; + + var _to_x0 = context_frame_sx; + var _to_y0 = context_frame_sy; + var _to_x1 = context_frame_ex; + var _to_y1 = context_frame_ey; + + var prog = context_frame_direct? context_frame_progress : 1 - context_frame_progress; + var frm_x0 = lerp(_fr_x0, _to_x0, prog); + var frm_y0 = lerp(_fr_y0, _to_y0, prog); + var frm_x1 = lerp(_fr_x1, _to_x1, prog); + var frm_y1 = lerp(_fr_y1, _to_y1, prog); + + draw_set_color(COLORS._main_accent); + draw_set_alpha(0.5); + draw_roundrect_ext(frm_x0, frm_y0, frm_x1, frm_y1, THEME_VALUE.panel_corner_radius, THEME_VALUE.panel_corner_radius, true); + draw_set_alpha(1); + } #endregion + + function resetContext() { #region + ds_list_clear(node_context); + nodes_list = project.nodes; + toCenterNode(); + } #endregion + + function addContext(node) { #region + var _node = node.getNodeBase(); + setContextFrame(false, _node); + + nodes_list = _node.nodes; + ds_list_add(node_context, _node); + + node_dragging = noone; + nodes_selecting = []; + selection_block = 1; + + toCenterNode(); + } #endregion + + function setContextFrame(dirr, node) { #region + context_framing = true; + context_frame_direct = dirr; + context_frame_progress = 0; + context_frame_sx = w / 2 - 8; + context_frame_sy = h / 2 - 8; + context_frame_ex = context_frame_sx + 16; + context_frame_ey = context_frame_sy + 16; + } #endregion + + function setTitle() { #region + title = title_raw + (project.modified? "*" : ""); + } #endregion + + function drawContent(panel) { #region >>>>>>>>>>>>>>>>>>>> MAIN DRAW <<<<<<<<<<<<<<<<<<<< + if(!project.active) return; + + if(project.path == "") title_raw = "New project"; + else title_raw = filename_name_only(project.path); + dragGraph(); + + var context = getCurrentContext(); + if(context != noone) title_raw += " > " + (context.renamed? context.display_name : context.name); + + bg_color = context == noone? COLORS.panel_bg_clear : merge_color(COLORS.panel_bg_clear, context.getColor(), 0.05); + draw_clear(bg_color); + node_bg_hovering = drawBasePreview(); + drawGrid(); + + draw_set_text(f_p0, fa_right, fa_top, COLORS._main_text_sub); + draw_text(w - ui(8), ui(8), $"x{graph_s_to}"); + + drawNodes(); + drawJunctionConnect(); + drawContextFrame(); + + mouse_on_graph = true; + drawToolBar(); + drawMinimap(); + + if(pFOCUS) array_foreach(nodes_selecting, function(node) { node.focusStep(); }); + + if(UPDATE == RENDER_TYPE.full) + draw_text(w - ui(8), ui(28), __txtx("panel_graph_rendering", "Rendering") + "..."); + else if(UPDATE == RENDER_TYPE.partial) + draw_text(w - ui(8), ui(28), __txtx("panel_graph_rendering_partial", "Rendering partial") + "..."); + + if(DRAGGING && pHOVER) { #region file dropping + if(node_hovering && node_hovering.droppable(DRAGGING)) { + node_hovering.draw_droppable = true; + if(mouse_release(mb_left)) + node_hovering.onDrop(DRAGGING); + } else { + draw_sprite_stretched_ext(THEME.ui_panel_active, 0, 2, 2, w - 4, h - 4, COLORS._main_value_positive, 1); + if(mouse_release(mb_left)) + checkDropItem(); + } + } #endregion + + graph_dragging_key = false; + graph_zooming_key = false; + + if(LIVE_UPDATE) { + draw_set_text(f_p0b, fa_right, fa_bottom, COLORS._main_value_negative); + draw_text(w - 8, h - toolbar_height, "Live Update"); + } + } #endregion + + #region ++++++++++++++++ node manipulation ++++++++++++++++ + function doTransform() { #region + for( var i = 0; i < array_length(nodes_selecting); i++ ) { + var node = nodes_selecting[i]; + if(ds_list_empty(node.outputs)) continue; + + var _o = node.outputs[| 0]; + if(_o.type == VALUE_TYPE.surface || _o.type == VALUE_TYPE.dynaSurface) { + var tr = nodeBuild("Node_Transform", node.x + node.w + 64, node.y); + tr.inputs[| 0].setFrom(_o); + } + } + } #endregion + + function doDuplicate() { #region + if(array_empty(nodes_selecting)) return; + + var _map = {}; + var _pmap = {}; + var _node = []; + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _n = nodes_selecting[i]; + + if(_n.inline_parent_object != "") + _pmap[$ _n.inline_context.node_id] = _n.inline_parent_object; + + SAVE_NODE(_node, _n,,,, getCurrentContext()); + } + + _map.nodes = _node; + + ds_map_clear(APPEND_MAP); + ds_list_clear(APPEND_LIST); + + CLONING = true; + var _pmap_keys = variable_struct_get_names(_pmap); + for( var i = 0, n = array_length(_pmap_keys); i < n; i++ ) { + var _pkey = _pmap_keys[i]; + var _original = PROJECT.nodeMap[? _pkey]; + var _nodeS = _pmap[$ _pkey]; + + CLONING_GROUP = _original; + var _newGroup = nodeBuild(_nodeS, _original.x, _original.y); + APPEND_MAP[? _pkey] = _newGroup; + } + + APPEND_LIST = __APPEND_MAP(_map,, APPEND_LIST); + recordAction(ACTION_TYPE.collection_loaded, array_create_from_list(APPEND_LIST)); + CLONING = false; + + if(ds_list_size(APPEND_LIST) == 0) return; + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _orignal = nodes_selecting[i]; + if(!_orignal.clonable) continue; + + var _cloned = ds_map_try_get(APPEND_MAP, _orignal.node_id, ""); + var _inline_ctx = _orignal.inline_context; + + if(_inline_ctx != noone && _cloned != "") { + _inline_ctx = ds_map_try_get(APPEND_MAP, _inline_ctx.node_id, _inline_ctx); + _inline_ctx.addNode(PROJECT.nodeMap[? _cloned]); + } + } + + var x0 = 99999999; + var y0 = 99999999; + for(var i = 0; i < ds_list_size(APPEND_LIST); i++) { + var _node = APPEND_LIST[| i]; + + x0 = min(x0, _node.x); + y0 = min(y0, _node.y); + } + + node_dragging = APPEND_LIST[| 0]; + node_drag_mx = x0; node_drag_my = y0; + node_drag_sx = x0; node_drag_sy = y0; + node_drag_ox = x0; node_drag_oy = y0; + + nodes_selecting = array_create_from_list(APPEND_LIST); + } #endregion + + function doInstance() { #region + var node = getFocusingNode(); + if(node == noone) return; + + if(node.instanceBase == noone) { + node.isInstancer = true; + + CLONING = true; + var _type = instanceof(node); + var _node = nodeBuild(_type, x, y); + CLONING = false; + + _node.setInstance(node); + } + + var _nodeNew = _node.clone(); + + node_dragging = _nodeNew; + node_drag_mx = _nodeNew.x; node_drag_my = _nodeNew.y; + node_drag_sx = _nodeNew.x; node_drag_sy = _nodeNew.y; + node_drag_ox = _nodeNew.x; node_drag_oy = _nodeNew.y; + } #endregion + + function doCopy() { #region + if(array_empty(nodes_selecting)) return; + clipboard_set_text(""); + + var _map = {}; + _map.nodes = []; + for(var i = 0; i < array_length(nodes_selecting); i++) + SAVE_NODE(_map.nodes, nodes_selecting[i],,,, getCurrentContext()); + + clipboard_set_text(json_stringify_minify(_map)); + } #endregion + + function doPaste() { #region + var txt = clipboard_get_text(); + var _map = json_try_parse(txt, noone); + + if(txt == "") return; + + if(is_struct(_map)) { + ds_map_clear(APPEND_MAP); + APPENDING = true; + CLONING = true; + var _app = __APPEND_MAP(_map); + APPENDING = false; + CLONING = false; + + if(_app == noone) + return; + + if(ds_list_size(_app) == 0) { + ds_list_destroy(_app); + return; + } + + var x0 = 99999999; + var y0 = 99999999; + for(var i = 0; i < ds_list_size(_app); i++) { + var _node = _app[| i]; + + x0 = min(x0, _node.x); + y0 = min(y0, _node.y); + } + + node_dragging = _app[| 0]; + node_drag_mx = x0; node_drag_my = y0; + node_drag_sx = x0; node_drag_sy = y0; + node_drag_ox = x0; node_drag_oy = y0; + + nodes_selecting = array_create_from_list(_app); + return; + } + + if(filename_ext(txt) == ".pxc") + APPEND(txt); + else if(filename_ext(txt) == ".pxcc") + APPEND(txt); + else if(filename_ext(txt) == ".png") { + if(file_exists_empty(txt)) { + Node_create_Image_path(0, 0, txt); + return; + } + + var path = TEMPDIR + "url_pasted_" + string(irandom_range(100000, 999999)) + ".png"; + var img = http_get_file(txt, path); + CLONING = true; + var node = Node_create_Image(0, 0); + CLONING = false; + var args = [node, path]; + + global.FILE_LOAD_ASYNC[? img] = [ function(args) { + args[0].inputs[| 0].setValue(args[1]); + args[0].doUpdate(); + }, args]; + } + } #endregion + + function doBlend() { #region + if(array_length(nodes_selecting) != 2) return; + + var _n0 = nodes_selecting[0].y < nodes_selecting[1].y? nodes_selecting[0] : nodes_selecting[1]; + var _n1 = nodes_selecting[0].y < nodes_selecting[1].y? nodes_selecting[1] : nodes_selecting[0]; + + if(_n0.outputs[| 0].type != VALUE_TYPE.surface || _n1.outputs[| 0].type != VALUE_TYPE.surface) return; + + var cx = max(_n0.x, _n1.x) + 160; + var cy = round((_n0.y + _n1.y) / 2 / 32) * 32; + + var _blend = new Node_Blend(cx, cy, getCurrentContext()); + _blend.inputs[| 0].setFrom(_n0.outputs[| 0]); + _blend.inputs[| 1].setFrom(_n1.outputs[| 0]); + + nodes_selecting = []; + } #endregion + + function doCompose() { #region + if(array_empty(nodes_selecting)) return; + + var cx = nodes_selecting[0].x; + var cy = 0; + var pr = ds_priority_create(); + var amo = array_length(nodes_selecting); + var len = 0; + + for(var i = 0; i < amo; i++) { + var _node = nodes_selecting[i]; + if(ds_list_size(_node.outputs) == 0) continue; + if(_node.outputs[| 0].type != VALUE_TYPE.surface) continue; + + cx = max(cx, _node.x); + cy += _node.y; + + ds_priority_add(pr, _node, _node.y); + len++; + } + + cx = cx + 160; + cy = round(cy / len / 32) * 32; + + var _compose = nodeBuild("Node_Composite", cx, cy); + + repeat(len) { + var _node = ds_priority_delete_min(pr); + _compose.addInput(_node.outputs[| 0]); + } + + nodes_selecting = []; + ds_priority_destroy(pr); + } #endregion + + function doArray() { #region + if(array_empty(nodes_selecting)) return; + + var cx = nodes_selecting[0].x; + var cy = 0; + var pr = ds_priority_create(); + var amo = array_length(nodes_selecting); + var len = 0; + + for(var i = 0; i < amo; i++) { + var _node = nodes_selecting[i]; + if(ds_list_size(_node.outputs) == 0) continue; + + cx = max(cx, _node.x); + cy += _node.y; + + ds_priority_add(pr, _node, _node.y); + len++; + } + + cx = cx + 160; + cy = round(cy / len / 32) * 32; + + var _array = nodeBuild("Node_Array", cx, cy); + + repeat(len) { + var _node = ds_priority_delete_min(pr); + _array.addInput(_node.outputs[| 0]); + } + + nodes_selecting = []; + ds_priority_destroy(pr); + } #endregion + + function doGroup() { #region + if(array_empty(nodes_selecting)) return; + groupNodes(nodes_selecting); + } #endregion + + function doUngroup() { #region + var _node = getFocusingNode(); + if(_node == noone) return; + if(!is_instanceof(_node, Node_Collection) || !_node.ungroupable) return; + + upgroupNode(_node); + } #endregion + + function doFrame() { #region + var x0 = 999999, y0 = 999999, x1 = -999999, y1 = -999999; + + for( var i = 0; i < array_length(nodes_selecting); i++ ) { + var _node = nodes_selecting[i]; + x0 = min(x0, _node.x); + y0 = min(y0, _node.y); + x1 = max(x1, _node.x + _node.w); + y1 = max(y1, _node.y + _node.h); + } + + x0 -= 64; + y0 -= 64; + x1 += 64; + y1 += 64; + + var f = new Node_Frame(x0, y0, getCurrentContext()); + f.inputs[| 0].setValue([x1 - x0, y1 - y0]); + } #endregion + + function doDelete(_merge = false) { #region + __temp_merge = _merge; + array_foreach(nodes_selecting, function(node) { if(node.manual_deletable) node.destroy(__temp_merge); }); + nodes_selecting = []; + } #endregion + + node_prop_clipboard = noone; + function doCopyProp() { #region + if(node_hover == noone) return; + node_prop_clipboard = node_hover; + } #endregion + + function doPasteProp() { #region + if(node_hover == noone) return; + if(node_prop_clipboard == noone) return; + if(!node_prop_clipboard.active) return; + + if(instanceof(node_prop_clipboard) != instanceof(node_hover)) return; + + var _vals = []; + for( var i = 0, n = ds_list_size(node_prop_clipboard.inputs); i < n; i++ ) { + var _inp = node_prop_clipboard.inputs[| i]; + _vals[i] = _inp.serialize(); + } + + for( var i = 0, n = ds_list_size(node_hover.inputs); i < n; i++ ) { + var _inp = node_hover.inputs[| i]; + if(_inp.value_from != noone) continue; + + _inp.applyDeserialize(_vals[i]); + } + + node_hover.clearInputCache(); + RENDER_PARTIAL + } #endregion + #endregion + + function dropFile(path) { #region + if(node_hovering && is_callable(node_hovering.on_drop_file)) + return node_hovering.on_drop_file(path); + return false; + } #endregion + + static checkDropItem = function() { #region + var node = noone; + + switch(DRAGGING.type) { + case "Color": + node = nodeBuild("Node_Color", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Palette": + node = nodeBuild("Node_Palette", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Gradient": + node = nodeBuild("Node_Gradient_Out", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Number": + if(is_array(DRAGGING.data) && array_length(DRAGGING.data) <= 4) { + switch(array_length(DRAGGING.data)) { + case 2 : node = nodeBuild("Node_Vector2", mouse_grid_x, mouse_grid_y, getCurrentContext()); break; + case 3 : node = nodeBuild("Node_Vector3", mouse_grid_x, mouse_grid_y, getCurrentContext()); break; + case 4 : node = nodeBuild("Node_Vector4", mouse_grid_x, mouse_grid_y, getCurrentContext()); break; + } + + for( var i = 0, n = array_length(DRAGGING.data); i < n; i++ ) + node.inputs[| i].setValue(DRAGGING.data[i]); + } else { + node = nodeBuild("Node_Number", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + } + break; + + case "Bool": + node = nodeBuild("Node_Boolean", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Text": + node = nodeBuild("Node_String", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Path": + node = nodeBuild("Node_Path", mouse_grid_x, mouse_grid_y, getCurrentContext()); + break; + + case "Struct": + node = nodeBuild("Node_Struct", mouse_grid_x, mouse_grid_y, getCurrentContext()); + break; + + case "Asset": + var app = Node_create_Image_path(mouse_grid_x, mouse_grid_y, DRAGGING.data.path); + break; + + case "Collection": + var path = DRAGGING.data.path; + nodes_selecting = []; + + var app = APPEND(DRAGGING.data.path, getCurrentContext()); + + if(!is_struct(app) && ds_exists(app, ds_type_list)) { + var cx = 0; + var cy = 0; + + for( var i = 0; i < ds_list_size(app); i++ ) { + cx += app[| i].x; + cy += app[| i].y; + } + + cx /= ds_list_size(app); + cy /= ds_list_size(app); + + for( var i = 0; i < ds_list_size(app); i++ ) { + app[| i].x = app[| i].x - cx + mouse_grid_x; + app[| i].y = app[| i].y - cy + mouse_grid_y; + } + + ds_list_destroy(app); + } else { + app.x = mouse_grid_x; + app.y = mouse_grid_y; + } + break; + + case "Project": + run_in(1, function(path) { LOAD_PATH(path); }, [ DRAGGING.data.path ]); + break; + + } + + if(!key_mod_press(SHIFT) && node && struct_has(DRAGGING, "from") && DRAGGING.from.isLeaf()) { + for( var i = 0; i < ds_list_size(node.outputs); i++ ) + if(DRAGGING.from.setFrom(node.outputs[| i])) break; + } + } #endregion + + static bringNodeToFront = function(node) { #region + if(!ds_list_exist(nodes_list, node)) return; + + ds_list_remove(nodes_list, node); + ds_list_add(nodes_list, node); + } #endregion + + static onFullScreen = function() { run_in(1, fullView); } + + function close() { #region + var panels = findPanels("Panel_Graph"); + for( var i = 0, n = array_length(panels); i < n; i++ ) { + if(panels[i] == self) continue; + if(panels[i].project == project) { + panel.remove(self); + return; + } + } + + if(!project.modified || project.readonly) { + closeProject(project); + return; + } + + var dia = dialogCall(o_dialog_save); + dia.project = project; + } #endregion +} \ No newline at end of file diff --git a/#backups/scripts/panel_graph/panel_graph.gml.backup1 b/#backups/scripts/panel_graph/panel_graph.gml.backup1 new file mode 100644 index 000000000..f315969f2 --- /dev/null +++ b/#backups/scripts/panel_graph/panel_graph.gml.backup1 @@ -0,0 +1,2332 @@ +// 2024-04-21 19:33:07 +#region funtion calls + function __fnInit_Graph() { + __registerFunction("graph_add_node", panel_graph_add_node); + __registerFunction("graph_focus_content", panel_graph_focus_content); + __registerFunction("graph_preview_focus", panel_graph_preview_focus); + __registerFunction("graph_preview_window", panel_graph_preview_window); + + __registerFunction("graph_import_image", panel_graph_import_image); + __registerFunction("graph_import_image_array", panel_graph_import_image_array); + __registerFunction("graph_add_number", panel_graph_add_number); + __registerFunction("graph_add_vec2", panel_graph_add_vec2); + __registerFunction("graph_add_vec3", panel_graph_add_vec3); + __registerFunction("graph_add_vec4", panel_graph_add_vec4); + __registerFunction("graph_add_transform", panel_graph_add_transform); + + __registerFunction("graph_select_all", panel_graph_select_all); + __registerFunction("graph_toggle_grid", panel_graph_toggle_grid); + __registerFunction("graph_toggle_preview", panel_graph_toggle_preview); + __registerFunction("graph_toggle_render", panel_graph_toggle_render); + + __registerFunction("graph_export", panel_graph_export); + + __registerFunction("graph_blend", panel_graph_blend); + __registerFunction("graph_compose", panel_graph_compose); + __registerFunction("graph_array", panel_graph_array); + __registerFunction("graph_group", panel_graph_group); + __registerFunction("graph_ungroup", panel_graph_ungroup); + + __registerFunction("graph_canvas", panel_graph_canvas); + __registerFunction("graph_canvas_blend", panel_graph_canvas_blend); + + __registerFunction("graph_frame", panel_graph_frame); + __registerFunction("graph_delete_break", panel_graph_delete_break); + __registerFunction("graph_delete_merge", panel_graph_delete_merge); + __registerFunction("graph_duplicate", panel_graph_duplicate); + __registerFunction("graph_copy", panel_graph_copy); + __registerFunction("graph_paste", panel_graph_paste); + + __registerFunction("graph_pan", panel_graph_pan); + __registerFunction("graph_zoom", panel_graph_zoom); + } + + function panel_graph_add_node() { CALL("graph_add_node"); PANEL_GRAPH.callAddDialog(); } + function panel_graph_focus_content() { CALL("graph_focus_content"); PANEL_GRAPH.fullView(); } + function panel_graph_preview_focus() { CALL("graph_preview_focus"); PANEL_GRAPH.setCurrentPreview(); } + function panel_graph_preview_window() { CALL("graph_preview_window"); PANEL_GRAPH.create_preview_window(PANEL_GRAPH.getFocusingNode()); } + + function panel_graph_import_image() { CALL("graph_import_image"); nodeBuild("Node_Image", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_import_image_array() { CALL("graph_import_image_array"); nodeBuild("Node_Image_Sequence", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_number() { CALL("graph_add_number"); nodeBuild("Node_Number", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_vec2() { CALL("graph_add_vec2"); nodeBuild("Node_Vector2", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_vec3() { CALL("graph_add_vec3"); nodeBuild("Node_Vector3", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_vec4() { CALL("graph_add_vec4"); nodeBuild("Node_Vector4", PANEL_GRAPH.mouse_grid_x, PANEL_GRAPH.mouse_grid_y); } + function panel_graph_add_transform() { CALL("graph_add_transform"); PANEL_GRAPH.doTransform(); } + + function panel_graph_select_all() { CALL("graph_select_all"); PANEL_GRAPH.nodes_selecting = ds_list_to_array(PANEL_GRAPH.nodes_list); } + function panel_graph_toggle_grid() { CALL("graph_toggle_grid"); PANEL_GRAPH.display_parameter.show_grid = !PANEL_GRAPH.display_parameter.show_grid; } + function panel_graph_toggle_preview() { CALL("graph_toggle_preview"); PANEL_GRAPH.setTriggerPreview(); } + function panel_graph_toggle_parameter() { CALL("graph_toggle_parameter"); PANEL_GRAPH.setTriggerParameter(); } + function panel_graph_toggle_render() { CALL("graph_toggle_render"); PANEL_GRAPH.setTriggerRender(); } + + function panel_graph_export() { CALL("graph_export"); PANEL_GRAPH.setCurrentExport(); } + + function panel_graph_blend() { CALL("graph_blend"); PANEL_GRAPH.doBlend(); } + function panel_graph_compose() { CALL("graph_compose"); PANEL_GRAPH.doCompose(); } + function panel_graph_array() { CALL("graph_array"); PANEL_GRAPH.doArray(); } + function panel_graph_group() { CALL("graph_group"); PANEL_GRAPH.doGroup(); } + function panel_graph_ungroup() { CALL("graph_ungroup"); PANEL_GRAPH.doUngroup(); } + + function panel_graph_canvas() { CALL("graph_canvas"); PANEL_GRAPH.setCurrentCanvas(); } + function panel_graph_canvas_blend() { CALL("graph_canvas_blend"); PANEL_GRAPH.setCurrentCanvasBlend(); } + + function panel_graph_frame() { CALL("graph_frame"); PANEL_GRAPH.doFrame(); } + function panel_graph_delete_break() { CALL("graph_delete_break"); PANEL_GRAPH.doDelete(false); } + function panel_graph_delete_merge() { CALL("graph_delete_merge"); PANEL_GRAPH.doDelete(true); } + function panel_graph_duplicate() { CALL("graph_duplicate"); PANEL_GRAPH.doDuplicate(); } + function panel_graph_copy() { CALL("graph_copy"); PANEL_GRAPH.doCopy(); } + function panel_graph_paste() { CALL("graph_paste"); PANEL_GRAPH.doPaste(); } + + function panel_graph_pan() { CALL("graph_pan"); PANEL_GRAPH.graph_dragging_key = true; } + function panel_graph_zoom() { CALL("graph_zoom"); PANEL_GRAPH.graph_zooming_key = true; } +#endregion + +function connectionParameter() constructor { #region + log = false; + active = true; + + x = 0; + y = 0; + s = 0; + mx = 0; + my = 0; + aa = 0; + bg = 0; + + minx = 0; + miny = 0; + maxx = 0; + maxy = 0; + + max_layer = 0; + highlight = 0; + cur_layer = 1; + + static setPos = function(_x, _y, _s, _mx, _my) { + self.x = _x; + self.y = _y; + self.s = _s; + self.mx = _mx; + self.my = _my; + } + + static setBoundary = function(_minx, _miny, _maxx, _maxy) { + self.minx = _minx; + self.miny = _miny; + self.maxx = _maxx; + self.maxy = _maxy; + } + + static setProp = function(_max_layer, _highlight) { + self.max_layer = _max_layer; + self.highlight = _highlight; + } + + static setDraw = function(_aa, _bg = c_black) { + self.aa = _aa; + self.bg = _bg; + } +} #endregion + +function Panel_Graph(project = PROJECT) : PanelContent() constructor { + title = __txt("Graph"); + title_raw = ""; + context_str = "Graph"; + icon = THEME.panel_graph_icon; + + static setProject = function(project) { + self.project = project; + nodes_list = project.nodes; + } + setProject(project); + + #region ---- display ---- + display_parameter = { + show_grid : true, + show_dimension : true, + show_compute : true, + + avoid_label : true, + preview_scale : 100, + highlight : false, + } + + connection_param = new connectionParameter(); + + bg_color = c_black; + #endregion + + #region ---- position ---- + scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0]; + graph_s = 1; + graph_s_to = graph_s; + + graph_dragging_key = false; + graph_zooming_key = false; + + graph_draggable= true; + graph_dragging = false; + graph_drag_mx = 0; + graph_drag_my = 0; + graph_drag_sx = 0; + graph_drag_sy = 0; + + graph_zooming = false; + graph_zoom_mx = 0; + graph_zoom_my = 0; + graph_zoom_m = 0; + graph_zoom_s = 0; + + drag_key = PREFERENCES.pan_mouse_key; + drag_locking = false; + #endregion + + #region ---- mouse ---- + mouse_graph_x = 0; + mouse_graph_y = 0; + mouse_grid_x = 0; + mouse_grid_y = 0; + mouse_on_graph = false; + + node_bg_hovering = false; + #endregion + + #region ---- nodes ---- + node_context = ds_list_create(); + + node_dragging = noone; + node_drag_mx = 0; + node_drag_my = 0; + node_drag_sx = 0; + node_drag_sy = 0; + node_drag_ox = 0; + node_drag_oy = 0; + + selection_block = 0; + nodes_selecting = []; + nodes_selecting_jun = []; + nodes_select_drag = 0; + nodes_select_frame = 0; + nodes_select_mx = 0; + nodes_select_my = 0; + + nodes_junction_d = noone; + nodes_junction_dx = 0; + nodes_junction_dy = 0; + + node_hovering = noone; + node_hover = noone; + + junction_hovering = noone; + junction_hover_direct = noone; + add_node_draw_junc = false; + add_node_draw_x_fix = 0; + add_node_draw_y_fix = 0; + add_node_draw_x = 0; + add_node_draw_y = 0; + + connection_aa = 2; + connection_surface = surface_create(1, 1); + connection_surface_aa = surface_create(1, 1); + + connection_draw_mouse = noone; + connection_draw_target = noone; + + value_focus = noone; + value_dragging = noone; + value_draggings = []; + + frame_hovering = noone; + _frame_hovering = noone; + #endregion + + #region ---- minimap ---- + minimap_show = false; + minimap_w = ui(160); + minimap_h = ui(160); + minimap_surface = -1; + + minimap_panning = false; + minimap_dragging = false; + minimap_drag_sx = 0; + minimap_drag_sy = 0; + minimap_drag_mx = 0; + minimap_drag_my = 0; + #endregion + + #region ---- context frame ---- + context_framing = false; + context_frame_progress = 0; + context_frame_direct = 0; + context_frame_sx = 0; context_frame_ex = 0; + context_frame_sy = 0; context_frame_ey = 0; + #endregion + + toolbar_height = ui(40); + + function toCenterNode(_list = nodes_list) { #region + if(!project.active) return; + + if(ds_list_empty(_list)) { + graph_x = round(w / 2 / graph_s); + graph_y = round(h / 2 / graph_s); + return; + } + + var minx = 99999; + var maxx = -99999; + var miny = 99999; + var maxy = -99999; + + for(var i = 0; i < ds_list_size(_list); i++) { + var _node = _list[| i]; + if(!is_struct(_node) || !is_instanceof(_node, Node) || !_node.active) + continue; + + minx = min(_node.x - 32, minx); + maxx = max(_node.x + _node.w + 32, maxx); + + miny = min(_node.y - 32, miny); + maxy = max(_node.y + _node.h + 32, maxy); + } + + graph_x = w / 2 / graph_s - (minx + maxx) / 2; + graph_y = (h - toolbar_height) / 2 / graph_s - (miny + maxy) / 2; + + graph_x = round(graph_x); + graph_y = round(graph_y); + } #endregion + + function initSize() { toCenterNode(); } initSize(); + + #region ++++ hotkeys ++++ + addHotkey("Graph", "Add node", "A", MOD_KEY.none, panel_graph_add_node); + addHotkey("Graph", "Focus content", "F", MOD_KEY.none, panel_graph_focus_content); + addHotkey("Graph", "Preview focusing node", "P", MOD_KEY.none, panel_graph_preview_focus); + addHotkey("Graph", "Preview window", "P", MOD_KEY.ctrl, panel_graph_preview_window); + + addHotkey("Graph", "Import image", "I", MOD_KEY.none, panel_graph_import_image); + addHotkey("Graph", "Import image array", "I", MOD_KEY.shift, panel_graph_import_image_array); + addHotkey("Graph", "Add number", "1", MOD_KEY.none, panel_graph_add_number); + addHotkey("Graph", "Add vector2", "2", MOD_KEY.none, panel_graph_add_vec2); + addHotkey("Graph", "Add vector3", "3", MOD_KEY.none, panel_graph_add_vec3); + addHotkey("Graph", "Add vector4", "4", MOD_KEY.none, panel_graph_add_vec4); + addHotkey("Graph", "Transform node", "T", MOD_KEY.ctrl, panel_graph_add_transform); + + addHotkey("Graph", "Select all", "A", MOD_KEY.ctrl, panel_graph_select_all); + addHotkey("Graph", "Toggle grid", "G", MOD_KEY.none, panel_graph_toggle_grid); + addHotkey("Graph", "Toggle preview", "H", MOD_KEY.none, panel_graph_toggle_preview); + addHotkey("Graph", "Toggle render", "R", MOD_KEY.none, panel_graph_toggle_render); + addHotkey("Graph", "Toggle parameters", "M", MOD_KEY.none, panel_graph_toggle_parameter); + + if(!DEMO) addHotkey("Graph", "Export", "E", MOD_KEY.ctrl, panel_graph_export); + + addHotkey("Graph", "Blend", "B", MOD_KEY.ctrl, panel_graph_blend); + addHotkey("Graph", "Compose", "B", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_compose); + addHotkey("Graph", "Array", "A", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_array); + addHotkey("Graph", "Group", "G", MOD_KEY.ctrl, panel_graph_group); + addHotkey("Graph", "Ungroup", "G", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_ungroup); + + addHotkey("Graph", "Canvas", "C", MOD_KEY.ctrl | MOD_KEY.shift, panel_graph_canvas); + addHotkey("Graph", "Canvas blend", "C", MOD_KEY.ctrl | MOD_KEY.alt, panel_graph_canvas_blend); + + addHotkey("Graph", "Frame", "F", MOD_KEY.ctrl, panel_graph_frame); + + addHotkey("Graph", "Delete (break)", vk_delete, MOD_KEY.shift, panel_graph_delete_break); + addHotkey("Graph", "Delete (merge)", vk_delete, MOD_KEY.none, panel_graph_delete_merge); + + addHotkey("Graph", "Duplicate", "D", MOD_KEY.ctrl, panel_graph_duplicate); + addHotkey("Graph", "Copy", "C", MOD_KEY.ctrl, panel_graph_copy); + addHotkey("Graph", "Paste", "V", MOD_KEY.ctrl, panel_graph_paste); + + addHotkey("Graph", "Pan", "", MOD_KEY.ctrl, panel_graph_pan); + addHotkey("Graph", "Zoom", "", MOD_KEY.alt | MOD_KEY.ctrl, panel_graph_zoom); + #endregion + + #region ++++ toolbars ++++ + tooltip_center = new tooltipHotkey(__txtx("panel_graph_center_to_nodes", "Center to nodes"), "Graph", "Focus content"); + + toolbars = [ + [ + THEME.icon_preview_export, + function() { return 0; }, + function() { return __txtx("panel_graph_export_image", "Export graph as image"); }, + function() { dialogPanelCall(new Panel_Graph_Export_Image(self)); } + ], + [ + THEME.icon_center_canvas, + function() { return 0; }, + function() { return tooltip_center; }, + function() { toCenterNode(); } + ], + [ + THEME.icon_minimap, + function() { return minimap_show; }, + function() { return minimap_show? __txtx("panel_graph_minimap_enabled", "Minimap enabled") : __txtx("panel_graph_minimap_disabled", "Minimap disabled"); }, + function() { minimap_show = !minimap_show; } + ], + [ + THEME.icon_curve_connection, + function() { return PREFERENCES.curve_connection_line; }, + function() { return __txtx("panel_graph_connection_line", "Connection render settings"); }, + function(param) { + dialogPanelCall(new Panel_Graph_Connection_Setting(), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); + } + ], + [ + THEME.icon_grid_setting, + function() { return 0; }, + function() { return __txtx("grid_title", "Grid settings"); }, + function(param) { + dialogPanelCall(new Panel_Graph_Grid_Setting(), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); + } + ], + [ + THEME.icon_visibility, + function() { return 0; }, + function() { return __txtx("graph_visibility_title", "Visibility settings"); }, + function(param) { + dialogPanelCall(new Panel_Graph_View_Setting(display_parameter), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); + } + ], + ]; + #endregion + + #region ++++ node setters ++++ + function setCurrentPreview(_node = getFocusingNode()) { #region + if(!_node) return; + + PANEL_PREVIEW.setNodePreview(_node); + } #endregion + + function setCurrentExport(_node = getFocusingNode()) { #region + if(DEMO) return; + if(!_node) return; + + var _outp = -1; + var _path = -1; + + for( var i = 0; i < ds_list_size(_node.outputs); i++ ) { + if(_node.outputs[| i].type == VALUE_TYPE.path) + _path = _node.outputs[| i]; + if(_node.outputs[| i].type == VALUE_TYPE.surface && _outp == -1) + _outp = _node.outputs[| i]; + } + + if(_outp == -1) return; + + var _export = nodeBuild("Node_Export", _node.x + _node.w + 64, _node.y); + if(_path != -1) + _export.inputs[| 1].setFrom(_path); + + _export.inputs[| 0].setFrom(_outp); + } #endregion + + function setCurrentCanvas(_node = getFocusingNode()) { #region + if(!_node) return; + + var _outp = -1; + var surf = -1; + + for( var i = 0; i < ds_list_size(_node.outputs); i++ ) { + if(_node.outputs[| i].type != VALUE_TYPE.surface) continue; + + _outp = _node.outputs[| i]; + surf = _outp.getValue(); + break; + } + + if(_outp == -1) return; + if(!is_array(surf)) surf = [ surf ]; + + var _canvas = nodeBuild("Node_Canvas", _node.x + _node.w + 64, _node.y); + var _dim = surface_get_dimension(surf[0]); + + _canvas.attributes.dimension = _dim; + _canvas.attributes.frames = array_length(surf); + _canvas.canvas_surface = surface_array_clone(surf); + _canvas.inputs[| 0].setValue(_dim); + + _canvas.apply_surfaces(); + + } #endregion + + function setTriggerPreview() { #region + __temp_show = false; + array_foreach(nodes_selecting, function(node, index) { + if(index == 0) __temp_show = !node.previewable; + node.previewable = __temp_show; + node.refreshNodeDisplay(); + }); + } #endregion + + function setTriggerParameter() { #region + __temp_show = false; + array_foreach(nodes_selecting, function(node, index) { + if(index == 0) __temp_show = !node.show_parameter; + node.show_parameter = __temp_show; + node.refreshNodeDisplay(); + }); + } #endregion + + function setTriggerRender() { #region + __temp_active = false; + array_foreach(nodes_selecting, function(node, index) { + if(index == 0) __temp_active = !node.renderActive; + node.renderActive = __temp_active; + }); + } #endregion + + function setCurrentCanvasBlend(_node = getFocusingNode()) { #region + if(!_node) return; + + var _outp = -1; + var surf = -1; + + for( var i = 0; i < ds_list_size(_node.outputs); i++ ) { + if(_node.outputs[| i].type == VALUE_TYPE.surface) { + _outp = _node.outputs[| i]; + var _val = _node.outputs[| i].getValue(); + if(is_array(_val)) + surf = _val[_node.preview_index]; + else + surf = _val; + break; + } + } + + if(_outp == -1) return; + + var _canvas = nodeBuild("Node_Canvas", _node.x, _node.y + _node.h + 64); + + _canvas.inputs[| 0].setValue([surface_get_width_safe(surf), surface_get_height_safe(surf)]); + _canvas.inputs[| 5].setValue(true); + + var _blend = new Node_Blend(_node.x + _node.w + 64, _node.y, getCurrentContext()); + _blend.inputs[| 0].setFrom(_outp); + _blend.inputs[| 1].setFrom(_canvas.outputs[| 0]); + } #endregion + #endregion + + #region ++++ context menu ++++ + menu_sent_to_preview = menuItem(__txtx("panel_graph_send_to_preview", "Send to preview"), function() { setCurrentPreview(node_hover); }); + menu_send_to_window = menuItem(__txtx("panel_graph_preview_window", "Send to preview window"), function() { create_preview_window(node_hover); }, noone, ["Graph", "Preview window"]); + menu_sent_to_inspector = menuItem(__txtx("panel_graph_inspector_panel", "Send to new inspector"), function() { + var pan = panelAdd("Panel_Inspector", true); + pan.destroy_on_click_out = false; + pan.content.setInspecting(node_hover); + pan.content.locked = true; + }); + menu_send_export = menuItem(__txtx("panel_graph_send_to_export", "Send to export"), function() { setCurrentExport(node_hover); }, noone, ["Graph", "Export"]); + menu_toggle_preview = menuItem(__txtx("panel_graph_toggle_preview", "Toggle node preview"), function() { setTriggerPreview(); }, noone, ["Graph", "Toggle preview"]); + menu_toggle_render = menuItem(__txtx("panel_graph_toggle_render", "Toggle node render"), function() { setTriggerRender(); }, noone, ["Graph", "Toggle render"]); + menu_toggle_param = menuItem(__txtx("panel_graph_toggle_parameter", "Toggle node parameters"),function() { setTriggerParameter(); }, noone, ["Graph", "Toggle parameters"]); + menu_open_group = menuItem(__txtx("panel_graph_enter_group", "Open group"), function() { PANEL_GRAPH.addContext(node_hover); }, THEME.group); + + function openGroupTab(group) { + var graph = new Panel_Graph(project); + panel.setContent(graph, true); + + for( var i = 0; i < ds_list_size(node_context); i++ ) + graph.addContext(node_context[| i]); + graph.addContext(group); + + setFocus(panel); + } + menu_open_group_tab = menuItem(__txtx("panel_graph_enter_group_new_tab", "Open group in new tab"), function() { openGroupTab(node_hover); }, THEME.group); + menu_group_ungroup = menuItem(__txt("Ungroup"), function() { doUngroup(); }, THEME.group, ["Graph", "Ungroup"]); + menu_group_tool = menuItem(__txt("Set as group tool"), function() { node_hover.setTool(!node_hover.isTool); }); + + menu_node_delete_merge = menuItem(__txtx("panel_graph_delete_and_merge_connection", "Delete and merge connection"), function() { doDelete(true); }, THEME.cross, ["Graph", "Delete (merge)"]); + menu_node_delete_cut = menuItem(__txtx("panel_graph_delete_and_cut_connection", "Delete and cut connection"), function() { doDelete(false); }, THEME.cross, ["Graph", "Delete (break)"]); + menu_node_duplicate = menuItem(__txt("Duplicate"), function() { doDuplicate(); }, THEME.duplicate, ["Graph", "Duplicate"]); + menu_node_copy = menuItem(__txt("Copy"), function() { doCopy(); }, THEME.copy, ["Graph", "Copy"]); + + menu_node_transform = menuItem(__txtx("panel_graph_add_transform", "Add transform"), function() { doTransform(); }, noone, ["Graph", "Transform node"]); + menu_node_canvas = menuItem(__txtx("panel_graph_canvas", "Canvas"), + function(_dat) { + return submenuCall(_dat, [ + menuItem(__txtx("panel_graph_copy_to_canvas", "Copy to canvas"), function() { setCurrentCanvas(node_hover); }, noone, ["Graph", "Canvas"]), + menuItem(__txtx("panel_graph_overlay_canvas", "Overlay canvas"), function() { setCurrentCanvasBlend(node_hover); }, noone, ["Graph", "Canvas blend"]) + ]); + }).setIsShelf(); + + menu_nodes_align = menuItem(__txtx("panel_graph_align_nodes", "Align nodes"), function(_dat) { + return submenuCall(_dat, [ + menuItemGroup(__txtx("horizontal", "Horizontal"), [ + [ [THEME.inspector_surface_halign, 0], function() { node_halign(nodes_selecting, fa_left); } ], + [ [THEME.inspector_surface_halign, 1], function() { node_halign(nodes_selecting, fa_center); } ], + [ [THEME.inspector_surface_halign, 2], function() { node_halign(nodes_selecting, fa_right); } ], + ]), + menuItemGroup(__txtx("vertical", "Vertical"), [ + [ [THEME.inspector_surface_valign, 0], function() { node_valign(nodes_selecting, fa_top); } ], + [ [THEME.inspector_surface_valign, 1], function() { node_valign(nodes_selecting, fa_middle); } ], + [ [THEME.inspector_surface_valign, 2], function() { node_valign(nodes_selecting, fa_bottom); } ], + ]), + menuItemGroup(__txtx("distribute", "Distribute"), [ + [ [THEME.obj_distribute_h, 0], function() { node_hdistribute(nodes_selecting); } ], + [ [THEME.obj_distribute_v, 0], function() { node_vdistribute(nodes_selecting); } ], + ]), + ]); + }).setIsShelf(); + menu_nodes_blend = menuItem(__txtx("panel_graph_blend_nodes", "Blend nodes"), function() { doBlend(); }, noone, ["Graph", "Blend"]); + menu_nodes_compose = menuItem(__txtx("panel_graph_compose_nodes", "Compose nodes"), function() { doCompose(); }, noone, ["Graph", "Compose"]); + menu_nodes_array = menuItem(__txtx("panel_graph_array_from_nodes", "Array from nodes"), function() { doArray(); }, noone, ["Graph", "Array"]); + menu_nodes_group = menuItem(__txtx("panel_graph_group_nodes", "Group nodes"), function() { doGroup(); }, THEME.group, ["Graph", "Group"]); + menu_nodes_frame = menuItem(__txtx("panel_graph_frame_nodes", "Frame nodes"), function() { doFrame(); }, noone, ["Graph", "Frame"]); + + menu_node_copy_prop = menuItem(__txtx("panel_graph_copy_prop", "Copy all properties"), function() { doCopyProp(); }); + menu_node_paste_prop = menuItem(__txtx("panel_graph_paste_prop", "Paste all properties"), function() { doPasteProp(); }); + + #region node color + function setSelectingNodeColor(color) { + __temp_color = color; + + if(node_hover) node_hover.attributes.color = __temp_color; + array_foreach(nodes_selecting, function(node) { node.attributes.color = __temp_color; }); + } + + var _clrs = COLORS.labels; + var _item = array_create(array_length(_clrs)); + + for( var i = 0, n = array_length(_clrs); i < n; i++ ) { + _item[i] = [ + [ THEME.timeline_color, i > 0, _clrs[i] ], + function(_data) { + setSelectingNodeColor(_data.color); + }, "", { color: i == 0? -1 : _clrs[i] } + ]; + } + + array_push(_item, [ + [ THEME.timeline_color, 2 ], + function(_data) { + colorSelectorCall(node_hover? node_hover.attributes.color : c_white, setSelectingNodeColor); + } + ]); + + menu_node_color = menuItemGroup(__txt("Node Color"), _item); + menu_node_color.spacing = ui(24); + #endregion + + #region junction color + __junction_hovering = noone; + + function setSelectingJuncColor(color) { + if(__junction_hovering == noone) return; + __junction_hovering.setColor(color); + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _node = nodes_selecting[i]; + + for( var j = 0, m = ds_list_size(_node.inputs); j < m; j++ ) { + var _input = _node.inputs[| j]; + if(_input.isLeaf()) continue; + _input.setColor(color); + } + } + } + + var _clrs = COLORS.labels; + var _item = array_create(array_length(_clrs)); + + for( var i = 0, n = array_length(_clrs); i < n; i++ ) { + _item[i] = [ + [ THEME.timeline_color, i > 0, _clrs[i] ], + function(_data) { + setSelectingJuncColor(_data.color); + }, "", { color: i == 0? -1 : _clrs[i] } + ]; + } + + array_push(_item, [ + [ THEME.timeline_color, 2 ], + function(_data) { + colorSelectorCall(__junction_hovering? __junction_hovering.color : c_white, setSelectingJuncColor); + } + ]); + + menu_junc_color = menuItemGroup(__txt("Connection Color"), _item); + menu_junc_color.spacing = ui(24); + #endregion + #endregion + + function getFocusingNode() { INLINE return array_empty(nodes_selecting)? noone : nodes_selecting[0]; } + + function getCurrentContext() { #region + if(ds_list_empty(node_context)) return noone; + return node_context[| ds_list_size(node_context) - 1]; + } #endregion + + function getNodeList(cont = getCurrentContext()) { #region + return cont == noone? project.nodes : cont.getNodeList(); + } #endregion + + function onFocusBegin() { #region + PANEL_GRAPH = self; + PROJECT = project; + + nodes_select_drag = 0; + } #endregion + + function stepBegin() { #region + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + var m_x = (mx - gr_x) / graph_s; + var m_y = (my - gr_y) / graph_s; + mouse_graph_x = m_x; + mouse_graph_y = m_y; + + mouse_grid_x = round(m_x / project.graphGrid.size) * project.graphGrid.size; + mouse_grid_y = round(m_y / project.graphGrid.size) * project.graphGrid.size; + + setTitle(); + } #endregion + + function focusNode(_node) { #region + if(_node == noone) { + nodes_selecting = []; + return; + } + + nodes_selecting = [ _node ]; + fullView(); + } #endregion + + function fullView() { #region + INLINE + var _l = ds_list_create_from_array(nodes_selecting); + toCenterNode(array_empty(nodes_selecting)? nodes_list : _l); + ds_list_destroy(_l); + + graph_s_to = 1; + } #endregion + + function dragGraph() { #region + if(graph_dragging) { + if(!MOUSE_WRAPPING) { + var dx = mx - graph_drag_mx; + var dy = my - graph_drag_my; + + graph_x += dx / graph_s; + graph_y += dy / graph_s; + } + + graph_drag_mx = mx; + graph_drag_my = my; + setMouseWrap(); + + if(mouse_release(drag_key)) + graph_dragging = false; + } + + if(graph_zooming) { + if(!MOUSE_WRAPPING) { + var dy = -(my - graph_zoom_m) / 200; + + var _s = graph_s; + + graph_s_to = clamp(graph_s_to * (1 + dy), scale[0], scale[array_length(scale) - 1]); + graph_s = graph_s_to; + + if(_s != graph_s) { + var mb_x = (graph_zoom_mx - graph_x * _s) / _s; + var ma_x = (graph_zoom_mx - graph_x * graph_s) / graph_s; + var md_x = ma_x - mb_x; + graph_x += md_x; + + var mb_y = (graph_zoom_my - graph_y * _s) / _s; + var ma_y = (graph_zoom_my - graph_y * graph_s) / graph_s; + var md_y = ma_y - mb_y; + graph_y += md_y; + } + } + + graph_zoom_m = my; + setMouseWrap(); + + if(mouse_release(drag_key)) + graph_zooming = false; + } + + if(mouse_on_graph && pFOCUS && graph_draggable) { + var _doDragging = false; + var _doZooming = false; + + if(mouse_press(PREFERENCES.pan_mouse_key)) { + _doDragging = true; + drag_key = PREFERENCES.pan_mouse_key; + } else if(mouse_press(mb_left) && graph_dragging_key) { + _doDragging = true; + drag_key = mb_left; + } else if(mouse_press(mb_left) && graph_zooming_key) { + _doZooming = true; + drag_key = mb_left; + } + + if(_doDragging) { + graph_dragging = true; + graph_drag_mx = mx; + graph_drag_my = my; + graph_drag_sx = graph_x; + graph_drag_sy = graph_y; + } + + if(_doZooming) { + graph_zooming = true; + graph_zoom_mx = mx; + graph_zoom_my = my; + graph_zoom_m = my; + graph_zoom_s = graph_s; + } + } + + if(mouse_on_graph && pHOVER && graph_draggable) { + var _s = graph_s; + if(mouse_wheel_down() && !key_mod_press_any()) { //zoom out + for( var i = 1, n = array_length(scale); i < n; i++ ) { + if(scale[i - 1] < graph_s_to && graph_s_to <= scale[i]) { + graph_s_to = scale[i - 1]; + break; + } + } + } + if(mouse_wheel_up() && !key_mod_press_any()) { // zoom in + for( var i = 1, n = array_length(scale); i < n; i++ ) { + if(scale[i - 1] <= graph_s_to && graph_s_to < scale[i]) { + graph_s_to = scale[i]; + break; + } + } + } + + graph_s = lerp_float(graph_s, graph_s_to, PREFERENCES.graph_zoom_smoooth); + + if(_s != graph_s) { + var mb_x = (mx - graph_x * _s) / _s; + var ma_x = (mx - graph_x * graph_s) / graph_s; + var md_x = ma_x - mb_x; + graph_x += md_x; + + var mb_y = (my - graph_y * _s) / _s; + var ma_y = (my - graph_y * graph_s) / graph_s; + var md_y = ma_y - mb_y; + graph_y += md_y; + } + } + + graph_draggable = true; + graph_x = round(graph_x); + graph_y = round(graph_y); + } #endregion + + function drawGrid() { #region + if(!display_parameter.show_grid) return; + var gls = project.graphGrid.size; + while(gls * graph_s < 8) gls *= 5; + + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + var gr_ls = gls * graph_s; + var xx = -gr_ls, xs = safe_mod(gr_x, gr_ls); + var yy = -gr_ls, ys = safe_mod(gr_y, gr_ls); + + draw_set_color(project.graphGrid.color); + var aa = 0.5; + if(graph_s < 0.25) + aa = 0.3; + var oa = project.graphGrid.opacity; + var ori = project.graphGrid.show_origin; + var hig = project.graphGrid.highlight; + + while(xx < w + gr_ls) { + draw_set_alpha( oa * aa * (1 + (round((xx + xs - gr_x) / gr_ls) % hig == 0) * 2) ); + draw_line(xx + xs, 0, xx + xs, h); + + if(ori && xx + xs - gr_x == 0) draw_line_width(xx + xs, 0, xx + xs, h, 3); + xx += gr_ls; + } + + while(yy < h + gr_ls) { + draw_set_alpha( oa * aa * (1 + (round((yy + ys - gr_y) / gr_ls) % hig == 0) * 2) ); + draw_line(0, yy + ys, w, yy + ys); + + if(ori && yy + ys - gr_y == 0) draw_line_width(0, yy + ys, w, yy + ys, 3); + yy += gr_ls; + } + draw_set_alpha(1); + } #endregion + + function drawBasePreview() { #region + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + var _hov = false; + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var h = nodes_list[| i].drawPreviewBackground(gr_x, gr_y, mx, my, graph_s); + _hov |= h; + } + + return _hov; + } #endregion + + function drawNodes() { #region + if(selection_block-- > 0) return; + + display_parameter.highlight = + !array_empty(nodes_selecting) && ( + (PREFERENCES.connection_line_highlight == 1 && key_mod_press(ALT)) || + PREFERENCES.connection_line_highlight == 2 + ); + + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + + var log = false; + var t = get_timer(); + printIf(log, "============ Draw start ============"); + + _frame_hovering = frame_hovering; + frame_hovering = noone; + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + nodes_list[| i].cullCheck(gr_x, gr_y, graph_s, -32, -32, w + 32, h + 64); + nodes_list[| i].preDraw(gr_x, gr_y, graph_s, gr_x, gr_y); + } + printIf(log, $"Predraw time: {get_timer() - t}"); t = get_timer(); + + #region draw frame + for(var i = 0; i < ds_list_size(nodes_list); i++) { + if(nodes_list[| i].drawNodeBG(gr_x, gr_y, mx, my, graph_s, display_parameter)) + frame_hovering = nodes_list[| i]; + } + #endregion + printIf(log, $"Frame draw time: {get_timer() - t}"); t = get_timer(); + + #region hover + node_hovering = noone; + if(pHOVER) + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + _node.branch_drawing = false; + if(_node.pointIn(gr_x, gr_y, mx, my, graph_s)) + node_hovering = _node; + } + + if(node_hovering != noone) + _HOVERING_ELEMENT = node_hovering; + + if(node_hovering != noone && pFOCUS && DOUBLE_CLICK && struct_has(node_hovering, "onDoubleClick")) { + + if(node_hovering.onDoubleClick(self)) { + DOUBLE_CLICK = false; + node_hovering = noone; + } + } + + if(node_hovering) node_hovering.onDrawHover(gr_x, gr_y, mx, my, graph_s); + #endregion + printIf(log, $"Hover time: {get_timer() - t}"); t = get_timer(); + + #region ++++++++++++ interaction ++++++++++++ + if(mouse_on_graph && pHOVER) { + #region select + if(NODE_DROPPER_TARGET != noone && node_hovering) { + node_hovering.draw_droppable = true; + if(mouse_press(mb_left, NODE_DROPPER_TARGET_CAN)) { + NODE_DROPPER_TARGET.expression += node_hovering.internalName; + NODE_DROPPER_TARGET.expressionUpdate(); + } + } else if(mouse_press(mb_left, pFOCUS)) { + if(key_mod_press(SHIFT)) { + if(node_hovering) { + if(array_exists(nodes_selecting, node_hovering)) + array_remove(nodes_selecting, node_hovering); + else + array_push(nodes_selecting, node_hovering); + } else + nodes_selecting = []; + } else if(value_focus || node_hovering == noone) { + nodes_selecting = []; + + if(DOUBLE_CLICK && !PANEL_INSPECTOR.locked) + PANEL_INSPECTOR.inspecting = noone; + } else { + if(is_instanceof(node_hovering, Node_Frame)) { + var fx0 = (node_hovering.x + graph_x) * graph_s; + var fy0 = (node_hovering.y + graph_y) * graph_s; + var fx1 = fx0 + node_hovering.w * graph_s; + var fy1 = fy0 + node_hovering.h * graph_s; + + nodes_selecting = [ node_hovering ]; + + if(!key_mod_press(CTRL)) + for(var i = 0; i < ds_list_size(nodes_list); i++) { //select content + var _node = nodes_list[| i]; + if(_node == node_hovering) continue; + + if(!_node.selectable) continue; + + var _x = (_node.x + graph_x) * graph_s; + var _y = (_node.y + graph_y) * graph_s; + var _w = _node.w * graph_s; + var _h = _node.h * graph_s; + + if(_w && _h && rectangle_inside_rectangle(fx0, fy0, fx1, fy1, _x, _y, _x + _w, _y + _h)) + array_push_unique(nodes_selecting, _node); + } + } else if(DOUBLE_CLICK) { + PANEL_PREVIEW.setNodePreview(node_hovering); + if(PREFERENCES.inspector_focus_on_double_click) { + if(PANEL_INSPECTOR.panel && struct_has(PANEL_INSPECTOR.panel, "switchContent")) + PANEL_INSPECTOR.panel.switchContent(PANEL_INSPECTOR); + } + } else { + var hover_selected = false; + for( var i = 0; i < array_length(nodes_selecting); i++ ) { + if(nodes_selecting[i] != node_hovering) continue; + + hover_selected = true; + break; + } + if(!hover_selected) + nodes_selecting = [ node_hovering ]; + } + + if(WIDGET_CURRENT) WIDGET_CURRENT.deactivate(); + array_foreach(nodes_selecting, function(node) { bringNodeToFront(node); }); + } + } + #endregion + + if(mouse_press(mb_right, pFOCUS)) { #region + node_hover = node_hovering; + + if(value_focus) { + __junction_hovering = value_focus; + + var menu = [ menu_junc_color ]; + + if(value_focus.connect_type == JUNCTION_CONNECT.output) { + var sep = false; + + for( var i = 0, n = array_length(value_focus.value_to); i < n; i++ ) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _to = value_focus.value_to[i]; + array_push(menu, menuItem($"[{_to.node.display_name}] {_to.getName()}", function(data) { + data.params.juncTo.removeFrom(); + }, THEME.cross,,, { juncTo: _to })); + } + + for( var i = 0, n = array_length(value_focus.value_to_loop); i < n; i++ ) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _to = value_focus.value_to_loop[i]; + array_push(menu, menuItem($"[{_to.junc_in.node.display_name}] {_to.junc_in.getName()}", function(data) { + data.params.juncTo.destroy(); + }, _to.icon_24,,, { juncTo: _to })); + } + } else { + var sep = false; + + if(value_focus.value_from) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _jun = value_focus.value_from; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.removeFrom(); + }, THEME.cross)); + } + + if(value_focus.value_from_loop) { + if(!sep) { array_push(menu, -1); sep = true; } + + var _jun = value_focus.value_from_loop.junc_out; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.removeFromLoop(); + }, value_focus.value_from_loop.icon_24)); + } + } + + menuCall("graph_node_selected_menu",,, menu); + + } else if(node_hover && node_hover.draggable) { + var menu = []; + array_push(menu, menu_node_color, -1, menu_sent_to_preview, menu_send_to_window, menu_sent_to_inspector); + if(!DEMO) + array_push(menu, menu_send_export); + array_push(menu, -1, menu_toggle_preview, menu_toggle_render, menu_toggle_param); + + if(is_instanceof(node_hover, Node_Collection)) + array_push(menu, -1, menu_open_group, menu_open_group_tab, menu_group_ungroup); + + if(node_hover.group != noone) + array_push(menu, menu_group_tool); + + array_push(menu, -1, menu_node_delete_merge, menu_node_delete_cut, menu_node_duplicate, menu_node_copy); + if(array_empty(nodes_selecting)) array_push(menu, menu_node_copy_prop, menu_node_paste_prop); + + array_push(menu, -1, menu_node_transform, menu_node_canvas); + + if(array_empty(nodes_selecting) >= 2) + array_push(menu, -1, menu_nodes_align, menu_nodes_blend, menu_nodes_compose, menu_nodes_array, menu_nodes_group, menu_nodes_frame); + + menuCall("graph_node_selected_multiple_menu",,, menu ); + } else if(node_hover == noone) { + var menu = []; + + __junction_hovering = junction_hovering; + if(junction_hovering != noone) + array_push(menu, menu_junc_color, -1); + + array_push(menu, menuItem(__txt("Copy"), function() { doCopy(); }, THEME.copy, ["Graph", "Copy"]).setActive(array_length(nodes_selecting))); + array_push(menu, menuItem(__txt("Paste"), function() { doPaste(); }, THEME.paste, ["Graph", "Paste"]).setActive(clipboard_get_text() != "")); + + if(junction_hovering != noone) { + array_push(menu, -1); + + if(is_instanceof(junction_hovering, Node_Feedback_Inline)) { + var _jun = junction_hovering.junc_out; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.destroy(); + }, THEME.feedback)); + } else { + var _jun = junction_hovering.value_from; + array_push(menu, menuItem($"[{_jun.node.display_name}] {_jun.getName()}", function(data) { + __junction_hovering.removeFrom(); + }, THEME.cross)); + } + } + + var ctx = is_instanceof(frame_hovering, Node_Collection_Inline)? frame_hovering : getCurrentContext(); + var _diaAdd = callAddDialog(ctx); + + var _dia = menuCall("graph_node_selected_menu", o_dialog_add_node.dialog_x - ui(8), o_dialog_add_node.dialog_y + ui(4), menu, fa_right ); + _dia.passthrough = true; + setFocus(_diaAdd, "Dialog"); + } + } #endregion + + if(is_instanceof(frame_hovering, Node_Collection_Inline) && DOUBLE_CLICK && array_empty(nodes_selecting)) { #region + nodes_selecting = [ frame_hovering ]; + } #endregion + } + #endregion + printIf(log, $"Node selection time: {get_timer() - t}"); t = get_timer(); + + #region draw active + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _node = nodes_selecting[i]; + if(!_node) continue; + _node.drawActive(gr_x, gr_y, graph_s); + } + #endregion + printIf(log, $"Draw active: {get_timer() - t}"); t = get_timer(); + + #region draw connections + var aa = floor(min(8192 / w, 8192 / h, PREFERENCES.connection_line_aa)); + + connection_surface = surface_verify(connection_surface, w * aa, h * aa); + connection_surface_aa = surface_verify(connection_surface_aa, w, h); + surface_set_target(connection_surface); + DRAW_CLEAR + + var hov = noone; + var hoverable = !bool(node_dragging) && pHOVER; + var param = connection_param; + + param.active = hoverable; + param.setPos(gr_x, gr_y, graph_s, mx, my); + param.setBoundary(-64, -64, w + 64, h + 64); + param.setProp(ds_list_size(nodes_list), display_parameter.highlight); + param.setDraw(aa, bg_color); + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + param.cur_layer = i + 1; + + var _hov = nodes_list[| i].drawConnections(param); + if(_hov != noone && is_struct(_hov)) hov = _hov; + } + + if(value_dragging && connection_draw_mouse != noone) { + var _cmx = connection_draw_mouse[0]; + var _cmy = connection_draw_mouse[1]; + var _cmt = connection_draw_target; + + if(array_empty(value_draggings)) + value_dragging.drawConnectionMouse(param, _cmx, _cmy, _cmt); + else { + var _stIndex = array_find(value_draggings, value_dragging); + + for( var i = 0, n = array_length(value_draggings); i < n; i++ ) { + var _dmx = _cmx; + var _dmy = value_draggings[i].connect_type == JUNCTION_CONNECT.output? _cmy + (i - _stIndex) * 24 * graph_s : _cmy; + + value_draggings[i].drawConnectionMouse(param, _dmx, _dmy, _cmt); + } + } + } + + surface_reset_target(); + + gpu_set_texfilter(true); + surface_set_shader(connection_surface_aa, sh_downsample); + shader_set_f("down", aa); + shader_set_dim("dimension", connection_surface); + draw_surface(connection_surface, 0, 0); + surface_reset_shader(); + gpu_set_texfilter(false); + + BLEND_ALPHA_MULP + draw_surface(connection_surface_aa, 0, 0); + BLEND_NORMAL + + junction_hovering = node_hovering == noone? hov : noone; + value_focus = noone; + #endregion + printIf(log, $"Draw connection: {get_timer() - t}"); t = get_timer(); + + #region draw node + var t = get_timer(); + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].onDrawNodeBehind(gr_x, gr_y, mx, my, graph_s); + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + + if(is_instanceof(_node, Node_Frame)) continue; + try { + var val = _node.drawNode(gr_x, gr_y, mx, my, graph_s, display_parameter); + if(val) { + value_focus = val; + if(key_mod_press(SHIFT)) + TOOLTIP = [ val.getValue(), val.type ]; + } + } catch(e) { + log_warning("NODE DRAW", exception_print(e)); + } + } + + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].drawBadge(gr_x, gr_y, graph_s); + + if(PANEL_INSPECTOR && PANEL_INSPECTOR.prop_hover != noone) + value_focus = PANEL_INSPECTOR.prop_hover; + #endregion + printIf(log, $"Draw node: {get_timer() - t}"); t = get_timer(); + + #region dragging + if(mouse_press(mb_left)) + node_dragging = noone; + + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].groupCheck(gr_x, gr_y, graph_s, mx, my); + + if(node_dragging && !key_mod_press(ALT)) { + var nx = node_drag_sx + (mouse_graph_x - node_drag_mx); + var ny = node_drag_sy + (mouse_graph_y - node_drag_my); + + if(!key_mod_press(CTRL) && project.graphGrid.snap) { + nx = round(nx / project.graphGrid.size) * project.graphGrid.size; + ny = round(ny / project.graphGrid.size) * project.graphGrid.size; + } + + if(node_drag_ox == -1 || node_drag_oy == -1) { + node_drag_ox = nx; + node_drag_oy = ny; + } else if(nx != node_drag_ox || ny != node_drag_oy) { + var dx = nx - node_drag_ox; + var dy = ny - node_drag_oy; + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _node = nodes_selecting[i]; + var _nx = _node.x + dx; + var _ny = _node.y + dy; + + if(!key_mod_press(CTRL) && project.graphGrid.snap) { + _nx = round(_nx / project.graphGrid.size) * project.graphGrid.size; + _ny = round(_ny / project.graphGrid.size) * project.graphGrid.size; + } + + _node.move(_nx, _ny, graph_s); + } + + node_drag_ox = nx; + node_drag_oy = ny; + } + + if(mouse_release(mb_left) && (nx != node_drag_sx || ny != node_drag_sy)) { + var shfx = node_drag_sx - nx; + var shfy = node_drag_sy - ny; + + UNDO_HOLDING = false; + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _n = nodes_selecting[i]; + if(_n == noone) continue; + recordAction(ACTION_TYPE.var_modify, _n, [ _n.x + shfx, "x", "node x position" ]); + recordAction(ACTION_TYPE.var_modify, _n, [ _n.y + shfy, "y", "node y position" ]); + } + } + } + + if(mouse_release(mb_left)) + node_dragging = noone; + #endregion + printIf(log, $"Drag node time : {get_timer() - t}"); t = get_timer(); + + if(mouse_on_graph && pFOCUS) { #region + var _node = getFocusingNode(); + if(_node && _node.draggable && value_focus == noone) { + if(mouse_press(mb_left) && !key_mod_press(ALT)) { + node_dragging = _node; + node_drag_mx = mouse_graph_x; + node_drag_my = mouse_graph_y; + node_drag_sx = _node.x; + node_drag_sy = _node.y; + + node_drag_ox = -1; + node_drag_oy = -1; + } + } + + if(DOUBLE_CLICK && junction_hovering != noone) { + var _mx = round(mouse_graph_x / project.graphGrid.size) * project.graphGrid.size; + var _my = round(mouse_graph_y / project.graphGrid.size) * project.graphGrid.size; + + var _pin = nodeBuild("Node_Pin", _mx, _my); + _pin.inputs[| 0].setFrom(junction_hovering.value_from); + junction_hovering.setFrom(_pin.outputs[| 0]); + } + } #endregion + + #region draw selection frame + if(nodes_select_drag) { + if(point_distance(nodes_select_mx, nodes_select_my, mx, my) > 16) + nodes_select_drag = 2; + + if(nodes_select_drag == 2) { + draw_sprite_stretched_points_clamp(THEME.ui_selection, 0, nodes_select_mx, nodes_select_my, mx, my, COLORS._main_accent); + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + + if(!_node.selectable) continue; + if(is_instanceof(_node, Node_Frame) && !nodes_select_frame) continue; + + var _x = (_node.x + graph_x) * graph_s; + var _y = (_node.y + graph_y) * graph_s; + var _w = _node.w * graph_s; + var _h = _node.h * graph_s; + + var _sel = _w && _h && rectangle_in_rectangle(_x, _y, _x + _w, _y + _h, nodes_select_mx, nodes_select_my, mx, my); + + if(!array_exists(nodes_selecting, _node) && _sel) + array_push(nodes_selecting, _node); + if(array_exists(nodes_selecting, _node) && !_sel) + array_remove(nodes_selecting, _node); + } + } + + if(mouse_release(mb_left)) + nodes_select_drag = 0; + } + + if(nodes_junction_d != noone) { + var shx = nodes_junction_dx + (mx - nodes_select_mx) / graph_s; + var shy = nodes_junction_dy + (my - nodes_select_my) / graph_s; + + shx = value_snap(shx, key_mod_press(CTRL)? 1 : 4); + shy = value_snap(shy, key_mod_press(CTRL)? 1 : 4); + + nodes_junction_d.draw_line_shift_x = shx; + nodes_junction_d.draw_line_shift_y = shy; + + if(mouse_release(mb_left)) + nodes_junction_d = noone; + } + + if(mouse_on_graph && !node_bg_hovering && mouse_press(mb_left, pFOCUS) && !graph_dragging_key && !graph_zooming_key) { + if(is_instanceof(junction_hovering, NodeValue) && junction_hovering.draw_line_shift_hover) { + nodes_select_mx = mx; + nodes_select_my = my; + nodes_junction_d = junction_hovering; + nodes_junction_dx = junction_hovering.draw_line_shift_x; + nodes_junction_dy = junction_hovering.draw_line_shift_y; + } else if(array_empty(nodes_selecting) && !value_focus && !drag_locking) { + nodes_select_drag = 1; + nodes_select_frame = frame_hovering == noone; + + nodes_select_mx = mx; + nodes_select_my = my; + } + drag_locking = false; + } + #endregion + printIf(log, $"Draw selection frame : {get_timer() - t}"); t = get_timer(); + } #endregion + + function drawJunctionConnect() { #region + if(value_dragging) { + var xx = value_dragging.x; + var yy = value_dragging.y; + var _mx = mx; + var _my = my; + var target = noone; + + if(value_focus && value_focus != value_dragging && value_focus.connect_type != value_dragging.connect_type) + target = value_focus; + + if(key_mod_press(CTRL) && node_hovering != noone) { + if(value_dragging.connect_type == JUNCTION_CONNECT.input) { + target = node_hovering.getOutput(value_dragging); + if(target != noone) + node_hovering.active_draw_index = 1; + } else { + target = node_hovering.getInput(value_dragging); + if(target != noone) + node_hovering.active_draw_index = 1; + } + } + + var _mmx = target != noone? target.x : _mx; + var _mmy = target != noone? target.y : _my; + + connection_draw_mouse = [ _mmx, _mmy ]; + connection_draw_target = target; + + value_dragging.drawJunction(graph_s, value_dragging.x, value_dragging.y); + if(target) target.drawJunction(graph_s, target.x, target.y); + + if(mouse_release(mb_left)) { // CONNECT junction + var _connect = [ 0, noone, noone ]; + + if(PANEL_INSPECTOR && PANEL_INSPECTOR.attribute_hovering != noone) { + PANEL_INSPECTOR.attribute_hovering(value_dragging); + } else if(target != noone) { + var _addInput = false; + if(target.isLeaf() && target.connect_type == JUNCTION_CONNECT.input && target.node.auto_input) + _addInput = true; + + if(value_dragging.connect_type == JUNCTION_CONNECT.input) { + if(array_empty(value_draggings)) { + _connect = [ value_dragging.setFrom(target), value_dragging, target ]; + } else { + for( var i = 0, n = array_length(value_draggings); i < n; i++ ) + value_draggings[i].setFrom(target); + } + } else if(_addInput && !array_empty(value_draggings)) { + for( var i = 0, n = array_length(value_draggings); i < n; i++ ) + target.node.addInput(value_draggings[i]); + } else { + _connect = [ target.setFrom(value_dragging), target, value_dragging ]; + } + } else { + if(value_dragging.connect_type == JUNCTION_CONNECT.input) + value_dragging.removeFrom(); + value_dragging.node.triggerRender(); + + if(value_focus != value_dragging) { + var ctx = is_instanceof(frame_hovering, Node_Collection_Inline)? frame_hovering : getCurrentContext(); + with(dialogCall(o_dialog_add_node, mouse_mx + 8, mouse_my + 8, { context: ctx })) { + node_target_x = other.mouse_grid_x; + node_target_y = other.mouse_grid_y; + node_called = other.value_dragging; + + alarm[0] = 1; + } + } + } + + value_dragging = noone; + connection_draw_mouse = noone; + + if(_connect[0] == -9) { + if(_connect[1].value_from_loop != noone) + _connect[1].value_from_loop.destroy(); + + var menu = [ + menuItem("Feedback", function(data) { + var junc_in = data.params.junc_in; + var junc_out = data.params.junc_out; + + var feed = nodeBuild("Node_Feedback_Inline", 0, 0); + feed.attributes.junc_in = [ junc_in .node.node_id, junc_in .index ]; + feed.attributes.junc_out = [ junc_out.node.node_id, junc_out.index ]; + feed.scanJunc(); + + }, THEME.feedback_24,,, { junc_in : _connect[1], junc_out : _connect[2] }), + + menuItem("Loop", function(data) { + var junc_in = data.params.junc_in; + var junc_out = data.params.junc_out; + + var feed = nodeBuild("Node_Iterate_Inline", 0, 0); + feed.attributes.junc_in = [ junc_in .node.node_id, junc_in .index ]; + feed.attributes.junc_out = [ junc_out.node.node_id, junc_out.index ]; + feed.scanJunc(); + + }, THEME.loop_24,,, { junc_in : _connect[1], junc_out : _connect[2] }), + ]; + + menuCall(,,, menu); + } + } + } else if(value_focus && mouse_press(mb_left, pFOCUS) && !key_mod_press(ALT)) { + value_dragging = value_focus; + value_draggings = []; + + if(value_dragging.connect_type == JUNCTION_CONNECT.output) { + if(key_mod_press(CTRL)) { + var _to = value_dragging.getJunctionTo(); + + if(array_length(_to)) { + value_dragging = _to[0]; + value_draggings = array_create(array_length(_to)); + + for( var i = 0, n = array_length(_to); i < n; i++ ) { + value_draggings[i] = _to[i]; + _to[i].removeFrom(); + } + } + } else if(array_exists(nodes_selecting_jun, value_dragging.node)) { + var _jlist = ds_priority_create(); + + for( var i = 0, n = array_length(nodes_selecting_jun); i < n; i++ ) { + var _node = nodes_selecting_jun[i]; + + if(_node == value_focus.node) { + ds_priority_add(_jlist, value_focus, value_focus.y); + } else { + for( var j = 0, m = ds_list_size(_node.outputs); j < m; j++ ) { + var _junction = _node.outputs[| j]; + if(!_junction.visible) continue; + if(value_bit(_junction.type) & value_bit(value_dragging.type) == 0) continue; + + ds_priority_add(_jlist, _junction, _junction.y); + break; + } + } + } + + while(!ds_priority_empty(_jlist)) + array_push(value_draggings, ds_priority_delete_min(_jlist)); + + ds_priority_destroy(_jlist); + } + } else { + if(key_mod_press(CTRL) && value_dragging.value_from) { + var fr = value_dragging.value_from; + value_dragging.removeFrom(); + value_dragging = fr; + } + } + } + + nodes_selecting_jun = array_clone(nodes_selecting, 1); + + #region draw junction name + var gr_x = graph_x * graph_s; + var gr_y = graph_y * graph_s; + for(var i = 0; i < ds_list_size(nodes_list); i++) + nodes_list[| i].drawJunctionNames(gr_x, gr_y, mx, my, graph_s); + #endregion + + } #endregion + + function callAddDialog(ctx = getCurrentContext()) { #region + var _dia = dialogCall(o_dialog_add_node, mouse_mx + 8, mouse_my + 8, { context: ctx }); + + with(_dia) { + node_target_x = other.mouse_grid_x; + node_target_y = other.mouse_grid_y; + junction_hovering = other.junction_hovering; + + resetPosition(); + alarm[0] = 1; + } + + return _dia; + } #endregion + + function drawContext() { #region + draw_set_text(f_p0, fa_left, fa_center); + var xx = ui(16), tt, tw, th; + var bh = toolbar_height - ui(12); + var tbh = h - toolbar_height / 2; + + for(var i = -1; i < ds_list_size(node_context); i++) { + if(i == -1) { + tt = __txt("Global"); + } else { + var _cnt = node_context[| i]; + tt = _cnt.renamed? _cnt.display_name : _cnt.name; + } + + tw = string_width(tt); + th = string_height(tt); + + if(i < ds_list_size(node_context) - 1) { + if(buttonInstant(THEME.button_hide_fill, xx - ui(6), tbh - bh / 2, tw + ui(12), bh, [mx, my], pFOCUS, pHOVER) == 2) { + node_hover = noone; + nodes_selecting = []; + PANEL_PREVIEW.resetNodePreview(); + setContextFrame(true, node_context[| i + 1]); + var _nodeFocus = node_context[| i + 1]; + + if(i == -1) + resetContext(); + else { + for(var j = ds_list_size(node_context) - 1; j > i; j--) + ds_list_delete(node_context, j); + nodes_list = node_context[| i].getNodeList(); + } + + nodes_selecting = [ _nodeFocus ]; + var _l = ds_list_create_from_array(nodes_selecting) + toCenterNode(_l); + ds_list_destroy(_l); + break; + } + + draw_sprite_ui_uniform(THEME.arrow, 0, xx + tw + ui(16), tbh, 1, COLORS._main_icon); + } + + draw_set_color(COLORS._main_text); + draw_set_alpha(i < ds_list_size(node_context) - 1? 0.33 : 1); + draw_text(xx, tbh - 2, tt); + draw_set_alpha(1); + xx += tw; + xx += ui(32); + } + } #endregion + + function drawToolBar() { #region + toolbar_height = ui(40); + var ty = h - toolbar_height; + + if(pHOVER && point_in_rectangle(mx, my, 0, ty, w, h)) + mouse_on_graph = false; + + draw_sprite_stretched(THEME.toolbar, 0, 0, ty, w, h); + drawContext(); + + var tbx = w - toolbar_height / 2; + var tby = ty + toolbar_height / 2; + + for( var i = 0, n = array_length(toolbars); i < n; i++ ) { + var tb = toolbars[i]; + var tbSpr = tb[0]; + var tbInd = tb[1](); + var tbTooltip = tb[2](); + + var b = buttonInstant(THEME.button_hide, tbx - ui(14), tby - ui(14), ui(28), ui(28), [mx, my], pFOCUS, pHOVER, tbTooltip, tbSpr, tbInd); + if(b == 2) tb[3]( { x: x + tbx - ui(14), y: y + tby - ui(14) } ); + + tbx -= ui(32); + } + + draw_set_color(COLORS.panel_toolbar_separator); + draw_line_width(tbx + ui(12), tby - toolbar_height / 2 + ui(8), tbx + ui(12), tby + toolbar_height / 2 - ui(8), 2); + } #endregion + + function drawMinimap() { #region + if(!minimap_show) return; + var mx1 = w - ui(8); + var my1 = h - toolbar_height - ui(8); + var mx0 = mx1 - minimap_w; + var my0 = my1 - minimap_h; + + minimap_w = min(minimap_w, w - ui(16)); + minimap_h = min(minimap_h, h - ui(16) - toolbar_height); + + var mini_hover = false; + if(pHOVER && point_in_rectangle(mx, my, mx0, my0, mx1, my1)) { + mouse_on_graph = false; + mini_hover = true; + } + + var hover = mini_hover && !point_in_rectangle(mx, my, mx0, my0, mx0 + ui(16), my0 + ui(16)) && !minimap_dragging; + + if(!is_surface(minimap_surface) || surface_get_width_safe(minimap_surface) != minimap_w || surface_get_height_safe(minimap_surface) != minimap_h) { + minimap_surface = surface_create_valid(minimap_w, minimap_h); + } + + surface_set_target(minimap_surface); + draw_clear_alpha(COLORS.panel_bg_clear_inner, 0.75); + if(!ds_list_empty(nodes_list)) { + var minx = 99999; + var maxx = -99999; + var miny = 99999; + var maxy = -99999; + + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + minx = min(_node.x - 32, minx); + maxx = max(_node.x + _node.w + 32, maxx); + + miny = min(_node.y - 32, miny); + maxy = max(_node.y + _node.h + 32, maxy); + } + + var cx = (minx + maxx) / 2; + var cy = (miny + maxy) / 2; + var spw = maxx - minx; + var sph = maxy - miny; + var ss = min(minimap_w / spw, minimap_h / sph); + + draw_set_alpha(0.4); + for(var i = 0; i < ds_list_size(nodes_list); i++) { + var _node = nodes_list[| i]; + + var nx = minimap_w / 2 + (_node.x - cx) * ss; + var ny = minimap_h / 2 + (_node.y - cy) * ss; + var nw = _node.w * ss; + var nh = _node.h * ss; + + draw_set_color(_node.getColor()); + draw_roundrect_ext(nx, ny, nx + nw, ny + nh, THEME_VALUE.minimap_corner_radius, THEME_VALUE.minimap_corner_radius, false); + } + draw_set_alpha(1); + + var gx = minimap_w / 2 - (graph_x + cx) * ss; + var gy = minimap_h / 2 - (graph_y + cy) * ss; + var gw = w / graph_s * ss; + var gh = h / graph_s * ss; + + draw_set_color(COLORS.panel_graph_minimap_focus); + draw_rectangle(gx, gy, gx + gw, gy + gh, 1); + + if(minimap_panning) { + graph_x = -((mx - mx0 - gw / 2) - minimap_w / 2) / ss - cx; + graph_y = -((my - my0 - gh / 2) - minimap_h / 2) / ss - cy; + + graph_x = round(graph_x); + graph_y = round(graph_y); + + if(mouse_release(mb_left)) + minimap_panning = false; + } + + if(mouse_click(mb_left, hover)) + minimap_panning = true; + } + + surface_reset_target(); + + draw_surface_ext_safe(minimap_surface, mx0, my0, 1, 1, 0, c_white, 0.5 + 0.35 * hover); + draw_set_color(COLORS.panel_graph_minimap_outline); + draw_rectangle(mx0, my0, mx1 - 1, my1 - 1, true); + + if(minimap_dragging) { + mouse_on_graph = false; + var sw = minimap_drag_sx + minimap_drag_mx - mx; + var sh = minimap_drag_sy + minimap_drag_my - my; + + minimap_w = max(ui(64), sw); + minimap_h = max(ui(64), sh); + + if(mouse_release(mb_left)) + minimap_dragging = false; + } + + if(pHOVER && point_in_rectangle(mx, my, mx0, my0, mx0 + ui(16), my0 + ui(16))) { + draw_sprite_ui(THEME.node_resize, 0, mx0 + ui(2), my0 + ui(2), 0.5, 0.5, 180, c_white, 0.75); + if(mouse_press(mb_left, pFOCUS)) { + minimap_dragging = true; + minimap_drag_sx = minimap_w; + minimap_drag_sy = minimap_h; + minimap_drag_mx = mx; + minimap_drag_my = my; + } + } else + draw_sprite_ui(THEME.node_resize, 0, mx0 + ui(2), my0 + ui(2), 0.5, 0.5, 180, c_white, 0.3); + } #endregion + + function drawContextFrame() { #region + if(!context_framing) return; + context_frame_progress = lerp_float(context_frame_progress, 1, 5); + if(context_frame_progress == 1) + context_framing = false; + + var _fr_x0 = 0, _fr_y0 = 0; + var _fr_x1 = w, _fr_y1 = h; + + var _to_x0 = context_frame_sx; + var _to_y0 = context_frame_sy; + var _to_x1 = context_frame_ex; + var _to_y1 = context_frame_ey; + + var prog = context_frame_direct? context_frame_progress : 1 - context_frame_progress; + var frm_x0 = lerp(_fr_x0, _to_x0, prog); + var frm_y0 = lerp(_fr_y0, _to_y0, prog); + var frm_x1 = lerp(_fr_x1, _to_x1, prog); + var frm_y1 = lerp(_fr_y1, _to_y1, prog); + + draw_set_color(COLORS._main_accent); + draw_set_alpha(0.5); + draw_roundrect_ext(frm_x0, frm_y0, frm_x1, frm_y1, THEME_VALUE.panel_corner_radius, THEME_VALUE.panel_corner_radius, true); + draw_set_alpha(1); + } #endregion + + function resetContext() { #region + ds_list_clear(node_context); + nodes_list = project.nodes; + toCenterNode(); + } #endregion + + function addContext(node) { #region + var _node = node.getNodeBase(); + setContextFrame(false, _node); + + nodes_list = _node.nodes; + ds_list_add(node_context, _node); + + node_dragging = noone; + nodes_selecting = []; + selection_block = 1; + + toCenterNode(); + } #endregion + + function setContextFrame(dirr, node) { #region + context_framing = true; + context_frame_direct = dirr; + context_frame_progress = 0; + context_frame_sx = w / 2 - 8; + context_frame_sy = h / 2 - 8; + context_frame_ex = context_frame_sx + 16; + context_frame_ey = context_frame_sy + 16; + } #endregion + + function setTitle() { #region + title = title_raw + (project.modified? "*" : ""); + } #endregion + + function drawContent(panel) { #region >>>>>>>>>>>>>>>>>>>> MAIN DRAW <<<<<<<<<<<<<<<<<<<< + if(!project.active) return; + + if(project.path == "") title_raw = "New project"; + else title_raw = filename_name_only(project.path); + dragGraph(); + + var context = getCurrentContext(); + if(context != noone) title_raw += " > " + (context.renamed? context.display_name : context.name); + + bg_color = context == noone? COLORS.panel_bg_clear : merge_color(COLORS.panel_bg_clear, context.getColor(), 0.05); + draw_clear(bg_color); + node_bg_hovering = drawBasePreview(); + drawGrid(); + + draw_set_text(f_p0, fa_right, fa_top, COLORS._main_text_sub); + draw_text(w - ui(8), ui(8), $"x{graph_s_to}"); + + drawNodes(); + drawJunctionConnect(); + drawContextFrame(); + + mouse_on_graph = true; + drawToolBar(); + drawMinimap(); + + if(pFOCUS) array_foreach(nodes_selecting, function(node) { node.focusStep(); }); + + if(UPDATE == RENDER_TYPE.full) + draw_text(w - ui(8), ui(28), __txtx("panel_graph_rendering", "Rendering") + "..."); + else if(UPDATE == RENDER_TYPE.partial) + draw_text(w - ui(8), ui(28), __txtx("panel_graph_rendering_partial", "Rendering partial") + "..."); + + if(DRAGGING && pHOVER) { #region file dropping + if(node_hovering && node_hovering.droppable(DRAGGING)) { + node_hovering.draw_droppable = true; + if(mouse_release(mb_left)) + node_hovering.onDrop(DRAGGING); + } else { + draw_sprite_stretched_ext(THEME.ui_panel_active, 0, 2, 2, w - 4, h - 4, COLORS._main_value_positive, 1); + if(mouse_release(mb_left)) + checkDropItem(); + } + } #endregion + + graph_dragging_key = false; + graph_zooming_key = false; + + if(LIVE_UPDATE) { + draw_set_text(f_p0b, fa_right, fa_bottom, COLORS._main_value_negative); + draw_text(w - 8, h - toolbar_height, "Live Update"); + } + } #endregion + + #region ++++++++++++++++ node manipulation ++++++++++++++++ + function doTransform() { #region + for( var i = 0; i < array_length(nodes_selecting); i++ ) { + var node = nodes_selecting[i]; + if(ds_list_empty(node.outputs)) continue; + + var _o = node.outputs[| 0]; + if(_o.type == VALUE_TYPE.surface || _o.type == VALUE_TYPE.dynaSurface) { + var tr = nodeBuild("Node_Transform", node.x + node.w + 64, node.y); + tr.inputs[| 0].setFrom(_o); + } + } + } #endregion + + function doDuplicate() { #region + if(array_empty(nodes_selecting)) return; + + var _map = {}; + var _pmap = {}; + var _node = []; + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _n = nodes_selecting[i]; + + if(_n.inline_parent_object != "") + _pmap[$ _n.inline_context.node_id] = _n.inline_parent_object; + + SAVE_NODE(_node, _n,,,, getCurrentContext()); + } + + _map.nodes = _node; + + ds_map_clear(APPEND_MAP); + ds_list_clear(APPEND_LIST); + + CLONING = true; + var _pmap_keys = variable_struct_get_names(_pmap); + for( var i = 0, n = array_length(_pmap_keys); i < n; i++ ) { + var _pkey = _pmap_keys[i]; + var _original = PROJECT.nodeMap[? _pkey]; + var _nodeS = _pmap[$ _pkey]; + + CLONING_GROUP = _original; + var _newGroup = nodeBuild(_nodeS, _original.x, _original.y); + APPEND_MAP[? _pkey] = _newGroup; + } + + APPEND_LIST = __APPEND_MAP(_map,, APPEND_LIST); + recordAction(ACTION_TYPE.collection_loaded, array_create_from_list(APPEND_LIST)); + CLONING = false; + + if(ds_list_size(APPEND_LIST) == 0) return; + + for(var i = 0; i < array_length(nodes_selecting); i++) { + var _orignal = nodes_selecting[i]; + if(!_orignal.clonable) continue; + + var _cloned = ds_map_try_get(APPEND_MAP, _orignal.node_id, ""); + var _inline_ctx = _orignal.inline_context; + + if(_inline_ctx != noone && _cloned != "") { + _inline_ctx = ds_map_try_get(APPEND_MAP, _inline_ctx.node_id, _inline_ctx); + _inline_ctx.addNode(PROJECT.nodeMap[? _cloned]); + } + } + + var x0 = 99999999; + var y0 = 99999999; + for(var i = 0; i < ds_list_size(APPEND_LIST); i++) { + var _node = APPEND_LIST[| i]; + + x0 = min(x0, _node.x); + y0 = min(y0, _node.y); + } + + node_dragging = APPEND_LIST[| 0]; + node_drag_mx = x0; node_drag_my = y0; + node_drag_sx = x0; node_drag_sy = y0; + node_drag_ox = x0; node_drag_oy = y0; + + nodes_selecting = array_create_from_list(APPEND_LIST); + } #endregion + + function doInstance() { #region + var node = getFocusingNode(); + if(node == noone) return; + + if(node.instanceBase == noone) { + node.isInstancer = true; + + CLONING = true; + var _type = instanceof(node); + var _node = nodeBuild(_type, x, y); + CLONING = false; + + _node.setInstance(node); + } + + var _nodeNew = _node.clone(); + + node_dragging = _nodeNew; + node_drag_mx = _nodeNew.x; node_drag_my = _nodeNew.y; + node_drag_sx = _nodeNew.x; node_drag_sy = _nodeNew.y; + node_drag_ox = _nodeNew.x; node_drag_oy = _nodeNew.y; + } #endregion + + function doCopy() { #region + if(array_empty(nodes_selecting)) return; + clipboard_set_text(""); + + var _map = {}; + _map.nodes = []; + for(var i = 0; i < array_length(nodes_selecting); i++) + SAVE_NODE(_map.nodes, nodes_selecting[i],,,, getCurrentContext()); + + clipboard_set_text(json_stringify_minify(_map)); + } #endregion + + function doPaste() { #region + var txt = clipboard_get_text(); + var _map = json_try_parse(txt, noone); + + if(txt == "") return; + + if(is_struct(_map)) { + ds_map_clear(APPEND_MAP); + APPENDING = true; + CLONING = true; + var _app = __APPEND_MAP(_map); + APPENDING = false; + CLONING = false; + + if(_app == noone) + return; + + if(ds_list_size(_app) == 0) { + ds_list_destroy(_app); + return; + } + + var x0 = 99999999; + var y0 = 99999999; + for(var i = 0; i < ds_list_size(_app); i++) { + var _node = _app[| i]; + + x0 = min(x0, _node.x); + y0 = min(y0, _node.y); + } + + node_dragging = _app[| 0]; + node_drag_mx = x0; node_drag_my = y0; + node_drag_sx = x0; node_drag_sy = y0; + node_drag_ox = x0; node_drag_oy = y0; + + nodes_selecting = array_create_from_list(_app); + return; + } + + if(filename_ext(txt) == ".pxc") + APPEND(txt); + else if(filename_ext(txt) == ".pxcc") + APPEND(txt); + else if(filename_ext(txt) == ".png") { + if(file_exists_empty(txt)) { + Node_create_Image_path(0, 0, txt); + return; + } + + var path = TEMPDIR + "url_pasted_" + string(irandom_range(100000, 999999)) + ".png"; + var img = http_get_file(txt, path); + CLONING = true; + var node = Node_create_Image(0, 0); + CLONING = false; + var args = [node, path]; + + global.FILE_LOAD_ASYNC[? img] = [ function(args) { + args[0].inputs[| 0].setValue(args[1]); + args[0].doUpdate(); + }, args]; + } + } #endregion + + function doBlend() { #region + if(array_length(nodes_selecting) != 2) return; + + var _n0 = nodes_selecting[0].y < nodes_selecting[1].y? nodes_selecting[0] : nodes_selecting[1]; + var _n1 = nodes_selecting[0].y < nodes_selecting[1].y? nodes_selecting[1] : nodes_selecting[0]; + + if(_n0.outputs[| 0].type != VALUE_TYPE.surface || _n1.outputs[| 0].type != VALUE_TYPE.surface) return; + + var cx = max(_n0.x, _n1.x) + 160; + var cy = round((_n0.y + _n1.y) / 2 / 32) * 32; + + var _blend = new Node_Blend(cx, cy, getCurrentContext()); + _blend.inputs[| 0].setFrom(_n0.outputs[| 0]); + _blend.inputs[| 1].setFrom(_n1.outputs[| 0]); + + nodes_selecting = []; + } #endregion + + function doCompose() { #region + if(array_empty(nodes_selecting)) return; + + var cx = nodes_selecting[0].x; + var cy = 0; + var pr = ds_priority_create(); + var amo = array_length(nodes_selecting); + var len = 0; + + for(var i = 0; i < amo; i++) { + var _node = nodes_selecting[i]; + if(ds_list_size(_node.outputs) == 0) continue; + if(_node.outputs[| 0].type != VALUE_TYPE.surface) continue; + + cx = max(cx, _node.x); + cy += _node.y; + + ds_priority_add(pr, _node, _node.y); + len++; + } + + cx = cx + 160; + cy = round(cy / len / 32) * 32; + + var _compose = nodeBuild("Node_Composite", cx, cy); + + repeat(len) { + var _node = ds_priority_delete_min(pr); + _compose.addInput(_node.outputs[| 0]); + } + + nodes_selecting = []; + ds_priority_destroy(pr); + } #endregion + + function doArray() { #region + if(array_empty(nodes_selecting)) return; + + var cx = nodes_selecting[0].x; + var cy = 0; + var pr = ds_priority_create(); + var amo = array_length(nodes_selecting); + var len = 0; + + for(var i = 0; i < amo; i++) { + var _node = nodes_selecting[i]; + if(ds_list_size(_node.outputs) == 0) continue; + + cx = max(cx, _node.x); + cy += _node.y; + + ds_priority_add(pr, _node, _node.y); + len++; + } + + cx = cx + 160; + cy = round(cy / len / 32) * 32; + + var _array = nodeBuild("Node_Array", cx, cy); + + repeat(len) { + var _node = ds_priority_delete_min(pr); + _array.addInput(_node.outputs[| 0]); + } + + nodes_selecting = []; + ds_priority_destroy(pr); + } #endregion + + function doGroup() { #region + if(array_empty(nodes_selecting)) return; + groupNodes(nodes_selecting); + } #endregion + + function doUngroup() { #region + var _node = getFocusingNode(); + if(_node == noone) return; + if(!is_instanceof(_node, Node_Collection) || !_node.ungroupable) return; + + upgroupNode(_node); + } #endregion + + function doFrame() { #region + var x0 = 999999, y0 = 999999, x1 = -999999, y1 = -999999; + + for( var i = 0; i < array_length(nodes_selecting); i++ ) { + var _node = nodes_selecting[i]; + x0 = min(x0, _node.x); + y0 = min(y0, _node.y); + x1 = max(x1, _node.x + _node.w); + y1 = max(y1, _node.y + _node.h); + } + + x0 -= 64; + y0 -= 64; + x1 += 64; + y1 += 64; + + var f = new Node_Frame(x0, y0, getCurrentContext()); + f.inputs[| 0].setValue([x1 - x0, y1 - y0]); + } #endregion + + function doDelete(_merge = false) { #region + __temp_merge = _merge; + array_foreach(nodes_selecting, function(node) { if(node.manual_deletable) node.destroy(__temp_merge); }); + nodes_selecting = []; + } #endregion + + node_prop_clipboard = noone; + function doCopyProp() { #region + if(node_hover == noone) return; + node_prop_clipboard = node_hover; + } #endregion + + function doPasteProp() { #region + if(node_hover == noone) return; + if(node_prop_clipboard == noone) return; + if(!node_prop_clipboard.active) return; + + if(instanceof(node_prop_clipboard) != instanceof(node_hover)) return; + + var _vals = []; + for( var i = 0, n = ds_list_size(node_prop_clipboard.inputs); i < n; i++ ) { + var _inp = node_prop_clipboard.inputs[| i]; + _vals[i] = _inp.serialize(); + } + + for( var i = 0, n = ds_list_size(node_hover.inputs); i < n; i++ ) { + var _inp = node_hover.inputs[| i]; + if(_inp.value_from != noone) continue; + + _inp.applyDeserialize(_vals[i]); + } + + node_hover.clearInputCache(); + RENDER_PARTIAL + } #endregion + #endregion + + function dropFile(path) { #region + if(node_hovering && is_callable(node_hovering.on_drop_file)) + return node_hovering.on_drop_file(path); + return false; + } #endregion + + static checkDropItem = function() { #region + var node = noone; + + switch(DRAGGING.type) { + case "Color": + node = nodeBuild("Node_Color", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Palette": + node = nodeBuild("Node_Palette", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Gradient": + node = nodeBuild("Node_Gradient_Out", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Number": + if(is_array(DRAGGING.data) && array_length(DRAGGING.data) <= 4) { + switch(array_length(DRAGGING.data)) { + case 2 : node = nodeBuild("Node_Vector2", mouse_grid_x, mouse_grid_y, getCurrentContext()); break; + case 3 : node = nodeBuild("Node_Vector3", mouse_grid_x, mouse_grid_y, getCurrentContext()); break; + case 4 : node = nodeBuild("Node_Vector4", mouse_grid_x, mouse_grid_y, getCurrentContext()); break; + } + + for( var i = 0, n = array_length(DRAGGING.data); i < n; i++ ) + node.inputs[| i].setValue(DRAGGING.data[i]); + } else { + node = nodeBuild("Node_Number", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + } + break; + + case "Bool": + node = nodeBuild("Node_Boolean", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Text": + node = nodeBuild("Node_String", mouse_grid_x, mouse_grid_y, getCurrentContext()); + node.inputs[| 0].setValue(DRAGGING.data); + break; + + case "Path": + node = nodeBuild("Node_Path", mouse_grid_x, mouse_grid_y, getCurrentContext()); + break; + + case "Struct": + node = nodeBuild("Node_Struct", mouse_grid_x, mouse_grid_y, getCurrentContext()); + break; + + case "Asset": + var app = Node_create_Image_path(mouse_grid_x, mouse_grid_y, DRAGGING.data.path); + break; + + case "Collection": + var path = DRAGGING.data.path; + nodes_selecting = []; + + var app = APPEND(DRAGGING.data.path, getCurrentContext()); + + if(!is_struct(app) && ds_exists(app, ds_type_list)) { + var cx = 0; + var cy = 0; + + for( var i = 0; i < ds_list_size(app); i++ ) { + cx += app[| i].x; + cy += app[| i].y; + } + + cx /= ds_list_size(app); + cy /= ds_list_size(app); + + for( var i = 0; i < ds_list_size(app); i++ ) { + app[| i].x = app[| i].x - cx + mouse_grid_x; + app[| i].y = app[| i].y - cy + mouse_grid_y; + } + + ds_list_destroy(app); + } else { + app.x = mouse_grid_x; + app.y = mouse_grid_y; + } + break; + + case "Project": + run_in(1, function(path) { LOAD_PATH(path); }, [ DRAGGING.data.path ]); + break; + + } + + if(!key_mod_press(SHIFT) && node && struct_has(DRAGGING, "from") && DRAGGING.from.isLeaf()) { + for( var i = 0; i < ds_list_size(node.outputs); i++ ) + if(DRAGGING.from.setFrom(node.outputs[| i])) break; + } + } #endregion + + static bringNodeToFront = function(node) { #region + if(!ds_list_exist(nodes_list, node)) return; + + ds_list_remove(nodes_list, node); + ds_list_add(nodes_list, node); + } #endregion + + static onFullScreen = function() { run_in(1, fullView); } + + function close() { #region + var panels = findPanels("Panel_Graph"); + for( var i = 0, n = array_length(panels); i < n; i++ ) { + if(panels[i] == self) continue; + if(panels[i].project == project) { + panel.remove(self); + return; + } + } + + if(!project.modified || project.readonly) { + closeProject(project); + return; + } + + var dia = dialogCall(o_dialog_save); + dia.project = project; + } #endregion +} \ No newline at end of file diff --git a/scripts/node_pin/node_pin.gml b/scripts/node_pin/node_pin.gml index 3e5206b29..78c8c4934 100644 --- a/scripts/node_pin/node_pin.gml +++ b/scripts/node_pin/node_pin.gml @@ -56,34 +56,32 @@ function Node_Pin(_x, _y, _group = noone) : Node(_x, _y, _group) constructor { static drawJunctionNames = function(_x, _y, _mx, _my, _s) {} static drawJunctions = function(_x, _y, _mx, _my, _s) { #region - isHovering = false; - var hover = noone; + + var _dval = PANEL_GRAPH.value_dragging; + var hover = _dval == noone || _dval.connect_type == JUNCTION_CONNECT.input? outputs[| 0] : inputs[| 0]; var xx = x * _s + _x; var yy = y * _s + _y; - var hov = PANEL_GRAPH.value_dragging; + isHovering = point_in_circle(_mx, _my, xx, yy, _s * 24); - if(hov == noone && point_in_circle(_mx, _my, xx, yy, _s * 24)) { - isHovering = true; - hover_scale_to = 1; - } + hover.drawJunction(_s, _mx, _my); - if(outputs[| 0].drawJunction(_s, _mx, _my)) - hover = outputs[| 0]; + if(!isHovering) return noone; + hover_scale_to = 1; return hover; } #endregion static drawNode = function(_x, _y, _mx, _my, _s) { #region - if(group != PANEL_GRAPH.getCurrentContext()) return; + // if(group != PANEL_GRAPH.getCurrentContext()) return; var xx = x * _s + _x; var yy = y * _s + _y; hover_alpha = 0.5; if(active_draw_index > -1) { - hover_alpha = 1; - hover_scale_to = 1; - active_draw_index = -1; + hover_alpha = 1; + hover_scale_to = 1; + active_draw_index = -1; } if(hover_scale > 0) { diff --git a/scripts/panel_graph/panel_graph.gml b/scripts/panel_graph/panel_graph.gml index 8b8261318..2afb428f0 100644 --- a/scripts/panel_graph/panel_graph.gml +++ b/scripts/panel_graph/panel_graph.gml @@ -157,7 +157,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { #endregion #region ---- position ---- - scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.5, 0.65, 0.8, 1, 1.2, 1.35, 1.5, 2.0]; + scale = [ 0.01, 0.02, 0.05, 0.10, 0.15, 0.20, 0.25, 0.33, 0.50, 0.65, 0.80, 1, 1.2, 1.35, 1.5, 2.0]; graph_s = 1; graph_s_to = graph_s; @@ -1182,7 +1182,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { draw_surface(connection_surface_aa, 0, 0); BLEND_NORMAL - junction_hovering = (node_hovering == noone && !is_struct(node_hovering))? hov : noone; + junction_hovering = node_hovering == noone? hov : noone; value_focus = noone; #endregion printIf(log, $"Draw connection: {get_timer() - t}"); t = get_timer(); @@ -1200,8 +1200,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { var val = _node.drawNode(gr_x, gr_y, mx, my, graph_s, display_parameter); if(val) { value_focus = val; - if(key_mod_press(SHIFT)) - TOOLTIP = [ val.getValue(), val.type ]; + if(key_mod_press(SHIFT)) TOOLTIP = [ val.getValue(), val.type ]; } } catch(e) { log_warning("NODE DRAW", exception_print(e));