166 lines
4.6 KiB
Lua
166 lines
4.6 KiB
Lua
local Time = require"time"
|
|
|
|
local YELLOW = {0.93, 0.8, 0}
|
|
local DARK_YELLOW = {0.74, 0.64, 0}
|
|
|
|
local numberFont = love.graphics.newFont(100)
|
|
|
|
local function pointToTurns(x, y)
|
|
local rawTurns = math.atan2(y, x) / 2 / math.pi
|
|
local _, clockTurns = math.modf(rawTurns + 1.25)
|
|
return clockTurns
|
|
end
|
|
|
|
local function turnsToRads(turns)
|
|
return turns * 2 * math.pi - 0.5 * math.pi
|
|
end
|
|
|
|
|
|
local Hand = {}
|
|
Hand.__index = Hand
|
|
|
|
function Hand:new(length, width, lineWidth)
|
|
local h = {
|
|
l = (length or 10),
|
|
w = (width or 40),
|
|
lineWidth = (lineWidth or 3)
|
|
}
|
|
return setmetatable(h, self)
|
|
end
|
|
|
|
function Hand:draw(turns)
|
|
love.graphics.push("all")
|
|
love.graphics.setColor(YELLOW)
|
|
local vertices = {-self.w/2,0, 0,self.w*0.75, self.w/2,0, 0,-self.l}
|
|
love.graphics.rotate(turnsToRads(turns) + 0.5 * math.pi)
|
|
love.graphics.polygon("fill", vertices)
|
|
love.graphics.setColor(DARK_YELLOW)
|
|
love.graphics.setLineWidth(self.lineWidth)
|
|
love.graphics.polygon("line", vertices)
|
|
love.graphics.pop()
|
|
end
|
|
|
|
|
|
local function drawFaceCanvas(r, lineWidth)
|
|
local oldCanvas = love.graphics.getCanvas()
|
|
local canvas = love.graphics.newCanvas(2*r,2*r)
|
|
love.graphics.setCanvas(canvas)
|
|
love.graphics.push("all")
|
|
love.graphics.translate(r, r)
|
|
local rbezel = r-lineWidth/2
|
|
love.graphics.setColor(YELLOW)
|
|
love.graphics.circle("fill", 0, 0, rbezel)
|
|
love.graphics.setLineWidth(lineWidth)
|
|
love.graphics.setColor(DARK_YELLOW)
|
|
love.graphics.circle("line", 0, 0, rbezel)
|
|
local rcrystal = 0.84*r
|
|
love.graphics.setColor(1, 1, 1)
|
|
love.graphics.circle("fill", 0, 0, rcrystal)
|
|
love.graphics.setColor(DARK_YELLOW)
|
|
love.graphics.circle("line", 0, 0, rcrystal)
|
|
love.graphics.setColor(0,0,0)
|
|
for i=1,60 do
|
|
love.graphics.rotate(math.pi/30)
|
|
love.graphics.circle("fill", 0.6*r, 0, 0.01*r)
|
|
end
|
|
love.graphics.setColor(0.87,0,0)
|
|
for i=1,12 do
|
|
love.graphics.rotate(math.pi/6)
|
|
love.graphics.circle("fill", 0.6*r, 0, 0.015*r)
|
|
end
|
|
|
|
local font = love.graphics.newFont("font/JosefinSans-Regular.ttf", r/6)
|
|
love.graphics.setColor(0,0,0)
|
|
for i=1,12 do
|
|
local s = tostring(i)
|
|
local h = font:getHeight()
|
|
local w = font:getWidth(s)
|
|
local tr = love.math.newTransform(0,0,-math.pi/6*i+math.pi)
|
|
tr = tr:apply(love.math.newTransform(w*0.5, h*0.4))
|
|
local x, y = tr:inverseTransformPoint(0, 0.72*r)
|
|
love.graphics.printf(s, font, x, y, r)
|
|
end
|
|
love.graphics.pop()
|
|
love.graphics.setCanvas(oldCanvas)
|
|
return canvas
|
|
end
|
|
|
|
local Clock = {}
|
|
Clock.__index = Clock
|
|
|
|
function Clock:new(time, diameter)
|
|
local radius = diameter and diameter/2 or 300
|
|
local transform = love.math.newTransform(radius, radius)
|
|
local lineWidth = radius/200
|
|
local c = {
|
|
time = (time or Time:new()),
|
|
minuteHand = Hand:new(radius*0.75, radius*0.08, lineWidth),
|
|
hourHand = Hand:new(radius*0.55, radius*0.08, lineWidth),
|
|
dragging = false,
|
|
radius = radius,
|
|
onSetHands = nil,
|
|
transform = transform,
|
|
faceCanvas = drawFaceCanvas(radius, lineWidth)
|
|
}
|
|
return setmetatable(c, self)
|
|
end
|
|
|
|
function Clock:setTime(time)
|
|
self.time = time
|
|
end
|
|
|
|
function Clock:getTime()
|
|
return self.time
|
|
end
|
|
|
|
function Clock:draw()
|
|
local _, m = self.time:get()
|
|
local h = self.time:getHoursSinceTwelve()
|
|
love.graphics.push("all")
|
|
love.graphics.draw(self.faceCanvas)
|
|
love.graphics.applyTransform(self.transform)
|
|
self.minuteHand:draw(m / 60)
|
|
self.hourHand:draw(h / 12)
|
|
love.graphics.pop()
|
|
end
|
|
|
|
local function clockContainsPoint(clock, x, y)
|
|
local localX, localY = clock.transform:inverseTransformPoint(x, y)
|
|
local dist = math.sqrt(localX^2 + localY^2)
|
|
return dist <= clock.radius
|
|
end
|
|
|
|
local function clockPointAt(clock, x, y)
|
|
local localX, localY = clock.transform:inverseTransformPoint(x, y)
|
|
local minutes = pointToTurns(localX, localY) * 60
|
|
local _, oldMinutes = clock.time:get()
|
|
local dMinutes = minutes - oldMinutes
|
|
-- Adjust for rolling over
|
|
if dMinutes < -30 then
|
|
dMinutes = dMinutes + 60
|
|
elseif dMinutes > 30 then
|
|
dMinutes = dMinutes - 60
|
|
end
|
|
clock.time = clock.time:addMinutes(dMinutes)
|
|
if clock.onSetHands then clock.onSetHands(clock.time) end
|
|
end
|
|
|
|
function Clock:movemouse(x, y)
|
|
if self.dragging then
|
|
local localX, localY = self.transform:inverseTransformPoint(x, y)
|
|
clockPointAt(self, x, y)
|
|
end
|
|
end
|
|
|
|
function Clock:pressmouse(x, y, button)
|
|
if not self.dragging and button == 1 and clockContainsPoint(self, x,y) then
|
|
self.dragging = true
|
|
clockPointAt(self, x, y)
|
|
end
|
|
end
|
|
|
|
function Clock:releasemouse(button)
|
|
if button == 1 then self.dragging = false end
|
|
end
|
|
|
|
return Clock |