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.
This commit is contained in:
+28
-41
@@ -10,8 +10,9 @@ const COLUMNS := 4
|
||||
const ROWS := 3
|
||||
const PAGE_SIZE := COLUMNS * ROWS
|
||||
|
||||
const CELL_MIN_SIZE := Vector2(140.0, 168.0)
|
||||
const THUMB_SIZE := Vector2(120.0, 120.0)
|
||||
const CELL_MIN_SIZE := Vector2(190.0, 220.0)
|
||||
const THUMB_SIZE := Vector2(156.0, 156.0)
|
||||
const ASSET_CARD := preload("res://scripts/ui/asset_card.gd")
|
||||
|
||||
var kind: String = ""
|
||||
|
||||
@@ -22,6 +23,7 @@ var _cell_texrects: Dictionary = {}
|
||||
var _placeholder_tex: ImageTexture = null
|
||||
var _ui_font: Font = null
|
||||
var _emoji_font: Font = null
|
||||
var _sandbox_theme: Variant = null
|
||||
|
||||
@onready var _title_label: Label = %TitleLabel
|
||||
@onready var _grid: GridContainer = %GridContainer
|
||||
@@ -87,6 +89,21 @@ func apply_font(ui_font: Font, emoji_font: Font) -> void:
|
||||
for c: Control in controls:
|
||||
_apply_font_to(c)
|
||||
|
||||
func apply_theme(theme: Variant) -> void:
|
||||
_sandbox_theme = theme
|
||||
if theme != null:
|
||||
self.theme = theme.control_theme()
|
||||
add_theme_stylebox_override("panel", theme.stylebox("popups.asset_selector"))
|
||||
var cell_size: Variant = theme.value("popups.asset_selector.cell_size", CELL_MIN_SIZE)
|
||||
if cell_size is Array and (cell_size as Array).size() == 2:
|
||||
_cell_min_size = Vector2(float(cell_size[0]), float(cell_size[1]))
|
||||
var thumbnail_size: Variant = theme.value("popups.asset_selector.thumbnail_size", THUMB_SIZE)
|
||||
if thumbnail_size is Array and (thumbnail_size as Array).size() == 2:
|
||||
_thumbnail_size = Vector2(float(thumbnail_size[0]), float(thumbnail_size[1]))
|
||||
|
||||
var _cell_min_size: Vector2 = CELL_MIN_SIZE
|
||||
var _thumbnail_size: Vector2 = THUMB_SIZE
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if visible and event is InputEventKey:
|
||||
@@ -152,46 +169,16 @@ func _rebuild() -> void:
|
||||
|
||||
func _build_cell(entry: Dictionary) -> Control:
|
||||
var key := _entry_key(entry)
|
||||
var cell := Button.new()
|
||||
cell.custom_minimum_size = CELL_MIN_SIZE
|
||||
cell.toggle_mode = false
|
||||
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
|
||||
cell.pressed.connect(_on_cell_pressed.bind(entry))
|
||||
|
||||
var vbox := VBoxContainer.new()
|
||||
vbox.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
vbox.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
vbox.add_theme_constant_override("separation", 2)
|
||||
cell.add_child(vbox)
|
||||
|
||||
var tex_rect := TextureRect.new()
|
||||
tex_rect.custom_minimum_size = THUMB_SIZE
|
||||
tex_rect.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
tex_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
tex_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
tex_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
cell.activated.connect(func(_payload: Dictionary) -> void: _on_cell_pressed(entry))
|
||||
var tex: Texture2D = _thumbnails.get(key, null)
|
||||
tex_rect.texture = tex if tex != null else _get_placeholder()
|
||||
vbox.add_child(tex_rect)
|
||||
_cell_texrects[key] = tex_rect
|
||||
|
||||
var name_label := Label.new()
|
||||
name_label.text = String(entry.get("name", ""))
|
||||
name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
name_label.add_theme_font_size_override("font_size", 14)
|
||||
_apply_font_to(name_label)
|
||||
vbox.add_child(name_label)
|
||||
|
||||
if kind == "prop":
|
||||
var badge := Label.new()
|
||||
badge.text = String(entry.get("material_label", ""))
|
||||
badge.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
badge.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
badge.add_theme_font_size_override("font_size", 12)
|
||||
badge.add_theme_color_override("font_color", Color(0.7, 0.7, 0.7, 1.0))
|
||||
_apply_font_to(badge)
|
||||
vbox.add_child(badge)
|
||||
cell.set_thumbnail(tex if tex != null else _get_placeholder())
|
||||
_cell_texrects[key] = cell.thumbnail_rect()
|
||||
|
||||
return cell
|
||||
|
||||
@@ -211,7 +198,7 @@ func _apply_font_to(c: Control) -> void:
|
||||
|
||||
func _get_placeholder() -> ImageTexture:
|
||||
if _placeholder_tex == null:
|
||||
var img := Image.create(THUMB_SIZE.x, THUMB_SIZE.y, false, Image.FORMAT_RGBA8)
|
||||
var img := Image.create(int(_thumbnail_size.x), int(_thumbnail_size.y), false, Image.FORMAT_RGBA8)
|
||||
img.fill(Color(0.16, 0.16, 0.16, 1.0))
|
||||
_placeholder_tex = ImageTexture.create_from_image(img)
|
||||
return _placeholder_tex
|
||||
|
||||
Reference in New Issue
Block a user