English uses the condensed font_en, but Japanese (font.ttf), Chinese (font_cn), Korean (font_kr) and the other languages get full-width fonts, so at the same point size their song, folder and header titles look far larger and fill the boards. Draw those titles at 0.8x when the language is not English. English is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
462 lines
21 KiB
Lua
462 lines
21 KiB
Lua
-- SongBox rendering (song board, difficulty plates, badges, diff select), split out of
|
|
-- song_select.lua. All shared helpers/state come from box_base.
|
|
|
|
local base = require("song_select/file_navigator/box_base")
|
|
|
|
local folder_leg = base.folder_leg
|
|
local DIFF_BACK, DIFF_MODIFIER = base.DIFF_BACK, base.DIFF_MODIFIER
|
|
local DIFF_EASY, DIFF_NORMAL, DIFF_HARD, DIFF_ONI, DIFF_URA =
|
|
base.DIFF_EASY, base.DIFF_NORMAL, base.DIFF_HARD, base.DIFF_ONI, base.DIFF_URA
|
|
local CROWN_NONE, CROWN_FC, CROWN_DFC = base.CROWN_NONE, base.CROWN_FC, base.CROWN_DFC
|
|
local BOARD_W = base.BOARD_W
|
|
local CEN_CLOSED_H, CEN_OPEN_H = base.CEN_CLOSED_H, base.CEN_OPEN_H
|
|
local SONG_TEXT_BOX_W, DS_TEXT_BOX_W = base.SONG_TEXT_BOX_W, base.DS_TEXT_BOX_W
|
|
local SONG_CLOSE_MS, SONG_STALE_MS = base.SONG_CLOSE_MS, base.SONG_STALE_MS
|
|
local URA_LOOP, URA_LOOP_F0, URA_LOOP_LEN = base.URA_LOOP, base.URA_LOOP_F0, base.URA_LOOP_LEN
|
|
local DS_SLOT_X, DS_BOARD_Y, DS_COURSE_NAME_DY = base.DS_SLOT_X, base.DS_BOARD_Y, base.DS_COURSE_NAME_DY
|
|
local URA_ANIM_MS, URA_SWAP_MS, URA_CELLS = base.URA_ANIM_MS, base.URA_SWAP_MS, base.URA_CELLS
|
|
local DS_BTN_Y, DS_CURSOR_Y, DS_NEIRO_Y = base.DS_BTN_Y, base.DS_CURSOR_Y, base.DS_NEIRO_Y
|
|
local DS_MARK_X, DS_MARK_Y = base.DS_MARK_X, base.DS_MARK_Y
|
|
local DS_MARK_DECIDE, DS_MARK_DECIDE_MS = base.DS_MARK_DECIDE, base.DS_MARK_DECIDE_MS
|
|
local get_any = base.get_any
|
|
local draw_centered, draw_centered_b = base.draw_centered, base.draw_centered_b
|
|
local draw_title = base.draw_title
|
|
local outline, board_outline = base.outline, base.board_outline
|
|
local draw_board, draw_glow, glow_pulse = base.draw_board, base.draw_glow, base.glow_pulse
|
|
local box_id = base.box_id
|
|
local go_get, leg_f, box_fade, fly_offset = base.go_get, base.leg_f, base.box_fade, base.fly_offset
|
|
local wheel_open_t, wheel_close_step = base.wheel_open_t, base.wheel_close_step
|
|
local song_open_timeline, song_close_timeline = base.song_open_timeline, base.song_close_timeline
|
|
|
|
local SONG_TITLE_OUTLINE = 5.0
|
|
local SONG_TITLE_SIZE = nil -- resolved once from skin_config song_select_box_name
|
|
local SONG_TITLE_CACHE_MAX = 128 -- bound the per-title texture cache
|
|
|
|
-- crown / rank badges (72x72) at arcade positions, one column per player.
|
|
local ICON_ARTS = nil -- name -> texture id (resolved lazily)
|
|
function SongSelect:song_icon(box)
|
|
if ICON_ARTS == nil then ICON_ARTS = { icon_new = self._id_new_icon } end
|
|
local list = {}
|
|
if box.is_new then list[#list + 1] = "icon_new" end
|
|
if #list == 0 then return nil end
|
|
local pick = list[(math.floor(tex.get_current_ms() / 1000.0) % #list) + 1]
|
|
return ICON_ARTS[pick]
|
|
end
|
|
|
|
function SongSelect:badge_diffs(box, pl)
|
|
local sel = self._mark_diff and self._mark_diff[pl]
|
|
local crown_d, rank_d
|
|
if sel and sel >= DIFF_EASY and sel <= DIFF_URA then
|
|
local info = box:course_info(sel)
|
|
if info.has_course then
|
|
if info.crown ~= CROWN_NONE then crown_d = sel end
|
|
if (info.rank or 0) > 0 then rank_d = sel end
|
|
end
|
|
end
|
|
if not crown_d or not rank_d then
|
|
local cbest, rbest
|
|
for d = DIFF_EASY, DIFF_URA do
|
|
local info = box:course_info(d)
|
|
if info.has_course then
|
|
if info.crown ~= CROWN_NONE then cbest = d end
|
|
if (info.rank or 0) > 0 then rbest = d end
|
|
end
|
|
end
|
|
crown_d = crown_d or cbest
|
|
rank_d = rank_d or rbest
|
|
end
|
|
return crown_d, rank_d
|
|
end
|
|
|
|
function SongSelect:draw_badges(box, bx, by, p, fade)
|
|
local scale = 0.75 + 0.25 * p
|
|
local size = 72 * scale
|
|
local players = math.min(2, tex.player_num())
|
|
for pl = 1, players do
|
|
local cx = bx + ((pl == 1) and -425 or 425)
|
|
local crown_d, rank_d = self:badge_diffs(box, pl)
|
|
if crown_d then
|
|
local info = box:course_info(crown_d)
|
|
local id = (info.crown == CROWN_DFC) and self._id_crown_dfc
|
|
or (info.crown == CROWN_FC) and self._id_crown_fc or self._id_crown_clear
|
|
local cy = by + (-27 + (-114 + 27) * p)
|
|
draw_centered(id, cx, cy, size, size, { frame = crown_d, x2 = size - 72, y2 = size - 72, fade = fade })
|
|
end
|
|
if rank_d then
|
|
local info = box:course_info(rank_d)
|
|
local cy = by + (27 + (-42 - 27) * p)
|
|
draw_centered(self._id_score_rank, cx, cy, size, size,
|
|
{ frame = (info.rank - 1) * 5 + rank_d, x2 = size - 72, y2 = size - 72, fade = fade })
|
|
end
|
|
end
|
|
end
|
|
|
|
-- SongBox
|
|
-- pb = board progress (0..1), ia = contents alpha, ic = NEW-icon alpha.
|
|
function SongSelect:draw_song_board(box, pb, ia, ic)
|
|
local bx, by = box:box_x(), box:box_y()
|
|
local fdx, fdy = fly_offset(box); bx, by = bx + fdx, by + fdy -- wheel fly-in
|
|
local fade = math.min(1.0, box_fade(box))
|
|
|
|
-- folder-ENTER/EXIT unfurl/furl: while the slab's sx < 1 only the slab is drawn,
|
|
-- and the contents alphas come from the clip's own channels.
|
|
local gof = leg_f()
|
|
local ltitle = 1.0
|
|
if gof and folder_leg.kind == "open" and gof < folder_leg.open_swap - 1 and box:draw_state() == "open" then
|
|
return -- the new content's board does not exist until the swap frame
|
|
end
|
|
if gof and box:draw_state() == "open" then
|
|
local sx, ba = go_get("song_board_sx", gof, 1), go_get("song_board_sx", gof, 2)
|
|
if sx and ba then
|
|
if ba <= 0.0 then return end -- board not on screen on this frame
|
|
if sx < 1.0 then -- unfurl / furl: the slab alone
|
|
draw_board(self._id_bar_genre, box:genre_frame(), bx, by, CEN_OPEN_H,
|
|
fade * ba, nil, sx)
|
|
return
|
|
end
|
|
local ia2 = go_get("song_info_a", gof, 1)
|
|
if ia2 then ia = math.min(ia or 1.0, ia2) end
|
|
ltitle = go_get("song_title_a", gof, 1) or 1.0
|
|
local ic2 = go_get("song_icon_a", gof, 1)
|
|
if ic2 then ic = math.min(ic or 0.0, ic2) end
|
|
end
|
|
end
|
|
|
|
local cen_h = CEN_CLOSED_H + (CEN_OPEN_H - CEN_CLOSED_H) * pb
|
|
if pb > 0 then draw_glow(self._id_glow, bx, by, cen_h, fade * pb * glow_pulse()) end
|
|
draw_board(self._id_bar_genre, box:genre_frame(), bx, by, cen_h, fade)
|
|
|
|
if pb <= 0.0 then
|
|
draw_title(self:song_title(box), bx, by, fade, SONG_TEXT_BOX_W, 0)
|
|
self:draw_badges(box, bx, by, 0.0, fade)
|
|
-- instance_icon hangs off the board's left edge (-532)
|
|
local icon = (ic > 0) and self:song_icon(box) or nil
|
|
if icon then
|
|
draw_centered(icon, bx - 532, by + 4, 120, 96, { fade = fade * ic })
|
|
end
|
|
return
|
|
end
|
|
|
|
local cfade = fade * ia
|
|
if cfade > 0 then
|
|
self:draw_plates(box, bx, by, cfade)
|
|
self:draw_badges(box, bx, by, pb, cfade)
|
|
end
|
|
|
|
-- title rises from the closed position (y=0) to the open one (y=-70) with the growth
|
|
draw_title(self:song_title(box), bx, by - 70 * pb, fade * ltitle, SONG_TEXT_BOX_W, 0)
|
|
local sub = self:song_subtitle(box)
|
|
if sub and cfade > 0 then draw_title(sub, bx, by - 28, cfade, SONG_TEXT_BOX_W) end
|
|
|
|
if tex.display_bpm() and cfade > 0 then
|
|
local bpm_cfg = tex.get_skin_config("song_select_box_bpm")
|
|
box:bpm_text():draw({ x = bx + bpm_cfg.x, y = by + bpm_cfg.y, fade = cfade })
|
|
end
|
|
local icon = (ic > 0) and self:song_icon(box) or nil
|
|
if icon then
|
|
draw_centered(icon, bx - 532, by + 4, 120, 96, { fade = fade * ic })
|
|
end
|
|
-- 新音 / 旧音 / 期間限定 marker, hung off the board's right edge (mirror of the icon)
|
|
local ok_exd, exd = pcall(function() return box:ex_data_flag() end)
|
|
if ok_exd and exd and exd > 0 and cfade > 0 then
|
|
local art = (exd == 1) and get_any("yellow_box", "ex_data_new_audio")
|
|
or (exd == 2) and get_any("yellow_box", "ex_data_old_audio")
|
|
or get_any("yellow_box", "ex_data_limited_time")
|
|
if art then
|
|
local s = tex.get_screen_scale()
|
|
draw_centered_b(art, { 458 * s, 120 * s }, bx + 532, by + 4,
|
|
224 * s, 64 * s, { fade = cfade })
|
|
end
|
|
end
|
|
if box.is_favorite and cfade > 0 then
|
|
local fav = get_any("yellow_box", "favorite_" .. tex.player_num() .. "p")
|
|
if fav then tex.draw_texture(fav, { x = bx - 480, y = by - 176, fade = cfade }) end
|
|
end
|
|
end
|
|
|
|
function SongSelect:draw_song_closed(box)
|
|
local key = "s\0" .. box_id(box) -- per-BOX, not per-title
|
|
local e = wheel_close_step(key, SONG_CLOSE_MS, SONG_STALE_MS)
|
|
if e then
|
|
self:draw_song_board(box, song_close_timeline(e))
|
|
return
|
|
end
|
|
self:draw_song_board(box, 0.0, 0.0, 1.0)
|
|
end
|
|
|
|
-- Diff plates row (song_kanban_info, board y +75): plate 184x96 with the course name
|
|
-- under the icon, a star and the level number.
|
|
function SongSelect:chip_label(diff)
|
|
local lbl = self._chip_labels[diff]
|
|
if lbl == nil then
|
|
local key = "chip_course_name_" .. diff
|
|
if tex.get_skin_config(key) then
|
|
lbl = text.create_text(key, { 255, 255, 255, 255 }, { 40, 20, 20, 255 }, false, outline(1.5), 1.0)
|
|
end
|
|
self._chip_labels[diff] = lbl or false
|
|
end
|
|
return lbl or nil
|
|
end
|
|
|
|
function SongSelect:draw_plates(box, bx, by, fade)
|
|
local has_ura = box:has_ura()
|
|
local ura_weight = 0.0
|
|
local oni_alpha = 1.0
|
|
if has_ura then
|
|
local f = URA_LOOP_F0 + (tex.get_current_ms() * 0.06) % URA_LOOP_LEN
|
|
ura_weight = URA_LOOP:get("ura/text_course_ura", f, "a") or 0.0
|
|
oni_alpha = URA_LOOP:get("oni/text_course_oni", f, "a") or 1.0
|
|
end
|
|
local py = by + 75
|
|
local function plate(cx, diff, f)
|
|
local info = box:course_info(diff)
|
|
if not info.has_course or f <= 0 then return end
|
|
draw_centered(self._id_plate, cx, py, 184, 96, { frame = diff, fade = f })
|
|
draw_centered(self._id_star, cx + 27, py, 40, 40, { frame = diff, fade = f })
|
|
local lv = math.max(1, math.min(11, info.level))
|
|
draw_centered(self._id_level_number, cx + 61, py, 48, 48, { frame = diff * 11 + (lv - 1), fade = f })
|
|
local name = self:chip_label(diff)
|
|
if name then draw_title(name, cx - 42, py + 30, f) end
|
|
if info.is_branching then
|
|
draw_centered(self._id_branch, cx - 69, py - 23, 40, 40, { fade = f })
|
|
end
|
|
end
|
|
-- charted columns: easy / normal / hard / (oni|ura)
|
|
local cols = {}
|
|
for d = 0, 2 do if box:course_info(d).has_course then cols[#cols + 1] = d end end
|
|
local has_oni = box:course_info(DIFF_ONI).has_course
|
|
if has_oni or has_ura then cols[#cols + 1] = DIFF_ONI end
|
|
local n = #cols
|
|
for i, d in ipairs(cols) do
|
|
local cx = bx + (i - 1 - (n - 1) / 2) * 182
|
|
if d == DIFF_ONI and has_ura then
|
|
if has_oni then
|
|
plate(cx, DIFF_ONI, fade * oni_alpha) -- oni below, ura on top
|
|
plate(cx, DIFF_URA, fade * ura_weight)
|
|
else
|
|
plate(cx, DIFF_URA, fade)
|
|
end
|
|
else
|
|
plate(cx, d, fade)
|
|
end
|
|
end
|
|
return ura_weight
|
|
end
|
|
|
|
function SongSelect:draw_song_open(box)
|
|
local key = "s\0" .. box_id(box)
|
|
local t = wheel_open_t(key)
|
|
if t == nil then -- 508 ms pre-growth hold: fully closed
|
|
self:draw_song_board(box, 0.0, 0.0, 1.0)
|
|
return
|
|
end
|
|
self:draw_song_board(box, song_open_timeline(t))
|
|
end
|
|
|
|
-- Difficulty select
|
|
function SongSelect:draw_diff_mark_decided(p, dec, fade)
|
|
local f = math.floor((tex.get_current_ms() - dec.t0) / DS_MARK_DECIDE_MS) + 1
|
|
local k = DS_MARK_DECIDE[math.min(f, #DS_MARK_DECIDE)]
|
|
local id, id_w = self._id_mark[dec.course], self._id_mark_w[dec.course]
|
|
local cx, cy = DS_MARK_X[p], DS_MARK_Y
|
|
local function stretched(tid, a, sy)
|
|
if a <= 0 then return end
|
|
tex.draw_texture(tid, { x = cx, y = cy, y2 = 680 * (sy - 1), origin = { 340, 340 * sy }, fade = a * fade })
|
|
end
|
|
stretched(id_w, k[5], 1) -- mark_course_white_2: backing
|
|
stretched(id, k[1], k[2]) -- mark_course
|
|
stretched(id_w, k[3], k[4]) -- mark_course_white: the flash on top
|
|
end
|
|
|
|
local function mark_intro_pose(i)
|
|
local function lerp(a, b, u) return a + (b - a) * u end
|
|
if i <= 11 then
|
|
local u = 1 - (1 - i / 11) ^ 2
|
|
return lerp(150, -48.55, u), lerp(1, 0.95, u), lerp(1, 1.099, u), lerp(0, 0.496, u)
|
|
elseif i <= 13 then
|
|
return -48.6, 0.95, 1.099, 0.5
|
|
end
|
|
local u = math.min(1, (i - 14) / 10) ^ 2
|
|
return lerp(-48.6, 0, u), lerp(0.951, 1, u), lerp(1.097, 1, u), lerp(0.504, 0.602, u)
|
|
end
|
|
local MARK_INTRO_FRAMES = 25
|
|
|
|
function SongSelect:draw_diff_mark_intro(p, d, i, fade)
|
|
local dy, sx, sy, a = mark_intro_pose(i)
|
|
local cx, cy = DS_MARK_X[p], DS_MARK_Y + dy
|
|
tex.draw_texture(self._id_mark[d], { x = cx, y = cy, x2 = 680 * (sx - 1), y2 = 680 * (sy - 1),
|
|
origin = { 340 * sx, 340 * sy }, fade = a * fade })
|
|
end
|
|
|
|
function SongSelect:draw_song_diff_select_bg(box)
|
|
local fade = box.diff_fade_in.attribute
|
|
local now = tex.get_current_ms()
|
|
local intro = self._mark_intro or {}
|
|
if now - (self._mark_bg_ms or -1e9) > 100 then intro = {} end
|
|
self._mark_bg_ms = now
|
|
self._mark_intro = intro
|
|
for p = 1, 2 do
|
|
local d = self._mark_diff[p]
|
|
local dec = self._mark_decided[p]
|
|
local shown = d and d >= DIFF_EASY and DS_MARK_X[p] and fade > 0
|
|
if not shown or dec then intro[p] = nil
|
|
elseif not intro[p] then intro[p] = now end
|
|
if dec and self._id_mark[dec.course] then
|
|
self:draw_diff_mark_decided(p, dec, fade)
|
|
elseif shown and self._id_mark[d] and (now - intro[p]) / DS_MARK_DECIDE_MS < MARK_INTRO_FRAMES then
|
|
self:draw_diff_mark_intro(p, d, math.floor((now - intro[p]) / DS_MARK_DECIDE_MS), fade)
|
|
elseif self._id_diff_mark and shown then
|
|
draw_centered(self._id_diff_mark, DS_MARK_X[p], DS_MARK_Y, 680, 680, { frame = d, fade = fade })
|
|
end
|
|
end
|
|
tex.draw_texture(self._id_backboard, { frame = box:genre_frame(), x = 960 - 636, y = 440 - 392, fade = fade })
|
|
end
|
|
|
|
function SongSelect:draw_song_diff_select(box)
|
|
folder_leg.diff_seen_ms = tex.get_current_ms()
|
|
local fade = box.diff_fade_in.attribute
|
|
local is_ura = box.is_ura
|
|
local side = (tex.player_num() == 2) and 1 or -1
|
|
local now = tex.get_current_ms()
|
|
|
|
-- oni<->ura toggle detection
|
|
if fade < 1.0 then
|
|
self._ura_prev = is_ura; self._ura_anim = nil
|
|
elseif self._ura_prev ~= nil and is_ura ~= self._ura_prev then
|
|
self._ura_anim = { t0 = now, to_ura = is_ura }
|
|
end
|
|
self._ura_prev = is_ura
|
|
local ura_elapsed = self._ura_anim and (now - self._ura_anim.t0) or nil
|
|
if ura_elapsed and ura_elapsed >= URA_ANIM_MS then self._ura_anim = nil; ura_elapsed = nil end
|
|
local ura_mid = (not ura_elapsed) or ura_elapsed >= URA_SWAP_MS
|
|
-- what the oni slot shows: before the swap point the previous course, after it the new one
|
|
local oni_shown = is_ura
|
|
if ura_elapsed and not ura_mid then oni_shown = not is_ura end
|
|
|
|
-- buttons: return + a small option wrench (the engine cursor can still reach MODIFIER)
|
|
draw_centered(self._id_btn_back, DS_SLOT_X[DIFF_BACK], DS_BTN_Y, 128, 128, { fade = fade })
|
|
draw_centered(self._id_btn_option, DS_SLOT_X[DIFF_MODIFIER], DS_BTN_Y, 128, 128, { fade = fade })
|
|
|
|
-- diff boards
|
|
for i = 0, 3 do
|
|
local cx = DS_SLOT_X[i]
|
|
local diff = (i == DIFF_ONI and oni_shown) and DIFF_URA or i
|
|
local info = box:course_info(diff)
|
|
local f = info.has_course and fade or math.min(fade, 0.4)
|
|
draw_centered(self._id_diff_board, cx, DS_BOARD_Y, 200, 360, { frame = diff, fade = f })
|
|
if info.has_course and not (i == DIFF_ONI and ura_elapsed) then
|
|
local crown = info.crown or 0
|
|
draw_centered(self._id_small_crown, cx + side * 58, DS_BOARD_Y - 138, 40, 40, { frame = crown, fade = f })
|
|
if (info.rank or 0) > 0 then
|
|
draw_centered(self._id_small_rank, cx + side * 20, DS_BOARD_Y - 138, 40, 40, { frame = info.rank - 1, fade = f })
|
|
end
|
|
local lv = math.max(1, math.min(11, info.level))
|
|
tex.draw_texture(self._id_small_star, { frame = 0, x = cx - 40, y = DS_BOARD_Y + 66, fade = f })
|
|
tex.draw_texture(self._id_small_star, { frame = lv, x = cx - 4, y = DS_BOARD_Y + 68, fade = f })
|
|
draw_centered(self._id_dot_bar, cx, DS_BOARD_Y + 116, 172, 24, { fade = f })
|
|
for k = 0, math.min(10, info.level) - 1 do
|
|
draw_centered(self._id_dot_star, cx - 67 + k * 15, DS_BOARD_Y + 116, 24, 24, { fade = f })
|
|
end
|
|
if info.is_branching then
|
|
draw_centered(self._id_branch_diff, cx, DS_BOARD_Y + 144, 40, 40, { fade = f })
|
|
end
|
|
end
|
|
end
|
|
|
|
-- change animation cells over the oni slot
|
|
if ura_elapsed then
|
|
local id = self._ura_anim.to_ura and self._id_ura_to_ura or self._id_ura_to_oni
|
|
if id then
|
|
local cell = math.min(URA_CELLS - 1, math.floor(ura_elapsed / URA_ANIM_MS * URA_CELLS))
|
|
tex.draw_texture(id, { frame = cell, x = DS_SLOT_X[DIFF_ONI] - 170, y = DS_BOARD_Y - 210, fade = fade })
|
|
end
|
|
end
|
|
for i = 0, 3 do
|
|
local diff = (i == DIFF_ONI and oni_shown) and DIFF_URA or i
|
|
local info = box:course_info(diff)
|
|
if info.has_course then
|
|
local lbl = self:course_label(diff)
|
|
if lbl then draw_title(lbl, DS_SLOT_X[i], DS_BOARD_Y + DS_COURSE_NAME_DY, fade) end
|
|
end
|
|
end
|
|
|
|
-- title / subtitle inside the backboard header
|
|
draw_title(self:header_title(box), 960, 178, fade, DS_TEXT_BOX_W, 0)
|
|
draw_title(self:header_subtitle(box), 960, 242, fade, DS_TEXT_BOX_W, 0)
|
|
|
|
end
|
|
|
|
function SongSelect:song_subtitle(box)
|
|
local str = box.text_subtitle
|
|
if not str or str == "" then return nil end
|
|
local gf = self._inside_frame or box:genre_frame()
|
|
local key = gf .. "\0" .. str
|
|
if self._sub_key ~= key then
|
|
self._sub_key = key
|
|
self._sub_label = text.create_raw_text(str, 24, { 255, 255, 255, 255 }, board_outline(gf), false, outline(3.5), 2.0)
|
|
end
|
|
return self._sub_label
|
|
end
|
|
|
|
-- Song board title, arcade-exact: font from skin_config song_select_box_name, black outline,
|
|
-- cached per title (the cache is dropped wholesale past SONG_TITLE_CACHE_MAX).
|
|
function SongSelect:song_title(box)
|
|
local name = box.text_name
|
|
if not name or name == "" then return box:name() end
|
|
local gf = self._inside_frame or box:genre_frame()
|
|
local scale = base.title_scale()
|
|
local key = gf .. "\0" .. scale .. "\0" .. name -- the outline follows the genre, so it keys the cache
|
|
local t = self._song_titles[key]
|
|
if t == nil then
|
|
if SONG_TITLE_SIZE == nil then
|
|
local cfg = tex.get_skin_config("song_select_box_name")
|
|
SONG_TITLE_SIZE = (cfg and cfg.font_size and cfg.font_size > 0) and cfg.font_size or 42
|
|
end
|
|
if self._song_titles_n >= SONG_TITLE_CACHE_MAX then
|
|
self._song_titles = {}
|
|
self._song_titles_n = 0
|
|
end
|
|
t = text.create_raw_text(name, math.floor(SONG_TITLE_SIZE * scale + 0.5), { 255, 255, 255, 255 }, board_outline(gf),
|
|
false, outline(SONG_TITLE_OUTLINE), 2.0)
|
|
self._song_titles[key] = t or false
|
|
self._song_titles_n = self._song_titles_n + 1
|
|
end
|
|
return t or box:name()
|
|
end
|
|
|
|
function SongSelect:header_title(box)
|
|
local name = box.text_name or ""
|
|
local scale = base.title_scale()
|
|
if self._header_title_key ~= name or self._header_title_scale ~= scale then
|
|
self._header_title_key = name
|
|
self._header_title_scale = scale
|
|
self._header_title = text.create_raw_text(name, math.floor(48 * scale + 0.5), { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, outline(7.0), 2.0)
|
|
end
|
|
return self._header_title
|
|
end
|
|
|
|
function SongSelect:header_subtitle(box)
|
|
local sub = box.text_subtitle
|
|
if sub == nil then return box:subtitle_large() end -- engine without the binding
|
|
if sub == "" then return nil end
|
|
local scale = base.title_scale()
|
|
if self._header_sub_key ~= sub or self._header_sub_scale ~= scale then
|
|
self._header_sub_key = sub
|
|
self._header_sub_scale = scale
|
|
self._header_sub = text.create_raw_text(sub, math.floor(30 * scale + 0.5), { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, outline(4.0), 2.0)
|
|
end
|
|
return self._header_sub
|
|
end
|
|
|
|
function SongSelect:course_label(diff)
|
|
local lbl = self._course_labels[diff]
|
|
if lbl == nil then
|
|
local key = "course_name_" .. diff
|
|
if tex.get_skin_config(key) then
|
|
lbl = text.create_text(key, { 255, 255, 255, 255 }, { 20, 20, 20, 255 }, false, outline(4.5), 1.0)
|
|
end
|
|
self._course_labels[diff] = lbl or false
|
|
end
|
|
return lbl or nil
|
|
end
|