@@ -6,7 +6,8 @@ use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier, NodeRelati
66use super :: misc:: PTZ ;
77use super :: nodes:: SelectedNodes ;
88use crate :: consts:: {
9- EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP , EXPORTS_TO_TOP_EDGE_PIXEL_GAP , GRID_SIZE , IMPORTS_TO_LEFT_EDGE_PIXEL_GAP , IMPORTS_TO_TOP_EDGE_PIXEL_GAP , LAYER_INDENT_OFFSET , NODE_CHAIN_WIDTH , STACK_VERTICAL_GAP ,
9+ EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP , EXPORTS_TO_TOP_EDGE_PIXEL_GAP , GRID_SIZE , HALF_GRID_SIZE , IMPORTS_TO_LEFT_EDGE_PIXEL_GAP , IMPORTS_TO_TOP_EDGE_PIXEL_GAP , LAYER_INDENT_OFFSET , NODE_CHAIN_WIDTH ,
10+ STACK_VERTICAL_GAP ,
1011} ;
1112use crate :: messages:: portfolio:: document:: graph_operation:: utility_types:: ModifyInputsContext ;
1213use crate :: messages:: portfolio:: document:: node_graph:: document_node_definitions:: { DefinitionIdentifier , resolve_document_node_type} ;
@@ -2503,7 +2504,7 @@ impl NodeNetworkInterface {
25032504 return ;
25042505 } ;
25052506
2506- let node_top_left = node_position. as_dvec2 ( ) * 24. ;
2507+ let node_top_left = node_position. as_dvec2 ( ) * GRID_SIZE as f64 ;
25072508 let mut port_click_targets = Ports :: new ( ) ;
25082509 let document_node_click_targets = if !node_metadata. persistent_metadata . is_layer ( ) {
25092510 // Create input/output click targets
@@ -2528,9 +2529,10 @@ impl NodeNetworkInterface {
25282529 port_click_targets. insert_node_output ( output_index, node_top_left) ;
25292530 }
25302531
2531- let height = input_row_count. max ( number_of_outputs) . max ( 1 ) as u32 * crate :: consts:: GRID_SIZE ;
2532- let width = 5 * crate :: consts:: GRID_SIZE ;
2533- let node_click_target_top_left = node_top_left + DVec2 :: new ( 0. , 12. ) ;
2532+ let height = input_row_count. max ( number_of_outputs) . max ( 1 ) as u32 * GRID_SIZE ;
2533+ let width = 5 * GRID_SIZE ;
2534+ // Offset down by half a grid so the click target sits below the top connector strip.
2535+ let node_click_target_top_left = node_top_left + DVec2 :: new ( 0. , HALF_GRID_SIZE as f64 ) ;
25342536 let node_click_target_bottom_right = node_click_target_top_left + DVec2 :: new ( width as f64 , height as f64 ) ;
25352537
25362538 let radius = 3. ;
@@ -2554,47 +2556,76 @@ impl NodeNetworkInterface {
25542556 log:: error!( "Could not get layer width in load_node_click_targets" ) ;
25552557 0
25562558 } ) ;
2557- let width = layer_width_cells * crate :: consts :: GRID_SIZE ;
2558- let height = 2 * crate :: consts :: GRID_SIZE ;
2559+ let width = layer_width_cells * GRID_SIZE ;
2560+ let height = 2 * GRID_SIZE ;
25592561 let locked = self . is_locked ( node_id, network_path) ;
25602562
2563+ // The layer is `2 * GRID_SIZE` tall, so its vertical center sits one grid unit below `node_top_left.y`.
2564+ // Visibility/lock buttons fill a 1-grid-cell square (so half-extents of HALF_GRID_SIZE each side of center).
2565+ const LAYER_VERTICAL_CENTER : f64 = GRID_SIZE as f64 ;
2566+ const ICON_HALF_EXTENT : f64 = HALF_GRID_SIZE as f64 ;
2567+
25612568 // Update visibility button click target
2562- let visibility_offset = node_top_left + DVec2 :: new ( width as f64 , 24. ) ;
2563- let subpath = Subpath :: new_rounded_rectangle ( DVec2 :: new ( -12. , -12. ) + visibility_offset, DVec2 :: new ( 12. , 12. ) + visibility_offset, [ 3. ; 4 ] ) ;
2569+ let visibility_offset = node_top_left + DVec2 :: new ( width as f64 , LAYER_VERTICAL_CENTER ) ;
2570+ let subpath = Subpath :: new_rounded_rectangle (
2571+ DVec2 :: new ( -ICON_HALF_EXTENT , -ICON_HALF_EXTENT ) + visibility_offset,
2572+ DVec2 :: new ( ICON_HALF_EXTENT , ICON_HALF_EXTENT ) + visibility_offset,
2573+ [ 3. ; 4 ] ,
2574+ ) ;
25642575 let visibility_click_target = ClickTarget :: new_with_subpath ( subpath, 0. ) ;
25652576
25662577 // Update lock button click target, positioned one grid unit to the left of the visibility button (only when locked)
25672578 let lock_click_target = if locked {
2568- let lock_offset = node_top_left + DVec2 :: new ( width as f64 - GRID_SIZE as f64 , 24. ) ;
2569- let subpath = Subpath :: new_rounded_rectangle ( DVec2 :: new ( -12. , -12. ) + lock_offset, DVec2 :: new ( 12. , 12. ) + lock_offset, [ 3. ; 4 ] ) ;
2579+ let lock_offset = node_top_left + DVec2 :: new ( width as f64 - GRID_SIZE as f64 , LAYER_VERTICAL_CENTER ) ;
2580+ let subpath = Subpath :: new_rounded_rectangle (
2581+ DVec2 :: new ( -ICON_HALF_EXTENT , -ICON_HALF_EXTENT ) + lock_offset,
2582+ DVec2 :: new ( ICON_HALF_EXTENT , ICON_HALF_EXTENT ) + lock_offset,
2583+ [ 3. ; 4 ] ,
2584+ ) ;
25702585 Some ( ClickTarget :: new_with_subpath ( subpath, 0. ) )
25712586 } else {
25722587 None
25732588 } ;
25742589
2575- // Update grip button click target, which is positioned to the left of the leftmost icon
2590+ // Update grip button click target, which is positioned to the left of the leftmost icon.
2591+ // The grip is 8px wide but spans the full layer-vertical-center band.
2592+ const GRIP_WIDTH : f64 = 8. ;
25762593 let icons_width = if locked { GRID_SIZE as f64 } else { 0. } ;
2577- let grip_offset_right_edge = node_top_left + DVec2 :: new ( width as f64 - ( GRID_SIZE as f64 ) / 2. - icons_width, 24. ) ;
2578- let subpath = Subpath :: new_rounded_rectangle ( DVec2 :: new ( -8. , -12. ) + grip_offset_right_edge, DVec2 :: new ( 0. , 12. ) + grip_offset_right_edge, [ 0. ; 4 ] ) ;
2594+ let grip_offset_right_edge = node_top_left + DVec2 :: new ( width as f64 - ICON_HALF_EXTENT - icons_width, LAYER_VERTICAL_CENTER ) ;
2595+ let subpath = Subpath :: new_rounded_rectangle (
2596+ DVec2 :: new ( -GRIP_WIDTH , -ICON_HALF_EXTENT ) + grip_offset_right_edge,
2597+ DVec2 :: new ( 0. , ICON_HALF_EXTENT ) + grip_offset_right_edge,
2598+ [ 0. ; 4 ] ,
2599+ ) ;
25792600 let grip_click_target = ClickTarget :: new_with_subpath ( subpath, 0. ) ;
25802601
25812602 // Update display-name text click target, used to detect double-click rename. Sized to the text bounds
2582- // (not the surrounding `.details` area) so the rest of the layer still drills into the subgraph on dblclick.
2583- // The text is rendered after the 72px thumbnail (with 1px side margins) and the 8px `.details` left margin,
2584- // so it starts at 82px from the layer's left edge. Width is clamped so it can't reach into the right-side
2585- // icon area (grip + lock + visibility).
2603+ // (not the surrounding `.details` area) so the rest of the layer still drills into the subgraph on double-click.
2604+
2605+ /// `.layer` margin-left (= 12), for chain layers the negative margin-left and positive padding-left cancel out, keeping content at this same offset
2606+ const LAYER_LEFT_MARGIN : f64 = HALF_GRID_SIZE as f64 ;
2607+ /// `.thumbnail` (70px) + its 1px side margins (= 72)
2608+ const THUMBNAIL_BLOCK_WIDTH : f64 = 3. * GRID_SIZE as f64 ;
2609+ /// `.details` margin-left
2610+ const DETAILS_LEFT_MARGIN : f64 = 8. ;
2611+ const NAME_LEFT_OFFSET : f64 = LAYER_LEFT_MARGIN + THUMBNAIL_BLOCK_WIDTH + DETAILS_LEFT_MARGIN ;
2612+ /// Distance from layer's right edge to visibility's left edge (= 12)
2613+ const VISIBILITY_INSET_FROM_LAYER_RIGHT : f64 = HALF_GRID_SIZE as f64 ;
2614+ const FONT_SIZE : f64 = 14. ;
2615+
25862616 let display_name = self . display_name ( node_id, network_path) ;
25872617 let name_click_target = if display_name. is_empty ( ) {
25882618 None
25892619 } else {
2590- let name_left = node_top_left. x + 82. ;
2591- let icons_reserve = ( GRID_SIZE as f64 / 2. ) + icons_width + 8. ;
2620+ let name_left = node_top_left. x + NAME_LEFT_OFFSET ;
2621+ let icons_reserve = VISIBILITY_INSET_FROM_LAYER_RIGHT + icons_width + GRIP_WIDTH ;
25922622 let name_right_max = node_top_left. x + width as f64 - icons_reserve;
2593- let text_w = crate :: messages:: portfolio:: document:: overlays:: utility_functions:: text_width ( & display_name, 14. ) ;
2623+ let text_w = crate :: messages:: portfolio:: document:: overlays:: utility_functions:: text_width ( & display_name, FONT_SIZE ) ;
25942624 let name_right = ( name_left + text_w) . min ( name_right_max) ;
25952625 if name_right > name_left {
2596- let name_top = node_top_left. y + 12. ;
2597- let name_bottom = node_top_left. y + 36. ;
2626+ // The 1-grid-tall name strip is centered vertically in the 2-grid-tall layer.
2627+ let name_top = node_top_left. y + HALF_GRID_SIZE as f64 ;
2628+ let name_bottom = node_top_left. y + GRID_SIZE as f64 + HALF_GRID_SIZE as f64 ;
25982629 let subpath = Subpath :: new_rounded_rectangle ( DVec2 :: new ( name_left, name_top) , DVec2 :: new ( name_right, name_bottom) , [ 3. ; 4 ] ) ;
25992630 Some ( ClickTarget :: new_with_subpath ( subpath, 0. ) )
26002631 } else {
@@ -2606,9 +2637,9 @@ impl NodeNetworkInterface {
26062637 let chain_width_grid_spaces = self . chain_width ( node_id, network_path) ;
26072638
26082639 let node_bottom_right = node_top_left + DVec2 :: new ( width as f64 , height as f64 ) ;
2609- let chain_top_left = node_top_left - DVec2 :: new ( ( chain_width_grid_spaces * crate :: consts :: GRID_SIZE ) as f64 , 0. ) ;
2610- let radius = 10. ;
2611- let subpath = Subpath :: new_rounded_rectangle ( chain_top_left, node_bottom_right, [ radius ; 4 ] ) ;
2640+ let chain_top_left = node_top_left - DVec2 :: new ( ( chain_width_grid_spaces * GRID_SIZE ) as f64 , 0. ) ;
2641+ const CORNER_RADIUS : f64 = 10. ;
2642+ let subpath = Subpath :: new_rounded_rectangle ( chain_top_left, node_bottom_right, [ CORNER_RADIUS ; 4 ] ) ;
26122643 let node_click_target = ClickTarget :: new_with_subpath ( subpath, 0. ) ;
26132644
26142645 DocumentNodeClickTargets {
0 commit comments