From 94853648c731a86e0455d57d04aa2130d0dae543 Mon Sep 17 00:00:00 2001 From: Tanasart Date: Wed, 3 Jul 2024 16:34:05 +0700 Subject: [PATCH] - [Graph Panel] Add node alignment options to toolbar. --- objects/o_dialog_splash/Create_0.gml | 10 +- .../gradients_function/gradients_function.gml | 2 +- .../node_align_functions.gml | 72 ++++++++- scripts/node_data/node_data.gml | 9 +- scripts/panel_graph/panel_graph.gml | 153 ++++++++++++------ scripts/shader_functions/shader_functions.gml | 8 + scripts/textBox/textBox.gml | 24 +-- shaders/sh_gradient/sh_gradient.fsh | 29 ++-- 8 files changed, 219 insertions(+), 88 deletions(-) diff --git a/objects/o_dialog_splash/Create_0.gml b/objects/o_dialog_splash/Create_0.gml index 61952349d..46f5fef84 100644 --- a/objects/o_dialog_splash/Create_0.gml +++ b/objects/o_dialog_splash/Create_0.gml @@ -161,7 +161,7 @@ event_inherited(); draw_text(mtx + ui(8), mty + mth / 2, tg); - mtx += mtw + ui(8); + mtx += mtw + ui(4); } hh += mth + ui(8); @@ -295,7 +295,7 @@ event_inherited(); name_height = max(name_height, string_height_ext(_name, -1, grid_width) + ui(8)); draw_text_ext_add(tx, ty - ui(2), _name, -1, grid_width); - if(++_cur_col >= col || i == node_count - 1) { + if(++_cur_col >= col) { if(name_height) { var hght = grid_heigh + name_height + grid_line; hh += hght; @@ -308,6 +308,12 @@ event_inherited(); } + if(name_height) { + var hght = grid_heigh + name_height + grid_line; + hh += hght; + yy += hght; + } + if(_group_label) { var len = array_length(group_labels); if(len) { diff --git a/scripts/gradients_function/gradients_function.gml b/scripts/gradients_function/gradients_function.gml index 22d7a8088..7bbe33e5f 100644 --- a/scripts/gradients_function/gradients_function.gml +++ b/scripts/gradients_function/gradients_function.gml @@ -239,7 +239,7 @@ function gradientObject(color = c_black) constructor { #region var _grad_time = _grad[1]; shader_set_i("gradient_blend", type); - shader_set_f("gradient_color", _grad_color); + shader_set_f_array("gradient_color", _grad_color, GRADIENT_LIMIT * 4); shader_set_f("gradient_time", _grad_time); shader_set_i("gradient_keys", array_length(keys)); } #endregion diff --git a/scripts/node_align_functions/node_align_functions.gml b/scripts/node_align_functions/node_align_functions.gml index 3bf1e791b..20a47562c 100644 --- a/scripts/node_align_functions/node_align_functions.gml +++ b/scripts/node_align_functions/node_align_functions.gml @@ -108,4 +108,74 @@ function node_vdistribute(nodeList) { } ds_priority_destroy(nodes); -} \ No newline at end of file +} + +function node_hdistribute_dist(nodeList, anchor, distance = 0) { + var amo = array_length(nodeList); + var nodes = ds_priority_create(); + + var x0 = 999999; + var x1 = -999999; + for( var i = 0; i < amo; i++ ) { + var _x = nodeList[i].x + nodeList[i].w / 2; + x0 = min(x0, _x); + x1 = max(x1, _x); + + ds_priority_add(nodes, nodeList[i], _x); + } + + var ar = array_create(ds_priority_size(nodes)); + + for( var i = 0; i < amo; i++ ) + ar[i] = ds_priority_delete_min(nodes); + ds_priority_destroy(nodes); + + var an_ind = array_find(ar, anchor); + var an_ind_x = anchor.x + anchor.w + distance; + + for (var i = an_ind + 1, n = array_length(ar); i < n; i++) { + ar[i].x = an_ind_x; + an_ind_x += ar[i].w + distance; + } + + var an_ind_x = anchor.x - distance; + for (var i = an_ind - 1; i >= 0; i--) { + ar[i].x = an_ind_x - ar[i].w; + an_ind_x -= ar[i].w + distance; + } +} + +function node_vdistribute_dist(nodeList, anchor, distance = 0) { + var amo = array_length(nodeList); + var nodes = ds_priority_create(); + + var y0 = 999999; + var y1 = -999999; + for( var i = 0; i < amo; i++ ) { + var _y = nodeList[i].y + nodeList[i].h / 2; + y0 = min(y0, _y); + y1 = max(y1, _y); + + ds_priority_add(nodes, nodeList[i], _y); + } + + var ar = array_create(ds_priority_size(nodes)); + + for( var i = 0; i < amo; i++ ) + ar[i] = ds_priority_delete_min(nodes); + ds_priority_destroy(nodes); + + var an_ind = array_find(ar, anchor); + var an_ind_y = anchor.y + anchor.h + distance; + + for (var i = an_ind + 1, n = array_length(ar); i < n; i++) { + ar[i].y = an_ind_y; + an_ind_y += ar[i].h + distance; + } + + var an_ind_y = anchor.y - distance; + for (var i = an_ind - 1; i >= 0; i--) { + ar[i].y = an_ind_y - ar[i].h; + an_ind_y -= ar[i].h + distance; + } +} diff --git a/scripts/node_data/node_data.gml b/scripts/node_data/node_data.gml index 4eb5f2f78..78d3181cf 100644 --- a/scripts/node_data/node_data.gml +++ b/scripts/node_data/node_data.gml @@ -118,7 +118,8 @@ function Node(_x, _y, _group = noone) : __Node_Base(_x, _y) constructor { badgePreview = 0; badgeInspect = 0; - active_draw_index = -1; + active_draw_index = -1; + active_draw_anchor = false; draw_droppable = false; @@ -1691,7 +1692,11 @@ function Node(_x, _y, _group = noone) : __Node_Base(_x, _y) constructor { if(active_draw_index > -1) { draw_sprite_stretched_ext(bg_sel_spr, 0, xx, yy, round(w * _s), round(h * _s), active_draw_index > 1? COLORS.node_border_file_drop : COLORS._main_accent, 1); - active_draw_index = -1; + + if(active_draw_anchor) draw_sprite_stretched_add(bg_sel_spr, 0, xx, yy, round(w * _s), round(h * _s), COLORS._main_accent, 0.5); + + active_draw_anchor = false; + active_draw_index = -1; } if(draw_droppable) { diff --git a/scripts/panel_graph/panel_graph.gml b/scripts/panel_graph/panel_graph.gml index 29df06fd1..7e16d908c 100644 --- a/scripts/panel_graph/panel_graph.gml +++ b/scripts/panel_graph/panel_graph.gml @@ -248,6 +248,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { selection_block = 0; nodes_selecting = []; nodes_selecting_jun = []; + nodes_select_anchor = noone; nodes_select_drag = 0; nodes_select_frame = 0; nodes_select_mx = 0; @@ -390,50 +391,64 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { #region ++++ toolbars ++++ tooltip_center = new tooltipHotkey(__txtx("panel_graph_center_to_nodes", "Center to nodes"), "Graph", "Focus content"); - toolbars = [ + toolbars_general = [ [ 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)); } + function() /*=>*/ {return 0}, function() /*=>*/ {return __txtx("panel_graph_export_image", "Export graph as image")}, + function(param) /*=>*/ { dialogPanelCall(new Panel_Graph_Export_Image(self)); } ], [ THEME.icon_center_canvas, - function() { return 0; }, - function() { return tooltip_center; }, - function() { toCenterNode(); } + function() /*=>*/ {return 0}, function() /*=>*/ {return tooltip_center}, + function(param) /*=>*/ { 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; } + function() /*=>*/ {return minimap_show}, function() /*=>*/ {return minimap_show? __txtx("panel_graph_minimap_enabled", "Minimap enabled") : __txtx("panel_graph_minimap_disabled", "Minimap disabled")}, + function(param) /*=>*/ { 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 }); - } + 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 }); - } + 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(self, display_parameter), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); - } + function() /*=>*/ {return 0}, function() /*=>*/ {return __txtx("graph_visibility_title", "Visibility settings")}, + function(param) /*=>*/ { dialogPanelCall(new Panel_Graph_View_Setting(self, display_parameter), param.x, param.y, { anchor: ANCHOR.bottom | ANCHOR.left }); } ], ]; + + toolbars_halign = [ + [ THEME.object_halign, function() /*=>*/ {return 2}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_halign(nodes_selecting, fa_right); } ], + [ THEME.object_halign, function() /*=>*/ {return 1}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_halign(nodes_selecting, fa_center); } ], + [ THEME.object_halign, function() /*=>*/ {return 0}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_halign(nodes_selecting, fa_left); } ], + ]; + + toolbars_valign = [ + [ THEME.object_valign, function() /*=>*/ {return 2}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_valign(nodes_selecting, fa_top); } ], + [ THEME.object_valign, function() /*=>*/ {return 1}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_valign(nodes_selecting, fa_middle); } ], + [ THEME.object_valign, function() /*=>*/ {return 0}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_valign(nodes_selecting, fa_bottom); } ], + ]; + + toolbars_distrib = [ + [ THEME.obj_distribute_h, function() /*=>*/ {return 0}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_hdistribute(nodes_selecting); } ], + [ THEME.obj_distribute_v, function() /*=>*/ {return 0}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_vdistribute(nodes_selecting); } ], + ]; + + distribution_spacing = 0; + toolbars_distrib_space = [ + [ THEME.obj_distribute_h, function() /*=>*/ {return 0}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_hdistribute_dist(nodes_selecting, nodes_select_anchor, distribution_spacing); } ], + [ THEME.obj_distribute_v, function() /*=>*/ {return 0}, function() /*=>*/ {return ""}, function(param) /*=>*/ { node_vdistribute_dist(nodes_selecting, nodes_select_anchor, distribution_spacing); } ], + [ new textBox(TEXTBOX_INPUT.number, function(val) { distribution_spacing = value_snap(val, 4); } ).setSlidable(1).setPadding(4), function() /*=>*/ {return distribution_spacing} ], + ]; + + toolbars = [ toolbars_general ]; #endregion //// =========== Get Set =========== @@ -1080,6 +1095,8 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { #region ++++++++++++ interaction ++++++++++++ if(mouse_on_graph && pHOVER) { + if(mouse_press(mb_left, _focus)) nodes_select_anchor = noone; + #region select if(NODE_DROPPER_TARGET != noone && node_hovering) { node_hovering.draw_droppable = true; @@ -1142,6 +1159,8 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { } if(!hover_selected) nodes_selecting = [ node_hovering ]; + + nodes_select_anchor = nodes_select_anchor == node_hovering? noone : node_hovering; } if(WIDGET_CURRENT) WIDGET_CURRENT.deactivate(); @@ -1283,6 +1302,8 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { if(!_node) continue; _node.drawActive(gr_x, gr_y, graph_s); } + + if(nodes_select_anchor) nodes_select_anchor.active_draw_anchor = true; #endregion printIf(log, $"Draw active: {get_timer() - t}"); t = get_timer(); @@ -1671,8 +1692,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { else if(!key_mod_press(CTRL) && node_hovering != noone) { if(value_dragging.connect_type == JUNCTION_CONNECT.input) { target = node_hovering.getOutput(my, value_dragging); - if(target != noone) - node_hovering.active_draw_index = 1; + if(target != noone) node_hovering.active_draw_index = 1; } else { target = node_hovering.getInput(my, value_dragging, 0); @@ -1798,7 +1818,7 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { function drawContext() { #region draw_set_text(f_p0, fa_left, fa_center); - var xx = ui(16), tt, tw, th; + var xx = ui(16), tt, tw, th; var bh = toolbar_height - ui(12); var tbh = h - toolbar_height / 2; @@ -1840,9 +1860,11 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { draw_set_alpha(i < array_length(node_context) - 1? 0.33 : 1); draw_text(xx, tbh, tt); draw_set_alpha(1); - xx += tw; - xx += ui(32); + + xx += tw + ui(32); } + + return xx; } #endregion function drawToolBar() { #region @@ -1853,25 +1875,57 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { mouse_on_graph = false; draw_sprite_stretched(THEME.toolbar, 0, 0, ty, w, h); - drawContext(); + var cont_x = drawContext(); - var tbx = w - toolbar_height / 2; + var tbx = w - ui(6); var tby = ty + toolbar_height / 2; + var _m = [ mx, my ]; 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 tbs = toolbars[i]; - 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) } ); + for (var j = 0, m = array_length(tbs); j < m; j++) { + var tb = tbs[j]; + var tbObj = tb[0]; + + if(is_instanceof(tbObj, widget)) { + tbObj.setFocusHover(pFOCUS, pHOVER); + + var _wdw = ui(32); + var _wdx = tbx - _wdw; + if(_wdx < cont_x) break; + + var _param = new widgetParam(_wdx, ty + ui(8), _wdw, toolbar_height - ui(16), tb[1](), {}, _m, x, y); + _param.font = f_p3; + + tbObj.color = COLORS._main_text_sub; + tbObj.drawParam(_param); + + tbx -= _wdw + ui(4); + + } else { + var tbInd = tb[1](); + var tbTooltip = tb[2](); + + var bs = ui(28); + if(tbx - (bs + ui(4)) < cont_x) break; + + var b = buttonInstant(THEME.button_hide, tbx - bs, tby - bs / 2, bs, bs, _m, pFOCUS, pHOVER, tbTooltip, tbObj, tbInd); + if(b == 2) tb[3]( { x: x + tbx - bs, y: y + tby - bs / 2 } ); + tbx -= bs + ui(4); + } + + } - tbx -= ui(32); + tbx -= ui(2); + + draw_set_color(COLORS.panel_toolbar_separator); + draw_line_width(tbx, tby - toolbar_height / 2 + ui(8), tbx, tby + toolbar_height / 2 - ui(8), 2); + + if(tbx < cont_x) break; + tbx -= ui(6); } - 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 @@ -2018,6 +2072,14 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { dragGraph(); + toolbars = [ toolbars_general ]; + if(array_length(nodes_selecting) > 1) { + if(array_exists(nodes_selecting, nodes_select_anchor)) + array_push(toolbars, toolbars_halign, toolbars_valign, toolbars_distrib_space); + else + array_push(toolbars, toolbars_halign, toolbars_valign, toolbars_distrib); + } + graph_cx = (w / 2) / graph_s - graph_x; graph_cy = (h / 2) / graph_s - graph_y; @@ -2045,13 +2107,10 @@ function Panel_Graph(project = PROJECT) : PanelContent() constructor { drawViewControl(); - if(pFOCUS && !view_hovering) - array_foreach(nodes_selecting, function(node) { node.focusStep(); }); + if(pFOCUS && !view_hovering) 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(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") + "..."); graph_dragging_key = false; graph_zooming_key = false; diff --git a/scripts/shader_functions/shader_functions.gml b/scripts/shader_functions/shader_functions.gml index 7e15c2788..af9fa6f9e 100644 --- a/scripts/shader_functions/shader_functions.gml +++ b/scripts/shader_functions/shader_functions.gml @@ -31,6 +31,14 @@ function shader_set_2(uniform, v) { INLINE var shader = shader_current(); shader function shader_set_3(uniform, v) { INLINE var shader = shader_current(); shader_set_uniform_f(shader_get_uniform(shader, uniform), aGetF(v, 0), aGetF(v, 1), aGetF(v, 2)); } function shader_set_4(uniform, v) { INLINE var shader = shader_current(); shader_set_uniform_f(shader_get_uniform(shader, uniform), aGetF(v, 0), aGetF(v, 1), aGetF(v, 2), aGetF(v, 3)); } +function shader_set_f_array(uniform, value, max_length = 128) { + var shader = shader_current(); + if(shader == -1) return; + + if(array_empty(value)) return; + shader_set_uniform_f_array_safe(shader_get_uniform(shader, uniform), value, max_length); +} + function shader_set_f(uniform, value) { #region INLINE diff --git a/scripts/textBox/textBox.gml b/scripts/textBox/textBox.gml index 8d33867ab..510d93693 100644 --- a/scripts/textBox/textBox.gml +++ b/scripts/textBox/textBox.gml @@ -98,25 +98,11 @@ function textBox(_input, _onModify) : textInput(_input, _onModify) constructor { return self; } #endregion - static setFont = function(font) { #region - self.font = font; - return self; - } #endregion - - static setLabel = function(label) { #region - self.label = label; - return self; - } #endregion - - static setPrecision = function(precision) { #region - self.precision = precision; - return self; - } #endregion - - static setEmpty = function() { #region - no_empty = false; - return self; - } #endregion + static setFont = function(font) { self.font = font; return self; } + static setLabel = function(label) { self.label = label; return self; } + static setPrecision = function(precision) { self.precision = precision; return self; } + static setPadding = function(padding) { self.padding = padding; return self; } + static setEmpty = function() { no_empty = false; return self; } static activate = function() { #region WIDGET_CURRENT = self; diff --git a/shaders/sh_gradient/sh_gradient.fsh b/shaders/sh_gradient/sh_gradient.fsh index ec84da262..927ad7528 100644 --- a/shaders/sh_gradient/sh_gradient.fsh +++ b/shaders/sh_gradient/sh_gradient.fsh @@ -120,16 +120,14 @@ uniform int uniAsp; vec2 samplePos = mix(gradient_map_range.xy, gradient_map_range.zw, prog); return texture2D( gradient_map, samplePos ); } - - vec4 col = vec4(0.); - + for(int i = 0; i < GRADIENT_LIMIT; i++) { if(gradient_time[i] == prog) { - col = gradient_color[i]; - break; + return gradient_color[i]; + } else if(gradient_time[i] > prog) { if(i == 0) - col = gradient_color[i]; + return gradient_color[i]; else { float t = (prog - gradient_time[i - 1]) / (gradient_time[i] - gradient_time[i - 1]); vec3 c0 = gradient_color[i - 1].rgb; @@ -137,29 +135,28 @@ uniform int uniAsp; float a = mix(gradient_color[i - 1].a, gradient_color[i].a, t); if(gradient_blend == 0) - col = vec4(mix(c0, c1, t), a); + return vec4(mix(c0, c1, t), a); else if(gradient_blend == 1) - col = gradient_color[i - 1]; + return gradient_color[i - 1]; else if(gradient_blend == 2) - col = vec4(hsvMix(c0, c1, t), a); + return vec4(hsvMix(c0, c1, t), a); else if(gradient_blend == 3) - col = vec4(oklabMax(c0, c1, t), a); + return vec4(oklabMax(c0, c1, t), a); else if(gradient_blend == 4) - col = vec4(rgbMix(c0, c1, t), a); + return vec4(rgbMix(c0, c1, t), a); } break; } - if(i >= gradient_keys - 1) { - col = gradient_color[gradient_keys - 1]; - break; - } + + if(i >= gradient_keys - 1) + return gradient_color[gradient_keys - 1]; } - return col; + return gradient_color[gradient_keys - 1]; } #endregion #endregion //////////////////////////////////// GRADIENT ////////////////////////////////////