diff --git a/scripts/dashboard_grid.gd b/scripts/dashboard_grid.gd index b23a757..3a195bd 100644 --- a/scripts/dashboard_grid.gd +++ b/scripts/dashboard_grid.gd @@ -25,8 +25,8 @@ var _drag_mouse_offset: Vector2 = Vector2.ZERO var _hover_col: int = -1 var _hover_row: int = -1 -# Styles cached per-cell so we can modify them during drag -var _cell_styles: Dictionary = {} # cell -> StyleBoxFlat +# Visible cell styles cached per-cell so we can modify them during drag +var _cell_styles: Dictionary = {} # "col,row" -> StyleBoxFlat func _ready() -> void: @@ -127,10 +127,13 @@ func _begin_drag(mouse_pos: Vector2) -> void: _drag_source_col = col _drag_source_row = row + # Show grid cells so the user can see drop zones + _show_cells(true) + # Calculate where the module sits in grid coordinates before reparenting. # module.position is relative to the cell; cell.position is relative to us (the grid). - var cell: PanelContainer = _cells[row][col] - var module_origin_in_grid := cell.position + module.position + var cell_ref: PanelContainer = _cells[row][col] + var module_origin_in_grid := cell_ref.position + module.position _drag_mouse_offset = mouse_pos - module_origin_in_grid _drag_module = _take_module_from_cell(col, row) @@ -168,51 +171,59 @@ func _end_drag(mouse_pos: Vector2) -> void: return _clear_hover() + _show_cells(false) _drag_module.modulate = Color(1, 1, 1, 1) var cell_pos := _cell_at_position(mouse_pos) var target_col := cell_pos.x var target_row := cell_pos.y - # Dropped on the same cell — just put it back - if target_col == _drag_source_col and target_row == _drag_source_row: - _place_module_in_cell(_drag_module, target_col, target_row) - module_placed.emit(_drag_module, target_col, target_row) + # Check whether the mouse is actually inside the cell bounds (not in the gap) + var on_cell := false + if _is_valid_cell(target_col, target_row): + var cell_ref: PanelContainer = _cells[target_row][target_col] + on_cell = Rect2(Vector2.ZERO, cell_ref.size).has_point(mouse_pos - cell_ref.position) + + if not on_cell or not _is_valid_cell(target_col, target_row): + _drop_to_source() _finish_drag() return - # Remove the module from its temporary home (the grid itself) + # Remove from its temporary parent (the grid) _drag_module.get_parent().remove_child(_drag_module) - if _is_valid_cell(target_col, target_row): - var existing := _get_cell_module(target_col, target_row) - if existing != null: - # SWAP: put existing module in source cell, drag module in target - existing.get_parent().remove_child(existing) - var was_source_valid := _is_valid_cell(_drag_source_col, _drag_source_row) - if was_source_valid: - _place_module_in_cell(existing, _drag_source_col, _drag_source_row) - module_placed.emit(existing, _drag_source_col, _drag_source_row) - else: - existing.queue_free() + var existing := _get_cell_module(target_col, target_row) + if existing != null: + # SWAP: put existing in source, dragged module in target + existing.get_parent().remove_child(existing) + var was_source_valid := _is_valid_cell(_drag_source_col, _drag_source_row) + if was_source_valid: + _place_module_in_cell(existing, _drag_source_col, _drag_source_row) + module_placed.emit(existing, _drag_source_col, _drag_source_row) + else: + existing.queue_free() - _place_module_in_cell(_drag_module, target_col, target_row) - module_placed.emit(_drag_module, target_col, target_row) - else: - # Place in the empty cell directly — you get full control of positioning - _place_module_in_cell(_drag_module, target_col, target_row) - module_placed.emit(_drag_module, target_col, target_row) + _place_module_in_cell(_drag_module, target_col, target_row) + module_placed.emit(_drag_module, target_col, target_row) else: - # Dropped outside the grid — return to source if still valid - if _is_valid_cell(_drag_source_col, _drag_source_row): - _place_module_in_cell(_drag_module, _drag_source_col, _drag_source_row) - module_placed.emit(_drag_module, _drag_source_col, _drag_source_row) - else: - _drag_module.queue_free() + # Place in the empty cell + _place_module_in_cell(_drag_module, target_col, target_row) + module_placed.emit(_drag_module, target_col, target_row) _finish_drag() +func _drop_to_source() -> void: + if _drag_module == null: + return + if _is_valid_cell(_drag_source_col, _drag_source_row): + _drag_module.get_parent().remove_child(_drag_module) + _place_module_in_cell(_drag_module, _drag_source_col, _drag_source_row) + module_placed.emit(_drag_module, _drag_source_col, _drag_source_row) + else: + _drag_module.queue_free() + + func _finish_drag() -> void: _drag_module = null _is_dragging = false @@ -235,16 +246,13 @@ func _highlight_cell(col: int, row: int, highlighted: bool) -> void: if not _is_valid_cell(col, row): return var cell: PanelContainer = _cells[row][col] - var style_key: String = "%d,%d" % [col, row] - var style: StyleBoxFlat = _cell_styles.get(style_key) + var style: StyleBoxFlat = cell.get_meta("visible_style") if style == null: return if highlighted: style.border_color = Color(0.5, 0.6, 1.0, 1.0) else: style.border_color = Color(0.25, 0.25, 0.35, 1.0) - cell.add_theme_stylebox_override("panel", style) - cell.add_theme_stylebox_override("panel_focused", style) # -------------------------------------------------------------------------- @@ -409,11 +417,12 @@ func _cancel_drag() -> void: _place_module_in_cell(_drag_module, _drag_source_col, _drag_source_row) else: _drag_module.queue_free() + _show_cells(false) + _clear_hover() _drag_module = null _is_dragging = false _drag_source_col = -1 _drag_source_row = -1 - _clear_hover() func _build_cells() -> void: @@ -430,20 +439,48 @@ func _build_cells() -> void: func _style_cell(cell: PanelContainer, col: int, row: int) -> void: - var style := StyleBoxFlat.new() - style.bg_color = Color(0.14, 0.14, 0.18, 1.0) - style.border_width_left = 1 - style.border_width_top = 1 - style.border_width_right = 1 - style.border_width_bottom = 1 - style.border_color = Color(0.25, 0.25, 0.35, 1.0) - style.corner_radius_top_left = 6 - style.corner_radius_top_right = 6 - style.corner_radius_bottom_right = 6 - style.corner_radius_bottom_left = 6 - cell.add_theme_stylebox_override("panel", style) - cell.add_theme_stylebox_override("panel_focused", style) - _cell_styles["%d,%d" % [col, row]] = style + # Hidden style — used when not dragging + var hidden := StyleBoxFlat.new() + hidden.bg_color = Color.TRANSPARENT + hidden.border_width_left = 1 + hidden.border_width_top = 1 + hidden.border_width_right = 1 + hidden.border_width_bottom = 1 + hidden.border_color = Color.TRANSPARENT + hidden.corner_radius_top_left = 6 + hidden.corner_radius_top_right = 6 + hidden.corner_radius_bottom_right = 6 + hidden.corner_radius_bottom_left = 6 + + # Visible style — used during drag, may be modified by highlights + var visible := StyleBoxFlat.new() + visible.bg_color = Color(0.14, 0.14, 0.18, 1.0) + visible.border_width_left = 1 + visible.border_width_top = 1 + visible.border_width_right = 1 + visible.border_width_bottom = 1 + visible.border_color = Color(0.25, 0.25, 0.35, 1.0) + visible.corner_radius_top_left = 6 + visible.corner_radius_top_right = 6 + visible.corner_radius_bottom_right = 6 + visible.corner_radius_bottom_left = 6 + + cell.add_theme_stylebox_override("panel", hidden) + cell.add_theme_stylebox_override("panel_focused", hidden) + cell.set_meta("hidden_style", hidden) + cell.set_meta("visible_style", visible) + _cell_styles["%d,%d" % [col, row]] = visible + + +func _show_cells(show: bool) -> void: + for row_idx in range(_cells.size()): + for col_idx in range(_cells[row_idx].size()): + var cell: PanelContainer = _cells[row_idx][col_idx] + if not is_instance_valid(cell): + continue + var style: StyleBoxFlat = cell.get_meta("visible_style") if show else cell.get_meta("hidden_style") + cell.add_theme_stylebox_override("panel", style) + cell.add_theme_stylebox_override("panel_focused", style) func _teardown_cells() -> void: