aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2019-11-01 20:04:18 +0000
committers-ol <s-ol@users.noreply.github.com>2019-11-01 20:04:18 +0000
commit5934b80f09c1c13fa4698e59a77d0c51b7c7b357 (patch)
tree265742939a732b06a224d870026b22e1154add71
parentAPI redesign (diff)
downloadwatch-cad-5934b80f09c1c13fa4698e59a77d0c51b7c7b357.tar.gz
watch-cad-5934b80f09c1c13fa4698e59a77d0c51b7c7b357.zip
make things work
-rw-r--r--api.moon118
m---------cpml0
-rw-r--r--examples/demo.moon7
-rw-r--r--init.moon2
-rw-r--r--input.moon5
-rw-r--r--session.moon3
-rw-r--r--spec/state_spec.moon62
-rw-r--r--state.moon58
8 files changed, 209 insertions, 46 deletions
diff --git a/api.moon b/api.moon
index 153c736..6a6158e 100644
--- a/api.moon
+++ b/api.moon
@@ -1,6 +1,7 @@
{ graphics: lg } = love
import vec2, bound2 from require 'cpml'
+import is_once, is_live, are_live, Once from require 'state'
random =
point: ->
@@ -11,7 +12,19 @@ random =
vec2 math.random! * 200 + 100, math.random! * 200 + 100
draw =
- rect: (mode, min, max) ->
+ cross: (pos) ->
+ hs = vec2 8, 8
+ mx, my = (pos - hs)\unpack!
+ Mx, My = (pos + hs)\unpack!
+
+ lg.setColor 1, 1, 1
+ lg.line mx, my, Mx, My
+ lg.line mx, My, Mx, my
+
+ contains = (INPUT.mouse - pos)\len2! < hs\len2!
+ INPUT\mouse_event! if contains
+
+ rect: (min, max) ->
x, y = min\unpack!
w, h = (max - min)\unpack!
lg.setColor 1, 1, 1
@@ -19,69 +32,88 @@ draw =
rect = bound2 min, max
contains = rect\contains INPUT.mouse
- contains and (not mode or INPUT["mouse_#{mode}"] INPUT, 1)
+ INPUT\mouse_event! if contains
- circle: (mode, center, r) ->
+ circle: (center, r) ->
x, y = center\unpack!
lg.setColor 1, 1, 1
lg.circle 'line', x, y, r
contains = (INPUT.mouse - center)\len! < r
- contains and (not mode or INPUT["mouse_#{mode}"] INPUT, 1)
+ INPUT\mouse_event! if contains
half_handle = vec2 15, 15
input =
- dot: (init, fixed) =>
- init or= random.point!
+ point: (fixed={}) =>
+ if vec = is_once fixed
+ fixed = {
+ x: Once vec.x
+ y: Once vec.y
+ }
- if fixed == true
- return init
-
- fixed or= x: false, y: false
- @pos = (rawget @, 'pos') or init
+ init = random.point!
+ @store 'x', fixed.x, init.x
+ @store 'y', fixed.y, init.y
+ pos = vec2 @x, @y
- if draw.rect 'held', @pos - half_handle, @pos + half_handle
- delta = INPUT\mouse_delta!
- @pos = @pos + delta
+ -- both values are 'live', no UI necessary
+ if are_live fixed.x, fixed.y
+ draw.cross pos
+ return pos
- @pos.x = init.x if fixed.x
- @pos.y = init.y if fixed.y
+ hh = half_handle\clone!
+ hh.x /= 2 if is_live fixed.x
+ hh.y /= 2 if is_live fixed.y
- @pos
+ @init 'drag', false
+ if 'down' == draw.rect pos - hh, pos + hh
+ @drag = true
- rectangle: (init={}, fixed={}) =>
- init.min or= random.point! * 0.8
- init.max or= init.min + random.size!
- @last_min = (rawget @, 'last_min') or init.min
+ if @drag
+ @drag = false if INPUT\mouse_up!
- max = input.dot @max, init.max, fixed.max
- min = input.dot @min, init.min, fixed.min
- delta = @last_min - min
- max += delta
- @last_min = min
+ pos += INPUT\mouse_delta!
- draw.rect nil, min, max
- { :min, :max }
+ @store 'x', pos.x unless is_live fixed.x
+ @store 'y', pos.y unless is_live fixed.y
- circle: (init={}, fixed={}) =>
- init.center or= random.point!
- init.radius or= math.random! * 100 + 50
- init.tangent or= do
- angle = math.random! * math.pi * 2
- init.center + vec2.from_cartesian init.radius, angle
-
- center = input.dot @c, init.center, fixed.center
+ vec2 @x, @y
- local tangent, radius
- if fixed.radius
- radius = init.radius
+ point_relative_to: (other, fixed) =>
+ assert (is_live other), "other needs to be live!"
+
+ @init 'last_other', other
+ @init 'last', fixed or random.point!
+ delta = other - @last_other
+
+ val = if delta\len2! > 0 and not is_live fixed
+ input.point @, @last + delta
else
- tangent = input.dot @t, init.tangent, fixed.tangent
- radius = (tangent - center)\len!
+ input.point @, fixed or Once @last
+
+ @store 'last_other', other
+ @store 'last', val
- draw.circle nil, center, radius
+ val
+
+ rectangle: (fixed={}) =>
+ min = input.point @min, fixed.min or Once random.point! * 0.8
+ max = input.point_relative_to @max, min, fixed.max or Once min + random.size!
+
+ draw.rect min, max
+ { :min, :max }
- { center, tangent, :radius }
+ circle: (fixed={}) =>
+ local tangent
+ center = 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
+ tangent = input.point_relative_to @tangent, center, fixed.tangent or Once center + init_tangent
+ center\dist tangent
+
+ draw.circle center, radius
+ { :center, :tangent, :radius }
selection: (init, fixed) =>
init or= {o for o in *OBJS when match and o.name\match init}
diff --git a/cpml b/cpml
-Subproject 74de1154aa32b9c7348b95faff3228512c0a2e1
+Subproject 6c4991511228758da7a0d9f647adefa5632e890
diff --git a/examples/demo.moon b/examples/demo.moon
new file mode 100644
index 0000000..cb2531f
--- /dev/null
+++ b/examples/demo.moon
@@ -0,0 +1,7 @@
+import vec2 from require 'cpml'
+
+=>
+ a = input.point @point, x: 200
+ rect = input.rectangle @rect, min: a + (vec2 30, 0), max: { y: 200 }
+
+ circle = input.circle @circ, center: rect.min, tangent: rect.max
diff --git a/init.moon b/init.moon
index 72abbae..c0ed6d2 100644
--- a/init.moon
+++ b/init.moon
@@ -17,8 +17,6 @@ for event in *{'keypressed', 'keyreleased', 'mousepressed', 'mousereleased'}
love.draw = SESSION\frame
-require 'moon.all'
-
-- Move = (obj, x, y) ->
-- if COMMIT
-- obj.x = x
diff --git a/input.moon b/input.moon
index 18dc30d..adb72ed 100644
--- a/input.moon
+++ b/input.moon
@@ -12,6 +12,11 @@ class Input
mouse_up: (button=1) => @key_up "mouse-#{button}"
mouse_held: (button=1) => @key_held "mouse-#{button}"
+ mouse_event: (button=1) =>
+ return 'down' if @mouse_down button
+ return 'up' if @mouse_up button
+ return 'held' if @mouse_held button
+
key_down: (key) => @keys[key] and not @last_keys[key]
key_up: (key) => not @keys[key] and @last_keys[key]
key_held: (key) => @keys[key]
diff --git a/session.moon b/session.moon
index 219a1c9..53780a0 100644
--- a/session.moon
+++ b/session.moon
@@ -1,4 +1,5 @@
lfs = require 'lfs'
+moon = require 'moonscript.base'
trace = (msg) -> debug.traceback msg, 2
@@ -46,7 +47,7 @@ class Script
if @last_modification < modification
@last_modification = modification
- module, msg = loadfile @file
+ module, msg = if @file\match '%.moon$' then moon.loadfile @file else loadfile @file
if not module
@error = at: 'parse', :msg
return
diff --git a/spec/state_spec.moon b/spec/state_spec.moon
new file mode 100644
index 0000000..b2085c5
--- /dev/null
+++ b/spec/state_spec.moon
@@ -0,0 +1,62 @@
+import Once, State from require 'state'
+
+describe "Once", ->
+ it "stores a value", ->
+ a = Once 3
+ assert.is.equal 3, a.value
+
+ it "can test for itself", ->
+ assert.is_true Once.is_once Once 3
+ assert.is_true Once.is_once Once 2
+ assert.is_true Once.is_once Once nil
+ assert.is_true Once.is_once Once { a: 3 }
+
+ it "can test other types", ->
+ assert.is_falsy Once.is_once nil
+ assert.is_falsy Once.is_once 3
+ assert.is_falsy Once.is_once "once impostor"
+ assert.is_falsy Once.is_once { a: 3 }
+
+describe "State", ->
+ local S
+ before_each ->
+ state = State!
+ S = state.state
+
+ it "can be indexed infinitely", ->
+ assert.is_table S.a.b.c.d
+
+ describe ":init", ->
+ it "stores default until changed", ->
+ S\init 'test', 2
+ assert.is.equal 2, S.test
+
+ S.test = 4
+ assert.is.equal 4, S.test
+
+ S\init 'test', 2
+ assert.is.equal 4, S.test
+
+ describe ":store", ->
+ it "stores defaults until changed", ->
+ S\store 'test', nil, 3
+ assert.is.equal 3, S.test
+
+ S\store 'test', nil, 4
+ assert.is.equal 3, S.test
+
+ it "follows live inputs", ->
+ S\store 'test', 3, 'nope'
+ assert.is.equal 3, S.test
+
+ S\store 'test', 4, 'nope'
+ assert.is.equal 4, S.test
+
+ it "lets Once() inputs override defaults", ->
+ S\store 'test', (Once 3), 'nope'
+ assert.is.equal 3, S.test
+
+ S\store 'test', 'changed'
+
+ S\store 'test', (Once 4), 'nope'
+ assert.is.equal 'changed', S.test
diff --git a/state.moon b/state.moon
index 52299c4..6916171 100644
--- a/state.moon
+++ b/state.moon
@@ -1,10 +1,65 @@
+unpack = unpack or table.unpack
+
+class Once
+ new: (@value) =>
+
+ @is_once: (val) ->
+ return unless val
+ return unless 'table' == type val
+ val.__class == @@
+
+all = (f) -> (...) ->
+ values = for i = 1, select '#', ...
+ val = f select i, ...
+ return unless val
+ val
+
+ unpack values
+
+is_once = (val) -> (Once.is_once val) and val.value
+is_live = (val) -> (not is_once val) and val
+
+are_once = all is_once
+are_live = all is_live
+
class State
@mt: {
__index: (t, k) ->
+ if v = @[k]
+ return v
+
with v = setmetatable {}, @@mt
rawset t, k, v
}
+ -- initialize state under 'key' with 'default' unless already set
+ init: (key, default) =>
+ if val = is_once default
+ default = val
+ rawset @, key, (rawget @, key) or default
+
+ -- store and return a piece of state under 'key'.
+ -- the current and stored value is the first of the following:
+ -- * 'fixed', if it is a 'live' value
+ -- * current state, if set
+ -- * 'fixed', if it is a 'once' value
+ -- * 'default'
+ store: (key, fixed, default) =>
+ state = rawget @, key
+ once = Once.is_once fixed
+
+ next_state = if is_live fixed
+ fixed
+ elseif state
+ state
+ elseif once
+ fixed.value
+ else
+ default
+
+ with next_state
+ rawset @, key, next_state
+
new: =>
@reset!
@@ -12,5 +67,8 @@ class State
@state = setmetatable {}, @@mt
{
+ :is_once, :are_once
+ :is_live, :are_live
+ :Once
:State
}