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.setLineJoin("bevel") 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, transform) local radius = diameter and diameter/2 or 300 transform = transform or love.math.newTransform() 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.applyTransform(self.transform) love.graphics.draw(self.faceCanvas, -self.radius, -self.radius) 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