Add progress bar

- Change process runner to return state table
- Add progress bar graphics
- Add progress bar UI
- Fill progress runner context state with more capturing info
This commit is contained in:
David Vogel 2022-07-29 19:42:44 +02:00
parent 014cba54af
commit a2cb806ffa
5 changed files with 51 additions and 14 deletions

View File

@ -79,6 +79,7 @@ local function captureScreenshot(pos, ensureLoaded, dontOverwrite, ctx, outputPi
if pos then CameraAPI.SetPos(pos) end
if ensureLoaded then
local delayFrames = 0
if ctx then ctx.state.WaitFrames = delayFrames end
repeat
-- Prematurely stop capturing if that is requested by the context.
if ctx and ctx:IsStopping() then return end
@ -88,11 +89,13 @@ local function captureScreenshot(pos, ensureLoaded, dontOverwrite, ctx, outputPi
if pos then CameraAPI.SetPos(pos + Vec2(math.random(-10, 10), math.random(-10, 10))) end
wait(0)
delayFrames = delayFrames + 1
if ctx then ctx.state.WaitFrames = delayFrames end
if pos then CameraAPI.SetPos(pos) end
end
wait(0)
delayFrames = delayFrames + 1
if ctx then ctx.state.WaitFrames = delayFrames end
local topLeftBounds, bottomRightBounds = CameraAPI:Bounds()
until DoesWorldExistAt(topLeftBounds.x, topLeftBounds.y, bottomRightBounds.x, bottomRightBounds.y)
@ -230,7 +233,7 @@ function Capture:StartCapturingArea(topLeft, bottomRight, captureGridSize, outpu
---@param ctx ProcessRunnerCtx
local function handleDo(ctx)
Modification.SetCameraFree(true)
ctx.progressCurrent, ctx.progressEnd = 0, gridSize.x * gridSize.y
ctx.state = {Current = 0, Max = gridSize.x * gridSize.y}
while t < tLimit do
-- Prematurely stop capturing if that is requested by the context.
@ -245,7 +248,7 @@ function Capture:StartCapturingArea(topLeft, bottomRight, captureGridSize, outpu
local pos = (hilbertPos + gridTopLeft) * captureGridSize
pos:Add(Vec2(256, 256)) -- Move to chunk center -- TODO: Align chunks with top left pixel
captureScreenshot(pos, true, true, ctx, outputPixelScale)
ctx.progressCurrent = ctx.progressCurrent + 1
ctx.state.Current = ctx.state.Current + 1
end
t = t + 1

View File

@ -21,8 +21,7 @@ local ProcessRunner = {}
---@class ProcessRunnerCtx
---@field running boolean|nil
---@field stopping boolean|nil
---@field progressCurrent number|nil
---@field progressEnd number|nil
---@field state table|nil
local Context = {}
Context.__index = Context
@ -52,11 +51,11 @@ function Context:IsStopping()
return self.stopping or false
end
---Returns the progress of the process.
---@return number current
---@return number end
function Context:GetProgress()
return self.progressCurrent or 0, self.progressEnd or 0
---Returns a table with information about the current state of the process.
---Will return nil if there is no process.
---@return table|nil -- Custom to the process.
function Context:GetState()
return self.state
end
---Tells the currently running process to stop.
@ -74,12 +73,12 @@ end
---@param doFunc fun(ctx:ProcessRunnerCtx)|nil -- Called after `initFunc` has been run.
---@param endFunc fun(ctx:ProcessRunnerCtx)|nil -- Called after `doFunc` has been run.
---@param errFunc fun(err:string, scope:"init"|"do"|"end") -- Called on any error.
---@return boolean -- True if process was started successfully.
function Context:Run(initFunc, doFunc, endFunc, errFunc)
if self.running then return end
if self.running then return false end
self.running, self.stopping, self.state = true, false, {}
async(function()
self.running, self.stopping, self.progressCurrent, self.progressEnd = true, false, nil, nil
-- Init function.
if initFunc then
local ok, err = pcall(initFunc, self)
@ -110,8 +109,10 @@ function Context:Run(initFunc, doFunc, endFunc, errFunc)
end
end
self.running, self.stopping = false, false
self.running, self.stopping, self.state = false, false, nil
end)
return true
end
return ProcessRunner

BIN
files/ui-gfx/progress-a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

BIN
files/ui-gfx/progress-b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

View File

@ -68,7 +68,7 @@ function UI:_DrawMessages(messages)
-- Abort if there is no messages list.
if not messages then return end
GuiZSet(gui, 0)
-- Unfortunately you can't stack multiple layout containers with the same direction.
@ -125,6 +125,38 @@ function UI:_DrawMessages(messages)
end
end
function UI:_DrawProgress()
local gui = self.gui
-- Check if there is progress to show.
local state = Capture.MapCapturingCtx:GetState()
if not state then return end
local factor
if state.Current and state.Max > 0 then
factor = state.Current / state.Max
end
local width, height = GuiGetScreenDimensions(gui)
local widthHalf, heightHalf = math.floor(width/2), math.floor(height/2)
GuiZSet(gui, -20)
local barWidth = width - 60
local y = heightHalf
if factor then
GuiImageNinePiece(gui, self:_GenID(), 30, y, barWidth, 9, 1, "mods/noita-mapcap/files/ui-gfx/progress-a.png", "mods/noita-mapcap/files/ui-gfx/progress-a.png")
GuiImageNinePiece(gui, self:_GenID(), 30, y, math.floor(barWidth * factor + 0.5), 9, 1, "mods/noita-mapcap/files/ui-gfx/progress-b.png", "mods/noita-mapcap/files/ui-gfx/progress-b.png")
GuiOptionsAddForNextWidget(gui, GUI_OPTION.Align_HorizontalCenter)
GuiText(gui, widthHalf, y, string.format("%d of %d (%.1f%%)", state.Current, state.Max, factor*100)) y = y + 11
y = y + 15
end
if state.WaitFrames then
GuiOptionsAddForNextWidget(gui, GUI_OPTION.Align_HorizontalCenter)
GuiText(gui, widthHalf, y, string.format("Waiting for %d frames.", state.WaitFrames)) y = y + 11
end
end
function UI:Draw()
self.gui = self.gui or GuiCreate()
local gui = self.gui
@ -143,6 +175,7 @@ function UI:Draw()
self:_DrawToolbar()
self:_DrawMessages(Message.List)
self:_DrawProgress()
GuiIdPop(gui)
end