feat(crafting-display): icon column with fit-to-bounds rendering
Recipe rows gain an icon column on the left (row_height-4 box,
fit-to-bounds, centered). The renderer calls widget._icon_resolver(
recipe) and renders the returned {atlas, uv} via
draw_sprite_transform when non-nil. Default resolver returns nil →
text-only layout preserved for modules that don't wire icons; modules
opt in by passing opts.icon_resolver to create() or via
set_icon_resolver after.
Module-side mapping (recipe.output.template → {atlas, uv}) is the
caller's responsibility — composition has no template-property
getter today (ADR-0001 keeps the read-side domain-free), so the
domain owner is the right place to hold the lookup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
29
init.lua
29
init.lua
@@ -250,13 +250,40 @@ function M._render_widget(widget, ctx)
|
|||||||
|
|
||||||
local cy = bounds.y + pad
|
local cy = bounds.y + pad
|
||||||
widget._render_rows = {}
|
widget._render_rows = {}
|
||||||
|
-- v0.3.0: icon column. Reserve row_h px on the left for the icon
|
||||||
|
-- box (fit-to-bounds rendering); shift label by the same amount.
|
||||||
|
-- Resolver returning nil collapses the icon box to a placeholder
|
||||||
|
-- (text-only layout preserved for non-icon resolvers).
|
||||||
|
local icon_box = row_h - 4
|
||||||
|
local label_x = bounds.x + pad + icon_box + pad
|
||||||
for i, row in ipairs(rows) do
|
for i, row in ipairs(rows) do
|
||||||
local color = row.available and txt_col_full or txt_col_dim
|
local color = row.available and txt_col_full or txt_col_dim
|
||||||
local label = widget._label_resolver(row.recipe)
|
local label = widget._label_resolver(row.recipe)
|
||||||
local summary = widget._summary_resolver(row.recipe)
|
local summary = widget._summary_resolver(row.recipe)
|
||||||
|
local icon = widget._icon_resolver(row.recipe)
|
||||||
|
|
||||||
|
if icon ~= nil and engine and engine.render and engine.render.draw_sprite_transform then
|
||||||
|
local ok, tex = pcall(engine.module.load_texture,
|
||||||
|
widget.widget_id, icon.atlas)
|
||||||
|
if ok and tex and icon.uv then
|
||||||
|
local uv = icon.uv
|
||||||
|
local max_uv = (uv.w > uv.h) and uv.w or uv.h
|
||||||
|
local s = icon_box / max_uv
|
||||||
|
local draw_x = bounds.x + pad + (icon_box - uv.w * s) / 2
|
||||||
|
local draw_y = cy + 2 + (icon_box - uv.h * s) / 2
|
||||||
|
engine.render.draw_sprite_transform(
|
||||||
|
tex,
|
||||||
|
draw_x, draw_y,
|
||||||
|
0, s, s,
|
||||||
|
0, 0,
|
||||||
|
0xFFFFFFFF,
|
||||||
|
uv.x, uv.y, uv.w, uv.h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if engine and engine.render and engine.render.draw_text then
|
if engine and engine.render and engine.render.draw_text then
|
||||||
engine.render.draw_text(label,
|
engine.render.draw_text(label,
|
||||||
bounds.x + pad, cy,
|
label_x, cy,
|
||||||
theme.font_size_body, color)
|
theme.font_size_body, color)
|
||||||
engine.render.draw_text(summary,
|
engine.render.draw_text(summary,
|
||||||
bounds.x + bounds.w - pad - 100, cy,
|
bounds.x + bounds.w - pad - 100, cy,
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"id":"lib-core.crafting-display","version":"0.2.0","api_min":"0.1","deps":[{"id":"lib-core.crafting","version":"0.2.0"},{"id":"lib-core.panel","version":"0.4.0"},{"id":"lib-core.inventory-list","version":"0.1.0"},{"id":"lib-core.composition","version":"0.3.0"}]}
|
{"id":"lib-core.crafting-display","version":"0.3.0","api_min":"0.1","deps":[{"id":"lib-core.crafting","version":"0.2.0"},{"id":"lib-core.panel","version":"0.4.0"},{"id":"lib-core.inventory-list","version":"0.1.0"},{"id":"lib-core.composition","version":"0.3.0"}]}
|
||||||
|
|||||||
Reference in New Issue
Block a user