From e6ac49b7fab2acb46844c6b545d6b1aad4d711df Mon Sep 17 00:00:00 2001 From: luboslenco Date: Thu, 25 Sep 2025 20:07:31 +0200 Subject: [PATCH] Begin node previews --- base/sources/iron_ui_nodes.c | 30 ++++++++- paint/sources/box_preferences.ts | 72 +++++++++++--------- paint/sources/config.ts | 9 ++- paint/sources/context.ts | 2 +- paint/sources/enums.ts | 6 -- paint/sources/ui_nodes.ts | 110 ++++++++++++++++++------------- 6 files changed, 139 insertions(+), 90 deletions(-) diff --git a/base/sources/iron_ui_nodes.c b/base/sources/iron_ui_nodes.c index 16d66795..79bfdc54 100644 --- a/base/sources/iron_ui_nodes.c +++ b/base/sources/iron_ui_nodes.c @@ -442,10 +442,38 @@ void ui_draw_node(ui_node_t *node, ui_node_canvas_t *canvas) { draw_set_color(node->color); draw_filled_rect(nx, ny + lineh - ui_p(3), w, ui_p(3)); + // Collapse button + bool hover = current->input_x > wx + nx && current->input_x < wx + nx + ui_p(20) && + current->input_y > wy + ny && current->input_y < wy + ny + ui_p(20); + draw_set_color(hover ? current->ops->theme->LABEL_COL : current->ops->theme->HOVER_COL); + int bx = nx + ui_p(4); + int by = ny + ui_p(8); + draw_filled_triangle(bx, by, bx + UI_ARROW_SIZE() * 2, by, bx + UI_ARROW_SIZE(), by + UI_ARROW_SIZE()); + + // Eye button + hover = current->input_x > wx + nx + w - ui_p(20) && current->input_x < wx + nx + w && + current->input_y > wy + ny && current->input_y < wy + ny + ui_p(20); + draw_set_color(hover ? current->ops->theme->LABEL_COL : current->ops->theme->HOVER_COL); + float ex = nx + w - ui_p(10); + float ey = ny + ui_p(10); + float hw = ui_p(6); + float hh = ui_p(3); + float x[4] = {ex - hw, ex - hw * 0.5, ex + hw * 0.5, ex + hw}; + float y_upper[4] = {ey, ey - hh * 1.5, ey - hh * 1.5, ey}; + f32_array_t xa; + f32_array_t ya; + xa.buffer = x; + ya.buffer = y_upper; + draw_cubic_bezier(&xa, &ya, 15, 1.0); + float y_lower[4] = {ey, ey + hh * 1.5, ey + hh * 1.5, ey}; + ya.buffer = y_lower; + draw_cubic_bezier(&xa, &ya, 15, 1.0); + draw_filled_circle(ex, ey, ui_p(2), 0); + // Title draw_set_color(current->ops->theme->TEXT_COL); float textw = draw_string_width(current->ops->font, current->font_size, text); - draw_string(text, nx + ui_p(10), ny + ui_p(6)); + draw_string(text, nx + ui_p(20), ny + ui_p(6)); ny += lineh * 0.5; // Outputs diff --git a/paint/sources/box_preferences.ts b/paint/sources/box_preferences.ts index 5f554a8b..d4e1131a 100644 --- a/paint/sources/box_preferences.ts +++ b/paint/sources/box_preferences.ts @@ -47,42 +47,22 @@ function box_preferences_show() { context_raw.hscale_was_changed = true; } - let hspeed: ui_handle_t = ui_handle(__ID__); - if (hspeed.init) { - hspeed.f = config_raw.camera_zoom_speed; + let h_selected_node_preview: ui_handle_t = ui_handle(__ID__); + if (h_selected_node_preview.init) { + h_selected_node_preview.b = config_raw.selected_node_preview; } - config_raw.camera_zoom_speed = ui_slider(hspeed, tr("Camera Zoom Speed"), 0.1, 4.0, true); - - hspeed = ui_handle(__ID__); - if (hspeed.init) { - hspeed.f = config_raw.camera_rotation_speed; - } - config_raw.camera_rotation_speed = ui_slider(hspeed, tr("Camera Rotation Speed"), 0.1, 4.0, true); - - hspeed = ui_handle(__ID__); - if (hspeed.init) { - hspeed.f = config_raw.camera_pan_speed; - } - config_raw.camera_pan_speed = ui_slider(hspeed, tr("Camera Pan Speed"), 0.1, 4.0, true); - - let zoom_direction_handle: ui_handle_t = ui_handle(__ID__); - if (zoom_direction_handle.init) { - zoom_direction_handle.i = config_raw.zoom_direction; - } - let zoom_direction_combo: string[] = [tr("Vertical"), tr("Vertical Inverted"), tr("Horizontal"), tr("Horizontal Inverted"), tr("Vertical and Horizontal"), tr("Vertical and Horizontal Inverted")]; - ui_combo(zoom_direction_handle, zoom_direction_combo, tr("Direction to Zoom"), true); - if (zoom_direction_handle.changed) { - config_raw.zoom_direction = zoom_direction_handle.i; + ui_check(h_selected_node_preview, tr("Selected Node Preview")); + if (h_selected_node_preview.changed) { + config_raw.selected_node_preview = h_selected_node_preview.b; } - let h_node_preview: ui_handle_t = ui_handle(__ID__); - if (h_node_preview.init) { - h_node_preview.i = config_raw.node_preview; + let h_node_previews: ui_handle_t = ui_handle(__ID__); + if (h_node_previews.init) { + h_node_previews.b = config_raw.node_previews; } - let node_preview_combo: string[] = [tr("Off"), tr("Selected Node")]; // , tr("All Nodes")]; - ui_combo(h_node_preview, node_preview_combo, tr("Node Preview"), true); - if (h_node_preview.changed) { - config_raw.node_preview = h_node_preview.i; + config_raw.node_previews = ui_check(h_node_previews, tr("Node Previews")); + if (ui.is_hovered) { + ui_tooltip(tr("Show node preview on each node by default")); } let h_wrap_mouse: ui_handle_t = ui_handle(__ID__); @@ -364,6 +344,34 @@ function box_preferences_show() { config_raw.camera_controls = camera_controls_handle.i; } + let hspeed: ui_handle_t = ui_handle(__ID__); + if (hspeed.init) { + hspeed.f = config_raw.camera_zoom_speed; + } + config_raw.camera_zoom_speed = ui_slider(hspeed, tr("Camera Zoom Speed"), 0.1, 4.0, true); + + hspeed = ui_handle(__ID__); + if (hspeed.init) { + hspeed.f = config_raw.camera_rotation_speed; + } + config_raw.camera_rotation_speed = ui_slider(hspeed, tr("Camera Rotation Speed"), 0.1, 4.0, true); + + hspeed = ui_handle(__ID__); + if (hspeed.init) { + hspeed.f = config_raw.camera_pan_speed; + } + config_raw.camera_pan_speed = ui_slider(hspeed, tr("Camera Pan Speed"), 0.1, 4.0, true); + + let zoom_direction_handle: ui_handle_t = ui_handle(__ID__); + if (zoom_direction_handle.init) { + zoom_direction_handle.i = config_raw.zoom_direction; + } + let zoom_direction_combo: string[] = [tr("Vertical"), tr("Vertical Inverted"), tr("Horizontal"), tr("Horizontal Inverted"), tr("Vertical and Horizontal"), tr("Vertical and Horizontal Inverted")]; + ui_combo(zoom_direction_handle, zoom_direction_combo, tr("Direction to Zoom"), true); + if (zoom_direction_handle.changed) { + config_raw.zoom_direction = zoom_direction_handle.i; + } + let layer_res_handle: ui_handle_t = ui_handle(__ID__); if (layer_res_handle.init) { layer_res_handle.i = config_raw.layer_res; diff --git a/paint/sources/config.ts b/paint/sources/config.ts index 547df5b2..f6aa4742 100644 --- a/paint/sources/config.ts +++ b/paint/sources/config.ts @@ -84,7 +84,8 @@ function config_save() { json_encode_f32("displace_strength", config_raw.displace_strength); json_encode_i32("layer_res", config_raw.layer_res); json_encode_bool("brush_live", config_raw.brush_live); - json_encode_i32("node_preview", config_raw.node_preview); + json_encode_bool("selected_node_preview", config_raw.selected_node_preview); + json_encode_bool("node_previews", config_raw.node_previews); json_encode_bool("pressure_hardness", config_raw.pressure_hardness); json_encode_bool("pressure_angle", config_raw.pressure_angle); json_encode_bool("pressure_opacity", config_raw.pressure_opacity); @@ -183,7 +184,8 @@ function config_init() { config_raw.touch_ui = false; config_raw.splash_screen = false; ///end - config_raw.node_preview = node_preview_t.SELECTED_NODE; + config_raw.selected_node_preview = true; + config_raw.node_previews = false; config_raw.pressure_hardness = true; config_raw.pressure_angle = false; config_raw.pressure_opacity = false; @@ -470,7 +472,8 @@ type config_t = { displace_strength?: f32; layer_res?: i32; brush_live?: bool; - node_preview?: i32; + selected_node_preview?: bool; + node_previews?: bool; pressure_hardness?: bool; pressure_angle?: bool; pressure_opacity?: bool; diff --git a/paint/sources/context.ts b/paint/sources/context.ts index 6bb44b11..d615de37 100644 --- a/paint/sources/context.ts +++ b/paint/sources/context.ts @@ -98,9 +98,9 @@ type context_t = { layers_preview_dirty?: bool; node_preview_dirty?: bool; node_preview?: gpu_texture_t; + node_preview_name?: string; node_previews?: map_t; node_previews_used?: string[]; - node_preview_name?: string; mask_preview_rgba32?: gpu_texture_t; mask_preview_last?: slot_layer_t; diff --git a/paint/sources/enums.ts b/paint/sources/enums.ts index e301774c..a8f75891 100644 --- a/paint/sources/enums.ts +++ b/paint/sources/enums.ts @@ -273,9 +273,3 @@ enum layout_size_t { STATUS_H = 5, HEADER = 6, // 0 - hidden, 1 - visible } - -enum node_preview_t { - OFF = 0, - SELECTED_NODE = 1, - ALL_NODES = 2, -} diff --git a/paint/sources/ui_nodes.ts b/paint/sources/ui_nodes.ts index 4df66e5c..9b184be5 100644 --- a/paint/sources/ui_nodes.ts +++ b/paint/sources/ui_nodes.ts @@ -819,7 +819,7 @@ function ui_nodes_render() { ui_nodes_grid_redraw = false; } - if (config_raw.node_preview == node_preview_t.SELECTED_NODE && context_raw.node_preview_dirty) { + if (config_raw.selected_node_preview && context_raw.node_preview_dirty) { ui_nodes_make_node_preview(); } @@ -975,55 +975,24 @@ function ui_nodes_render() { ui_nodes_uichanged_last = ui.changed; // Node previews - if (config_raw.node_preview == node_preview_t.SELECTED_NODE && nodes.nodes_selected_id.length > 0) { - let img: gpu_texture_t = null; + if (config_raw.selected_node_preview && nodes.nodes_selected_id.length > 0) { let sel: ui_node_t = ui_get_node(c.nodes, nodes.nodes_selected_id[0]); - - let single_channel: bool = sel.type == "LAYER_MASK"; - if (sel.type == "LAYER" || sel.type == "LAYER_MASK") { - let id: i32 = sel.buttons[0].default_value[0]; - if (id < project_layers.length) { - img = project_layers[id].texpaint_preview; - } - } - else if (sel.type == "MATERIAL") { - let id: i32 = sel.buttons[0].default_value[0]; - if (id < project_materials.length) { - img = project_materials[id].image; - } - } - else if (sel.type == "OUTPUT_MATERIAL_PBR") { - img = context_raw.material.image; - } - else if (sel.type == "brush_output_node") { - img = context_raw.brush.image; - } - else if (ui_nodes_canvas_type == canvas_type_t.MATERIAL) { - img = context_raw.node_preview; - } - - if (img != null) { - let tw: f32 = 128 * UI_SCALE(); - let th: f32 = tw * (img.height / img.width); - let tx: f32 = ui_nodes_ww - tw - 8 * UI_SCALE(); - let ty: f32 = ui_nodes_wh - th - 8 * UI_SCALE(); - let invert_y: bool = false; - if (single_channel) { - draw_set_pipeline(ui_view2d_pipe); - gpu_set_int(ui_view2d_channel_loc, 1); - } - - draw_set_color(0xffffffff); - invert_y ? - draw_scaled_image(img, tx, ty + th, tw, -th) : - draw_scaled_image(img, tx, ty, tw, th); - - if (single_channel) { - draw_set_pipeline(null); - } - } + let tw: f32 = 128 * UI_SCALE(); + let tx: f32 = ui_nodes_ww - tw - 8 * UI_SCALE(); + let ty: f32 = ui_nodes_wh - tw - 8 * UI_SCALE(); + ui_nodes_draw_node_preview(sel, tx, ty, tw); } + // if (config_raw.selected_node_preview) { + // for (let i: i32 = 0; i < c.nodes.length; ++i) { + // let n: ui_node_t = c.nodes[i]; + // let tw: f32 = 128 * UI_SCALE() * UI_NODES_SCALE(); + // let tx: f32 = UI_NODE_X(n) + UI_NODE_W(n) / 2 - tw / 2; + // let ty: f32 = UI_NODE_Y(n) - tw - 6; + // ui_nodes_draw_node_preview(n, tx, ty, tw); + // } + // } + ui_nodes_draw_menubar(); ui.window_border_right = 0; @@ -1123,6 +1092,53 @@ function ui_nodes_render() { ui.input_enabled = true; } +function ui_nodes_get_node_preview_image(n: ui_node_t): gpu_texture_t { + let img: gpu_texture_t = null; + if (n.type == "LAYER" || n.type == "LAYER_MASK") { + let id: i32 = n.buttons[0].default_value[0]; + if (id < project_layers.length) { + img = project_layers[id].texpaint_preview; + } + } + else if (n.type == "MATERIAL") { + let id: i32 = n.buttons[0].default_value[0]; + if (id < project_materials.length) { + img = project_materials[id].image; + } + } + else if (n.type == "OUTPUT_MATERIAL_PBR") { + img = context_raw.material.image; + } + else if (n.type == "brush_output_node") { + img = context_raw.brush.image; + } + else if (ui_nodes_canvas_type == canvas_type_t.MATERIAL) { + img = context_raw.node_preview; + } + return img; +} + +function ui_nodes_draw_node_preview(n: ui_node_t, tx: i32, ty: i32, tw: i32) { + let img: gpu_texture_t = ui_nodes_get_node_preview_image(n); + if (img != null) { + + if (img == context_raw.node_preview) { + ui_draw_shadow(tx, ty, tw, tw); + } + + let single_channel: bool = n.type == "LAYER_MASK"; + if (single_channel) { + draw_set_pipeline(ui_view2d_pipe); + gpu_set_int(ui_view2d_channel_loc, 1); + } + draw_set_color(0xffffffff); + draw_scaled_image(img, tx, ty, tw, tw); + if (single_channel) { + draw_set_pipeline(null); + } + } +} + function ui_nodes_draw_menubar() { let c: ui_node_canvas_t = ui_nodes_get_canvas(true); let ew: i32 = math_floor(UI_ELEMENT_W() * 0.7);