refactor: sticky reclaim state unified into fewer functions
This commit is contained in:
parent
6def38a166
commit
0b1c726c2e
|
|
@ -206,7 +206,7 @@ func populate_board(card_names: Array[StringName]):
|
||||||
# marking the first card as random picks
|
# marking the first card as random picks
|
||||||
new_card.picked_random = new_card.name == card_names[1]
|
new_card.picked_random = new_card.name == card_names[1]
|
||||||
for new_sticky_note: StickyNote in all_new["sticky_notes"]: # spawning a sticky note
|
for new_sticky_note: StickyNote in all_new["sticky_notes"]: # spawning a sticky note
|
||||||
add_sticky_note(new_sticky_note, false)
|
reclaim_sticky_to_panel(new_sticky_note, false)
|
||||||
# marking the first sticky as random picks
|
# marking the first sticky as random picks
|
||||||
new_sticky_note.picked_random = new_sticky_note.name == card_names[3]
|
new_sticky_note.picked_random = new_sticky_note.name == card_names[3]
|
||||||
|
|
||||||
|
|
@ -265,13 +265,39 @@ func add_card(card: Card, re_parent:bool = true):
|
||||||
card.set_owner(self)
|
card.set_owner(self)
|
||||||
card.is_dragable = true
|
card.is_dragable = true
|
||||||
|
|
||||||
func add_sticky_note(sticky: StickyNote, re_parent:bool = true):
|
## Unified function to reclaim any sticky note to a panel
|
||||||
var new_panel := StickyNotePanel.new()
|
## Handles ALL scenarios: initial setup, drag-drop, exchanges, keyboard navigation
|
||||||
sticky_note_container.add_child(new_panel, true, Node.INTERNAL_MODE_DISABLED)
|
func reclaim_sticky_to_panel(sticky: StickyNote, animate: bool = true, prefer_panel_index: int = -1) -> void:
|
||||||
#WARNING this for some reason would break the tweens
|
# Find or create target panel
|
||||||
new_panel.set_owner(self)
|
var target_panel: StickyNotePanel = null
|
||||||
sticky.current_handle = self
|
|
||||||
new_panel.attatch_sticky_note(sticky, self, false, re_parent)
|
# Try preferred panel first (for exchanges)
|
||||||
|
if prefer_panel_index >= 0 and prefer_panel_index < sticky_note_container.get_child_count():
|
||||||
|
var panel = sticky_note_container.get_child(prefer_panel_index)
|
||||||
|
if panel is StickyNotePanel and panel.is_empty():
|
||||||
|
target_panel = panel
|
||||||
|
|
||||||
|
# Find any empty panel
|
||||||
|
if not target_panel:
|
||||||
|
for panel in sticky_note_container.get_children():
|
||||||
|
if panel is StickyNotePanel and panel.is_empty():
|
||||||
|
target_panel = panel
|
||||||
|
break
|
||||||
|
|
||||||
|
# Create new panel if needed
|
||||||
|
if not target_panel:
|
||||||
|
target_panel = StickyNotePanel.new()
|
||||||
|
sticky_note_container.add_child(target_panel, true, Node.INTERNAL_MODE_DISABLED)
|
||||||
|
target_panel.set_owner(self)
|
||||||
|
|
||||||
|
# Attach sticky to panel (handles all state setup and animation)
|
||||||
|
target_panel.attatch_sticky_note(sticky, self, animate)
|
||||||
|
|
||||||
|
# Clean up other empty panels
|
||||||
|
if animate: # Only clean up during interactive use, not initial setup
|
||||||
|
for panel in sticky_note_container.get_children():
|
||||||
|
if panel is StickyNotePanel and panel != target_panel:
|
||||||
|
panel.clear_if_empty()
|
||||||
|
|
||||||
# Checks if a Node is currently inside the dropzone
|
# Checks if a Node is currently inside the dropzone
|
||||||
func is_in_dropzone(to_check: Node) -> bool:
|
func is_in_dropzone(to_check: Node) -> bool:
|
||||||
|
|
@ -316,13 +342,17 @@ func _end_drag(draggable: Draggable) -> void:
|
||||||
|
|
||||||
# Handle exchange result (sticky swapped with card's sticky)
|
# Handle exchange result (sticky swapped with card's sticky)
|
||||||
if result == Draggable.DropResult.EXCHANGED:
|
if result == Draggable.DropResult.EXCHANGED:
|
||||||
_handle_sticky_exchange(draggable, drop_target)
|
var old_sticky = (drop_target as Card).get_last_exchanged_sticky()
|
||||||
|
if old_sticky:
|
||||||
|
# Return exchanged sticky to panel where new one came from (if applicable)
|
||||||
|
var prefer_panel = current_sticky_note_id if (draggable as StickyNote)._came_from_panel else -1
|
||||||
|
reclaim_sticky_to_panel(old_sticky, true, prefer_panel)
|
||||||
# If sticky was dropped on board (not card), reclaim it to panel with animation
|
# If sticky was dropped on board (not card), reclaim it to panel with animation
|
||||||
elif result == Draggable.DropResult.ACCEPTED and draggable is StickyNote and drop_target == self:
|
elif result == Draggable.DropResult.ACCEPTED and draggable is StickyNote and drop_target == self:
|
||||||
_reclaim_sticky_to_panel(draggable)
|
reclaim_sticky_to_panel(draggable, true)
|
||||||
elif draggable is StickyNote and not is_in_dropzone(draggable):
|
elif draggable is StickyNote and not is_in_dropzone(draggable):
|
||||||
# Sticky dropped in panel area but no empty panel found - reclaim to panel
|
# Sticky dropped in panel area - reclaim to panel with animation
|
||||||
_reclaim_sticky_to_panel(draggable)
|
reclaim_sticky_to_panel(draggable, true)
|
||||||
else:
|
else:
|
||||||
# Fallback: use default board drop (for cards)
|
# Fallback: use default board drop (for cards)
|
||||||
handle_drop(draggable)
|
handle_drop(draggable)
|
||||||
|
|
@ -337,85 +367,6 @@ func _end_drag(draggable: Draggable) -> void:
|
||||||
check_board_comnpletion()
|
check_board_comnpletion()
|
||||||
|
|
||||||
|
|
||||||
## Handles the exchange when a sticky is dropped on a card that already has one
|
|
||||||
## The exchanged sticky always goes to the sticky_note_container (panel zone)
|
|
||||||
func _handle_sticky_exchange(new_sticky: StickyNote, card: Card) -> void:
|
|
||||||
var old_sticky = card.get_last_exchanged_sticky()
|
|
||||||
|
|
||||||
if not old_sticky:
|
|
||||||
push_warning("CardBoard: Exchange occurred but no sticky returned")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Reset visual state for old sticky
|
|
||||||
old_sticky.rotation = 0.0
|
|
||||||
old_sticky.scale = Vector2.ONE
|
|
||||||
old_sticky.z_index = 0
|
|
||||||
|
|
||||||
# Exchanged sticky always goes to sticky_note_container with smooth animation
|
|
||||||
if new_sticky._came_from_panel and sticky_note_container.get_child_count() > 0:
|
|
||||||
# New sticky came from panel - return old sticky to that panel (swap positions)
|
|
||||||
var target_panel = sticky_note_container.get_child(current_sticky_note_id)
|
|
||||||
old_sticky.reparent(dropzone)
|
|
||||||
old_sticky.on_board = true
|
|
||||||
old_sticky.attached_to = dropzone.get_parent() # Detach from card, attach to board temporarily
|
|
||||||
target_panel.attached_sticky_note = old_sticky
|
|
||||||
# Use reclaim to smoothly animate the sticky back to the panel
|
|
||||||
target_panel.reclaim_sticky_note()
|
|
||||||
else:
|
|
||||||
# New sticky was loose - reclaim old sticky to new panel with animation
|
|
||||||
_reclaim_sticky_to_panel(old_sticky)
|
|
||||||
|
|
||||||
# Clean up empty panel if the new sticky came from one
|
|
||||||
if new_sticky._came_from_panel and sticky_note_container.get_child_count() > 0:
|
|
||||||
sticky_note_container.get_child(current_sticky_note_id).clear_if_empty()
|
|
||||||
|
|
||||||
|
|
||||||
## Smoothly reclaims a sticky note to a panel (creates one if needed)
|
|
||||||
func _reclaim_sticky_to_panel(sticky: StickyNote) -> void:
|
|
||||||
var target_panel: StickyNotePanel = null
|
|
||||||
|
|
||||||
# Try to find or create an appropriate panel
|
|
||||||
if sticky._came_from_panel and current_sticky_note_id < sticky_note_container.get_child_count():
|
|
||||||
# Try to use the panel the sticky came from
|
|
||||||
var original_panel = sticky_note_container.get_child(current_sticky_note_id)
|
|
||||||
if original_panel is StickyNotePanel and original_panel.is_empty():
|
|
||||||
target_panel = original_panel
|
|
||||||
|
|
||||||
# If no reusable panel, find any empty one
|
|
||||||
if not target_panel:
|
|
||||||
for panel in sticky_note_container.get_children():
|
|
||||||
if panel is StickyNotePanel and panel.is_empty():
|
|
||||||
target_panel = panel
|
|
||||||
break
|
|
||||||
|
|
||||||
# Create new panel if needed
|
|
||||||
if not target_panel:
|
|
||||||
target_panel = StickyNotePanel.new()
|
|
||||||
sticky_note_container.add_child(target_panel, true, Node.INTERNAL_MODE_DISABLED)
|
|
||||||
target_panel.set_owner(self)
|
|
||||||
|
|
||||||
# Ensure sticky is in dropzone temporarily (for smooth animation from board to panel)
|
|
||||||
if sticky.get_parent() != dropzone:
|
|
||||||
sticky.reparent(dropzone)
|
|
||||||
sticky.on_board = true
|
|
||||||
sticky.attached_to = self
|
|
||||||
sticky.current_handle = self
|
|
||||||
|
|
||||||
# Reset visual state
|
|
||||||
sticky.rotation = 0.0
|
|
||||||
sticky.scale = Vector2.ONE
|
|
||||||
sticky.z_index = 0
|
|
||||||
|
|
||||||
# Set panel reference and trigger smooth reclaim animation
|
|
||||||
target_panel.attached_sticky_note = sticky
|
|
||||||
target_panel.reclaim_sticky_note()
|
|
||||||
|
|
||||||
# Clean up other empty panels
|
|
||||||
for panel in sticky_note_container.get_children():
|
|
||||||
if panel is StickyNotePanel and panel != target_panel:
|
|
||||||
panel.clear_if_empty()
|
|
||||||
|
|
||||||
|
|
||||||
## Updates focus and navigation state after a drop
|
## Updates focus and navigation state after a drop
|
||||||
func _update_focus_after_drop(draggable: Draggable) -> void:
|
func _update_focus_after_drop(draggable: Draggable) -> void:
|
||||||
# Update focus based on where the item ended up
|
# Update focus based on where the item ended up
|
||||||
|
|
@ -427,7 +378,10 @@ func _update_focus_after_drop(draggable: Draggable) -> void:
|
||||||
func _return_sticky_notes_to_panels() -> void:
|
func _return_sticky_notes_to_panels() -> void:
|
||||||
if not (current_context == ASSIGN and focus_stickies): return #FIXME this is an early return to prevent race conditions. Check if it is save to be removed.
|
if not (current_context == ASSIGN and focus_stickies): return #FIXME this is an early return to prevent race conditions. Check if it is save to be removed.
|
||||||
for panel:StickyNotePanel in sticky_note_container.get_children():
|
for panel:StickyNotePanel in sticky_note_container.get_children():
|
||||||
panel.reclaim_sticky_note()
|
if panel is StickyNotePanel and panel.attached_sticky_note:
|
||||||
|
# Reclaim if sticky is not already in the panel
|
||||||
|
if panel.attached_sticky_note.get_parent() != panel:
|
||||||
|
panel.attatch_sticky_note(panel.attached_sticky_note, self, true)
|
||||||
|
|
||||||
for node in dropzone.get_children():
|
for node in dropzone.get_children():
|
||||||
if node is StickyNote:
|
if node is StickyNote:
|
||||||
|
|
@ -633,7 +587,9 @@ func _input(event) -> void:
|
||||||
if current_context == NAVIGATE:
|
if current_context == NAVIGATE:
|
||||||
focus_stickies = true
|
focus_stickies = true
|
||||||
elif current_context == ASSIGN:
|
elif current_context == ASSIGN:
|
||||||
sticky_note_container.get_children()[current_sticky_note_id].reclaim_sticky_note()
|
var panel = sticky_note_container.get_children()[current_sticky_note_id]
|
||||||
|
if panel is StickyNotePanel and panel.attached_sticky_note:
|
||||||
|
reclaim_sticky_to_panel(panel.attached_sticky_note, true, current_sticky_note_id)
|
||||||
current_context = NAVIGATE
|
current_context = NAVIGATE
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
@ -682,14 +638,14 @@ func _input(event) -> void:
|
||||||
current_dropzone_id = find_first_free_card()
|
current_dropzone_id = find_first_free_card()
|
||||||
else:
|
else:
|
||||||
if currently_active_node is StickyNote:
|
if currently_active_node is StickyNote:
|
||||||
add_sticky_note(currently_active_node)
|
reclaim_sticky_to_panel(currently_active_node, true)
|
||||||
current_sticky_note_id = sticky_note_container.get_child_count()-1
|
current_sticky_note_id = sticky_note_container.get_child_count()-1
|
||||||
current_context = ASSIGN
|
current_context = ASSIGN
|
||||||
focus_stickies = false
|
focus_stickies = false
|
||||||
if currently_active_node is Card:
|
if currently_active_node is Card:
|
||||||
if currently_active_node.has_sticky_note_attached():
|
if currently_active_node.has_sticky_note_attached():
|
||||||
currently_active_node = currently_active_node.remove_sticky_note()
|
currently_active_node = currently_active_node.remove_sticky_note()
|
||||||
add_sticky_note(currently_active_node)
|
reclaim_sticky_to_panel(currently_active_node, true)
|
||||||
current_sticky_note_id = sticky_note_container.get_child_count()-1
|
current_sticky_note_id = sticky_note_container.get_child_count()-1
|
||||||
focus_stickies = true
|
focus_stickies = true
|
||||||
else:
|
else:
|
||||||
|
|
@ -847,7 +803,7 @@ func initialise_from_save(savegame: SaveGame) -> void:
|
||||||
for sticky: StickyNote in card_pile["sticky_notes"]:
|
for sticky: StickyNote in card_pile["sticky_notes"]:
|
||||||
# Check if sticky is in panel
|
# Check if sticky is in panel
|
||||||
if savegame.board_in_panel.has(sticky.name):
|
if savegame.board_in_panel.has(sticky.name):
|
||||||
add_sticky_note(sticky, false)
|
reclaim_sticky_to_panel(sticky, false)
|
||||||
print_debug(" Sticky '%s' added to panel" % sticky.name)
|
print_debug(" Sticky '%s' added to panel" % sticky.name)
|
||||||
|
|
||||||
# Check if sticky is attached to a card
|
# Check if sticky is attached to a card
|
||||||
|
|
@ -862,7 +818,7 @@ func initialise_from_save(savegame: SaveGame) -> void:
|
||||||
print_debug(" Sticky '%s' attached to card '%s'" % [sticky.name, card_name])
|
print_debug(" Sticky '%s' attached to card '%s'" % [sticky.name, card_name])
|
||||||
else:
|
else:
|
||||||
push_warning("CardBoard: Sticky '%s' attached to non-existent card '%s', adding to panel" % [sticky.name, card_name])
|
push_warning("CardBoard: Sticky '%s' attached to non-existent card '%s', adding to panel" % [sticky.name, card_name])
|
||||||
add_sticky_note(sticky, false)
|
reclaim_sticky_to_panel(sticky, false)
|
||||||
|
|
||||||
# Sticky is loose on board
|
# Sticky is loose on board
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -18,35 +18,50 @@ func _ready():
|
||||||
custom_minimum_size = Vector2(custom_minimum_size.x, 0)
|
custom_minimum_size = Vector2(custom_minimum_size.x, 0)
|
||||||
|
|
||||||
var is_attatching: bool = false
|
var is_attatching: bool = false
|
||||||
func attatch_sticky_note(attatchment: StickyNote, custom_owner: Node, tween:bool = true, re_parent:bool = true):
|
func attatch_sticky_note(attatchment: StickyNote, custom_owner: Node, animate:bool = true):
|
||||||
is_attatching = true
|
is_attatching = true
|
||||||
attatchment.on_board = false
|
|
||||||
attached_sticky_note = attatchment
|
attached_sticky_note = attatchment
|
||||||
attatchment.attached_to = null
|
attatchment.current_handle = custom_owner
|
||||||
if tween:
|
attatchment.owner = custom_owner
|
||||||
await get_tree().process_frame
|
|
||||||
|
# Expand panel height
|
||||||
|
if animate:
|
||||||
var height_tween: Tween = create_tween()
|
var height_tween: Tween = create_tween()
|
||||||
height_tween.tween_property(self, "custom_minimum_size", minimum_size, 0.1)
|
height_tween.tween_property(self, "custom_minimum_size", minimum_size, 0.1)
|
||||||
var target_post := get_global_transform().origin+ancor_position
|
|
||||||
for panel: StickyNotePanel in get_parent().get_children():
|
|
||||||
if panel.attached_sticky_note == attatchment and panel.get_index() < get_index():
|
|
||||||
target_post = get_global_transform().origin+ancor_position - Vector2(0, minimum_size.y)
|
|
||||||
attatchment.tween_transform_to(Transform2D(0, target_post))
|
|
||||||
await attatchment.transform_tween_finished
|
|
||||||
await get_tree().process_frame
|
|
||||||
attatchment.reparent(self)
|
|
||||||
attatchment.position = ancor_position
|
|
||||||
else:
|
else:
|
||||||
custom_minimum_size = minimum_size
|
custom_minimum_size = minimum_size
|
||||||
if re_parent:
|
|
||||||
|
# Position sticky
|
||||||
|
if animate:
|
||||||
|
await get_tree().process_frame
|
||||||
|
attatchment.on_board = false
|
||||||
|
attatchment.z_index = 125 # On top during animation
|
||||||
|
|
||||||
|
# Reparent while keeping world position for smooth animation
|
||||||
|
attatchment.reparent(self, true)
|
||||||
|
attatchment.attached_to = self
|
||||||
|
|
||||||
|
# Tween to anchor position in panel's coordinate space
|
||||||
|
var tween := create_tween().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_BACK)
|
||||||
|
tween.tween_property(attatchment, "position", ancor_position, 0.7)
|
||||||
|
tween.tween_property(attatchment, "rotation", 0.0, 0.7)
|
||||||
|
tween.parallel().tween_property(attatchment, "scale", Vector2.ONE, 0.7)
|
||||||
|
await tween.finished
|
||||||
|
|
||||||
|
attatchment.z_index = 0
|
||||||
|
else:
|
||||||
|
# Immediate placement (for initial board setup)
|
||||||
|
if attatchment.get_parent():
|
||||||
attatchment.reparent(self)
|
attatchment.reparent(self)
|
||||||
else:
|
else:
|
||||||
add_child(attatchment)
|
add_child(attatchment)
|
||||||
attatchment.position = ancor_position
|
attatchment.on_board = false
|
||||||
is_attatching = false
|
|
||||||
attatchment.owner = custom_owner
|
|
||||||
attatchment.attached_to = self
|
attatchment.attached_to = self
|
||||||
attatchment.current_handle = custom_owner
|
attatchment.position = ancor_position
|
||||||
|
attatchment.rotation = 0.0
|
||||||
|
attatchment.scale = Vector2.ONE
|
||||||
|
|
||||||
|
is_attatching = false
|
||||||
|
|
||||||
|
|
||||||
var is_gapped: bool = false
|
var is_gapped: bool = false
|
||||||
|
|
@ -69,29 +84,6 @@ func collapse_gap():
|
||||||
var height_tween: Tween = create_tween()
|
var height_tween: Tween = create_tween()
|
||||||
height_tween.tween_property(self, "custom_minimum_size", minimum_size, 0.1)
|
height_tween.tween_property(self, "custom_minimum_size", minimum_size, 0.1)
|
||||||
|
|
||||||
func reclaim_sticky_note() -> bool:
|
|
||||||
# Don't reclaim if sticky is already attached to this panel (prevents double reclaim)
|
|
||||||
if is_empty() and attached_sticky_note.attached_to != self and attached_sticky_note.attached_to is not Card:
|
|
||||||
is_attatching = true
|
|
||||||
attached_sticky_note.on_board = false
|
|
||||||
|
|
||||||
attached_sticky_note.z_index = 125 # Make sure it's on top of all other stickies'
|
|
||||||
# Reparent while keeping world position (global transform)
|
|
||||||
attached_sticky_note.reparent(self, true)
|
|
||||||
attached_sticky_note.attached_to = self
|
|
||||||
attached_sticky_note.owner = self.owner
|
|
||||||
|
|
||||||
# Tween from current position to target anchor position in panel's coordinate space
|
|
||||||
var tween := create_tween().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_BACK)
|
|
||||||
tween.tween_property(attached_sticky_note, "position", ancor_position, 0.7)
|
|
||||||
await tween.finished
|
|
||||||
|
|
||||||
attached_sticky_note.z_index = 0
|
|
||||||
|
|
||||||
is_attatching = false
|
|
||||||
return true
|
|
||||||
return false
|
|
||||||
|
|
||||||
var invalid: bool = false
|
var invalid: bool = false
|
||||||
func clear_if_empty():
|
func clear_if_empty():
|
||||||
if !is_empty(): return
|
if !is_empty(): return
|
||||||
|
|
@ -122,8 +114,8 @@ func handle_drop(draggable: StickyNote) -> int:
|
||||||
if not can_accept_drop(draggable):
|
if not can_accept_drop(draggable):
|
||||||
return Draggable.DropResult.REJECTED
|
return Draggable.DropResult.REJECTED
|
||||||
|
|
||||||
# Attach sticky to this panel
|
# Attach sticky to this panel with animation
|
||||||
attatch_sticky_note(draggable, owner, true, true)
|
attatch_sticky_note(draggable, owner, true)
|
||||||
|
|
||||||
# Clean up other empty panels
|
# Clean up other empty panels
|
||||||
for panel in get_parent().get_children():
|
for panel in get_parent().get_children():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue