Files
stickman/scripts/ui/asset_card.gd
T
ryan 1a2a43c805 Add reusable UI components for Phase 7 UI Polish
- Introduced `EmojiQuickGrid`, `FontPresetPicker`, and `PresetSizeToggle` classes for emoji selection, font presets, and size toggles respectively.
- Implemented configuration methods for each component to handle dynamic content and theming.
- Created tests for the new components to ensure functionality and integration with the existing UI.
- Added a comprehensive architecture specification for Phase 7 UI Polish detailing scope, implementation, and validation strategies.
- Updated existing theme handling to support new UI elements and ensure consistent styling across the application.
2026-09-18 09:42:48 -04:00

59 lines
3.2 KiB
GDScript

class_name AssetCard
extends Button
signal activated(payload: Dictionary)
signal drag_started(payload: Dictionary)
var _payload: Dictionary = {}
var _press_position: Vector2 = Vector2.ZERO
var _dragging: bool = false
var _drag_threshold: float = 8.0
var _icon: TextureRect = null
var _glyph: Label = null
var _label: Label = null
func configure(payload: Dictionary, icon_texture: Texture2D = null, theme: Variant = null) -> void:
_payload = payload.duplicate(true)
_drag_threshold = theme.number("palette.drag_threshold", 8.0, 1.0, 128.0) if theme != null else 8.0
custom_minimum_size = Vector2(96, 108)
clip_contents = true
if theme != null:
var size_data: Variant = theme.value("palette.card_size", [96, 94])
if size_data is Array and (size_data as Array).size() == 2: custom_minimum_size = Vector2(float(size_data[0]), maxf(108.0, float(size_data[1])))
add_theme_stylebox_override("normal", theme.stylebox("palette"))
var thumbnail_size: Vector2 = _payload.get("thumbnail_size", Vector2(64, 64))
focus_mode = Control.FOCUS_ALL
tooltip_text = String(_payload.get("label", ""))
for child: Node in get_children(): child.queue_free()
var box := VBoxContainer.new(); box.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT); box.mouse_filter = Control.MOUSE_FILTER_IGNORE; box.clip_contents = true
box.alignment = BoxContainer.ALIGNMENT_CENTER; box.add_theme_constant_override("separation", 2); add_child(box)
_icon = TextureRect.new(); _icon.custom_minimum_size = thumbnail_size; _icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE; _icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED; _icon.texture = icon_texture; _icon.visible = icon_texture != null; _icon.mouse_filter = Control.MOUSE_FILTER_IGNORE; box.add_child(_icon)
_glyph = Label.new(); _glyph.text = String(_payload.get("icon", "")); _glyph.visible = icon_texture == null; _glyph.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER; _glyph.mouse_filter = Control.MOUSE_FILTER_IGNORE; _glyph.add_theme_font_size_override("font_size", 30); box.add_child(_glyph)
_label = Label.new(); _label.text = String(_payload.get("label", "")); _label.custom_minimum_size = Vector2(0, 28); _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER; _label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART; _label.clip_text = true; _label.mouse_filter = Control.MOUSE_FILTER_IGNORE; box.add_child(_label)
func set_thumbnail(texture: Texture2D) -> void:
if _icon != null: _icon.texture = texture; _icon.visible = texture != null
if _glyph != null and texture != null: _glyph.visible = false
func thumbnail_rect() -> TextureRect:
return _icon
func set_selected(selected: bool) -> void:
button_pressed = selected
func payload() -> Dictionary:
return _payload.duplicate(true)
func _gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
if event.pressed:
_press_position = event.position; _dragging = false
elif _dragging:
accept_event()
elif event is InputEventMouseMotion and Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and not _dragging:
if event.position.distance_to(_press_position) >= _drag_threshold:
_dragging = true; drag_started.emit(payload()); accept_event()
func _pressed() -> void:
if not _dragging: activated.emit(payload())