The folder texts are cached on first draw, but the engine fills in a folder's song count with a background scan after the boxes are first drawn, so the count text stayed at 0 for the rest of the session (e.g. the folder under the cursor at startup kept showing 0 songs). The cache now remembers the count it was built with and rebuilds that one text when box.tja_count changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
233 lines
9.3 KiB
Lua
233 lines
9.3 KiB
Lua
-- FolderBox rendering (genre folder closed/open), split out of song_select.lua.
|
|
-- Mirrors src/objects/song_select/file_navigator/box_folder.cpp.
|
|
|
|
local base = require("song_select/file_navigator/box_base")
|
|
|
|
local T = base.T
|
|
local draw_shadows = base.draw_shadows
|
|
local draw_base_closed = base.draw_base_closed
|
|
local vertical_name = base.vertical_name
|
|
|
|
local WHITE = { 255, 255, 255, 255 }
|
|
local BLACK = { 0, 0, 0, 255 }
|
|
|
|
local function is_2p_screen()
|
|
return (tex.current_screen and tex.current_screen() or "") == "SONG_SELECT_2P"
|
|
end
|
|
|
|
local function make_count_text(count)
|
|
local count_cfg = tex.get_skin_config("song_tja_count") or { font_size = 35 }
|
|
return text.create_raw_text(base.format_song_count(count), count_cfg.font_size or 35, WHITE, BLACK, false, 5.0, 2.0, 1.0)
|
|
end
|
|
|
|
-- Folder text objects (hori_name, tja_count_text, explanation) from FolderBox::load_text,
|
|
-- cached per box on self. The song count is filled in by a background scan after the box is
|
|
-- first drawn, so its text is rebuilt whenever the count changes (it stayed at 0 otherwise).
|
|
local function folder_texts(self, box)
|
|
self._folder_texts = self._folder_texts or {}
|
|
local key = box:path()
|
|
local t = self._folder_texts[key]
|
|
if t == nil then
|
|
local name = box.text_name or ""
|
|
|
|
local hori_cfg = tex.get_skin_config("song_hori_name") or { font_size = 40 }
|
|
local hori_name = text.create_raw_text(name, hori_cfg.font_size or 40, WHITE, BLACK, false, 5.0, 2.0, 1.0)
|
|
|
|
local count = box.tja_count or 0
|
|
local tja_count_text = make_count_text(count)
|
|
|
|
local explanation = box:explanation() or {}
|
|
local exp_cfg = tex.get_skin_config("box_folder_explanation") or { font_size = 34 }
|
|
local exp_box = tex.get_skin_config("box_folder_explanation_box") or { width = 160 }
|
|
local lang = tex.language()
|
|
local is_cjk = text.language_is_cjk(lang)
|
|
local exp_texts = {}
|
|
for i = 1, 3 do
|
|
local s = explanation[i]
|
|
if s and s ~= "" then
|
|
local content = s
|
|
if not is_cjk then
|
|
content = text.word_wrap(s, exp_cfg.font_size or 34, 2.0, (exp_box.width or 160) - 20.0)
|
|
end
|
|
exp_texts[i] = text.create_raw_text(content, exp_cfg.font_size or 34, WHITE, BLACK, is_cjk, 5.0, 2.0, 1.0)
|
|
end
|
|
end
|
|
|
|
t = { hori_name = hori_name, tja_count_text = tja_count_text, count = count, explanation = exp_texts }
|
|
self._folder_texts[key] = t
|
|
else
|
|
local count = box.tja_count or 0
|
|
if count ~= t.count then
|
|
t.tja_count_text = make_count_text(count)
|
|
t.count = count
|
|
end
|
|
end
|
|
return t
|
|
end
|
|
|
|
-- FolderBox::draw_closed crown badge (best crown, no fade).
|
|
local function draw_folder_crown(box, bx, by)
|
|
local function draw_one(info, px)
|
|
if not info then return end
|
|
base.draw_crown(info.crown, info.frame, px, by, 1.0)
|
|
end
|
|
local crown_1p = box:highest_crown()
|
|
local crown_2p
|
|
if is_2p_screen() then crown_2p = box:highest_crown_p2() end
|
|
|
|
if crown_2p then
|
|
local info = tex.get_texture_info("yellow_box", "crown_dfc")
|
|
local half = (info and info.width or 0) * 0.35
|
|
draw_one(crown_1p, bx - half)
|
|
draw_one(crown_2p, bx + half)
|
|
elseif crown_1p then
|
|
draw_one(crown_1p, bx)
|
|
end
|
|
end
|
|
|
|
function SongSelect:draw_folder_closed(box)
|
|
draw_base_closed(box)
|
|
|
|
local bx = box:box_x()
|
|
local by = box:box_y()
|
|
local fade = box.fade.attribute
|
|
local tex_index = box:texture_index()
|
|
local use_shader = box:has_recolor()
|
|
|
|
if use_shader then box:begin_recolor() end
|
|
tex.draw_texture(T("box", "folder_clip"), { frame = tex_index, x = bx - (1.0 * tex.get_screen_scale()), y = by, fade = fade })
|
|
if use_shader then box:end_recolor() end
|
|
|
|
local name = vertical_name(self, box)
|
|
local name_cfg = tex.get_skin_config("song_box_name") or { x = 47, y = 129, height = 417 }
|
|
local name_h = math.min(name.height, name_cfg.height)
|
|
name:draw({
|
|
x = bx + name_cfg.x - math.floor(name.width / 2),
|
|
y = name_cfg.y + by,
|
|
y2 = name_h - name.height,
|
|
fade = fade
|
|
})
|
|
|
|
draw_folder_crown(box, bx, by)
|
|
end
|
|
|
|
local function draw_open_bg(self, box, fade)
|
|
local bx = box:box_x()
|
|
local by = box:box_y()
|
|
local shadow_fade = math.min(fade, box.open_fade.attribute)
|
|
draw_shadows(bx, by, shadow_fade, 1)
|
|
|
|
local tex_index = box:texture_index()
|
|
local use_shader = box:has_recolor()
|
|
local open_anim = box.open_anim.attribute
|
|
|
|
if open_anim >= (100.0 * tex.get_screen_scale()) then
|
|
if use_shader then box:begin_recolor() end
|
|
tex.draw_texture(T("box", "folder_top_edge"), { frame = tex_index, mirror = "horizontal", y = by - open_anim, fade = fade })
|
|
tex.draw_texture(T("box", "folder_top"), { frame = tex_index, y = by - open_anim, fade = fade })
|
|
local top_cfg = tex.get_skin_config("song_folder_top") or { x = 268 }
|
|
tex.draw_texture(T("box", "folder_top_edge"), { frame = tex_index, x = top_cfg.x, y = by - open_anim, fade = fade })
|
|
if use_shader then box:end_recolor() end
|
|
end
|
|
|
|
if use_shader then box:begin_recolor() end
|
|
tex.draw_texture(T("box", "folder_texture_left"), { frame = tex_index, x = bx - open_anim, y = by, fade = fade })
|
|
tex.draw_texture(T("box", "folder_texture"), { frame = tex_index, x = bx - open_anim, y = by, x2 = (open_anim * 2.0) + base.song_box_bg_width(), fade = fade })
|
|
tex.draw_texture(T("box", "folder_texture_right"), { frame = tex_index, x = bx + open_anim, y = by, fade = fade })
|
|
if use_shader then box:end_recolor() end
|
|
end
|
|
|
|
local function draw_open_fg(self, box, fade)
|
|
local texts = folder_texts(self, box)
|
|
local open_anim = box.open_anim.attribute
|
|
|
|
if open_anim >= (100.0 * tex.get_screen_scale()) then
|
|
local hori_cfg = tex.get_skin_config("song_hori_name") or { x = 642, y = 204, width = 300 }
|
|
local dest_width = math.min(hori_cfg.width, texts.hori_name.width)
|
|
texts.hori_name:draw({
|
|
x = hori_cfg.x - dest_width / 2.0,
|
|
y = hori_cfg.y - open_anim,
|
|
x2 = dest_width - texts.hori_name.width,
|
|
fade = fade
|
|
})
|
|
end
|
|
|
|
if box:texture_index() == base.TI_DEFAULT then
|
|
tex.draw_texture(T("box", "genre_overlay_large"), { fade = fade })
|
|
end
|
|
if box:genre_index() == base.GI_DIFFICULTY then
|
|
tex.draw_texture(T("box", "diff_overlay_large"), { fade = fade })
|
|
end
|
|
|
|
if box:genre_index() ~= base.GI_DIFFICULTY then
|
|
tex.draw_texture(T("yellow_box", "song_count_back"), { fade = math.min(fade, 0.5) })
|
|
local count_cfg = tex.get_skin_config("song_tja_count") or { x = 560, y = 130, width = 184 }
|
|
local dest_width = math.min(count_cfg.width, texts.tja_count_text.width)
|
|
texts.tja_count_text:draw({
|
|
x = count_cfg.x - dest_width / 2.0,
|
|
y = count_cfg.y,
|
|
x2 = dest_width - texts.tja_count_text.width,
|
|
fade = fade
|
|
})
|
|
end
|
|
|
|
if box:has_box_texture() then
|
|
local box_cfg = tex.get_skin_config("box_texture") or { x = 48, y = 330 }
|
|
local max_size = tex.get_skin_config("box_folder_max_size") or { width = 344, height = 424 }
|
|
box:draw_box_texture({
|
|
cx = box:box_x() + box_cfg.x,
|
|
cy = box_cfg.y + box:box_y(),
|
|
max_w = max_size.width,
|
|
max_h = max_size.height,
|
|
fade = fade
|
|
})
|
|
elseif box:texture_index() ~= base.TI_DEFAULT then
|
|
tex.draw_texture(T("box", "folder_graphic"), { frame = box:genre_index(), fade = fade })
|
|
|
|
local exp_cfg = tex.get_skin_config("box_folder_explanation") or { x = 776, y = 131, width = 43, height = 73 }
|
|
local exp_box = tex.get_skin_config("box_folder_explanation_box") or { x = 650, y = 125, width = 160, height = 400 }
|
|
local lang = tex.language()
|
|
local is_cjk = text.language_is_cjk(lang)
|
|
if is_cjk then
|
|
for i = 1, 3 do
|
|
local t = texts.explanation[i]
|
|
if t then
|
|
local idx = i - 1
|
|
local center_x = exp_cfg.x - exp_cfg.width * idx
|
|
t:draw({ x = center_x - t.width / 2.0, y = exp_cfg.y + exp_cfg.height * idx, fade = fade })
|
|
end
|
|
end
|
|
else
|
|
local total_h = 0.0
|
|
for i = 1, 3 do
|
|
if texts.explanation[i] then total_h = total_h + texts.explanation[i].height end
|
|
end
|
|
local scale = total_h > exp_box.height and (exp_box.height / total_h) or 1.0
|
|
local y = exp_box.y
|
|
for i = 1, 3 do
|
|
local t = texts.explanation[i]
|
|
if t then
|
|
local dest_h = t.height * scale
|
|
t:draw({
|
|
x = exp_box.x + (exp_box.width - t.width) / 2.0,
|
|
y = y,
|
|
y2 = dest_h - t.height,
|
|
fade = fade
|
|
})
|
|
y = y + dest_h
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function SongSelect:draw_folder_open(box)
|
|
if box.entered then
|
|
draw_open_bg(self, box, 0.0)
|
|
draw_open_fg(self, box, box:enter_fade().attribute)
|
|
else
|
|
draw_open_bg(self, box, math.min(1.0, box.fade.attribute))
|
|
draw_open_fg(self, box, math.min(box.open_fade.attribute, box.fade.attribute))
|
|
end
|
|
end
|