local gui = require("gui") local color = require("gui.core.color") local multi, thread = require("multi"):init() local function startTimer(opt) local default = { duration = 30, autoText = true, autoColor = true, autoCleanup = false, startColor = color.green, textColor = color.black, warnColor = color.yellow, timeColor = color.red, finegrained = false, visibility = 1 } if type(opt) == "number" then local d = opt opt = default opt.duration = d elseif type(opt) ~= "table" then opt = default else for i, v in pairs(opt) do default[i] = v end opt = default end local timeRemaining = opt.duration or 30 local tpie = gui:newFrame():makeArc("pie", -200, 0, 100, 1, 0, 0, 1.5*math.pi, 3.5*math.pi, 360) local tlabel = tpie:newTextLabel("") tlabel.textColor = opt.textColor tlabel.align = gui.ALIGN_CENTER tlabel:fullFrame() tlabel.visibility = 0 tlabel:centerFont() tlabel:scaleFont(.5) tpie.color = opt.startColor tpie.visibility = opt.visibility local tm local stopped = false local onTimeConn = multi:newConnection() local onStopConn = multi:newConnection() local function cleanup() if stopped then return end stopped = true if onTimeConn and not onTimeConn.destroyed then onTimeConn:Destroy() end if not tpie.destroyed then tpie:destroy() end end local timerThread = thread:newThread("Pie Timer", function() local startTime = love.timer.getTime() local lastSecond = timeRemaining while not stopped do thread.sleep(1/60) local now = love.timer.getTime() local elapsed = now - startTime local t = math.min(elapsed, timeRemaining) local num = timeRemaining - math.floor(t) local p = 3.5 - (t / timeRemaining) * 2 if opt.autoColor then tpie.color = opt.startColor if num <= timeRemaining / 3 then tpie.color = opt.timeColor elseif num <= timeRemaining / 2 then tpie.color = opt.warnColor end end tpie:makeArc("pie", -200, 0, 100, 1, 0, 0, 1.5*math.pi, p*math.pi, 360) if opt.autoText then tlabel.text = num end if opt.finegrained then onTimeConn:Fire(tm, num, t) elseif num < lastSecond then -- crossed a second boundary lastSecond = num onTimeConn:Fire(tm, num, t) end if elapsed >= timeRemaining then break end end -- Timer finished if stopped then return end if opt.autoText then tlabel.text = "Time" tlabel:fitFont(nil, nil, {scale=1/2}) tlabel:centerFont() end tpie:makeArc("pie", -200, 0, 100, 1, 0, 0, 1.5*math.pi, 3.5*math.pi, 360) local onStop = onStopConn cleanup() onStop:Fire(tm) end) tm = { Duration = timeRemaining, OnTime = onTimeConn, OnStop = onStopConn, SetText = function(str) tlabel.text = str end, SetColor = function(c) tpie.color = c end, Cleanup = function() timerThread:Kill() cleanup() end, } return tm end return { startTimer = startTimer }