Add new test file for phase 19 scenery with unique identifier
This commit is contained in:
@@ -10,7 +10,10 @@ var _dragging: bool = false
|
||||
var _drag_threshold: float = 8.0
|
||||
var _icon: TextureRect = null
|
||||
var _glyph: Label = null
|
||||
var _box: VBoxContainer = null
|
||||
var _label: Label = null
|
||||
var _description: Label = null
|
||||
var _status_label: Label = null
|
||||
|
||||
func configure(payload: Dictionary, icon_texture: Texture2D = null, theme: Variant = null) -> void:
|
||||
_payload = payload.duplicate(true)
|
||||
@@ -25,11 +28,55 @@ func configure(payload: Dictionary, icon_texture: Texture2D = null, theme: Varia
|
||||
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)
|
||||
_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)
|
||||
var description: String = String(_payload.get("description", ""))
|
||||
var status: String = String(_payload.get("status", ""))
|
||||
if not status.is_empty():
|
||||
_status_label = Label.new()
|
||||
_status_label.name = "StatusLabel"
|
||||
_status_label.text = status
|
||||
_status_label.custom_minimum_size = Vector2(0.0, 22.0)
|
||||
_status_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
_status_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
_status_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_status_label.add_theme_font_size_override("font_size", 16)
|
||||
_status_label.add_theme_color_override("font_color", _payload.get("status_color", Color.WHITE))
|
||||
_status_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_box.add_child(_status_label)
|
||||
if not description.is_empty():
|
||||
_description = Label.new()
|
||||
_description.text = description
|
||||
_description.custom_minimum_size = Vector2(0.0, 34.0)
|
||||
_description.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
_description.vertical_alignment = VERTICAL_ALIGNMENT_TOP
|
||||
_description.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_description.max_lines_visible = 2
|
||||
_description.add_theme_font_size_override("font_size", 14)
|
||||
_description.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_box.add_child(_description)
|
||||
|
||||
|
||||
func set_preview_control(preview: Control) -> void:
|
||||
if preview == null or _box == null:
|
||||
return
|
||||
var preview_size: Vector2 = _icon.custom_minimum_size if _icon != null else Vector2(64.0, 64.0)
|
||||
if _icon != null and _icon.get_parent() == _box:
|
||||
_box.remove_child(_icon)
|
||||
_icon.queue_free()
|
||||
_icon = null
|
||||
if _glyph != null and _glyph.get_parent() == _box:
|
||||
_box.remove_child(_glyph)
|
||||
_glyph.queue_free()
|
||||
_glyph = null
|
||||
preview.custom_minimum_size = preview_size
|
||||
preview.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
preview.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_box.add_child(preview)
|
||||
_box.move_child(preview, 0)
|
||||
|
||||
func set_thumbnail(texture: Texture2D) -> void:
|
||||
if _icon != null: _icon.texture = texture; _icon.visible = texture != null
|
||||
@@ -38,8 +85,20 @@ func set_thumbnail(texture: Texture2D) -> void:
|
||||
func thumbnail_rect() -> TextureRect:
|
||||
return _icon
|
||||
|
||||
func set_selected(selected: bool) -> void:
|
||||
button_pressed = selected
|
||||
func set_selected(selected: bool, selected_surface: Color = Color("#12394A"), selected_border: Color = Color("#22C6FF")) -> void:
|
||||
toggle_mode = true
|
||||
set_pressed_no_signal(selected)
|
||||
if not selected:
|
||||
return
|
||||
var selected_style := StyleBoxFlat.new()
|
||||
selected_style.bg_color = selected_surface
|
||||
selected_style.border_color = selected_border
|
||||
selected_style.set_border_width_all(3)
|
||||
selected_style.set_corner_radius_all(8)
|
||||
add_theme_stylebox_override("normal", selected_style)
|
||||
add_theme_stylebox_override("pressed", selected_style)
|
||||
add_theme_stylebox_override("hover", selected_style)
|
||||
add_theme_stylebox_override("hover_pressed", selected_style)
|
||||
|
||||
func payload() -> Dictionary:
|
||||
return _payload.duplicate(true)
|
||||
|
||||
@@ -5,6 +5,8 @@ signal item_selected(entry: Dictionary)
|
||||
signal cancelled()
|
||||
signal browse_requested()
|
||||
signal refresh_requested()
|
||||
signal make_artwork_requested()
|
||||
signal edit_scenery_requested()
|
||||
|
||||
const COLUMNS := 4
|
||||
const ROWS := 3
|
||||
@@ -13,6 +15,8 @@ const PAGE_SIZE := COLUMNS * ROWS
|
||||
const CELL_MIN_SIZE := Vector2(190.0, 220.0)
|
||||
const THUMB_SIZE := Vector2(156.0, 156.0)
|
||||
const ASSET_CARD := preload("res://scripts/shared/ui/asset_card.gd")
|
||||
const BACKGROUND_CARD_PREVIEW := preload("res://scripts/stage/scenery/stage_background_card_preview.gd")
|
||||
const STARTER_CARD_PREVIEW := preload("res://scripts/stage/scenery/stage_starter_card_preview.gd")
|
||||
|
||||
var kind: String = ""
|
||||
|
||||
@@ -24,6 +28,10 @@ var _placeholder_tex: ImageTexture = null
|
||||
var _ui_font: Font = null
|
||||
var _emoji_font: Font = null
|
||||
var _sandbox_theme: Variant = null
|
||||
var _gallery_tab: String = "backgrounds"
|
||||
var _tag_id: String = "all"
|
||||
var _current_sky_id: String = ""
|
||||
var _sky_card_group: ButtonGroup
|
||||
|
||||
@onready var _title_label: Label = %TitleLabel
|
||||
@onready var _grid: GridContainer = %GridContainer
|
||||
@@ -34,15 +42,29 @@ var _sandbox_theme: Variant = null
|
||||
@onready var _browse_button: Button = %BrowseButton
|
||||
@onready var _refresh_button: Button = %RefreshButton
|
||||
@onready var _close_button: Button = %CloseButton
|
||||
@onready var _tabs: HBoxContainer = %GalleryTabs
|
||||
@onready var _backgrounds_tab: Button = %BackgroundsTab
|
||||
@onready var _artwork_tab: Button = %ArtworkTab
|
||||
@onready var _tag_filter: OptionButton = %TagFilter
|
||||
@onready var _make_artwork_button: Button = %MakeArtworkButton
|
||||
@onready var _edit_scenery_button: Button = %EditSceneryButton
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
exclusive = true
|
||||
if _tag_filter.item_count == 0:
|
||||
for label: String in ["All artwork", "Nature", "Buildings", "Walls", "Roads", "Objects"]:
|
||||
_tag_filter.add_item(label)
|
||||
_prev_button.pressed.connect(_on_prev)
|
||||
_next_button.pressed.connect(_on_next)
|
||||
_browse_button.pressed.connect(func() -> void: browse_requested.emit())
|
||||
_refresh_button.pressed.connect(func() -> void: refresh_requested.emit())
|
||||
_close_button.pressed.connect(func() -> void: cancelled.emit())
|
||||
_backgrounds_tab.pressed.connect(func() -> void: _set_gallery_tab("backgrounds"))
|
||||
_artwork_tab.pressed.connect(func() -> void: _set_gallery_tab("artwork"))
|
||||
_tag_filter.item_selected.connect(_on_tag_filter_selected)
|
||||
_make_artwork_button.pressed.connect(func() -> void: make_artwork_requested.emit())
|
||||
_edit_scenery_button.pressed.connect(func() -> void: edit_scenery_requested.emit())
|
||||
get_tree().root.size_changed.connect(_on_root_size_changed)
|
||||
|
||||
|
||||
@@ -51,13 +73,25 @@ func _on_root_size_changed() -> void:
|
||||
popup_centered()
|
||||
|
||||
|
||||
func open(p_kind: String, entries: Array[Dictionary]) -> void:
|
||||
func open(p_kind: String, entries: Array[Dictionary], current_sky_id: String = "") -> void:
|
||||
kind = p_kind
|
||||
_title_label.text = "Choose Your Stickman" if kind == "stickman" else "Choose a Prop"
|
||||
_browse_button.visible = kind == "stickman" or kind == "prop"
|
||||
_refresh_button.visible = kind == "stickman" or kind == "prop"
|
||||
_empty_label.text = "No props found. Browse for a .prop file." if kind == "prop" else "No stickmen found."
|
||||
_current_sky_id = current_sky_id if kind == "scenery" else ""
|
||||
_title_label.text = "Choose Your Stickman" if kind == "stickman" else ("Choose Scenery" if kind == "scenery" else ("Choose a starter scene" if kind == "starters" else "Choose a Prop"))
|
||||
_tabs.visible = kind == "scenery"
|
||||
_tag_filter.visible = false
|
||||
_make_artwork_button.visible = false
|
||||
_edit_scenery_button.visible = false
|
||||
_browse_button.visible = kind == "stickman" or kind == "prop" or kind == "scenery"
|
||||
_refresh_button.visible = kind == "stickman" or kind == "prop" or kind == "scenery"
|
||||
_empty_label.text = "No scenery found. Choose Make artwork to draw a new piece." if kind == "scenery" else ("No props found. Browse for a .prop file." if kind == "prop" else ("No starter scenes are available." if kind == "starters" else "No stickmen found."))
|
||||
_gallery_tab = "backgrounds"
|
||||
_tag_id = "all"
|
||||
_backgrounds_tab.set_pressed_no_signal(true)
|
||||
_artwork_tab.set_pressed_no_signal(false)
|
||||
_tag_filter.select(0)
|
||||
set_entries(entries)
|
||||
if kind == "scenery":
|
||||
_set_gallery_tab("backgrounds")
|
||||
popup_centered()
|
||||
|
||||
|
||||
@@ -76,6 +110,15 @@ func set_thumbnail(entry: Dictionary, tex: Texture2D) -> void:
|
||||
(_cell_texrects[key] as TextureRect).texture = tex
|
||||
|
||||
|
||||
func set_current_sky(sky_id: StringName) -> void:
|
||||
var next_id: String = String(sky_id)
|
||||
if kind != "scenery" or _current_sky_id == next_id:
|
||||
return
|
||||
_current_sky_id = next_id
|
||||
if _gallery_tab == "backgrounds":
|
||||
_rebuild()
|
||||
|
||||
|
||||
func close() -> void:
|
||||
hide()
|
||||
|
||||
@@ -129,6 +172,42 @@ func _entry_key(entry: Dictionary) -> String:
|
||||
return String(entry.get("id", ""))
|
||||
|
||||
|
||||
func _on_tag_filter_selected(index: int) -> void:
|
||||
var ids: Array[String] = ["all", "nature", "buildings", "walls", "roads", "objects"]
|
||||
_tag_id = ids[clampi(index, 0, ids.size() - 1)]
|
||||
_page = 0
|
||||
_rebuild()
|
||||
|
||||
|
||||
func _set_gallery_tab(tab: String) -> void:
|
||||
_gallery_tab = tab
|
||||
_backgrounds_tab.set_pressed_no_signal(tab == "backgrounds")
|
||||
_artwork_tab.set_pressed_no_signal(tab == "artwork")
|
||||
_tag_filter.visible = kind == "scenery" and tab == "artwork"
|
||||
_make_artwork_button.visible = kind == "scenery" and tab == "artwork"
|
||||
_edit_scenery_button.visible = kind == "scenery"
|
||||
_browse_button.visible = kind == "stickman" or kind == "prop" or (kind == "scenery" and tab == "artwork")
|
||||
_refresh_button.visible = kind == "stickman" or kind == "prop" or (kind == "scenery" and tab == "artwork")
|
||||
_empty_label.text = "No artwork in this group yet." if tab == "artwork" else "Choose a Sky look or wall finish."
|
||||
_page = 0
|
||||
_rebuild()
|
||||
|
||||
|
||||
func _filtered_entries() -> Array[Dictionary]:
|
||||
if kind != "scenery":
|
||||
return _entries
|
||||
var filtered: Array[Dictionary] = []
|
||||
for entry: Dictionary in _entries:
|
||||
if String(entry.get("gallery_tab", "artwork")) != _gallery_tab:
|
||||
continue
|
||||
if _gallery_tab == "artwork" and _tag_id != "all":
|
||||
var tags: Array = entry.get("tags", []) as Array
|
||||
if not tags.has(_tag_id):
|
||||
continue
|
||||
filtered.append(entry)
|
||||
return filtered
|
||||
|
||||
|
||||
func _on_prev() -> void:
|
||||
if _page > 0:
|
||||
_page -= 1
|
||||
@@ -136,36 +215,39 @@ func _on_prev() -> void:
|
||||
|
||||
|
||||
func _on_next() -> void:
|
||||
if (_page + 1) * PAGE_SIZE < _entries.size():
|
||||
if (_page + 1) * PAGE_SIZE < _filtered_entries().size():
|
||||
_page += 1
|
||||
_rebuild()
|
||||
|
||||
|
||||
func _page_count() -> int:
|
||||
if _entries.is_empty():
|
||||
var entries: Array[Dictionary] = _filtered_entries()
|
||||
if entries.is_empty():
|
||||
return 1
|
||||
return int(ceil(float(_entries.size()) / float(PAGE_SIZE)))
|
||||
return int(ceil(float(entries.size()) / float(PAGE_SIZE)))
|
||||
|
||||
|
||||
func _rebuild() -> void:
|
||||
_sky_card_group = ButtonGroup.new()
|
||||
for c: Node in _grid.get_children():
|
||||
c.queue_free()
|
||||
_cell_texrects.clear()
|
||||
_empty_label.visible = _entries.is_empty()
|
||||
_grid.visible = not _entries.is_empty()
|
||||
var filtered: Array[Dictionary] = _filtered_entries()
|
||||
_empty_label.visible = filtered.is_empty()
|
||||
_grid.visible = not filtered.is_empty()
|
||||
var total := _page_count()
|
||||
var single := total <= 1
|
||||
_prev_button.visible = not single
|
||||
_next_button.visible = not single
|
||||
_page_label.visible = not single
|
||||
_prev_button.disabled = _page <= 0
|
||||
_next_button.disabled = (_page + 1) * PAGE_SIZE >= _entries.size()
|
||||
_next_button.disabled = (_page + 1) * PAGE_SIZE >= filtered.size()
|
||||
_page_label.text = "Page %d/%d" % [_page + 1, total]
|
||||
if _entries.is_empty():
|
||||
if filtered.is_empty():
|
||||
return
|
||||
var bounds := page_bounds(_entries.size(), _page)
|
||||
var bounds := page_bounds(filtered.size(), _page)
|
||||
for i: int in range(int(bounds["start"]), int(bounds["end"])):
|
||||
_grid.add_child(_build_cell(_entries[i]))
|
||||
_grid.add_child(_build_cell(filtered[i]))
|
||||
|
||||
|
||||
func _build_cell(entry: Dictionary) -> Control:
|
||||
@@ -173,17 +255,52 @@ func _build_cell(entry: Dictionary) -> Control:
|
||||
var cell: Variant = ASSET_CARD.new()
|
||||
# Selector cells inherit the popup theme. Avoid a per-card state override so
|
||||
# opening a selector never implies that one asset is pre-selected.
|
||||
cell.configure({"placement_id": _entry_key(entry), "label": String(entry.get("name", entry.get("id", ""))), "icon": "", "category": String(entry.get("material_label", "")), "thumbnail_size": _thumbnail_size}, _thumbnails.get(key, null), null)
|
||||
cell.custom_minimum_size = _cell_min_size
|
||||
cell.focus_mode = Control.FOCUS_NONE
|
||||
var categories: Array = entry.get("tags", []) as Array
|
||||
var category: String = ", ".join(PackedStringArray(categories)) if not categories.is_empty() else String(entry.get("category", entry.get("material_label", "")))
|
||||
var card_size: Vector2 = _cell_min_size
|
||||
var thumb_size: Vector2 = _thumbnail_size
|
||||
if kind == "starters":
|
||||
card_size.y = maxf(card_size.y, 248.0)
|
||||
thumb_size = Vector2(128.0, 128.0)
|
||||
var card_payload: Dictionary = {"placement_id": _entry_key(entry), "label": String(entry.get("name", entry.get("id", ""))), "icon": String(entry.get("icon", "")), "category": category, "description": String(entry.get("description", "")), "thumbnail_size": thumb_size}
|
||||
if entry.has("background_kind"):
|
||||
card_payload["background_kind"] = entry["background_kind"]
|
||||
card_payload["finish_id"] = entry.get("finish_id", "")
|
||||
card_payload["id"] = entry.get("id", "")
|
||||
var is_sky_choice: bool = String(entry.get("background_kind", "")) == "sky"
|
||||
var is_current_sky: bool = is_sky_choice and String(entry.get("id", "")) == _current_sky_id
|
||||
if is_current_sky:
|
||||
card_payload["status"] = "Current Sky"
|
||||
card_payload["status_color"] = _theme_color("mode_colors.edit", Color("#22C6FF"))
|
||||
cell.configure(card_payload, _thumbnails.get(key, null), null)
|
||||
cell.custom_minimum_size = card_size
|
||||
cell.focus_mode = Control.FOCUS_ALL
|
||||
cell.activated.connect(func(_payload: Dictionary) -> void: _on_cell_pressed(entry))
|
||||
if is_sky_choice:
|
||||
cell.button_group = _sky_card_group
|
||||
cell.set_selected(is_current_sky, _theme_color("stage_panels.choice.selected_surface", Color("#12394A")), _theme_color("mode_colors.edit", Color("#22C6FF")))
|
||||
var tex: Texture2D = _thumbnails.get(key, null)
|
||||
cell.set_thumbnail(tex if tex != null else _get_placeholder())
|
||||
_cell_texrects[key] = cell.thumbnail_rect()
|
||||
if kind == "starters":
|
||||
var preview: Control = STARTER_CARD_PREVIEW.new() as Control
|
||||
preview.call("configure", entry)
|
||||
cell.set_preview_control(preview)
|
||||
elif entry.has("background_kind"):
|
||||
var preview: StageBackgroundCardPreview = BACKGROUND_CARD_PREVIEW.new() as StageBackgroundCardPreview
|
||||
preview.configure(entry)
|
||||
cell.set_preview_control(preview)
|
||||
else:
|
||||
cell.set_thumbnail(tex if tex != null else _get_placeholder())
|
||||
_cell_texrects[key] = cell.thumbnail_rect()
|
||||
|
||||
return cell
|
||||
|
||||
|
||||
func _theme_color(path: String, fallback: Color) -> Color:
|
||||
if _sandbox_theme != null:
|
||||
return _sandbox_theme.color(path, fallback)
|
||||
return fallback
|
||||
|
||||
|
||||
func _on_cell_pressed(entry: Dictionary) -> void:
|
||||
item_selected.emit(entry)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user