Add instance playback controls to the inspector
This commit is contained in:
parent
52f25e0bb1
commit
1c520e6a68
3 changed files with 94 additions and 0 deletions
|
|
@ -757,6 +757,32 @@
|
|||
(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
|
||||
::instance-playback
|
||||
(fn [db [_ sid id field value]]
|
||||
(let [valid? (case field
|
||||
:mode (#{:once :loop :frame} value)
|
||||
(:in :speed) (and (node/finite-number? value) (<= 0 value))
|
||||
false)]
|
||||
(if-not valid?
|
||||
db
|
||||
(edit/edit
|
||||
db
|
||||
(fn [document]
|
||||
(let [path [:symbols sid :nodes id]
|
||||
n (get-in document path)]
|
||||
(if-not (= :instance (:kind n))
|
||||
document
|
||||
(let [{:keys [speed]} (node/playback-of n)
|
||||
updated (if (= :mode field)
|
||||
(-> n
|
||||
(update :time dissoc :loop?)
|
||||
(assoc-in [:playback :end] (if (= :loop value) :loop :stop))
|
||||
(assoc-in [:playback :speed]
|
||||
(if (= :frame value) 0 (if (pos? speed) speed 1))))
|
||||
(assoc-in n [:playback field] value))]
|
||||
(assoc-in document path updated))))))))))
|
||||
|
||||
(defn- seed-palette-choice [document sid id]
|
||||
(if (get-in document [:symbols sid :nodes id :channels [:palette]])
|
||||
document
|
||||
|
|
|
|||
|
|
@ -236,6 +236,34 @@
|
|||
:on-click #(rf/dispatch [::project/set-channel sid id [:style :color] frame i])}]))]
|
||||
(when keyed? [:span.dim "hold"])]))
|
||||
|
||||
(defn- instance-playback [[sid id n]]
|
||||
(let [{:keys [in speed end]} (node/playback-of n)
|
||||
mode (cond (zero? speed) :frame
|
||||
(or (= :loop end) (get-in n [:time :loop?])) :loop
|
||||
:else :once)
|
||||
change! (fn [field value]
|
||||
(rf/dispatch [::project/instance-playback sid id field value]))]
|
||||
[section "playback"
|
||||
[:div.inspector-form
|
||||
[:label.inspector-field "mode"
|
||||
[:select {:value (name mode)
|
||||
:aria-label "instance playback mode"
|
||||
:on-change #(change! :mode (keyword (.. % -target -value)))}
|
||||
[:option {:value "once"} "play once"]
|
||||
[:option {:value "loop"} "loop"]
|
||||
[:option {:value "frame"} "hold frame"]]]
|
||||
[:label.inspector-field "start frame"
|
||||
[number-input {:min 0 :step 1 :value in
|
||||
:aria-label "instance start frame"
|
||||
:parse #(js/parseInt % 10)
|
||||
:on-number #(change! :in %)}]]
|
||||
[:label.inspector-field "speed"
|
||||
[number-input {:min 0 :step 0.1 :value speed
|
||||
:disabled (= :frame mode)
|
||||
:aria-label "instance playback speed"
|
||||
:parse js/parseFloat
|
||||
:on-number #(change! :speed %)}]]]]))
|
||||
|
||||
(defn- node-section [[sid id n]]
|
||||
(let [[start end] (:span n)
|
||||
auto-key? @(rf/subscribe [::sub/auto-key?])
|
||||
|
|
@ -787,6 +815,7 @@
|
|||
[palette-placement-section node]
|
||||
[clip-section])
|
||||
(when (and node (not palette-placement?)) [node-section node])
|
||||
(when (and placed (not palette-placement?)) [instance-playback node])
|
||||
(when (and node (not palette-placement?)) [palette/remap-section])
|
||||
(when (and placed (not palette-placement?)) [symbol-section placed "source symbol"])
|
||||
(when (and node (not palette-placement?)) ^{:key (str (first node) "/" (second node))}
|
||||
|
|
|
|||
39
frontend/test/arthur/events/instance_playback_test.cljs
Normal file
39
frontend/test/arthur/events/instance_playback_test.cljs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
(ns arthur.events.instance-playback-test
|
||||
(:require [cljs.test :refer [deftest is]]
|
||||
[arthur.domain.clip :as clip]
|
||||
[arthur.events.project :as project]
|
||||
[arthur.footage.store :as store]
|
||||
[re-frame.core :as rf]
|
||||
[re-frame.db :as rf-db]))
|
||||
|
||||
(deftest playback-controls-change-only-the-selected-instance
|
||||
(let [n {:id :wheel :kind :instance :source {:symbol :spin}
|
||||
:span [0 240] :playback {:in 0 :speed 2 :end :stop
|
||||
:tracks {:mouth []}}}
|
||||
document (-> (clip/blank)
|
||||
(assoc-in [:symbols :spin] {:frames 24 :fps 30 :nodes {}})
|
||||
(assoc-in [:symbols :main :nodes :wheel] n)
|
||||
(assoc-in [:symbols :main :nodes :other] (assoc n :id :other)))
|
||||
id (store/install! {:clip document :store {}} "instance-playback-controls")
|
||||
current #(get-in (:clip (store/entry (:clip/current @rf-db/app-db)))
|
||||
[:symbols :main :nodes :wheel])]
|
||||
(reset! rf-db/app-db {:clip/current id :paint/revision 0})
|
||||
(rf/dispatch-sync [::project/instance-playback :main :wheel :mode :loop])
|
||||
(is (= 0 (:frame (clip/placed-frame document :main (current) 24))))
|
||||
(is (= :loop (get-in (current) [:playback :end])))
|
||||
(is (= 2 (get-in (current) [:playback :speed])))
|
||||
(rf/dispatch-sync [::project/instance-playback :main :wheel :in 5])
|
||||
(rf/dispatch-sync [::project/instance-playback :main :wheel :mode :frame])
|
||||
(is (= 5 (:frame (clip/placed-frame document :main (current) 100))))
|
||||
(rf/dispatch-sync [::project/instance-playback :main :wheel :mode :once])
|
||||
(is (nil? (clip/placed-frame document :main (current) 100)))
|
||||
(is (= [0 240] (:span (current))))
|
||||
(is (= {:mouth []} (get-in (current) [:playback :tracks])))
|
||||
(let [before (current)]
|
||||
(doseq [[field value] [[:in -1] [:speed js/Infinity] [:mode :invalid]]]
|
||||
(rf/dispatch-sync [::project/instance-playback :main :wheel field value]))
|
||||
(is (= before (current))))
|
||||
(is (= n (assoc (get-in (:clip (store/entry (:clip/current @rf-db/app-db)))
|
||||
[:symbols :main :nodes :other]) :id :wheel)))
|
||||
(is (= 24 (get-in (:clip (store/entry (:clip/current @rf-db/app-db)))
|
||||
[:symbols :spin :frames])))))
|
||||
Loading…
Add table
Add a link
Reference in a new issue