A little timer app


A friend was looking for a timer app, and I took the opportunity to also package up my little helper for managing GUI widgets that I've shown before (1, 2, 3). I also added support for long-press, which allows for a clean UI: tap on the timer to pause, long-press on the timer to stop.

Step 1: run the screen of abbreviations that comes with Lua Carousel:

-- Some abbreviations to reduce typing.
g = love.graphics
pt, line = g.points, g.line
rect, poly = g.rectangle, g.polygon
circle, arc, ellipse = g.circle, g.arc, g.ellipse
color = g.setColor
min, max = math.min, math.max
floor, ceil = math.floor, math.ceil
abs, rand = math.abs, math.random
pi, cos, sin = math.pi, math.cos, math.sin
touches = love.touch.getTouches
touch = love.touch.getPosition
audio = love.audio.newSource
-- Hit 'run', Now they're available to other
-- panes.

Step 2: Copy this into a screen and save it as 'widgets'

-- helper screen for creating UI widgets on screen
widgets = {}
long_press_duration = 1
function widgets.__draw()
  for name,w in pairs(widgets) do
    if name:find('__') == nil and w.draw then
      w.draw()
    end end end
function widgets.__mousepressed(x,y, b)
  for name,w in pairs(widgets) do
    if name:find('__') == nil then
      if w.ispress(x,y) then
        return w.press()
      end end end end
function widgets.__update(dt)
  local x, y = App.mouse_x(), App.mouse_y()
  local mouse_down = App.mouse_down(1)
  for name,w in pairs(widgets) do
    if name:find('__') == nil then
      if w.update then w.update(dt, x,y) end
      if w.long_press then
        if mouse_down and w.ispress(x,y) then
          if w.press_time == nil then
            w.press_time = 0
          else
            w.press_time = w.press_time+dt
            if w.press_time > long_press_duration then
              w.long_press()
              w.press_time = nil
            end
          end
        else
          w.press_time = nil
        end
      end end end end
function widgets.__mousereleased(x,y, b)
  for name,w in pairs(widgets) do
    if name:find('__') == nil and w.release then
      w.release()
    end end end

Step 3: Create a third screen for the timer itself.

run_screen('widgets')
timer_x, timer_y = 60, 100
timer_font_height = min(App.screen.width, App.screen.height)/2
timer_font = g.newFont(timer_font_height)
timer_width = timer_font:getWidth('60')
button_font_height = timer_font_height/4
button_font = g.newFont(button_font_height)
time = 0
state = 'stop'
function main_button()
  local x,y, w,h = timer_x, timer_y, timer_width, timer_font_height+4
  local press_time = nil
  local draw = function()
    if state == 'paused' then
      color(0.8,0.4,0)
    else
      color(0.4,0.4,0.4)
    end
    rect('fill', x,y, w,h, 2,2)
    color(0.6,0.6,0.6)
    rect('line', x,y, w,h, 2,2)
    color(1,1,1)
    local t = math.ceil(time)
    g.setFont(timer_font)
    g.print(t, x+(timer_width-timer_font:getWidth(tostring(t)))/2, y+2)
  end
  local ispress = function(x2,y2)
    return x2 >= x and x2 <= x+w and y2 >= y and y2 <= y+h
  end
  local press = function()
    if state == 'paused' then state = 'run'
    else state = 'paused'
    end
  end
  local long_press = function()
    state = 'stop'
    time = 0
  end
  local update = function(dt, x,y)
    if state == 'run' then
      if time > 0 then
        time = time - dt
      else
        time = 0
      end end end
  return {draw=draw, update=update, ispress=ispress, press=press, long_press=long_press}
end
widgets.main = main_button()
function timer_button(offset, y, x, align)
  local title = '+'..tostring(offset)
  local w = button_font:getWidth(title)+4
  if align == 'center' then x = x - w/2
  elseif align == 'right' then x = x - w
  end
  local h = button_font:getHeight()
  local draw = function()
    color(0.4,0.7,1)
    rect('fill', x,y, w,h, 2,2)
    color(0,0,0)
    g.setFont(button_font)
    g.print(title, x+2, y+2)
  end
  local ispress = function(x2,y2)
    return x2 >= x and x2 <= x+w and y2 >= y and y2 <= y+h
  end
  local press = function()
    time = time + offset
    state = 'run'
  end
  return {draw=draw, ispress=ispress, press=press}
end
local buttony = timer_y+timer_font_height+10
widgets.plus1 = timer_button(1, buttony, timer_x, 'left')
widgets.plus2 = timer_button(2, buttony, timer_x+timer_width/2, 'center')
widgets.plus5 = timer_button(5, buttony, timer_x+timer_width, 'right')
function car.draw()
  widgets.__draw()
end
function car.mousepressed(x,y, b)
  widgets.__mousepressed(x,y, b)
end
function car.update(dt)
  widgets.__update(dt)
end
function car.mousereleased(x,y, b)
  widgets.__mousereleased(x,y, b)
end

You need the last dozen or so lines to use the widget screen because each screen gets independent car.* handlers.

Get Lua Carousel

Leave a comment

Log in with itch.io to leave a comment.