166 lines
6.8 KiB
Lua
166 lines
6.8 KiB
Lua
-- Practice mode pause menu: the row of bars, and the confirm dialogs (end / another song / restart /
|
|
-- auto play). The engine's PracticeMenu keeps the state (open, selected row, dialog, selected button)
|
|
-- and the actions; this draws it and says which bar or button a pointer is over.
|
|
--
|
|
-- Rows, in order: end game, another song, restart, auto play, jump to mark, set mark, close.
|
|
|
|
PracticeMenu = {}
|
|
PracticeMenu.__index = PracticeMenu
|
|
|
|
local S = tex.get_screen_scale()
|
|
local SKIN = {
|
|
panel = { y = 188.0001, width = 940 * S, height = 460 * S },
|
|
bar = { gap = 36 * S, width = 92 * S, height = 378 * S },
|
|
label = { y = 16 * S, width = 350 * S, font_size = 32 },
|
|
dialog_font_size = 32,
|
|
dialog_title_y = 100 * S,
|
|
dialog_title_auto_y = 56 * S,
|
|
button = { x = 160 * S, y = 240 * S, width = 212 * S, height = 102 * S },
|
|
auto_label = { y = 150 * S, width = 290 * S },
|
|
auto_toggle = { gap = 40 * S, y = 280 * S, width = 240 * S },
|
|
toggle_y = 6 * S,
|
|
}
|
|
|
|
local WHITE, BLACK = { 255, 255, 255, 255 }, { 0, 0, 0, 255 }
|
|
|
|
local ROWS = {
|
|
"practice_menu_end_game", "practice_menu_another_song", "practice_menu_restart",
|
|
"practice_menu_auto_play", "practice_menu_jump_to_mark", "practice_menu_set_mark",
|
|
"practice_menu_close",
|
|
}
|
|
|
|
local DIALOGS = {
|
|
auto = { title = "practice_menu_confirm_auto", left = "practice_menu_auto_on", right = "practice_menu_auto_off" },
|
|
restart = { title = "practice_menu_confirm_restart", left = "practice_menu_yes", right = "practice_menu_no" },
|
|
another = { title = "practice_menu_confirm_another", left = "practice_menu_yes", right = "practice_menu_no" },
|
|
["end"] = { title = "practice_menu_confirm_end", left = "practice_menu_yes", right = "practice_menu_no" },
|
|
}
|
|
|
|
local function sprite(name)
|
|
return tex.get_texture("practice/" .. name)
|
|
end
|
|
|
|
function PracticeMenu.new()
|
|
return setmetatable({ lang = nil }, PracticeMenu)
|
|
end
|
|
|
|
-- the texts, rebuilt when the language changes
|
|
function PracticeMenu:texts()
|
|
local lang = tex.language()
|
|
if self.lang == lang then return end
|
|
self.lang = lang
|
|
self.rows, self.dialogs = {}, {}
|
|
|
|
local base = SKIN.label.font_size > 0 and SKIN.label.font_size or 1
|
|
for i, key in ipairs(ROWS) do
|
|
local label = tex.skin_text(key)
|
|
local _, chars = label:gsub("[^\128-\191]", "")
|
|
local fs, v = base, 1.0
|
|
if chars > 1 then
|
|
v = (SKIN.label.width / fs - 1.0) / (chars - 1)
|
|
if v < 0.7 then
|
|
v = 0.7
|
|
fs = math.max(1, math.floor(SKIN.label.width / (1.0 + (chars - 1) * 0.7)))
|
|
elseif v > 1.0 then
|
|
v = 1.0
|
|
end
|
|
end
|
|
self.rows[i] = text.create_raw_text(label, fs, WHITE, BLACK, true, 5.0 * fs / base, 2.0, v)
|
|
end
|
|
|
|
local fs = SKIN.dialog_font_size > 0 and SKIN.dialog_font_size or 1
|
|
for name, d in pairs(DIALOGS) do
|
|
self.dialogs[name] = {
|
|
title = text.create_raw_text(tex.skin_text(d.title), fs, WHITE, BLACK, false),
|
|
left = text.create_raw_text(tex.skin_text(d.left), fs, WHITE, BLACK, false),
|
|
right = text.create_raw_text(tex.skin_text(d.right), fs, WHITE, BLACK, false),
|
|
}
|
|
end
|
|
end
|
|
|
|
local function panel_x()
|
|
return (tex.get_screen_width() - SKIN.panel.width) / 2.0
|
|
end
|
|
|
|
-- x of the left and right dialog buttons, and their y
|
|
local function dialog_buttons(dialog)
|
|
local px, b = panel_x(), SKIN.button
|
|
if dialog == "auto" then
|
|
local t = SKIN.auto_toggle
|
|
local total = b.width * 2 + t.width + t.gap * 2
|
|
local left = px + (SKIN.panel.width - total) / 2.0
|
|
return left, left + b.width + t.gap + t.width + t.gap, SKIN.panel.y + t.y
|
|
end
|
|
return px + b.x, px + SKIN.panel.width - b.x - b.width, SKIN.panel.y + b.y
|
|
end
|
|
|
|
local function inside(x, y, left, top, w, h)
|
|
return x >= left and x <= left + w and y >= top and y <= top + h
|
|
end
|
|
|
|
-- bar under the pointer (0-based), or the dialog button (0 = left, 1 = right); nil if none
|
|
function PracticeMenu:hit_test(x, y, dialog)
|
|
local b = SKIN.button
|
|
if dialog then
|
|
local left, right, row_y = dialog_buttons(dialog)
|
|
if inside(x, y, left, row_y, b.width, b.height) then return 0 end
|
|
if inside(x, y, right, row_y, b.width, b.height) then return 1 end
|
|
return nil
|
|
end
|
|
local n, bar = #ROWS, SKIN.bar
|
|
local pad = (SKIN.panel.width - n * bar.width - (n - 1) * bar.gap) / 2.0
|
|
local top = SKIN.panel.y + (SKIN.panel.height - bar.height) / 2.0
|
|
for i = 0, n - 1 do
|
|
if inside(x, y, panel_x() + pad + i * (bar.width + bar.gap), top, bar.width, bar.height) then
|
|
return i
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function PracticeMenu:draw(index)
|
|
self:texts()
|
|
local n, bar, px = #ROWS, SKIN.bar, panel_x()
|
|
local pad = (SKIN.panel.width - n * bar.width - (n - 1) * bar.gap) / 2.0
|
|
tex.draw_texture(sprite("menu_panel"), { x = px, y = SKIN.panel.y })
|
|
|
|
for i = 0, n - 1 do
|
|
local x = px + pad + i * (bar.width + bar.gap)
|
|
local y = SKIN.panel.y + (SKIN.panel.height - bar.height) / 2.0
|
|
tex.draw_texture(sprite(i == index and "menu_bar_selected" or "menu_bar"), { x = x, y = y })
|
|
local label = self.rows[i + 1]
|
|
-- top-aligned like the arcade, not centred
|
|
label:draw({ x = x + (bar.width - label.width) / 2.0, y = y + SKIN.label.y })
|
|
end
|
|
end
|
|
|
|
-- sel: 0 = left button, 1 = right
|
|
function PracticeMenu:draw_dialog(dialog, sel)
|
|
self:texts()
|
|
local px, pw, b = panel_x(), SKIN.panel.width, SKIN.button
|
|
local d = self.dialogs[dialog]
|
|
if not d then return end
|
|
tex.draw_texture(sprite("menu_panel"), { x = px, y = SKIN.panel.y })
|
|
|
|
-- the auto dialog stacks a label chip and the toggle row below its title, so the title sits
|
|
-- high; the yes/no confirms sit lower
|
|
local title_y = (dialog == "auto") and SKIN.dialog_title_auto_y or SKIN.dialog_title_y
|
|
d.title:draw({ x = px + (pw - d.title.width) / 2.0, y = SKIN.panel.y + title_y })
|
|
|
|
local left, right, row_y = dialog_buttons(dialog)
|
|
if dialog == "auto" then
|
|
tex.draw_texture(sprite("menu_auto_label"),
|
|
{ x = px + (pw - SKIN.auto_label.width) / 2.0, y = SKIN.panel.y + SKIN.auto_label.y })
|
|
-- the red knob slides toward whichever side is picked
|
|
tex.draw_texture(sprite("menu_toggle"), {
|
|
mirror = sel == 1 and "horizontal" or nil,
|
|
x = left + b.width + SKIN.auto_toggle.gap, y = row_y + SKIN.toggle_y,
|
|
})
|
|
end
|
|
|
|
tex.draw_texture(sprite(sel == 0 and "menu_button_selected" or "menu_button"), { x = left, y = row_y })
|
|
tex.draw_texture(sprite(sel == 1 and "menu_button_selected" or "menu_button"), { x = right, y = row_y })
|
|
d.left:draw({ x = left + (b.width - d.left.width) / 2.0, y = row_y + (b.height - d.left.height) / 2.0 })
|
|
d.right:draw({ x = right + (b.width - d.right.width) / 2.0, y = row_y + (b.height - d.right.height) / 2.0 })
|
|
end
|