mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-26 15:31:15 +02:00
b796c30278
Inset save-editor chrome and pickers into SafeArea so Save stays tappable on punch-hole phones (#917), replace move cycling with a ranked search modal that reflows on phones/RGxxx, and omit the engine version from window titles on stamped release builds.
137 lines
5.0 KiB
Lua
137 lines
5.0 KiB
Lua
-- Type-to-search move picker. The inspector used to change moves by cycling
|
|
-- the catalog one tap at a time -- 165 taps to walk Gen1 -- which is the same
|
|
-- class of friction the species arrows had before #541. This is the
|
|
-- replacement: one modal list, filtered as you type, committing through
|
|
-- Ops.setMove so an unusable / scalar id refuses instead of asserting.
|
|
--
|
|
-- Modal is literal. Kit hit-tests without a z-order, so App.draw raises
|
|
-- Kit.blockClicks over the chrome and the panel while this is open and lowers
|
|
-- it only for this overlay; nothing underneath can take the same tap.
|
|
|
|
local Theme = require("Theme")
|
|
local Ops = require("Ops")
|
|
local PickerChrome = require("PickerChrome")
|
|
local PAL = Theme.PAL
|
|
|
|
local Picker = {}
|
|
|
|
local FIELD_ID = "move-picker"
|
|
|
|
function Picker.results(S)
|
|
local p = S.movePicker
|
|
return Ops.moveSearch(S, p and p.query or "")
|
|
end
|
|
|
|
local function commit(S, id)
|
|
local p = S.movePicker
|
|
if not p then return false end
|
|
return Ops.setMove(S, S.editingMon, p.slot, id)
|
|
end
|
|
|
|
-- Enter commits the top match, which is the whole point of a search field.
|
|
function Picker.commitFirst(S, Kit)
|
|
local hits = Picker.results(S)
|
|
if not hits[1] then return Ops.say(S, "No move matches that") end
|
|
local ok = commit(S, hits[1])
|
|
if ok then Ops.closeMovePicker(S, Kit) end
|
|
return ok
|
|
end
|
|
|
|
function Picker.draw(S, Kit, width, height)
|
|
local p = S.movePicker
|
|
if not p then return end
|
|
local s = Kit.scale
|
|
|
|
-- The click that opened the picker is still the frame's click: the
|
|
-- inspector dispatches earlier in App.draw than this overlay does, so
|
|
-- without swallowing it the scrim below would read it as a tap outside and
|
|
-- shut the picker in the same frame it went up. App re-raises the shield
|
|
-- at the top of the next frame, so leaving it up here is safe.
|
|
if p.opened then
|
|
p.opened = nil
|
|
Kit.blockClicks = true
|
|
end
|
|
|
|
-- the scrim doubles as the "tap outside to cancel" target; it covers the
|
|
-- full window so unsafe bands (notch / home indicator) stay dimmed too
|
|
Theme.col(PAL.bgBot, 0.72)
|
|
love.graphics.rectangle("fill", 0, 0, width, height)
|
|
|
|
-- Card fills / centres in SafeArea so phones and RGxxx landscapes keep a
|
|
-- usable list (#917 / #715).
|
|
local x, y, w, h, pad = PickerChrome.card(Kit, width, height)
|
|
if Kit.press(0, 0, width, height) and not Kit.hit(x, y, w, h) then
|
|
Ops.closeMovePicker(S, Kit)
|
|
return
|
|
end
|
|
|
|
Kit.card(x, y, w, h)
|
|
local cx, cy = x + pad, y + pad
|
|
local inner = w - 2 * pad
|
|
|
|
local closeW = PickerChrome.closeSize(Kit)
|
|
local captionH = Kit.textHeight("caption")
|
|
local headH = math.max(captionH, closeW)
|
|
Kit.caption(cx, cy + (headH - captionH) / 2, ("CHOOSE MOVE %d"):format(p.slot or 1))
|
|
if Kit.button(x + w - pad - closeW, cy + (headH - closeW) / 2, closeW, closeW, "x",
|
|
{ font = "small", radius = 7 * s }) then
|
|
Ops.closeMovePicker(S, Kit)
|
|
return
|
|
end
|
|
cy = cy + headH + 10 * s
|
|
|
|
local fieldH = PickerChrome.fieldH(Kit)
|
|
p.query = Kit.textfield(FIELD_ID, cx, cy, inner, fieldH, p.query,
|
|
"type a name, an id, or a type")
|
|
cy = cy + fieldH + 10 * s
|
|
|
|
local hits = Picker.results(S)
|
|
local listH, rowH, rowGap, pagerH = PickerChrome.listMetrics(Kit, y, h, pad, cy)
|
|
local perPage = math.max(1, math.floor((listH + rowGap) / (rowH + rowGap)))
|
|
p.offset = Theme.clamp(p.offset or 0, 0, math.max(0, #hits - perPage))
|
|
-- wheel / touch drag scroll the modal list too; the shield is already
|
|
-- lowered for this layer, so Kit.scroll works here and only here (#715)
|
|
p.offset = Kit.scroll(cx, cy, inner, listH, p.offset, #hits, perPage)
|
|
|
|
local mon = S.editingMon
|
|
local currentId = mon and mon.moves and mon.moves[p.slot]
|
|
and mon.moves[p.slot].id
|
|
|
|
if #hits == 0 then
|
|
Kit.emptyBox(cx, cy, inner, listH, "Nothing matches that.")
|
|
else
|
|
Kit.pushClip(cx, cy, inner, listH)
|
|
for i = 1, perPage do
|
|
local id = hits[p.offset + i]
|
|
if not id then break end
|
|
local ry = cy + (i - 1) * (rowH + rowGap)
|
|
local def = S.data.moves[id]
|
|
local usable = Ops.moveUsable(S, id)
|
|
local current = currentId == id
|
|
if Kit.row(cx, ry, inner, rowH, current, PAL.green, 9 * s) then
|
|
if commit(S, id) then
|
|
Ops.closeMovePicker(S, Kit)
|
|
Kit.popClip()
|
|
return
|
|
end
|
|
end
|
|
local typ = usable and tostring(def and def.type or "?") or "no data"
|
|
local pp = usable and ("PP %d"):format(tonumber(def and def.pp) or 0) or ""
|
|
local tail = pp ~= "" and (typ .. " " .. pp) or typ
|
|
local tailW = Kit.textWidth("tiny", tail)
|
|
Kit.text("monoRow",
|
|
Kit.ellipsize("monoRow", id, inner - tailW - 28 * s),
|
|
cx + 12 * s, ry + (rowH - Kit.textHeight("monoRow")) / 2,
|
|
usable and PAL.text or PAL.faint)
|
|
Kit.textRight("tiny", tail, cx + inner - 10 * s,
|
|
ry + (rowH - Kit.textHeight("tiny")) / 2, PAL.caption)
|
|
end
|
|
Kit.popClip()
|
|
Kit.scrollbar(cx, cy, inner, listH, p.offset, #hits, perPage)
|
|
end
|
|
|
|
p.offset = Kit.pager(cx, y + h - pad - pagerH, inner, p.offset, #hits, perPage)
|
|
end
|
|
|
|
return Picker
|