{ graphics: lg } = love import vec2, bound2 from require 'cpml' import is_once, is_live, are_live, Once from require 'state' import Object from require 'object' pushpop = (fn) -> (...) -> lg.push 'all' with fn ... lg.pop! random = point: -> w, h = lg.getDimensions! vec2 w*math.random!, h*math.random! size: -> vec2 math.random! * 200 + 100, math.random! * 200 + 100 hit = radius: (pos, r) -> hit.radius2 pos, r*r radius2: (pos, r2) -> contains = (INPUT.mouse - pos)\len2! < r2 INPUT\mouse_event! or 'hover' if contains line: (frm, to, r2=10) -> delta = to - frm mouse = INPUT.mouse - frm dot = (mouse\dot delta) / delta\len2! dot = math.min 1, math.max 0, dot p = frm + delta * dot hit.radius2 p, r2 rect: (min, max) -> rect = bound2 min, max contains = rect\contains INPUT.mouse INPUT\mouse_event! or 'hover' if contains draw = cross: (pos) -> hs = vec2 8, 8 mx, my = (pos - hs)\unpack! Mx, My = (pos + hs)\unpack! lg.line mx, my, Mx, My lg.line mx, My, Mx, my hit.radius2 pos, hs\len2! line: (frm, to) -> lg.line frm.x, frm.y, to.x, to.y hit.line frm, to arrow: (frm, to) -> dir = (to - frm)\normalize! up = dir\perpendicular! draw.line to - dir * 15 + up * 7, to draw.line to - dir * 15 - up * 7, to draw.line frm, to rect: (min, max) -> x, y = min\unpack! w, h = (max - min)\unpack! lg.rectangle 'line', x, y, w, h hit.rect min, max circle: (center, r) -> x, y = center\unpack! lg.circle 'line', x, y, r hit.radius2 center, r*r half_handle = vec2 15, 15 input = slider: (min=0, max=1) => @init min origin = vec2 50, 50 length = 200 final = origin + vec2 length, 0 draw.line origin, final if input.point @value, y: origin.y, x: Once min val = math.max origin.x, math.min final.x, @value!.x @value!.x = val @set min + (val - origin.x) / length * max return true point: (fixed={}) => init = if val = is_once fixed val else with random.point! if x = is_once fixed.x .x = x if y = is_once fixed.y .y = y last = @init init pos = last\clone! live_x, live_y = (is_live fixed.x), is_live fixed.y pos.x = fixed.x if live_x pos.y = fixed.y if live_y -- both values are 'live', no UI necessary if live_x and live_y draw.cross pos @set pos delta = pos - last return delta\len2! > 0 and delta -- handle size (square or rect) hh = half_handle\clone! hh.y /= 2 if live_x hh.x /= 2 if live_y if 'down' == draw.rect pos - hh, pos + hh @drag\set true if @drag! if INPUT\mouse_up! @drag\set false delta = INPUT\mouse_delta! delta.x = 0 if live_x delta.y = 0 if live_y pos += delta @set pos delta = last and pos - last return delta and delta\len2! > 0 and delta line: (frm, to) => input.point @frm, frm input.point @to, to frm, to = @frm!, @to! @set :frm, :to draw.line frm, to arrow: (frm, to) => input.point @frm, frm input.point @to, to frm, to = @frm!, @to! @set :frm, :to draw.arrow frm, to rect: do meta = size: => @max - @min meta.__index = meta (fixed={}) => @init setmetatable {}, meta delta = input.point @min, fixed.min or Once random.point! * 0.8 input.point @max, fixed.max or Once @min! + random.size! @max\set @max! + delta if delta min, max = @min!, @max! draw.rect min, max self = @get! self.min, self.max = min, max circle: (fixed={}) => local tangent delta = input.point @center, fixed.center radius = (is_live fixed.radius) or do radius = (is_once fixed.radius) or math.random! * 100 + 50 init_tangent = vec2.from_cartesian radius, math.random! * 2 * math.pi input.point @tangent, fixed.tangent or Once @center! + init_tangent tangent = @tangent! radius = @center!\dist tangent radius, tangent if delta and tangent @tangent\set @tangent! + delta center, tangent = @center!, @tangent! draw.circle center, radius @set { :center, :tangent, :radius } selection: (pattern) => -- @TOOD: fix @init {o,o for o in *SESSION.objects when match and o.name\match init} selection = @! index = {o,i for i,o in ipairs selection} to_remove = {} for obj in *SESSION.objects selected = index[obj] if selected draw.cross obj.pos -- obj\draw 'line', orng if obj\hit! == 'down' if selected table.insert to_remove, selected else table.insert selection, obj table.sort to_remove for i=#to_remove,1,-1 table.remove selection, to_remove[i] op = move: pushpop (obj, to) -> draw.arrow obj.pos, to lg.setColor .8, .8, 0 copy = obj\copy! copy.pos = to copy\draw! if COMMIT obj.pos = to add: pushpop (pos, size) -> tmp = Object pos, size lg.setColor 0, .8, 0 tmp\draw! if COMMIT table.insert SESSION.objects, tmp tmp remove: pushpop (obj) -> lg.setColor .8, 0, 0 copy = obj\copy! copy\draw! if COMMIT SESSION.objects = [o for o in *SESSION.objects when o != obj] copy: pushpop (obj, pos) -> lg.setColor 0, .8, 0 copy = obj\copy! copy.pos = pos copy\draw! if COMMIT table.insert SESSION.objects, copy copy { :hit :random :draw :input :op }