Hold or tween any keyed channel's gaps, as a drawing's
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
da7e293814
commit
2a0426707a
7 changed files with 46 additions and 24 deletions
|
|
@ -94,6 +94,16 @@
|
||||||
(:segments c) (update :segments dissoc f))
|
(:segments c) (update :segments dissoc f))
|
||||||
:else (ch/framed v)))))
|
:else (ch/framed v)))))
|
||||||
|
|
||||||
|
(defn set-segment-interp
|
||||||
|
"Choose how channel `path`'s key at `left` leads to the next one: `:hold` cuts
|
||||||
|
there, `:linear` tweens. The same for a drawing's points as for a transform —
|
||||||
|
only a gap that exists, between a key and a later one, can be chosen."
|
||||||
|
[n path left interp]
|
||||||
|
(let [ks (:keys (get (channels n) path))]
|
||||||
|
(if (and (contains? ks left) (some #(< left %) (keys ks)) (#{:hold :linear} interp))
|
||||||
|
(assoc-in n [:channels path :segments left] interp)
|
||||||
|
n)))
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
;; time maps
|
;; time maps
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
|
|
@ -46,13 +46,3 @@
|
||||||
(if (and points (< (inc i) (count points)))
|
(if (and points (< (inc i) (count points)))
|
||||||
(assoc-in clip path (-> points (assoc i x) (assoc (inc i) y)))
|
(assoc-in clip path (-> points (assoc i x) (assoc (inc i) y)))
|
||||||
clip)))
|
clip)))
|
||||||
|
|
||||||
(defn set-segment-interp [clip sid id key-frame interp]
|
|
||||||
(let [node (get-in clip [:symbols sid :nodes id])
|
|
||||||
keys (get-in node [:channels geometry :keys])]
|
|
||||||
(if (and (:paint? node) (contains? keys key-frame)
|
|
||||||
(some #(< key-frame %) (clojure.core/keys keys))
|
|
||||||
(#{:hold :linear} interp))
|
|
||||||
(assoc-in clip [:symbols sid :nodes id :channels geometry
|
|
||||||
:segments key-frame] interp)
|
|
||||||
clip)))
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,3 @@
|
||||||
::set-vertex
|
::set-vertex
|
||||||
(fn [db [_ sid id key-frame vertex point]]
|
(fn [db [_ sid id key-frame vertex point]]
|
||||||
(edit/edit db #(paint/set-vertex % sid id key-frame vertex point))))
|
(edit/edit db #(paint/set-vertex % sid id key-frame vertex point))))
|
||||||
|
|
||||||
(rf/reg-event-db
|
|
||||||
::set-segment-interp
|
|
||||||
(fn [db [_ sid id key-frame interp]]
|
|
||||||
(edit/edit db #(paint/set-segment-interp % sid id key-frame interp))))
|
|
||||||
|
|
|
||||||
|
|
@ -624,6 +624,11 @@
|
||||||
(fn [db [_ sid id path frame]]
|
(fn [db [_ sid id path frame]]
|
||||||
(edit/edit db #(update-in % [:symbols sid :nodes id] node/toggle-key path frame))))
|
(edit/edit db #(update-in % [:symbols sid :nodes id] node/toggle-key path frame))))
|
||||||
|
|
||||||
|
(rf/reg-event-db
|
||||||
|
::set-segment-interp
|
||||||
|
(fn [db [_ sid id path left interp]]
|
||||||
|
(edit/edit db #(update-in % [:symbols sid :nodes id] node/set-segment-interp path left interp))))
|
||||||
|
|
||||||
(rf/reg-event-fx
|
(rf/reg-event-fx
|
||||||
::list
|
::list
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,16 @@
|
||||||
:else (let [v (:value ch)]
|
:else (let [v (:value ch)]
|
||||||
(str "framed · " (if (channel/nothing? v) "absent" (pr-str v))))))
|
(str "framed · " (if (channel/nothing? v) "absent" (pr-str v))))))
|
||||||
|
|
||||||
|
(defn- segment-select
|
||||||
|
"Hold or tween, for the gap after the key at `left` — the same choice on a
|
||||||
|
drawing as on a transform."
|
||||||
|
[sid id path ch left]
|
||||||
|
[:select.interp {:value (name (or (channel/segment-interp ch left) :hold))
|
||||||
|
:on-change #(rf/dispatch [::project/set-segment-interp
|
||||||
|
sid id path left (keyword (.. % -target -value))])}
|
||||||
|
[:option {:value "hold"} "hold"]
|
||||||
|
[:option {:value "linear"} "tween"]])
|
||||||
|
|
||||||
(defn- drawing-keys
|
(defn- drawing-keys
|
||||||
"The polygon controls: jump to a drawing key, add one here, and choose what the
|
"The polygon controls: jump to a drawing key, add one here, and choose what the
|
||||||
gap after the current one does. Lifted out of the old stage toolbar unchanged —
|
gap after the current one does. Lifted out of the old stage toolbar unchanged —
|
||||||
|
|
@ -158,23 +168,23 @@
|
||||||
(when next-k
|
(when next-k
|
||||||
[:div.row {:style {:margin-top "5px"}}
|
[:div.row {:style {:margin-top "5px"}}
|
||||||
[:label.dim (str "key " active " → " next-k " ")
|
[:label.dim (str "key " active " → " next-k " ")
|
||||||
[:select {:value (name (or (channel/segment-interp geom active) :hold))
|
[segment-select sid id paint/geometry geom active]]])]))
|
||||||
:on-change #(rf/dispatch [::paint-events/set-segment-interp
|
|
||||||
sid id active (keyword (.. % -target -value))])}
|
|
||||||
[:option {:value "hold"} "hold"]
|
|
||||||
[:option {:value "linear"} "tween"]]]])]))
|
|
||||||
|
|
||||||
;; The transform and visibility, which every node has, as one row each: ◆ keys
|
;; The transform and visibility, which every node has, as one row each: ◆ keys
|
||||||
;; the channel here or takes the key here off, and an edit writes a key on a
|
;; the channel here or takes the key here off, and an edit writes a key on a
|
||||||
;; keyed channel or the one value on one that is not. `frame` is the node's own,
|
;; keyed channel or the one value on one that is not. `frame` is the node's own,
|
||||||
;; nil when it is not on screen, where a keyed channel has no here to write to.
|
;; nil when it is not on screen, where a keyed channel has no here to write to.
|
||||||
;; Rotation is shown in degrees.
|
;; Rotation is shown in degrees. Between two keys, the gap after the one here
|
||||||
|
;; holds or tweens, as a drawing's does.
|
||||||
|
|
||||||
(defn- channel-control [sid id path ch frame]
|
(defn- channel-control [sid id path ch frame]
|
||||||
(let [keyed? (some? (:keys ch))
|
(let [keyed? (some? (:keys ch))
|
||||||
v (channel/value-at ch (or frame 0))
|
v (channel/value-at ch (or frame 0))
|
||||||
off? (and keyed? (nil? frame))
|
off? (and keyed? (nil? frame))
|
||||||
deg? (= path [:xform :rot])
|
deg? (= path [:xform :rot])
|
||||||
|
;; A boolean has nothing between true and false to tween through.
|
||||||
|
left (when (and keyed? frame (not (boolean? v))) (paint/active-frame ch frame))
|
||||||
|
gap? (and left (some #(< left %) (keys (:keys ch))))
|
||||||
put #(rf/dispatch [::project/set-channel sid id path frame %])
|
put #(rf/dispatch [::project/set-channel sid id path frame %])
|
||||||
field (fn [i x on-number]
|
field (fn [i x on-number]
|
||||||
^{:key i}
|
^{:key i}
|
||||||
|
|
@ -193,7 +203,8 @@
|
||||||
:on-change #(put (.. % -target -checked))}]
|
:on-change #(put (.. % -target -checked))}]
|
||||||
(number? v) (field 0 v put)
|
(number? v) (field 0 v put)
|
||||||
:else (doall (map-indexed (fn [i x] (field i x #(put (assoc (vec v) i %))))
|
:else (doall (map-indexed (fn [i x] (field i x #(put (assoc (vec v) i %))))
|
||||||
v)))]))
|
v)))
|
||||||
|
(when gap? [segment-select sid id path ch left])]))
|
||||||
|
|
||||||
(defn- node-section [[sid id n]]
|
(defn- node-section [[sid id n]]
|
||||||
(let [[start end] (:span n)]
|
(let [[start end] (:span n)]
|
||||||
|
|
|
||||||
|
|
@ -200,4 +200,13 @@
|
||||||
(let [d (node/toggle-key b [:xform :rot] 3)]
|
(let [d (node/toggle-key b [:xform :rot] 3)]
|
||||||
(is (not (:animated? (get-in d [:channels [:xform :rot]]))) "the last key off is one value again")
|
(is (not (:animated? (get-in d [:channels [:xform :rot]]))) "the last key off is one value again")
|
||||||
(is (= 1.0 (rot d 0))))
|
(is (= 1.0 (rot d 0))))
|
||||||
(is (= :hold (get-in (node/toggle-key n [:vis] 0) [:channels [:vis] :interp])) "a boolean holds")))
|
(is (= :hold (get-in (node/toggle-key n [:vis] 0) [:channels [:vis] :interp])) "a boolean holds")
|
||||||
|
(let [h (node/set-segment-interp c [:xform :pos] 0 :hold)]
|
||||||
|
(is (= [5 5] (pos h 5)) "a gap set to hold cuts at the next key")
|
||||||
|
(is (= [10 0] (pos h 10)))
|
||||||
|
(is (= [7.5 2.5] (pos (node/set-segment-interp h [:xform :pos] 0 :linear) 5)) "and back to a tween")
|
||||||
|
(is (= h (node/set-segment-interp h [:xform :pos] 10 :hold)) "the last key has no gap after it")
|
||||||
|
(is (empty? (ch/problems (get-in h [:channels [:xform :pos]])))))
|
||||||
|
(let [d (node/toggle-key (node/set-segment-interp c [:xform :pos] 0 :hold) [:xform :pos] 0)]
|
||||||
|
(is (not (contains? (get-in d [:channels [:xform :pos] :segments]) 0))
|
||||||
|
"taking a key off takes its gap's choice with it"))))
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
[arthur.demo :as demo]
|
[arthur.demo :as demo]
|
||||||
[arthur.domain.channel :as channel]
|
[arthur.domain.channel :as channel]
|
||||||
[arthur.domain.leaf :as leaf]
|
[arthur.domain.leaf :as leaf]
|
||||||
|
[arthur.domain.node :as node]
|
||||||
[arthur.domain.paint :as paint]
|
[arthur.domain.paint :as paint]
|
||||||
[arthur.domain.symbol :as symbol]))
|
[arthur.domain.symbol :as symbol]))
|
||||||
|
|
||||||
|
|
@ -17,7 +18,8 @@
|
||||||
c3 (paint/add-key c2 :main :paint-test 15)
|
c3 (paint/add-key c2 :main :paint-test 15)
|
||||||
c4 (paint/set-vertex c3 :main :paint-test 15 0 [34 10])
|
c4 (paint/set-vertex c3 :main :paint-test 15 0 [34 10])
|
||||||
held (geometry c4)
|
held (geometry c4)
|
||||||
mixed-clip (paint/set-segment-interp c4 :main :paint-test 9 :linear)
|
mixed-clip (update-in c4 [:symbols :main :nodes :paint-test]
|
||||||
|
node/set-segment-interp paint/geometry 9 :linear)
|
||||||
mixed (geometry mixed-clip)]
|
mixed (geometry mixed-clip)]
|
||||||
(is (= [3 229] (get-in c2 [:symbols :main :nodes :paint-test :span])))
|
(is (= [3 229] (get-in c2 [:symbols :main :nodes :paint-test :span])))
|
||||||
(is (= a (channel/value-at held 8)))
|
(is (= a (channel/value-at held 8)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue