NEO-122: Fix craft recipe panel scroll and row clipping.
Stack recipe label above Craft button so rows fit panel width, disable horizontal scroll, reset scroll to top on populate, and bump panel height.pull/161/head
parent
b36fe6d863
commit
e041c02959
|
|
@ -1357,7 +1357,7 @@ text = "Gig XP:
|
|||
Loading…"
|
||||
|
||||
[node name="CraftRecipePanel" type="Control" parent="UICanvas/HudRoot/EconomyHudSection/Body" unique_id=9000011]
|
||||
custom_minimum_size = Vector2(656, 320)
|
||||
custom_minimum_size = Vector2(656, 360)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
script = ExtResource("19_craft_panel")
|
||||
|
|
@ -1369,6 +1369,9 @@ anchor_right = 1.0
|
|||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
horizontal_scroll_mode = 0
|
||||
vertical_scroll_mode = 1
|
||||
follow_focus = true
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="UICanvas/HudRoot/EconomyHudSection/Body/CraftRecipePanel/ScrollContainer" unique_id=9000013]
|
||||
layout_mode = 2
|
||||
|
|
|
|||
|
|
@ -5,13 +5,22 @@ extends Control
|
|||
signal craft_requested(recipe_id: String)
|
||||
|
||||
const PrototypeHudTheme := preload("res://scripts/prototype_hud_theme.gd")
|
||||
const HudThemeConstants := preload("res://scripts/prototype_hud_theme_constants.gd")
|
||||
|
||||
var _item_defs_client: Node = null
|
||||
var _craft_buttons: Array[Button] = []
|
||||
|
||||
@onready var _scroll: ScrollContainer = $ScrollContainer
|
||||
@onready var _vbox: VBoxContainer = $ScrollContainer/VBoxContainer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if is_instance_valid(_scroll):
|
||||
_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
_scroll.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_AUTO
|
||||
resized.connect(_sync_vbox_width)
|
||||
|
||||
|
||||
func setup(item_defs_client: Node) -> void:
|
||||
_item_defs_client = item_defs_client
|
||||
|
||||
|
|
@ -29,21 +38,26 @@ func populate(recipes: Array) -> void:
|
|||
var recipe_id: String = str(recipe.get("id", ""))
|
||||
if recipe_id.is_empty():
|
||||
continue
|
||||
var row := HBoxContainer.new()
|
||||
var row := VBoxContainer.new()
|
||||
row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_theme_constant_override("separation", 4)
|
||||
var info := Label.new()
|
||||
info.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
info.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
info.text = _format_recipe_line(recipe)
|
||||
PrototypeHudTheme.apply_to_label(info, false)
|
||||
_apply_recipe_row_label(info)
|
||||
row.add_child(info)
|
||||
var btn_row := HBoxContainer.new()
|
||||
btn_row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
btn_row.alignment = BoxContainer.ALIGNMENT_END
|
||||
var craft_btn := Button.new()
|
||||
craft_btn.text = "Craft"
|
||||
PrototypeHudTheme.apply_to_button(craft_btn, false)
|
||||
craft_btn.pressed.connect(_on_craft_pressed.bind(recipe_id))
|
||||
row.add_child(craft_btn)
|
||||
btn_row.add_child(craft_btn)
|
||||
row.add_child(btn_row)
|
||||
_vbox.add_child(row)
|
||||
_craft_buttons.append(craft_btn)
|
||||
call_deferred("_reset_scroll_after_populate")
|
||||
|
||||
|
||||
func set_craft_busy(busy: bool) -> void:
|
||||
|
|
@ -85,3 +99,24 @@ func _item_display_name(item_id: String) -> String:
|
|||
|
||||
func _on_craft_pressed(recipe_id: String) -> void:
|
||||
craft_requested.emit(recipe_id)
|
||||
|
||||
|
||||
func _apply_recipe_row_label(label: Label) -> void:
|
||||
label.add_theme_font_size_override("font_size", HudThemeConstants.FONT_SIZE_SECONDARY)
|
||||
label.add_theme_constant_override("outline_size", HudThemeConstants.OUTLINE_SIZE)
|
||||
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
|
||||
|
||||
func _sync_vbox_width() -> void:
|
||||
if not is_instance_valid(_scroll) or not is_instance_valid(_vbox):
|
||||
return
|
||||
var width: float = _scroll.size.x
|
||||
if width <= 0.0:
|
||||
return
|
||||
_vbox.custom_minimum_size.x = width
|
||||
|
||||
|
||||
func _reset_scroll_after_populate() -> void:
|
||||
_sync_vbox_width()
|
||||
if is_instance_valid(_scroll):
|
||||
_scroll.scroll_vertical = 0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
extends GdUnitTestSuite
|
||||
|
||||
## NEO-122 follow-up: craft recipe panel layout + scroll reset on populate.
|
||||
|
||||
const CraftRecipePanel := preload("res://scripts/craft_recipe_panel.gd")
|
||||
|
||||
|
||||
static func _sample_recipes() -> Array:
|
||||
return [
|
||||
{
|
||||
"id": "refine_scrap_standard",
|
||||
"displayName": "Refine Scrap (Standard)",
|
||||
"inputs": [{"itemId": "scrap_metal_bulk", "quantity": 5}],
|
||||
},
|
||||
{
|
||||
"id": "refine_scrap_efficient",
|
||||
"displayName": "Refine Scrap (Efficient)",
|
||||
"inputs": [{"itemId": "scrap_metal_bulk", "quantity": 10}],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
func _build_panel() -> Control:
|
||||
var panel: Control = CraftRecipePanel.new()
|
||||
panel.custom_minimum_size = Vector2(656, 360)
|
||||
var scroll := ScrollContainer.new()
|
||||
scroll.name = "ScrollContainer"
|
||||
scroll.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
var vbox := VBoxContainer.new()
|
||||
vbox.name = "VBoxContainer"
|
||||
scroll.add_child(vbox)
|
||||
panel.add_child(scroll)
|
||||
auto_free(panel)
|
||||
add_child(panel)
|
||||
await get_tree().process_frame
|
||||
return panel
|
||||
|
||||
|
||||
func test_populate_builds_one_row_per_recipe() -> void:
|
||||
# Arrange
|
||||
var panel := await _build_panel()
|
||||
# Act
|
||||
panel.call("populate", _sample_recipes())
|
||||
await get_tree().process_frame
|
||||
# Assert
|
||||
var vbox: VBoxContainer = panel.get_node("ScrollContainer/VBoxContainer")
|
||||
assert_that(vbox.get_child_count()).is_equal(2)
|
||||
|
||||
|
||||
func test_populate_resets_scroll_to_top() -> void:
|
||||
# Arrange
|
||||
var panel := await _build_panel()
|
||||
var scroll: ScrollContainer = panel.get_node("ScrollContainer")
|
||||
panel.call("populate", _sample_recipes())
|
||||
await get_tree().process_frame
|
||||
scroll.scroll_vertical = 999
|
||||
# Act
|
||||
panel.call("populate", _sample_recipes())
|
||||
await get_tree().process_frame
|
||||
# Assert
|
||||
assert_that(scroll.scroll_vertical).is_equal(0)
|
||||
|
||||
|
||||
func test_populate_emits_craft_requested_for_row() -> void:
|
||||
# Arrange
|
||||
var panel := await _build_panel()
|
||||
var captured: Array = []
|
||||
panel.connect(
|
||||
"craft_requested", func(recipe_id: String) -> void: captured.append(recipe_id)
|
||||
)
|
||||
panel.call("populate", _sample_recipes())
|
||||
await get_tree().process_frame
|
||||
var vbox: VBoxContainer = panel.get_node("ScrollContainer/VBoxContainer")
|
||||
var first_row: VBoxContainer = vbox.get_child(0) as VBoxContainer
|
||||
var btn_row: HBoxContainer = first_row.get_child(1) as HBoxContainer
|
||||
var craft_btn: Button = btn_row.get_child(0) as Button
|
||||
# Act
|
||||
craft_btn.pressed.emit()
|
||||
# Assert
|
||||
assert_that(captured.size()).is_equal(1)
|
||||
assert_that(str(captured[0])).is_equal("refine_scrap_standard")
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bneo122craftpanel1
|
||||
|
|
@ -34,8 +34,9 @@
|
|||
4. Gather scrap until gather quest completes (resource node **R**). Verify counter updates on **`QuestProgressLabel`** after each successful gather (may lag one GET).
|
||||
5. Press **Shift+Q** before gather is complete — verify **`Quest accept: denied — prerequisite_incomplete`** for refine (or **`no eligible quest`** if refine is not yet eligible).
|
||||
6. After gather completes, press **Shift+Q**. Verify refine quest becomes **`active`**.
|
||||
7. Craft **`refine_scrap_standard`** with Economy HUD open. Verify refine quest **`completed`** after successful craft.
|
||||
8. Press **Q** again on already-completed gather. Verify deny feedback on **`QuestAcceptFeedbackLabel`** without Bruno.
|
||||
7. Open **Economy HUD** recipe panel — **Refine Scrap (Standard)** is the **first** row (scroll starts at top). Craft when **≥5** scrap in bag.
|
||||
8. Craft **`refine_scrap_standard`** with Economy HUD open. Verify refine quest **`completed`** after successful craft.
|
||||
9. Press **Q** again on already-completed gather. Verify deny feedback on **`QuestAcceptFeedbackLabel`** without Bruno.
|
||||
9. Optional: stop server while Godot running, press **Q** — verify **`Quests: error — …`** or **`Quest accept: failed — …`** visible on HUD.
|
||||
10. Optional: block **`GET /game/world/quest-definitions`** only while progress GET succeeds — verify **`definitions error — …`** under **`QuestProgressLabel`** with raw quest ids as fallback.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue