implement list-reflow insert for drag-and-drop: dropping on empty cell now inserts and reflows all modules row-major; _rebuild_grid calculates rows from module count; _restore_modules uses reflow
This commit is contained in:
parent
0f11343c05
commit
f33cf3d7f8
1 changed files with 115 additions and 27 deletions
|
|
@ -168,6 +168,7 @@ func _end_drag(mouse_pos: Vector2) -> void:
|
||||||
return
|
return
|
||||||
|
|
||||||
_clear_hover()
|
_clear_hover()
|
||||||
|
_drag_module.modulate = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
var cell_pos := _cell_at_position(mouse_pos)
|
var cell_pos := _cell_at_position(mouse_pos)
|
||||||
var target_col := cell_pos.x
|
var target_col := cell_pos.x
|
||||||
|
|
@ -175,22 +176,18 @@ func _end_drag(mouse_pos: Vector2) -> void:
|
||||||
|
|
||||||
# Dropped on the same cell — just put it back
|
# Dropped on the same cell — just put it back
|
||||||
if target_col == _drag_source_col and target_row == _drag_source_row:
|
if target_col == _drag_source_col and target_row == _drag_source_row:
|
||||||
_drag_module.modulate = Color(1, 1, 1, 1)
|
|
||||||
_place_module_in_cell(_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)
|
module_placed.emit(_drag_module, target_col, target_row)
|
||||||
_drag_module = null
|
_finish_drag()
|
||||||
_is_dragging = false
|
|
||||||
_drag_source_col = -1
|
|
||||||
_drag_source_row = -1
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Remove the module from the grid (we'll reparent it below)
|
# Remove the module from its temporary home (the grid itself)
|
||||||
_drag_module.get_parent().remove_child(_drag_module)
|
_drag_module.get_parent().remove_child(_drag_module)
|
||||||
|
|
||||||
if _is_valid_cell(target_col, target_row):
|
if _is_valid_cell(target_col, target_row):
|
||||||
var existing := _get_cell_module(target_col, target_row)
|
var existing := _get_cell_module(target_col, target_row)
|
||||||
if existing != null:
|
if existing != null:
|
||||||
# Swap: put existing module in source cell, drag module in target
|
# SWAP: put existing module in source cell, drag module in target
|
||||||
existing.get_parent().remove_child(existing)
|
existing.get_parent().remove_child(existing)
|
||||||
var was_source_valid := _is_valid_cell(_drag_source_col, _drag_source_row)
|
var was_source_valid := _is_valid_cell(_drag_source_col, _drag_source_row)
|
||||||
if was_source_valid:
|
if was_source_valid:
|
||||||
|
|
@ -199,19 +196,29 @@ func _end_drag(mouse_pos: Vector2) -> void:
|
||||||
else:
|
else:
|
||||||
existing.queue_free()
|
existing.queue_free()
|
||||||
|
|
||||||
# Place dragged module in target cell
|
|
||||||
_drag_module.modulate = Color(1, 1, 1, 1)
|
|
||||||
_place_module_in_cell(_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)
|
module_placed.emit(_drag_module, target_col, target_row)
|
||||||
|
else:
|
||||||
|
# INSERT: flatten all modules, insert dragged one at target, reflow
|
||||||
|
var all_modules := _collect_all_modules()
|
||||||
|
|
||||||
|
var insert_index := target_row * columns + target_col
|
||||||
|
insert_index = clampi(insert_index, 0, all_modules.size())
|
||||||
|
all_modules.insert(insert_index, _drag_module)
|
||||||
|
|
||||||
|
_reflow_modules(all_modules)
|
||||||
else:
|
else:
|
||||||
# Dropped outside the grid — return to source if still valid
|
# Dropped outside the grid — return to source if still valid
|
||||||
if _is_valid_cell(_drag_source_col, _drag_source_row):
|
if _is_valid_cell(_drag_source_col, _drag_source_row):
|
||||||
_drag_module.modulate = Color(1, 1, 1, 1)
|
|
||||||
_place_module_in_cell(_drag_module, _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)
|
module_placed.emit(_drag_module, _drag_source_col, _drag_source_row)
|
||||||
else:
|
else:
|
||||||
_drag_module.queue_free()
|
_drag_module.queue_free()
|
||||||
|
|
||||||
|
_finish_drag()
|
||||||
|
|
||||||
|
|
||||||
|
func _finish_drag() -> void:
|
||||||
_drag_module = null
|
_drag_module = null
|
||||||
_is_dragging = false
|
_is_dragging = false
|
||||||
_drag_source_col = -1
|
_drag_source_col = -1
|
||||||
|
|
@ -281,6 +288,69 @@ func _set_cell_child(cell: PanelContainer, child: Control) -> void:
|
||||||
cell.add_child(child)
|
cell.add_child(child)
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
# List-reflow helpers
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Returns all modules in the grid, in row-major order (left-to-right, top-to-bottom).
|
||||||
|
func _collect_all_modules() -> Array[Control]:
|
||||||
|
var result: Array[Control] = []
|
||||||
|
for r in range(rows):
|
||||||
|
for c in range(columns):
|
||||||
|
var mod := _get_cell_module(c, r)
|
||||||
|
if mod != null:
|
||||||
|
result.append(mod)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# Clears every cell, then places the given modules in row-major order,
|
||||||
|
# adding extra rows as needed to fit them all.
|
||||||
|
func _reflow_modules(modules: Array[Control]) -> void:
|
||||||
|
# Remove all modules from cells
|
||||||
|
for r in range(rows):
|
||||||
|
for c in range(columns):
|
||||||
|
_take_module_from_cell(c, r)
|
||||||
|
|
||||||
|
if columns == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ensure enough rows exist
|
||||||
|
var needed := maxi(rows, ceili(float(modules.size()) / float(columns)))
|
||||||
|
while _cells.size() < needed:
|
||||||
|
_add_row()
|
||||||
|
rows = _cells.size()
|
||||||
|
|
||||||
|
# Place modules sequentially
|
||||||
|
for i in range(modules.size()):
|
||||||
|
var c := i % columns
|
||||||
|
var r := floori(i / columns)
|
||||||
|
_place_module_in_cell(modules[i], c, r)
|
||||||
|
module_placed.emit(modules[i], c, r)
|
||||||
|
|
||||||
|
|
||||||
|
func _add_row() -> void:
|
||||||
|
var new_row := _cells.size()
|
||||||
|
_cells.append([])
|
||||||
|
for col in range(columns):
|
||||||
|
var cell := PanelContainer.new()
|
||||||
|
cell.name = "Cell_%d_%d" % [col, new_row]
|
||||||
|
cell.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
|
_style_cell(cell, col, new_row)
|
||||||
|
add_child(cell)
|
||||||
|
_cells[new_row].append(cell)
|
||||||
|
rows = _cells.size()
|
||||||
|
_layout_cells()
|
||||||
|
|
||||||
|
|
||||||
|
func _count_modules_in_grid() -> int:
|
||||||
|
var count := 0
|
||||||
|
for r in range(rows):
|
||||||
|
for c in range(columns):
|
||||||
|
if _get_cell_module(c, r) != null:
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# Grid rebuild
|
# Grid rebuild
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|
@ -313,7 +383,12 @@ func _rebuild_grid() -> void:
|
||||||
return
|
return
|
||||||
|
|
||||||
var new_cols := maxi(1, int(avail.x / (cell_min_size.x + cell_spacing)))
|
var new_cols := maxi(1, int(avail.x / (cell_min_size.x + cell_spacing)))
|
||||||
var new_rows := maxi(1, int(avail.y / (cell_min_size.y + cell_spacing)))
|
|
||||||
|
# Ensure enough rows for all current modules after column change
|
||||||
|
var module_count := _count_modules_in_grid()
|
||||||
|
var min_rows := maxi(1, ceili(float(module_count) / float(new_cols)))
|
||||||
|
var avail_rows := maxi(1, int(avail.y / (cell_min_size.y + cell_spacing)))
|
||||||
|
var new_rows := maxi(avail_rows, min_rows)
|
||||||
|
|
||||||
if new_cols == columns and new_rows == rows and _cells.size() > 0:
|
if new_cols == columns and new_rows == rows and _cells.size() > 0:
|
||||||
_layout_cells()
|
_layout_cells()
|
||||||
|
|
@ -419,20 +494,33 @@ func _save_modules() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _restore_modules() -> void:
|
func _restore_modules() -> void:
|
||||||
|
# Collect modules in insertion order (row-major from _save_modules)
|
||||||
|
var module_list: Array[Control] = []
|
||||||
for key in _module_positions:
|
for key in _module_positions:
|
||||||
var parts: PackedStringArray = key.split(",")
|
module_list.append(_module_positions[key])
|
||||||
var col: int = int(parts[0])
|
|
||||||
var row := int(parts[1])
|
|
||||||
var module: Control = _module_positions[key]
|
|
||||||
|
|
||||||
if _is_valid_cell(col, row):
|
|
||||||
_place_module_in_cell(module, col, row)
|
|
||||||
else:
|
|
||||||
if _cells.size() > 0 and _cells[0].size() > 0:
|
|
||||||
var last_row := _cells.size() - 1
|
|
||||||
var last_col: int = _cells[last_row].size() - 1
|
|
||||||
_place_module_in_cell(module, last_col, last_row)
|
|
||||||
else:
|
|
||||||
module.queue_free()
|
|
||||||
|
|
||||||
_module_positions.clear()
|
_module_positions.clear()
|
||||||
|
|
||||||
|
if module_list.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Reflow onto the new grid dimensions
|
||||||
|
var module_count := module_list.size()
|
||||||
|
var needed := maxi(rows, ceili(float(module_count) / float(columns)))
|
||||||
|
while _cells.size() < needed:
|
||||||
|
var new_row := _cells.size()
|
||||||
|
_cells.append([])
|
||||||
|
for col in range(columns):
|
||||||
|
var cell := PanelContainer.new()
|
||||||
|
cell.name = "Cell_%d_%d" % [col, new_row]
|
||||||
|
cell.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
|
_style_cell(cell, col, new_row)
|
||||||
|
add_child(cell)
|
||||||
|
_cells[new_row].append(cell)
|
||||||
|
rows = _cells.size()
|
||||||
|
|
||||||
|
for i in range(module_list.size()):
|
||||||
|
var c := i % columns
|
||||||
|
var r := floori(i / columns)
|
||||||
|
if _is_valid_cell(c, r):
|
||||||
|
_place_module_in_cell(module_list[i], c, r)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue