diff --git a/common/uxbox/common/geom/shapes.cljc b/common/uxbox/common/geom/shapes.cljc index 8655d9560..ae0dd5973 100644 --- a/common/uxbox/common/geom/shapes.cljc +++ b/common/uxbox/common/geom/shapes.cljc @@ -168,24 +168,7 @@ :proportion 1 :proportion-lock false)) -;; --- Resize (Dimentsions) - -(defn resize-rect - [shape attr value] - (us/assert map? shape) - (us/assert #{:width :height} attr) - (us/assert number? value) - - (let [{:keys [proportion proportion-lock]} shape] - (if-not proportion-lock - (assoc shape attr value) - (if (= attr :width) - (-> shape - (assoc :width value) - (assoc :height (/ value proportion))) - (-> shape - (assoc :height value) - (assoc :width (* value proportion))))))) +;; --- Resize (Dimensions) (defn resize [shape width height] @@ -199,6 +182,24 @@ :x2 (+ (:x1 selrect) width) :y2 (+ (:y1 selrect) height)))))) +(defn resize-rect + [shape attr value] + (us/assert map? shape) + (us/assert #{:width :height} attr) + (us/assert number? value) + (let [{:keys [proportion proportion-lock]} shape + size (select-keys shape [:width :height]) + new-size (if-not proportion-lock + (assoc size attr value) + (if (= attr :width) + (-> size + (assoc :width value) + (assoc :height (/ value proportion))) + (-> size + (assoc :height value) + (assoc :width (* value proportion)))))] + (resize shape (:width new-size) (:height new-size)))) + ;; --- Setup (Initialize) (declare setup-rect) diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index 77a542f78..1dd887221 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -238,13 +238,17 @@ } &.selected { - svg { fill: $color-primary; } - } + &.disabled { + cursor: unset; + svg { + fill: $color-gray-40; + } + } } .save-btn { diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 688f6dacf..0922b954a 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -924,29 +924,29 @@ ;; object from workspace sidebar options inputs. (defn update-dimensions - [id attr value] - (us/verify ::us/uuid id) + [ids attr value] + (us/verify (s/coll-of ::us/uuid) ids) (us/verify #{:width :height} attr) (us/verify ::us/number value) (ptk/reify ::update-dimensions ptk/WatchEvent (watch [_ state stream] - (rx/of (dwc/update-shapes [id] #(geom/resize-rect % attr value)))))) + (rx/of (dwc/update-shapes ids #(geom/resize-rect % attr value)))))) ;; --- Shape Proportions -(defn toggle-shape-proportion-lock - [id] - (ptk/reify ::toggle-shape-proportion-lock +(defn set-shape-proportion-lock + [id lock] + (ptk/reify ::set-shape-proportion-lock ptk/UpdateEvent (update [_ state] (let [page-id (:current-page-id state) shape (get-in state [:workspace-data page-id :objects id])] - (if (:proportion-lock shape) - (assoc-in state [:workspace-data page-id :objects id :proportion-lock] false) - (->> (geom/assign-proportions (assoc shape :proportion-lock true)) - (assoc-in state [:workspace-data page-id :objects id]))))))) + (if-not lock + (assoc-in state [:workspace-data page-id :objects id :proportion-lock] lock)) + (->> (geom/assign-proportions (assoc shape :proportion-lock lock)) + (assoc-in state [:workspace-data page-id :objects id])))))) ;; --- Update Shape Position diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs index b67d60799..a250c3418 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs @@ -133,8 +133,7 @@ [{:keys [page local] :as props}] (let [section (:options-mode local) shapes (mf/deref refs/selected-objects)] - [:& options-content {:selected selected - :shape shape + [:& options-content {:shapes shapes :page page :section section}])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs index 00ec070c2..794849abc 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/circle.cljs @@ -10,17 +10,20 @@ (ns uxbox.main.ui.workspace.sidebar.options.circle (:require [rumext.alpha :as mf] + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] - [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) (mf/defc options [{:keys [shape] :as props}] (let [ids [(:id shape)] type (:type shape) + measure-values (select-keys shape measure-attrs) stroke-values (select-keys shape stroke-attrs)] [:* - [:& measures-menu {:shape shape + [:& measures-menu {:ids ids + :type type + :values measure-values :options #{:size :position :rotation}}] [:& fill-menu {:ids ids :type type diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs index d427ea2c3..c78baed5f 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs @@ -33,8 +33,8 @@ on-preset-selected (fn [width height] - (st/emit! (udw/update-dimensions (:id shape) :width width) - (udw/update-dimensions (:id shape) :height height))) + (st/emit! (udw/update-dimensions [(:id shape)] :width width) + (udw/update-dimensions [(:id shape)] :height height))) on-orientation-clicked (fn [orientation] @@ -42,19 +42,19 @@ height (:height shape) new-width (if (= orientation :horiz) (max width height) (min width height)) new-height (if (= orientation :horiz) (min width height) (max width height))] - (st/emit! (udw/update-dimensions (:id shape) :width new-width) - (udw/update-dimensions (:id shape) :height new-height)))) + (st/emit! (udw/update-dimensions [(:id shape)] :width new-width) + (udw/update-dimensions [(:id shape)] :height new-height)))) on-size-change (fn [event attr] (let [value (-> (dom/get-target event) (dom/get-value) (d/parse-integer 0))] - (st/emit! (udw/update-dimensions (:id shape) attr value)))) + (st/emit! (udw/update-dimensions [(:id shape)] attr value)))) on-proportion-lock-change (fn [event] - (st/emit! (udw/toggle-shape-proportion-lock (:id shape)))) + (st/emit! (udw/set-shape-proportion-lock (:id shape) (not (:proportion-lock shape))))) on-position-change (fn [event attr] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/group.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/group.cljs index 965c09503..a3d7d1801 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/group.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/group.cljs @@ -12,8 +12,8 @@ (:require [rumext.alpha :as mf] [uxbox.main.refs :as refs] - [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] [uxbox.main.ui.workspace.sidebar.options.multiple :refer [get-multi]] + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) @@ -21,13 +21,14 @@ [{:keys [shape] :as props}] (let [child-ids (:shapes shape) children (mf/deref (refs/objects-by-id child-ids)) - type (:type shape) + measure-values (select-keys shape measure-attrs) fill-values (get-multi children fill-attrs) stroke-values (get-multi children stroke-attrs)] [:* - [:& measures-menu {:options #{:position :rotation} - :shape shape}] + [:& measures-menu {:ids (:id shape) + :type type + :values measure-values}] [:& fill-menu {:ids child-ids :type type :values fill-values}] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs index 0846e9334..3b687a6bd 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/icon.cljs @@ -10,7 +10,7 @@ (ns uxbox.main.ui.workspace.sidebar.options.icon (:require [rumext.alpha :as mf] - [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) @@ -18,9 +18,12 @@ [{:keys [shape] :as props}] (let [ids [(:id shape)] type (:type shape) + measure-values (select-keys shape measure-attrs) stroke-values (select-keys shape stroke-attrs)] [:* - [:& measures-menu {:shape shape}] + [:& measures-menu {:ids ids + :type type + :values measure-values}] [:& fill-menu {:ids ids :type type :values (select-keys shape fill-attrs)}] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/image.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/image.cljs index fd9f375e6..01771378e 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/image.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/image.cljs @@ -10,9 +10,14 @@ (ns uxbox.main.ui.workspace.sidebar.options.image (:require [rumext.alpha :as mf] - [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]])) + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]])) (mf/defc options [{:keys [shape] :as props}] - [:* - [:& measures-menu {:shape shape}]]) + (let [ids [(:id shape)] + type (:type shape) + measure-values (select-keys shape measure-attrs)] + [:* + [:& measures-menu {:ids ids + :type type + :values measure-values}]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs index 2fcae68d2..bc16697de 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/measures.cljs @@ -15,32 +15,58 @@ [uxbox.main.refs :as refs] [uxbox.common.data :as d] [uxbox.util.dom :as dom] + [uxbox.util.data :refer [classnames]] [uxbox.common.geom.shapes :as gsh] [uxbox.common.geom.point :as gpt] [uxbox.main.data.workspace :as udw] + [uxbox.main.data.workspace.common :as dwc] [uxbox.common.math :as math] [uxbox.util.i18n :refer [t] :as i18n])) +(def measure-attrs [:proportion-lock :width :height :x :y :rotation :rx :ry :selrect]) + +(defn attr->string [attr values] + (let [value (attr values)] + (if (= value :multiple) + "" + (str (-> value + (d/coalesce 0) + (math/precision 2)))))) + ;; -- User/drawing coords (mf/defc measures-menu - [{:keys [shape options] :as props}] + [{:keys [options ids values] :as props}] (let [options (or options #{:size :position :rotation :radius}) locale (i18n/use-locale) - frame (deref (refs/object-by-id (:frame-id shape))) - old-shape shape - shape (->> shape - (gsh/transform-shape frame)) + + old-shapes (deref (refs/objects-by-id ids)) + frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes) + shapes (map gsh/transform-shape frames old-shapes) + + values (cond-> values + (not= (:x values) :multiple) (assoc :x (:x (:selrect (first shapes)))) + (not= (:y values) :multiple) (assoc :y (:y (:selrect (first shapes))))) + + proportion-lock (:proportion-lock values) on-size-change (fn [event attr] (let [value (-> (dom/get-target event) (dom/get-value) (d/parse-integer 0))] - (st/emit! (udw/update-dimensions (:id shape) attr value)))) + (st/emit! (udw/update-dimensions ids attr value)))) on-proportion-lock-change (fn [event] - (st/emit! (udw/toggle-shape-proportion-lock (:id shape)))) + (let [new-lock (if (= proportion-lock :multiple) true (not proportion-lock))] + (run! #(st/emit! (udw/set-shape-proportion-lock % new-lock)) ids))) + + do-position-change + (fn [shape' frame' value attr] + (let [from (-> shape' :selrect attr) + to (+ value (attr frame')) + target (+ (attr shape') (- to from))] + (st/emit! (udw/update-position (:id shape') {attr target})))) on-position-change (fn [event attr] @@ -48,31 +74,37 @@ (dom/get-value) (d/parse-integer 0))] (when value - (let [from (-> shape :selrect attr) - to (+ value (attr frame)) - target (+ (attr shape) (- to from))] - (st/emit! (udw/update-position (:id shape) {attr target})))))) + (doall (map #(do-position-change %1 %2 value attr) shapes frames))))) + + do-rotation-change + (fn [shape' old-shape' value] + (st/emit! (udw/set-rotation (- value (:rotation shape')) [old-shape']) + (udw/apply-modifiers #{(:id shape')}))) on-rotation-change (fn [event] (let [value (-> (dom/get-target event) (dom/get-value) (d/parse-integer 0))] - (st/emit! (udw/set-rotation (- value (:rotation shape)) [old-shape]) - (udw/apply-modifiers #{(:id shape)})))) + (doall (map #(do-rotation-change %1 %2 value) shapes old-shapes)))) on-radius-change (fn [event] (let [value (-> (dom/get-target event) (dom/get-value) (d/parse-integer 0))] - (st/emit! (udw/update-shape (:id shape) {:rx value :ry value})))) + (st/emit! (dwc/update-shapes-recursive + ids + #(if (:rx %) + (assoc % :rx value :ry value) + %))))) on-width-change #(on-size-change % :width) on-height-change #(on-size-change % :height) on-pos-x-change #(on-position-change % :x) on-pos-y-change #(on-position-change % :y) select-all #(-> % (dom/get-target) (.select))] + [:div.element-set [:div.element-set-content @@ -80,50 +112,50 @@ (when (options :size) [:div.row-flex [:span.element-set-subtitle (t locale "workspace.options.size")] - [:div.lock-size {:class (when (:proportion-lock shape) "selected") + [:div.lock-size {:class (classnames + :selected (true? proportion-lock) + :disabled (= proportion-lock :multiple)) :on-click on-proportion-lock-change} - (if (:proportion-lock shape) + (if proportion-lock i/lock i/unlock)] [:div.input-element.width [:input.input-text {:type "number" :min "0" :no-validate true + :placeholder "--" :on-click select-all :on-change on-width-change - :value (str (-> (:width shape) - (d/coalesce 0) - (math/precision 2)))}]] + :value (attr->string :width values)}]] [:div.input-element.height [:input.input-text {:type "number" :min "0" :no-validate true + :placeholder "--" :on-click select-all :on-change on-height-change - :value (str (-> (:height shape) - (d/coalesce 0) - (math/precision 2)))}]]]) + :value (attr->string :height values)}]]]) ;; POSITION (when (options :position) [:div.row-flex [:span.element-set-subtitle (t locale "workspace.options.position")] [:div.input-element.Xaxis - [:input.input-text {:placeholder "x" - :type "number" + [:input.input-text {:type "number" :no-validate true + :placeholder "--" :on-click select-all :on-change on-pos-x-change - :value (-> shape :selrect :x (math/precision 2))}]] + :value (attr->string :x values)}]] [:div.input-element.Yaxis - [:input.input-text {:placeholder "y" - :type "number" + [:input.input-text {:type "number" :no-validate true + :placeholder "--" :on-click select-all :on-change on-pos-y-change - :value (-> shape :selrect :y (math/precision 2))}]]]) + :value (attr->string :y values)}]]]) ;; ROTATION (when (options :rotation) @@ -131,16 +163,14 @@ [:span.element-set-subtitle (t locale "workspace.options.rotation")] [:div.input-element.degrees [:input.input-text - {:placeholder "" - :type "number" + {:type "number" :no-validate true :min "0" :max "359" + :placeholder "--" :on-click select-all :on-change on-rotation-change - :value (str (-> (:rotation shape) - (d/coalesce 0) - (math/precision 2)))}]] + :value (attr->string :rotation values)}]] [:input.slidebar {:type "range" :min "0" @@ -148,9 +178,7 @@ :step "10" :no-validate true :on-change on-rotation-change - :value (str (-> (:rotation shape) - (d/coalesce 0) - (math/precision 2)))}]]) + :value (attr->string :rotation values)}]]) ;; RADIUS (when (options :radius) @@ -158,11 +186,9 @@ [:span.element-set-subtitle (t locale "workspace.options.radius")] [:div.input-element.pixels [:input.input-text - {:placeholder "rx" - :type "number" + {:type "number" + :placeholder "--" :on-click select-all :on-change on-radius-change - :value (str (-> (:rx shape) - (d/coalesce 0) - (math/precision 2)))}]] + :value (attr->string :rx values)}]] [:div.input-element]])]])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/multiple.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/multiple.cljs index bccea5208..1645ef722 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/multiple.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/multiple.cljs @@ -10,7 +10,7 @@ (ns uxbox.main.ui.workspace.sidebar.options.multiple (:require [rumext.alpha :as mf] - [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) @@ -31,9 +31,13 @@ {::mf/wrap [mf/memo]} [{:keys [shapes] :as props}] (let [ids (map :id shapes) + measure-values (get-multi shapes measure-attrs) fill-values (get-multi shapes fill-attrs) stroke-values (get-multi shapes stroke-attrs)] - [:div + [:* + [:& measures-menu {:ids ids + :type :multiple + :values measure-values}] [:& fill-menu {:ids ids :type :multiple :values fill-values}] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs index 10cc9292d..c73635576 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/rect.cljs @@ -10,7 +10,7 @@ (ns uxbox.main.ui.workspace.sidebar.options.rect (:require [rumext.alpha :as mf] - [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-attrs fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-attrs stroke-menu]])) @@ -19,10 +19,13 @@ [{:keys [shape] :as props}] (let [ids [(:id shape)] type (:type shape) + measure-values (select-keys shape measure-attrs) fill-values (select-keys shape fill-attrs) stroke-values (select-keys shape stroke-attrs)] [:* - [:& measures-menu {:shape shape}] + [:& measures-menu {:ids ids + :type type + :values measure-values}] [:& fill-menu {:ids ids :type type :values fill-values}] diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs index 5cffa620a..0f9e0349b 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/text.cljs @@ -18,7 +18,7 @@ [uxbox.main.data.workspace.texts :as dwt] [uxbox.main.store :as st] [uxbox.main.refs :as refs] - [uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]] + [uxbox.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]] [uxbox.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [uxbox.util.dom :as dom] [uxbox.main.fonts :as fonts] @@ -395,6 +395,11 @@ (mf/defc options [{:keys [shape] :as props}] - [:div - [:& measures-menu {:shape shape}] - [:& text-menu {:shape shape}]]) + (let [ids [(:id shape)] + type (:type shape) + measure-values (select-keys shape measure-attrs)] + [:div + [:& measures-menu {:ids ids + :type type + :values measure-values}] + [:& text-menu {:shape shape}]]))