mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
123feef3a1
CLOSES #2425, CLOSES #2428, CLOSES #2431, CLOSES #2432, CLOSES #2433, CLOSES #2435, CLOSES #2436, CLOSES #2437, CLOSES #2440
511 lines
19 KiB
Lua
511 lines
19 KiB
Lua
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
love = require("tests.love_stub")
|
|
love.graphics.setLineJoin = function() end
|
|
love.graphics.newShader = function() return {} end
|
|
local T = require("tests.harness")
|
|
local Kit = require("src.ui.kit.Kit")
|
|
local View = require("src.import.LauncherView")
|
|
local Transition = require("src.ui.kit.Transition")
|
|
local Importer = require("src.import.RomImporter")
|
|
local GameVersion = require("src.core.GameVersion")
|
|
|
|
local width, height = 853, 480
|
|
love.graphics.getDimensions = function() return width, height end
|
|
love.graphics.getPixelDimensions = love.graphics.getDimensions
|
|
local mouseX, mouseY = -100, -100
|
|
love.mouse.getPosition = function() return mouseX, mouseY end
|
|
local now = 100
|
|
love.timer.getTime = function() return now end
|
|
|
|
local CATEGORIES = { "graphics", "gameplay", "audio", "qol", "translation", "challenge", "ui" }
|
|
|
|
local function fixture(tab)
|
|
local imp = Importer.new(function() end, { launcher = true, onEditSave = function() end })
|
|
for _, v in ipairs(GameVersion.ORDER) do imp.ready[v] = true end
|
|
imp._ensureSlots, imp._ensureMods = function() end, function() end
|
|
imp._refreshMods = function() end
|
|
imp._resetModOrder = function(self) self.didReset = true end
|
|
imp.mods = {}
|
|
imp.tab = tab
|
|
return imp
|
|
end
|
|
|
|
local MODALS = {
|
|
{ key = "_modScopePopup", tab = "mods", close = "Close",
|
|
open = function(imp) imp._modScopePopup = true end },
|
|
{ key = "_filterPopup", tab = "find", close = "Close",
|
|
open = function(imp)
|
|
imp.findIndex = { categories = CATEGORIES, baseGames = {} }
|
|
imp._filterPopup = true
|
|
end },
|
|
{ key = "_sortPopup", tab = "mods", close = "Close",
|
|
open = function(imp) imp._sortPopup = "mods" end },
|
|
{ key = "_indexManage", tab = "find", close = "Close",
|
|
open = function(imp)
|
|
imp.findSources = {}
|
|
for i = 1, 6 do imp.findSources[i] = { feed = "https://x/" .. i, label = "Index " .. i } end
|
|
imp._indexManage = true
|
|
end },
|
|
}
|
|
|
|
local function draw(imp)
|
|
Kit.audit = {}
|
|
View.draw(imp)
|
|
Transition.reset()
|
|
Kit.audit = {}
|
|
View.draw(imp)
|
|
local rects = Kit.audit
|
|
Kit.audit = nil
|
|
return rects
|
|
end
|
|
|
|
local function opened(spec)
|
|
local imp = fixture(spec.tab)
|
|
View.draw(imp)
|
|
spec.open(imp)
|
|
return imp, draw(imp)
|
|
end
|
|
|
|
local function inside(r, W, H)
|
|
return r.x >= 0 and r.y >= 0 and r.x + r.w <= W + 0.5 and r.y + r.h <= H + 0.5
|
|
end
|
|
|
|
local function within(inner, outer)
|
|
return inner.x >= outer.x - 0.5 and inner.y >= outer.y - 0.5
|
|
and inner.x + inner.w <= outer.x + outer.w + 0.5
|
|
and inner.y + inner.h <= outer.y + outer.h + 0.5
|
|
end
|
|
|
|
for _, size in ipairs({ { 853, 480 }, { 780, 360 }, { 1280, 720 } }) do
|
|
width, height = size[1], size[2]
|
|
for _, spec in ipairs(MODALS) do
|
|
local imp, rects = opened(spec)
|
|
local tag = ("%s at %dx%d"):format(spec.key, width, height)
|
|
T.eq(View.modalKey(imp), spec.key, tag .. " is the open modal")
|
|
local state = imp._modalScroll and imp._modalScroll[spec.key]
|
|
T.check(state ~= nil and state.rect ~= nil, tag .. " records a scroll rect")
|
|
local closeSeen, escaped = false, {}
|
|
for _, r in ipairs(rects) do
|
|
if r.clip then
|
|
if not inside(r.clip, width, height) then escaped[#escaped + 1] = r.label .. " clip" end
|
|
if state and not within(r.clip, state.rect) then escaped[#escaped + 1] = r.label .. " clip outside body" end
|
|
elseif not inside(r, width, height) then
|
|
escaped[#escaped + 1] = r.label
|
|
end
|
|
if r.label == spec.close and not r.clip then
|
|
closeSeen = true
|
|
T.check(inside(r, width, height), tag .. " Close is on screen")
|
|
end
|
|
end
|
|
T.check(closeSeen, tag .. " draws a pinned Close")
|
|
T.check(#escaped == 0, tag .. " keeps every control on screen or in the scroll clip: "
|
|
.. table.concat(escaped, ", "))
|
|
if state and state.rect then
|
|
T.check(inside(state.rect, width, height), tag .. " scroll body is on screen")
|
|
end
|
|
end
|
|
end
|
|
|
|
width, height = 1280, 720
|
|
do
|
|
local imp = opened(MODALS[1])
|
|
T.eq(imp._modalScroll._modScopePopup.maxScroll, 0, "Show-for fits without scrolling at 1280x720")
|
|
end
|
|
|
|
for _, size in ipairs({ { 853, 480 }, { 780, 360 } }) do
|
|
width, height = size[1], size[2]
|
|
local imp = opened(MODALS[1])
|
|
local state = imp._modalScroll._modScopePopup
|
|
T.check(state.maxScroll > 0, ("Show-for list overflows at %dx%d"):format(width, height))
|
|
local r = state.rect
|
|
local scopeBefore = imp.modScope
|
|
now = now + 1
|
|
View.touchpressed(imp, 7, r.x + 20, r.y + r.h - 5)
|
|
View.touchmoved(imp, 7, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
now = now + 1
|
|
View.touchreleased(imp, 7, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.check(state.scroll > 0, ("touch drag scrolls Show-for at %dx%d"):format(width, height))
|
|
T.check(imp._modScopePopup ~= nil, "drag leaves Show-for open")
|
|
T.eq(imp.modScope, scopeBefore, "drag does not pick a scope")
|
|
|
|
state.scroll = 0
|
|
mouseX, mouseY = r.x + 20, r.y + 10
|
|
imp._wheelY = -1
|
|
draw(imp)
|
|
mouseX, mouseY = -100, -100
|
|
T.check(state.scroll > 0, ("mouse wheel scrolls Show-for at %dx%d"):format(width, height))
|
|
|
|
state.scroll = 0
|
|
now = now + 1
|
|
Kit.setFocus("scopepop-leafgreen")
|
|
local rects = draw(imp)
|
|
local shown = false
|
|
for _, a in ipairs(rects) do
|
|
if a.label == GameVersion.info("leafgreen").label and a.clip
|
|
and a.y >= a.clip.y - 0.5 and a.y + a.h <= a.clip.y + a.clip.h + 0.5 then
|
|
shown = true
|
|
end
|
|
end
|
|
T.check(shown, ("focusing LeafGreen scrolls it into view at %dx%d"):format(width, height))
|
|
Kit.activateFocused()
|
|
View.draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.eq(imp.modScope, "leafgreen", "LeafGreen is selectable from the Show-for list")
|
|
T.eq(imp._modScopePopup, nil, "choosing a scope closes Show-for")
|
|
draw(imp)
|
|
T.eq(imp._modalScroll and imp._modalScroll._modScopePopup, nil, "closing drops the scroll state")
|
|
Kit.setFocus(nil)
|
|
end
|
|
|
|
width, height = 780, 360
|
|
do
|
|
local imp = opened(MODALS[2])
|
|
local state = imp._modalScroll._filterPopup
|
|
T.check(state.maxScroll > 0, "FIND filter overflows at 780x360")
|
|
local r = state.rect
|
|
now = now + 1
|
|
View.touchpressed(imp, 9, r.x + 20, r.y + r.h - 5)
|
|
View.touchmoved(imp, 9, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
now = now + 1
|
|
View.touchreleased(imp, 9, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.check(state.scroll > 0, "touch drag scrolls the FIND filter")
|
|
T.check(imp._filterPopup ~= nil, "drag leaves the FIND filter open")
|
|
now = now + 1
|
|
Kit.setFocus("filterpop-ui")
|
|
draw(imp)
|
|
Kit.activateFocused()
|
|
View.draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.eq(imp.findCategory, "ui", "last FIND category is selectable")
|
|
Kit.setFocus(nil)
|
|
end
|
|
|
|
do
|
|
local imp = opened(MODALS[3])
|
|
local state = imp._modalScroll._sortPopup
|
|
T.check(state.maxScroll > 0, "sort list overflows at 780x360")
|
|
now = now + 1
|
|
Kit.setFocus("sortpop-reset-order")
|
|
draw(imp)
|
|
Kit.activateFocused()
|
|
View.draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.check(imp.didReset == true, "Reset load order is reachable at 780x360")
|
|
Kit.setFocus(nil)
|
|
end
|
|
|
|
local LONG = "This paragraph is long on purpose so it wraps across several lines of the"
|
|
.. " modal body at phone widths and pushes the controls below it off a short window."
|
|
|
|
local function richMods(imp)
|
|
local imports = {}
|
|
for i = 1, 6 do
|
|
imports[i] = { id = "f" .. i, name = "File " .. i, file = "file" .. i .. ".bin",
|
|
required = i % 2 == 1, description = "Needed piece " .. i, present = i == 2 }
|
|
end
|
|
imp.mods = {
|
|
{ id = "alpha", name = "Alpha", version = "1.0.0", status = "enabled", github = "o/alpha",
|
|
dependencySpecs = { { id = "beta" } }, imports = imports, loadRank = 1,
|
|
missingRequiredImports = 3 },
|
|
{ id = "beta", name = "Beta", version = "1.0.0", status = "enabled", loadRank = 2 },
|
|
{ id = "gamma", name = "Gamma", version = "1.0.0", status = "enabled", loadRank = 3 },
|
|
}
|
|
imp.requiredImportNotice = { modId = "alpha", importId = "f1", text = LONG }
|
|
end
|
|
|
|
local function profiles(imp, n)
|
|
local list = {}
|
|
for i = 1, n do list[i] = { name = "Profile " .. i } end
|
|
imp._profileCache = { options = {}, list = list, active = "Profile 1" }
|
|
end
|
|
|
|
local function syncEngine(linked)
|
|
local devices = {}
|
|
for i = 1, 4 do devices[i] = { id = "d" .. i, label = "Device " .. i, current = i == 1 } end
|
|
return {
|
|
phase = "idle", status = "Last sync a minute ago", devices = devices,
|
|
codes = linked and { code1 = "ABCD-EFGH", code2 = "IJKL-MNOP" } or nil,
|
|
shareCode = "QRSTUV", conflicts = {},
|
|
busy = function() return false end,
|
|
linked = function() return linked end,
|
|
}
|
|
end
|
|
|
|
local SWEEP = {
|
|
{ key = "_saveExport", tab = "red", open = function(imp)
|
|
imp._saveExport = { scope = "red", version = "red", label = LONG, slotId = "a" }
|
|
end },
|
|
{ key = "_rename", tab = "red", foot = "Cancel", open = function(imp)
|
|
imp._rename = { text = "slot" }
|
|
end },
|
|
{ key = "_indexPrompt", tab = "find", foot = "Cancel", open = function(imp)
|
|
imp._indexPrompt = { text = "" }
|
|
end },
|
|
{ key = "_profileSavePrompt", tab = "mods", foot = "Cancel", open = function(imp)
|
|
imp._profileSavePrompt = { text = "P" }
|
|
end },
|
|
{ key = "_modConfirm", tab = "mods", foot = "Cancel", scrolls = true, open = function(imp)
|
|
imp._modConfirm = { title = "Enable this mod for every game in the list below",
|
|
lines = { LONG, LONG, LONG, LONG, LONG, LONG, LONG, LONG }, toggle = { label = "Remember this", on = false } }
|
|
end },
|
|
{ key = "_singleProfileActions", tab = "mods", foot = "Close", open = function(imp)
|
|
profiles(imp, 3)
|
|
imp._singleProfileActions = { name = "Profile 2" }
|
|
end },
|
|
{ key = "_profilesPopup", tab = "mods", foot = "Close", scrolls = true, open = function(imp)
|
|
profiles(imp, 8)
|
|
imp._profilesPopup = true
|
|
end },
|
|
{ key = "_modHeaderActionsPopup", tab = "mods", foot = "Close", scrolls = true, open = function(imp)
|
|
imp._modHeaderActionsPopup = true
|
|
end },
|
|
{ key = "_gamePopup", tab = "red", foot = "Close", open = function(imp)
|
|
imp._gamePopup = true
|
|
end },
|
|
{ key = "_cartSave", tab = "mods", foot = "Cancel", scrolls = true, open = function(imp)
|
|
local pins = {}
|
|
for i = 1, 6 do pins[i] = { id = "m" .. i, name = "Mod " .. i, reason = LONG } end
|
|
imp._cartSave = { version = "red", count = 6, text = "My cart", cartVersion = "1.0.0",
|
|
author = "me", unresolved = pins, publishable = false, error = LONG }
|
|
end },
|
|
{ key = "_skinActions", tab = "skins", foot = "Close", scrolls = true, open = function(imp)
|
|
imp._skins = { { id = "pad", format = "native", pages = 1, controls = 8 } }
|
|
imp._ensureSkins = function(self) return self._skins end
|
|
imp.onOpenSkinStudio = function() end
|
|
imp._skinExport = { dir = "/tmp" }
|
|
imp._skinActions = { id = "pad" }
|
|
end },
|
|
{ key = "_modActions", tab = "mods", foot = "Close", scrolls = true, open = function(imp)
|
|
richMods(imp)
|
|
imp._modActions = "alpha"
|
|
end },
|
|
{ key = "_modImports", tab = "mods", foot = "Close", scrolls = true, open = function(imp)
|
|
richMods(imp)
|
|
imp._modImports = "alpha"
|
|
end },
|
|
{ key = "_findEntry", tab = "find", foot = "Close", open = function(imp)
|
|
imp._findEntry = { id = "alpha", title = "Alpha", version = "1.0.0", author = "someone",
|
|
categories = { "qol" }, repo = "https://example.invalid/alpha" }
|
|
end },
|
|
{ key = "_gameManage", tab = "red", foot = "Close", open = function(imp)
|
|
imp._webClipNotice = { key = "red:", ok = false, text = LONG }
|
|
imp._gameManage = "red"
|
|
end },
|
|
{ key = "_syncModal", tab = "red", foot = "Close", label = "sync home", scrolls = true,
|
|
open = function(imp)
|
|
imp._syncTransportOk = true
|
|
imp._sync = syncEngine(true)
|
|
imp._syncModal = { view = "home" }
|
|
end },
|
|
{ key = "_syncModal", tab = "red", foot = "Back", label = "sync mods", open = function(imp)
|
|
imp._syncTransportOk = true
|
|
imp._sync = syncEngine(true)
|
|
imp._sync.modPlan = { toInstall = { 1, 2 }, indexes = { 1 } }
|
|
imp._syncModal = { view = "mods" }
|
|
end },
|
|
{ key = "_syncModal", tab = "red", foot = "Back", label = "sync link", open = function(imp)
|
|
imp._syncTransportOk = true
|
|
imp._sync = syncEngine(false)
|
|
imp._syncModal = { view = "link" }
|
|
end },
|
|
}
|
|
|
|
local function sweepTag(spec)
|
|
return ("%s at %dx%d"):format(spec.label or spec.key, width, height)
|
|
end
|
|
|
|
local sawScroll = {}
|
|
for _, size in ipairs({ { 853, 480 }, { 780, 360 }, { 1280, 720 } }) do
|
|
width, height = size[1], size[2]
|
|
for _, spec in ipairs(SWEEP) do
|
|
local imp, rects = opened(spec)
|
|
local tag = sweepTag(spec)
|
|
T.eq(View.modalKey(imp), spec.key, tag .. " is the open modal")
|
|
local state = imp._modalScroll and imp._modalScroll[spec.key]
|
|
T.check(state ~= nil and state.rect ~= nil, tag .. " lays out through a scroll body")
|
|
local escaped, footSeen = {}, not spec.foot
|
|
for _, r in ipairs(rects) do
|
|
if r.clip then
|
|
if not inside(r.clip, width, height) then escaped[#escaped + 1] = r.label .. " clip" end
|
|
if state and not within(r.clip, state.rect) then
|
|
escaped[#escaped + 1] = r.label .. " clip outside body"
|
|
end
|
|
elseif not inside(r, width, height) then
|
|
escaped[#escaped + 1] = r.label
|
|
end
|
|
if spec.foot and r.label == spec.foot and not r.clip and inside(r, width, height) then
|
|
footSeen = true
|
|
end
|
|
end
|
|
T.check(footSeen, tag .. " pins " .. tostring(spec.foot) .. " on screen")
|
|
T.check(#escaped == 0, tag .. " keeps every control on screen or in the scroll clip: "
|
|
.. table.concat(escaped, ", "))
|
|
if state and state.rect then
|
|
T.check(inside(state.rect, width, height), tag .. " scroll body is on screen")
|
|
if width == 1280 and not spec.scrolls then
|
|
T.eq(state.maxScroll, 0, tag .. " fits without scrolling")
|
|
end
|
|
if state.maxScroll > 0 then sawScroll[spec.label or spec.key] = true end
|
|
end
|
|
end
|
|
end
|
|
|
|
local PAGED = {
|
|
{ key = "_modVersions", tab = "mods", open = function(imp)
|
|
local rel = {}
|
|
for i = 1, 8 do rel[i] = { version = "1." .. i, body = LONG } end
|
|
imp._modVersions = { id = "alpha", name = "Alpha", current = "1.1", releases = rel }
|
|
end },
|
|
{ key = "_modDepResolver", tab = "mods", open = function(imp)
|
|
local deps = {}
|
|
for i = 1, 6 do deps[i] = { id = "d" .. i, name = "Dep " .. i, status = "missing", github = "o/d" } end
|
|
imp._modDepResolver = { targetMod = { id = "alpha", name = "Alpha" }, deps = deps }
|
|
end },
|
|
{ key = "_modReleaseNotes", tab = "mods", open = function(imp)
|
|
imp._modReleaseNotes = { version = "1.0", body = LONG .. LONG .. LONG }
|
|
end },
|
|
{ key = "_cartPopup", tab = "red", open = function(imp) imp._cartPopup = "red" end },
|
|
}
|
|
|
|
for _, size in ipairs({ { 853, 480 }, { 780, 360 } }) do
|
|
width, height = size[1], size[2]
|
|
for _, spec in ipairs(PAGED) do
|
|
local imp, rects = opened(spec)
|
|
local tag = sweepTag(spec)
|
|
T.eq(View.modalKey(imp), spec.key, tag .. " is the open modal")
|
|
local escaped = {}
|
|
for _, r in ipairs(rects) do
|
|
if not inside(r.clip or r, width, height) then escaped[#escaped + 1] = r.label end
|
|
end
|
|
T.check(#escaped == 0, tag .. " keeps every control on screen: " .. table.concat(escaped, ", "))
|
|
end
|
|
end
|
|
|
|
for _, spec in ipairs(SWEEP) do
|
|
if spec.scrolls then
|
|
T.check(sawScroll[spec.label or spec.key] == true,
|
|
(spec.label or spec.key) .. " overflows somewhere in the sweep")
|
|
end
|
|
end
|
|
|
|
width, height = 780, 360
|
|
do
|
|
local imp = opened(SWEEP[8])
|
|
local state = imp._modalScroll._modHeaderActionsPopup
|
|
T.check(state.maxScroll > 0, "More Mod Actions overflows at 780x360")
|
|
local r = state.rect
|
|
now = now + 1
|
|
View.touchpressed(imp, 11, r.x + 20, r.y + r.h - 5)
|
|
View.touchmoved(imp, 11, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
now = now + 1
|
|
View.touchreleased(imp, 11, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.check(state.scroll > 0, "touch drag scrolls More Mod Actions")
|
|
T.check(imp._modHeaderActionsPopup ~= nil, "drag leaves More Mod Actions open")
|
|
state.scroll = 0
|
|
now = now + 1
|
|
Kit.setFocus("modheadact-6")
|
|
local rects = draw(imp)
|
|
local shown = false
|
|
for _, a in ipairs(rects) do
|
|
if a.label == "Sort mods..." and a.clip
|
|
and a.y >= a.clip.y - 0.5 and a.y + a.h <= a.clip.y + a.clip.h + 0.5 then
|
|
shown = true
|
|
end
|
|
end
|
|
T.check(shown, "focusing Sort mods scrolls it into view")
|
|
Kit.activateFocused()
|
|
View.draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.eq(imp._sortPopup, "mods", "Sort mods is reachable from More Mod Actions at 780x360")
|
|
Kit.setFocus(nil)
|
|
end
|
|
|
|
do
|
|
local imp = opened(SWEEP[7])
|
|
local state = imp._modalScroll._profilesPopup
|
|
T.check(state.maxScroll > 0, "profile list scrolls at 780x360")
|
|
now = now + 1
|
|
Kit.setFocus("prof-sw-8")
|
|
draw(imp)
|
|
Kit.activateFocused()
|
|
View.draw(imp)
|
|
View.update(imp, 1 / 60)
|
|
T.check(state.scroll > 0, "focusing the last profile scrolls the list")
|
|
Kit.setFocus(nil)
|
|
end
|
|
|
|
do
|
|
local imp = opened(SWEEP[5])
|
|
local state = imp._modalScroll._modConfirm
|
|
T.check(state.maxScroll > 0, "long confirm scrolls at 780x360")
|
|
local yes
|
|
for _, r in ipairs(draw(imp)) do
|
|
if r.label == "OK" and not r.clip then yes = r end
|
|
end
|
|
T.check(yes ~= nil and inside(yes, width, height), "confirm OK stays pinned on screen")
|
|
end
|
|
|
|
do
|
|
local imp = fixture("red")
|
|
View.draw(imp)
|
|
local rows = {}
|
|
for i = 1, 40 do
|
|
rows[i] = { label = "OPTION " .. i, value = function() return "ON" end,
|
|
step = function() return true end }
|
|
end
|
|
imp._settings = { opts = {}, sections = { { title = "Options", rows = rows } },
|
|
save = function() end }
|
|
draw(imp)
|
|
local model = imp._settings
|
|
T.check(model.maxScroll > 0, "settings list overflows at 780x360")
|
|
local lines = {}
|
|
for i = 1, 10 do lines[i] = LONG end
|
|
model.confirm = { title = "Reset everything?", lines = lines,
|
|
yesLabel = "Yes", noLabel = "No", close = function() model.confirm = nil end }
|
|
draw(imp)
|
|
local all = imp._modalScroll or {}
|
|
local cs = all._settingsConfirm or all._settings
|
|
T.check(all._settingsConfirm ~= nil, "settings confirm keeps its own scroll state")
|
|
T.check(cs ~= nil and cs.maxScroll > 0, "long settings confirm scrolls at 780x360")
|
|
if cs and cs.rect then
|
|
local r, before = cs.rect, model.scroll or 0
|
|
now = now + 1
|
|
View.touchpressed(imp, 21, r.x + 20, r.y + r.h - 5)
|
|
View.touchmoved(imp, 21, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
now = now + 1
|
|
View.touchreleased(imp, 21, r.x + 20, r.y + 5)
|
|
draw(imp)
|
|
T.check(cs.scroll > 0, "touch drag scrolls the settings confirm body")
|
|
T.eq(model.scroll or 0, before, "confirm drag leaves the settings list alone")
|
|
T.check(model.confirm ~= nil, "drag leaves the settings confirm open")
|
|
T.check(imp._modalScroll._settingsConfirm == cs, "confirm scroll survives redraw")
|
|
end
|
|
model.confirm = nil
|
|
draw(imp)
|
|
T.eq(imp._modalScroll._settingsConfirm, nil, "closing the confirm drops its scroll state")
|
|
end
|
|
|
|
width, height = 1280, 720
|
|
do
|
|
local spec
|
|
for _, s in ipairs(SWEEP) do if s.key == "_modActions" then spec = s end end
|
|
local imp = opened(spec)
|
|
local state = imp._modalScroll._modActions
|
|
local del = state.rows["modact-del"]
|
|
T.check(state.rows["modact-top"] ~= nil, "mod actions shows the reorder rows")
|
|
T.eq(state.maxScroll, 0, "mod actions fits at 1280x720")
|
|
T.eq(del[1] + del[2], state.rect.h, "mod actions body ends at Delete with no blank row")
|
|
end
|
|
|
|
T.finish("launcher modal scroll")
|