forked from Yonokid/YataiDONNijiiro
202 lines
8.8 KiB
Lua
202 lines
8.8 KiB
Lua
-- Difficulty sort window, split out of song_select.lua.
|
|
|
|
local base = require("song_select/file_navigator/box_base")
|
|
|
|
local draw_centered = base.draw_centered
|
|
local draw_title = base.draw_title
|
|
local draw_guide_label = base.draw_guide_label
|
|
local outline = base.outline
|
|
local GUIDE_SELECT_CX, GUIDE_DECIDE_CX = base.GUIDE_SELECT_CX, base.GUIDE_DECIDE_CX
|
|
|
|
local SW_ROW_Y = { 410, 551, 692 }
|
|
local SW_BOARD_W, SW_BOARD_H = 1320, 760
|
|
local SW_CURSOR_W, SW_CURSOR_H = 1240, 180
|
|
local SW_PILL_CX = 1124 -- 960 + 164
|
|
local SW_PILL_W, SW_PILL_H = 792, 104
|
|
local SW_MARK_CX = 871 -- 960 - 89
|
|
local SW_ARROW_LX = 786 -- 960 - 174
|
|
local SW_ARROW_RX = 1462 -- 960 + 502
|
|
local SW_HEADER_CX = 560 -- 960 - 400
|
|
local SW_TEXT_DY = -13
|
|
local SW_GUIDE_Y = 827
|
|
local SW_GUIDE_W, SW_GUIDE_H = 372, 96
|
|
local SW_NUM_RIGHT = 1379
|
|
local SW_NUM_Y = 289
|
|
local SW_NUM_PITCH = 34
|
|
local SW_NUM_W, SW_NUM_H = 48, 56
|
|
local SW_SONGS_X = 1402 -- ink LEFT edge (EditText align = left)
|
|
local SW_SONGS_Y = 277
|
|
local SW_TITLE_X = 405
|
|
local SW_TITLE_Y = 272
|
|
local SW_TITLE_OUTLINE = { 119, 26, 45, 255 }
|
|
local SW_HEADER_BOX_W = 310
|
|
local SW_ITEM_BOX_W = { 620, 430, 430 }
|
|
local SW_CURSOR_CYCLE = 51.0
|
|
|
|
local SW_KEYS = {
|
|
header = { "sort_window_diff", "sort_window_star", "sort_window_order" },
|
|
course = { "course_name_0", "course_name_1", "course_name_2", "course_name_3", "course_name_3" },
|
|
order = { "sort_window_order_0", "sort_window_order_1", "sort_window_order_2", "sort_window_order_3" },
|
|
title = "folder_sort_select",
|
|
songs = "sort_window_songs",
|
|
}
|
|
|
|
local function sw_words(group)
|
|
local k = SW_KEYS[group]
|
|
if type(k) == "table" then
|
|
local out = {}
|
|
for i, key in ipairs(k) do out[i] = tex.skin_text(key) end
|
|
return out
|
|
end
|
|
return tex.skin_text(k)
|
|
end
|
|
|
|
-- OutlinedText cache: key = group .. "\0" .. index.
|
|
function SongSelect:_sw_text(key, str, size, thickness, outline)
|
|
self._sw_texts = self._sw_texts or {}
|
|
local t = self._sw_texts[key]
|
|
if t == nil then
|
|
t = text.create_raw_text(str, size, { 255, 255, 255, 255 },
|
|
outline or { 0, 0, 0, 255 }, false, thickness, 2.0)
|
|
self._sw_texts[key] = t or false
|
|
end
|
|
return t or nil
|
|
end
|
|
|
|
-- Fit-shrink: when a string does not fit its box, re-rasterise it at a smaller (uniformly
|
|
-- scaled) point size instead of stretching the bitmap, so glyphs keep their proportions.
|
|
local SW_FIT_MIN_SIZE = 22
|
|
function SongSelect:_sw_text_fit(key, str, size, thickness, outline, max_w)
|
|
self._sw_texts = self._sw_texts or {}
|
|
local t = self._sw_texts[key]
|
|
if t == nil then
|
|
t = text.create_raw_text(str, size, { 255, 255, 255, 255 },
|
|
outline or { 0, 0, 0, 255 }, false, thickness, 2.0)
|
|
if t and max_w and t.width > max_w then
|
|
local fit_size = math.max(SW_FIT_MIN_SIZE, math.floor(size * max_w / t.width))
|
|
if fit_size < size then
|
|
local fit_thickness = thickness * fit_size / size
|
|
local t2 = text.create_raw_text(str, fit_size, { 255, 255, 255, 255 },
|
|
outline or { 0, 0, 0, 255 }, false, fit_thickness, 2.0)
|
|
if t2 then t = t2 end
|
|
end
|
|
end
|
|
self._sw_texts[key] = t or false
|
|
end
|
|
return t or nil
|
|
end
|
|
|
|
-- Draw an OutlinedText with its ink LEFT edge on x.
|
|
local function draw_text_left(t, x, cy, fade)
|
|
if not t then return end
|
|
t:draw({ x = math.floor(x + 0.5), y = math.floor(cy - t.height / 2 + 0.5), fade = fade })
|
|
end
|
|
|
|
-- cursor glow alpha over the 51-frame loop, sampled from anim/sort_cursor.
|
|
local sort_cursor_ok, sort_cursor_anim = pcall(require, "anim/sampler")
|
|
local SW_CURSOR_CLIP = (sort_cursor_ok and sort_cursor_anim.safe("anim/sort_cursor"))
|
|
or { get = function() return nil end, label = function() return nil end }
|
|
local SW_ON_F = SW_CURSOR_CLIP:label("on") or 9
|
|
local function sw_cursor_glow(ms)
|
|
local r = (ms * 0.06) % SW_CURSOR_CYCLE
|
|
local a = SW_CURSOR_CLIP:get("#3@0", SW_ON_F + r, "a")
|
|
if a then return a end
|
|
if r <= 20.0 then return 1.0 - r / 20.0 end
|
|
return (r - 20.0) / 30.0
|
|
end
|
|
|
|
function SongSelect:_sw_ids()
|
|
if self._sw_loaded then return end
|
|
tex.load_folder("song_select", "diff_sort")
|
|
self._id_sw_board = tex.get_texture("song_select/diff_sort/background") -- 1320x760 window
|
|
self._id_sw_pill = tex.get_texture("song_select/diff_sort/level_box") -- 792x104 white item pill
|
|
self._id_sw_cur = tex.get_texture("song_select/diff_sort/box_highlight") -- 1240x180 flat yellow bar
|
|
self._id_sw_glow = tex.get_texture("song_select/diff_sort/box_outline") -- 1240x180 pulsing glow
|
|
self._id_sw_mark = tex.get_texture("song_select/diff_sort/diff") -- 96x96, frame = course
|
|
self._id_sw_arrow = tex.get_texture("song_select/diff_sort/arrow") -- 48x56, frame 1 = rotated
|
|
self._id_sw_digit = tex.get_texture("song_select/diff_sort/stat_num") -- 48x56, frame = digit
|
|
self._id_sw_guide = tex.get_texture("song_select/diff_sort/star_select_text") -- s_menfuchi_kp loop
|
|
self._sw_loaded = true
|
|
end
|
|
|
|
function SongSelect:draw_sort_window(w)
|
|
-- the classic two-step window is the default sort_window module's
|
|
if not w:one_menu() then return false end
|
|
self:_sw_ids()
|
|
local a = w:alpha()
|
|
if a <= 0.0 or not self._id_sw_board then return end
|
|
local ms = tex.get_current_ms()
|
|
local session = w:session()
|
|
local vals = { w:diff(), w:star(), w:order() }
|
|
|
|
draw_centered(self._id_sw_board, 960, 540, SW_BOARD_W, SW_BOARD_H, { fade = a })
|
|
|
|
-- the three rows, in the cabinet's own depth order (order, star, diff)
|
|
for row = 3, 1, -1 do
|
|
local ry = SW_ROW_Y[row]
|
|
local idx = row - 1 -- 0-based, matching SortWindow:session()
|
|
if idx == session and self._id_sw_cur then
|
|
if self._id_sw_glow then
|
|
draw_centered(self._id_sw_glow, 960, ry, SW_CURSOR_W, SW_CURSOR_H,
|
|
{ fade = a * sw_cursor_glow(ms) })
|
|
end
|
|
draw_centered(self._id_sw_cur, 960, ry, SW_CURSOR_W, SW_CURSOR_H, { fade = a })
|
|
end
|
|
if self._id_sw_pill then
|
|
draw_centered(self._id_sw_pill, SW_PILL_CX, ry, SW_PILL_W, SW_PILL_H, { fade = a })
|
|
end
|
|
-- diff_mark is visible on the むずかしさ row only
|
|
if row == 1 and self._id_sw_mark then
|
|
draw_centered(self._id_sw_mark, SW_MARK_CX, ry, 96, 96,
|
|
{ frame = math.max(0, math.min(4, vals[1] - 1)), fade = a })
|
|
end
|
|
if self._id_sw_arrow then
|
|
local dx = w:arrow_offset(idx)
|
|
draw_centered(self._id_sw_arrow, SW_ARROW_LX + dx, ry, 48, 56, { frame = 0, fade = a })
|
|
draw_centered(self._id_sw_arrow, SW_ARROW_RX - dx, ry, 48, 56, { frame = 1, fade = a })
|
|
end
|
|
-- item value
|
|
local str, key
|
|
if row == 1 then
|
|
local n = math.max(1, math.min(5, vals[1]))
|
|
str, key = sw_words("course")[n], "course" .. n
|
|
elseif row == 2 then
|
|
str, key = tostring(vals[2]), "star" .. vals[2]
|
|
else
|
|
local n = math.max(1, math.min(4, vals[3]))
|
|
str, key = sw_words("order")[n], "order" .. n
|
|
end
|
|
draw_title(self:_sw_text_fit(key, str, 42, outline(6.5), nil, SW_ITEM_BOX_W[row]),
|
|
SW_PILL_CX, ry + SW_TEXT_DY, a, SW_ITEM_BOX_W[row], 0)
|
|
-- header
|
|
draw_title(self:_sw_text_fit("hdr" .. row, sw_words("header")[row], 42, outline(6.5), nil, SW_HEADER_BOX_W),
|
|
SW_HEADER_CX, ry + SW_TEXT_DY, a, SW_HEADER_BOX_W, 0)
|
|
end
|
|
|
|
-- control guide + its two pill labels
|
|
if self._id_sw_guide then
|
|
local cell = math.floor((ms * 0.06) % 210)
|
|
draw_centered(self._id_sw_guide, 960, SW_GUIDE_Y, SW_GUIDE_W, SW_GUIDE_H,
|
|
{ frame = cell, fade = a })
|
|
local labels = self:guide_labels()
|
|
if labels then
|
|
draw_guide_label(labels.select, GUIDE_SELECT_CX, SW_GUIDE_Y + 2, a)
|
|
draw_guide_label(labels.decide, GUIDE_DECIDE_CX, SW_GUIDE_Y + 2, a)
|
|
end
|
|
end
|
|
|
|
-- song counter: 「N 曲」 (right-aligned digits, then the unit label)
|
|
local n = math.max(0, math.min(9999, w:song_num()))
|
|
local digits = tostring(n)
|
|
for i = 1, #digits do
|
|
local d = tonumber(digits:sub(i, i))
|
|
local x = SW_NUM_RIGHT - (#digits - i) * SW_NUM_PITCH
|
|
draw_centered(self._id_sw_digit, x, SW_NUM_Y, SW_NUM_W, SW_NUM_H, { frame = d, fade = a })
|
|
end
|
|
draw_text_left(self:_sw_text("songs", sw_words("songs"), 42, outline(6.5)), SW_SONGS_X, SW_SONGS_Y, a)
|
|
|
|
-- board title, with the cabinet's dark-red outline add
|
|
draw_text_left(self:_sw_text("title", sw_words("title"), 54, outline(7.5), SW_TITLE_OUTLINE),
|
|
SW_TITLE_X, SW_TITLE_Y, a)
|
|
end
|