Add auto-key mode to main toolbar
This commit is contained in:
parent
3879d76d57
commit
34f62ab007
11 changed files with 82 additions and 17 deletions
|
|
@ -162,6 +162,7 @@
|
|||
:time-view :timeline
|
||||
:tone :skin-base
|
||||
:tool nil
|
||||
:auto-key? false
|
||||
:draft []
|
||||
:knobs {}
|
||||
:trace {:faces #{} :opacity trace/opacity-default}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
is in the placement's matrices, so a shape five symbols down moves under the
|
||||
pointer like one on top.
|
||||
|
||||
THE KEYING RULE IS `node/set-channel`, the inspector's: a channel with keys
|
||||
gets one on the node's own frame, and one without has its one value changed.
|
||||
After Effects' stopwatch — there is no mode to be in, and nothing snaps back
|
||||
on the next frame as an unkeyed change does in Blender."
|
||||
The normal keying rule is `node/set-channel`, the inspector's: a channel with
|
||||
keys gets one on the node's own frame, and one without has its one value
|
||||
changed. Auto-key deliberately replaces that rule with `set-keyed-channel`,
|
||||
so touching an otherwise static transform starts its animation at this frame."
|
||||
(:require [arthur.domain.channel :as ch]
|
||||
[arthur.domain.node :as node]))
|
||||
|
||||
|
|
@ -78,7 +78,10 @@
|
|||
|
||||
(defn apply-values
|
||||
"Clip with channel values `vs`, `{path value}`, written into node `id` of
|
||||
symbol `sid` on the node's own frame `f`, by the keying rule above."
|
||||
[clip sid id f vs]
|
||||
(update-in clip [:symbols sid :nodes id]
|
||||
#(reduce-kv (fn [n path v] (node/set-channel n path f v)) % vs)))
|
||||
symbol `sid` on the node's own frame `f`, by the keying rule above. The sixth
|
||||
argument arms auto-key; the five-argument form retains the normal rule."
|
||||
([clip sid id f vs] (apply-values clip sid id f vs false))
|
||||
([clip sid id f vs auto-key?]
|
||||
(let [put (if auto-key? node/set-keyed-channel node/set-channel)]
|
||||
(update-in clip [:symbols sid :nodes id]
|
||||
#(reduce-kv (fn [n path v] (put n path f v)) % vs)))))
|
||||
|
|
|
|||
|
|
@ -104,6 +104,17 @@
|
|||
(assoc-in n [:channels path]
|
||||
(if (:keys c) (assoc-in c [:keys f] v) (ch/framed v)))))
|
||||
|
||||
(defn set-keyed-channel
|
||||
"Write `v` as a key at `f`, starting an animated channel when needed. This is
|
||||
the auto-key counterpart to `set-channel`; an existing channel keeps its
|
||||
interpolation and segment choices."
|
||||
[n path f v]
|
||||
(let [c (get (channels n) path)]
|
||||
(assoc-in n [:channels path]
|
||||
(if (:keys c)
|
||||
(assoc-in c [:keys f] v)
|
||||
(ch/keyed {f v} (if (boolean? v) :hold :linear))))))
|
||||
|
||||
(defn toggle-key
|
||||
"Key channel `path` on the node's own frame `f` with the value it has there, or
|
||||
take the key there off. The first key starts the channel animating and taking
|
||||
|
|
|
|||
|
|
@ -635,7 +635,8 @@
|
|||
::set-channel
|
||||
;; `frame` is the node's own, as for a drawing key.
|
||||
(fn [db [_ sid id path frame value]]
|
||||
(edit/edit db #(update-in % [:symbols sid :nodes id] node/set-channel path frame value))))
|
||||
(let [put (if (get-in db [:ui :auto-key?]) node/set-keyed-channel node/set-channel)]
|
||||
(edit/edit db #(update-in % [:symbols sid :nodes id] put path frame value)))))
|
||||
|
||||
(rf/reg-event-db
|
||||
::toggle-key
|
||||
|
|
|
|||
|
|
@ -621,6 +621,11 @@
|
|||
(fn [db [_ scope id knob value]]
|
||||
(assoc-in db [:ui :knobs [scope id knob]] value)))
|
||||
|
||||
(rf/reg-event-db
|
||||
::toggle-auto-key
|
||||
(fn [db _]
|
||||
(update-in db [:ui :auto-key?] not)))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; a new symbol
|
||||
|
||||
|
|
@ -754,14 +759,19 @@
|
|||
;; A transform in the middle of a drag on the stage, `{:sid :id :frame
|
||||
;; :values}`, drawn by `::render/clip` as `::sliding` is; nil when abandoned.
|
||||
(fn [db [_ g]]
|
||||
(if g (assoc-in db [:ui :gesture] g) (update db :ui dissoc :gesture))))
|
||||
(if g
|
||||
(assoc-in db [:ui :gesture]
|
||||
(assoc g :auto-key? (boolean (get-in db [:ui :auto-key?]))))
|
||||
(update db :ui dissoc :gesture))))
|
||||
|
||||
(rf/reg-event-db
|
||||
::transform
|
||||
;; The drag let go: one edit, so one undo step and one write to collaborators.
|
||||
(fn [db [_ {:keys [sid id frame values]}]]
|
||||
(cond-> (update db :ui dissoc :gesture)
|
||||
(seq values) (edit/edit #(gesture/apply-values % sid id frame values)))))
|
||||
(seq values) (edit/edit #(gesture/apply-values
|
||||
% sid id frame values
|
||||
(boolean (get-in db [:ui :auto-key?])))))))
|
||||
|
||||
(rf/reg-event-db
|
||||
::delete-selected
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@
|
|||
(let [c (:clip (footage/entry id))]
|
||||
(or (when-let [{:keys [path df]} sliding]
|
||||
(:clip (nest/slide c open path df)))
|
||||
(when-let [{:keys [sid id frame values]} gesture]
|
||||
(when c (gesture/apply-values c sid id frame values)))
|
||||
(when-let [{:keys [sid id frame values auto-key?]} gesture]
|
||||
(when c (gesture/apply-values c sid id frame values auto-key?)))
|
||||
c))))
|
||||
|
||||
(rf/reg-sub
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
(rf/reg-sub ::lane-retry (fn [db _] (get-in db [:ui :lane-retry])))
|
||||
(rf/reg-sub ::tone (fn [db _] (get-in db [:ui :tone])))
|
||||
(rf/reg-sub ::tool (fn [db _] (get-in db [:ui :tool])))
|
||||
(rf/reg-sub ::auto-key? (fn [db _] (boolean (get-in db [:ui :auto-key?]))))
|
||||
(rf/reg-sub ::draft (fn [db _] (get-in db [:ui :draft])))
|
||||
(rf/reg-sub ::convert (fn [db _] (get-in db [:ui :convert])))
|
||||
(rf/reg-sub ::drop (fn [db _] (get-in db [:ui :drop])))
|
||||
|
|
|
|||
|
|
@ -42,11 +42,19 @@
|
|||
(defn bar []
|
||||
(let [tone @(rf/subscribe [::sub/tone])
|
||||
tool @(rf/subscribe [::sub/tool])
|
||||
auto? @(rf/subscribe [::sub/auto-key?])
|
||||
draft @(rf/subscribe [::sub/draft])]
|
||||
[:div.palette-bar
|
||||
[:div.swatches (doall (map #(swatch % tone) (range slots)))]
|
||||
[:span.dim (name tone)]
|
||||
[:span {:style {:flex 1}}]
|
||||
[:button.auto-key {:class (when auto? "on")
|
||||
:aria-pressed auto?
|
||||
:title (if auto?
|
||||
"auto-key is on — edited parameters get a key at this frame"
|
||||
"auto-key edited parameters at this frame")
|
||||
:on-click #(rf/dispatch [::ui/toggle-auto-key])}
|
||||
"◆ auto key"]
|
||||
(if (= :polygon tool)
|
||||
[:<>
|
||||
[:span.dim (str (quot (count draft) 2) " points")]
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@
|
|||
;; 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 auto-key?]
|
||||
(let [keyed? (some? (:keys ch))
|
||||
;; No store: the call site below hands this only channels that are not
|
||||
;; `:dense`, which are the only ones with anything in tier 2 to read.
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
:value (if deg? (/ (js/Math.round (* x (/ 18000 js/Math.PI))) 100) x)
|
||||
:parse js/parseFloat
|
||||
:on-number #(on-number (if deg? (* % (/ js/Math.PI 180)) %))}])]
|
||||
[:dd.channel
|
||||
[:dd.channel {:class (when auto-key? "live")}
|
||||
[:button.key {:class (cond (contains? (:keys ch) frame) "on" keyed? "keyed")
|
||||
:disabled (nil? frame)
|
||||
:title (if keyed? (str (count (:keys ch)) " keys") "key this here")
|
||||
|
|
@ -199,7 +199,8 @@
|
|||
(when gap? [segment-select sid id path ch left])]))
|
||||
|
||||
(defn- node-section [[sid id n]]
|
||||
(let [[start end] (:span n)]
|
||||
(let [[start end] (:span n)
|
||||
auto-key? @(rf/subscribe [::sub/auto-key?])]
|
||||
[section (str (name (:kind n)) " · in " (name sid))
|
||||
[facts
|
||||
"name" (or (:name n) (brief id))
|
||||
|
|
@ -221,7 +222,7 @@
|
|||
[:<>
|
||||
[:dt (str/join " " (map name path))]
|
||||
(if (and (contains? (node/defaults-of n) path) (not (:dense ch)))
|
||||
[channel-control sid id path ch frame]
|
||||
[channel-control sid id path ch frame auto-key?]
|
||||
[:dd (channel-state ch)])]))])]))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -216,3 +216,13 @@
|
|||
(let [d (node/toggle-key (node/set-segment-interp c [:xform :pos] 0 :hold) [:xform :pos] 0 nil)]
|
||||
(is (not (contains? (get-in d [:channels [:xform :pos] :segments]) 0))
|
||||
"taking a key off takes its gap's choice with it"))))
|
||||
|
||||
(deftest auto-keying-a-channel-from-a-parameter-edit
|
||||
(let [n {:id :x :kind :group}
|
||||
keyed (node/set-keyed-channel n [:xform :rot] 7 1.25)
|
||||
moved (node/set-keyed-channel keyed [:xform :rot] 11 2.5)
|
||||
visible (node/set-keyed-channel n [:vis] 7 false)]
|
||||
(is (= {7 1.25, 11 2.5} (get-in moved [:channels [:xform :rot] :keys])))
|
||||
(is (= :linear (get-in moved [:channels [:xform :rot] :interp])))
|
||||
(is (= :hold (get-in visible [:channels [:vis] :interp]))
|
||||
"boolean parameters do not tween")))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue