frame-of-mind/src/logic-scenes/board/sticky-note.gd

223 lines
7.0 KiB
GDScript3
Raw Normal View History

extends Draggable
2023-10-12 16:25:21 +00:00
class_name StickyNote
var sticky_id
var parent_id
2025-01-31 02:22:07 +00:00
var sibling: StickyNote
var shift_tween: Tween
var modulate_tween: Tween
2025-02-24 15:14:08 +00:00
var attached_to: Node = null:
set(new_attatchement):
attached_to = new_attatchement
# cannot be explicitly typed, as this can be both handled by picker and physics-board
var current_handle: Node
2023-04-19 16:53:24 +00:00
var position_locked: bool = false
2023-09-23 14:19:58 +00:00
signal transform_tween_finished
@onready var background_sprite: AnimatedSprite2D = %BackgroundSprite
2023-04-19 16:53:24 +00:00
@export var text: String = "" :
2024-09-15 09:30:31 +00:00
set (value):
if is_node_ready():
_on_text_updated.call_deferred()
2024-09-15 09:30:31 +00:00
text = value
var content: Node2D
var label: Label
@export var picked_random: bool = false
@export var shift_by: Vector2 = Vector2(-32, 0)
@export_color_no_alpha var highlight_color: Color = Color(1.5, 1.5, 1.5)
@export var highlighted: bool = false:
2024-09-15 09:30:31 +00:00
set(highlight):
if highlight != highlighted:
highlighted = highlight
if is_inside_tree() and is_node_ready():
if modulate_tween: modulate_tween.kill()
if shift_tween: shift_tween.kill()
if highlighted:
2025-03-24 16:07:43 +00:00
modulate_tween = get_tree().create_tween()
2024-09-15 09:30:31 +00:00
modulate_tween.tween_property(self, "modulate", highlight_color, 0.1)
2025-03-24 16:07:43 +00:00
shift_tween = get_tree().create_tween()
shift_tween.tween_property(content, "position", shift_by, 0.2)
2024-09-15 09:30:31 +00:00
else:
modulate_tween = get_tree().create_tween()
modulate_tween.tween_property(self, "modulate", Color(1, 1, 1), 0.3)
shift_tween = get_tree().create_tween()
shift_tween.tween_property(content, "position", Vector2.ZERO, 0.5)
2024-09-15 09:30:31 +00:00
else:
if highlighted:
modulate = Color(1, 1, 1)
else:
modulate = Color(1, 1, 1)
2023-04-19 16:53:24 +00:00
@export var voice_line: AudioStream = null
@export var is_dragable: bool = false
@onready var base_rotation := rotation
@onready var base_scale := scale
2023-07-14 19:36:20 +00:00
var mouse_offset: Vector2
2023-04-19 16:53:24 +00:00
@onready var diameter := 312.0
@export_range(1.0, 10.0) var bounce_speed: float = 8
var on_board: bool = false
2025-02-24 15:14:08 +00:00
func init(sticky_name: String = "sticky_note", card_id: StringName = "-1") -> void:
name = sticky_name
text = sticky_name
2025-05-30 14:10:44 +00:00
parent_id = StringName(card_id.rsplit(".", false, 1)[0])
sticky_id = card_id
2023-04-19 16:53:24 +00:00
func _ready() -> void:
label = $Content/Label
background_sprite = $Content/BackgroundSprite
content = $Content
_on_text_updated.call_deferred()
2025-01-31 02:22:07 +00:00
input_event.connect(_on_input_event)
mouse_entered.connect(_on_mouse_entered)
mouse_exited.connect(_on_mouse_exited)
area_entered.connect(_on_area_enter)
area_exited.connect(_on_area_exit)
func _on_text_updated():
label.text = text
background_sprite.frame = text.hash() % background_sprite.sprite_frames.get_frame_count(background_sprite.animation)
2023-04-19 16:53:24 +00:00
func _process(delta: float) -> void:
2024-09-15 09:30:31 +00:00
if get_overlapping_areas().size() > 0 and is_dragable and on_board:
for area in get_overlapping_areas():
if area is Card or area is CardCollider:
if area is CardCollider:
position += area.direction * delta
elif not area.highlighted or self.highlighted:
2024-09-15 09:30:31 +00:00
var diff:Vector2 = position - area.position
position -= diff.normalized() * ((diff.length()-diameter)/diameter) * bounce_speed * (delta/(1.0/60))
2024-09-15 09:30:31 +00:00
_move_sticky_note()
func _on_mouse_entered():
if not Input.is_action_pressed("mouse_left") and "handle_hover" in current_handle:
current_handle.handle_hover(self)
func _on_mouse_exited():
highlighted = false
# Let parent card re-check hover state if this sticky is attached to it
2025-02-24 15:14:08 +00:00
if is_sticky_note_attached() and "check_hover" in attached_to:
attached_to.check_hover()
2025-01-31 02:22:07 +00:00
func _on_area_enter(area: Area2D):
# Handle sticky note panel gap creation
if area is StickyNote and is_sticky_note_in_panel() and not is_dragged:
2025-02-24 15:14:08 +00:00
attached_to.create_gap()
2025-01-31 02:22:07 +00:00
func _on_area_exit(area: Area2D):
# Handle sticky note panel gap collapse
if area is StickyNote and is_sticky_note_in_panel():
2025-02-24 15:14:08 +00:00
attached_to.collapse_gap()
func _on_input_event(_viewport, event, _shape_idx):
if event is InputEventMouseButton and "handle_mouse_button" in current_handle:
2025-02-24 15:14:08 +00:00
if (event.button_index == MOUSE_BUTTON_LEFT and event.pressed) or event.button_index == MOUSE_BUTTON_RIGHT:
mouse_offset = get_viewport().get_mouse_position() - global_position
current_handle.handle_mouse_button(event, self)
2023-10-12 16:25:21 +00:00
func _move_sticky_note():
2024-09-15 09:30:31 +00:00
if is_dragged:
2026-01-16 19:46:16 +00:00
update_drag_position(get_viewport().get_mouse_position())
2023-10-12 16:25:21 +00:00
func is_sticky_note_attached() -> bool:
2025-05-21 17:42:45 +00:00
# FIXME: this breaks if attatched to is previousely freed because GODOT IS FUCKING STUPID
2025-02-24 15:14:08 +00:00
return attached_to is Card
func is_sticky_note_in_panel() -> bool:
2025-05-21 17:42:45 +00:00
## fixme ~> see above
2025-02-24 15:14:08 +00:00
return attached_to is StickyNotePanel
2023-07-02 13:10:33 +00:00
var transform_tween: Tween
2023-10-12 16:25:21 +00:00
func tween_transform_to(target: Transform2D):
if transform_tween and transform_tween.is_running():
transform_tween.stop()
transform_tween = create_tween()
2024-09-15 09:30:31 +00:00
transform_tween.tween_property(self, "transform", target, 0.25)
2024-09-15 09:30:31 +00:00
await transform_tween.finished
transform_tween_finished.emit()
2023-11-01 22:19:47 +00:00
2026-01-16 19:46:16 +00:00
# === DRAG LIFECYCLE OVERRIDES ===
## Track whether this sticky came from a panel (for exchange logic)
var _came_from_panel: bool = false
## Start drag: if in panel, immediately move to board
func start_drag(offset: Vector2) -> void:
super.start_drag(offset)
_came_from_panel = is_sticky_note_in_panel()
# If attached to a card, detach it first
if is_sticky_note_attached():
var card := attached_to as Card
if card and card.has_method("remove_sticky_note"):
card.remove_sticky_note()
# If in panel, immediately reparent to board for dragging
if _came_from_panel and current_handle:
var board := current_handle
var dropzone := board.get_node_or_null("HBoxContainer/dropzone")
if dropzone:
reparent(dropzone)
else:
reparent(board)
on_board = true
attached_to = board
## Find best drop target: Card > Panel > Board (in priority order)
func find_drop_target() -> Node:
# Priority 1: Check for overlapping cards in dropzone
for area in get_overlapping_areas():
if area is Card and Draggable.is_drop_target(area):
return area
# Priority 2: Check if dropped outside dropzone (over panel area)
if current_handle and not current_handle.is_in_dropzone(self):
var target_panel := _find_nearest_panel()
if target_panel:
return target_panel
# Priority 3: Default to board (stay loose in dropzone)
return current_handle
## Find the nearest panel that can accept this sticky
func _find_nearest_panel() -> StickyNotePanel:
if not current_handle or not current_handle.has_node("HBoxContainer/ScrollContainer/VBoxContainer"):
return null
var panel_container := current_handle.get_node("HBoxContainer/ScrollContainer/VBoxContainer")
var sticky_rect := Rect2(global_position - Vector2(diameter/2, 10), Vector2(diameter/2, 10))
# First pass: look for empty panels we're hovering over
for panel in panel_container.get_children():
if panel is StickyNotePanel:
if panel.is_empty() and panel.get_global_rect().intersects(sticky_rect):
return panel
# Second pass: if no empty panel found, find first empty panel
for panel in panel_container.get_children():
if panel is StickyNotePanel and panel.is_empty():
return panel
# No empty panels found - will need to create one (handled by board)
return null