diff --git a/common/uxbox/common/geom/shapes.cljc b/common/uxbox/common/geom/shapes.cljc index f8d959f94..e09cb4802 100644 --- a/common/uxbox/common/geom/shapes.cljc +++ b/common/uxbox/common/geom/shapes.cljc @@ -856,34 +856,63 @@ :else srect)))) (defn get-attrs-multi - [values attrs] - ;; Extract some attributes of a list of shape values. + [shapes attrs] + ;; Extract some attributes of a list of shapes. ;; For each attribute, if the value is the same in all shapes, ;; wll take this value. If there is any shape that is different, ;; the value of the attribute will be the keyword :multiple. ;; + ;; If some shape has the value nil in any attribute, it's + ;; considered a different value. If the shape does not contain + ;; the attribute, it's ignored in the final result. + ;; ;; Example: - ;; (def values [{:stroke-color "#ff0000' + ;; (def shapes [{:stroke-color "#ff0000" ;; :stroke-width 3 - ;; :x 1000 :y 2000} - ;; {:stroke-width "#ff0000' + ;; :fill-color "#0000ff" + ;; :x 1000 :y 2000 :rx nil} + ;; {:stroke-width "#ff0000" ;; :stroke-width 5 ;; :x 1500 :y 2000}]) ;; - ;; (get-attrs-multi values [:stroke-color :stroke-width :fill-color]) - ;; >>> {:stroke-color "#ff0000' + ;; (get-attrs-multi shapes [:stroke-color + ;; :stroke-width + ;; :fill-color + ;; :rx + ;; :ry]) + ;; >>> {:stroke-color "#ff0000" ;; :stroke-width :multiple - ;; :fill-color nil} + ;; :fill-color "#0000ff" + ;; :rx nil + ;; :ry nil} ;; - (let [defined-values (filter some? values) + (let [defined-shapes (filter some? shapes) - combine-value #(if (= %1 %2) %1 :multiple) + combine-value (fn [v1 v2] (cond + (= v1 v2) v1 + (= v1 :undefined) v2 + (= v2 :undefined) v1 + :else :multiple)) combine-values (fn [attrs shape values] - (map #(combine-value (get shape %) (get values %)) attrs)) + (map #(combine-value (get shape % :undefined) + (get values % :undefined)) attrs)) + + select-attrs (fn [shape attrs] + (zipmap attrs (map #(get shape % :undefined) attrs))) reducer (fn [result shape] - (zipmap attrs (combine-values attrs shape result)))] + (zipmap attrs (combine-values attrs shape result))) - (reduce reducer (select-keys (first defined-values) attrs) (rest defined-values)))) + combined (reduce reducer + (select-attrs (first defined-shapes) attrs) + (rest defined-shapes)) + + cleanup-value (fn [value] + (if (= value :undefined) nil value)) + + cleanup (fn [result] + (zipmap attrs (map #(cleanup-value (get result %)) attrs)))] + + (cleanup combined))) diff --git a/common/uxbox/common/pages.cljc b/common/uxbox/common/pages.cljc index 0ac68faa0..bee30ed4e 100644 --- a/common/uxbox/common/pages.cljc +++ b/common/uxbox/common/pages.cljc @@ -233,36 +233,61 @@ [{:type :rect :name "Rect" :fill-color default-color - :stroke-alignment :center - :rx 0 - :ry 0} - {:type :image} - {:type :icon} - {:type :circle - :name "Circle" - :fill-color default-color} - {:type :path - :name "Path" - :stroke-style :solid - :stroke-color "#000000" - :stroke-width 2 - :stroke-alignment :center - :fill-color "#000000" - :fill-opacity 0 - :segments []} - {:type :frame + :fill-opacity 1 :stroke-style :none :stroke-alignment :center - :name "Artboard"} - {:type :curve - :name "Path" - :stroke-style :solid + :stroke-width 0 :stroke-color "#000000" - :stroke-width 2 + :stroke-opacity 0 + :rx 0 + :ry 0} + + {:type :image} + + {:type :icon} + + {:type :circle + :name "Circle" + :fill-color default-color + :fill-opacity 1 + :stroke-style :none :stroke-alignment :center + :stroke-width 0 + :stroke-color "#000000" + :stroke-opacity 0} + + {:type :path + :name "Path" :fill-color "#000000" :fill-opacity 0 + :stroke-style :solid + :stroke-alignment :center + :stroke-width 2 + :stroke-color "#000000" + :stroke-opacity 1 :segments []} + + {:type :frame + :name "Artboard" + :fill-color "#ffffff" + :fill-opacity 1 + :stroke-style :none + :stroke-alignment :center + :stroke-width 0 + :stroke-color "#000000" + :stroke-opacity 0} + + {:type :curve + :name "Path" + :fill-color "#000000" + :fill-opacity 0 + :stroke-style :solid + :stroke-alignment :center + :stroke-width 2 + :stroke-color "#000000" + :stroke-opacity 1 + :segments []} + {:type :text :name "Text" :content nil}]) diff --git a/frontend/src/uxbox/main/refs.cljs b/frontend/src/uxbox/main/refs.cljs index 56a6d8167..1d9248317 100644 --- a/frontend/src/uxbox/main/refs.cljs +++ b/frontend/src/uxbox/main/refs.cljs @@ -136,6 +136,16 @@ (into selected children)))] (l/derived selector st/state))) +(def selected-objects-with-children + (letfn [(selector [state] + (let [selected (get-in state [:workspace-local :selected]) + page-id (get-in state [:workspace-page :id]) + objects (get-in state [:workspace-data page-id :objects]) + children (mapcat #(cph/get-children % objects) selected) + accumulated (into selected children)] + (mapv #(get objects %) accumulated)))] + (l/derived selector st/state))) + (defn make-selected [id] (l/derived #(contains? % id) selected-shapes)) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs index 32bfb2fcc..64d72ca68 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options.cljs @@ -37,11 +37,11 @@ (mf/defc shape-options {::mf/wrap [#(mf/throttle % 60)]} - [{:keys [shape page] :as props}] + [{:keys [shape shapes-with-children page] :as props}] [:* (case (:type shape) :frame [:& frame/options {:shape shape}] - :group [:& group/options {:shape shape}] + :group [:& group/options {:shape shape :shape-with-children shapes-with-children}] :text [:& text/options {:shape shape}] :rect [:& rect/options {:shape shape}] :icon [:& icon/options {:shape shape}] @@ -55,7 +55,7 @@ (mf/defc options-content {::mf/wrap [mf/memo]} - [{:keys [section shapes page] :as props}] + [{:keys [section shapes shapes-with-children page] :as props}] (let [locale (mf/deref i18n/locale)] [:div.tool-window [:div.tool-window-content @@ -67,8 +67,8 @@ [:& align-options] (case (count shapes) 0 [:& page/options {:page page}] - 1 [:& shape-options {:shape (first shapes)}] - [:& multiple/options {:shapes shapes}])]] + 1 [:& shape-options {:shape (first shapes) :shapes-with-children shapes-with-children}] + [:& multiple/options {:shapes shapes-with-children}])]] [:& tab-element {:id :prototype :title (t locale "workspace.options.prototype")} @@ -79,9 +79,11 @@ (mf/defc options-toolbox {::mf/wrap [mf/memo]} [{:keys [page local] :as props}] - (let [section (:options-mode local) - shapes (mf/deref refs/selected-objects)] + (let [section (:options-mode local) + shapes (mf/deref refs/selected-objects) + shapes-with-children (mf/deref refs/selected-objects-with-children)] [:& options-content {:shapes shapes + :shapes-with-children shapes-with-children :page page :section section}])) 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 a87e11aa4..31b1cbf83 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/group.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/group.cljs @@ -12,6 +12,7 @@ (:require [rumext.alpha :as mf] [uxbox.common.geom.shapes :as geom] + [uxbox.common.pages-helpers :as cph] [uxbox.main.refs :as refs] [uxbox.main.data.workspace.texts :as dwt] [uxbox.main.ui.workspace.sidebar.options.multiple :refer [get-shape-attrs]] @@ -28,19 +29,19 @@ text-menu]])) (mf/defc options - [{:keys [shape] :as props}] - (let [child-ids (:shapes shape) - children (mf/deref (refs/objects-by-id child-ids)) - text-ids (map :id (filter #(= (:type %) :text) children)) - other-ids (map :id (filter #(not= (:type %) :text) children)) + [{:keys [shape shape-with-children] :as props}] + (let [id (:id shape) + ids-with-children (map :id shape-with-children) + text-ids (map :id (filter #(= (:type %) :text) shape-with-children)) + other-ids (map :id (filter #(not= (:type %) :text) shape-with-children)) - type (:type shape) + type (:type shape) ; always be :group measure-values (select-keys shape measure-attrs) fill-values - (geom/get-attrs-multi children fill-attrs) + (geom/get-attrs-multi shape-with-children fill-attrs) stroke-values (geom/get-attrs-multi (map #(get-shape-attrs @@ -49,7 +50,7 @@ nil nil nil) - children) + shape-with-children) stroke-attrs) font-values @@ -59,7 +60,7 @@ text-font-attrs nil dwt/current-text-values) - children) + shape-with-children) text-font-attrs) align-values @@ -69,7 +70,7 @@ text-align-attrs nil dwt/current-paragraph-values) - children) + shape-with-children) text-align-attrs) spacing-values @@ -79,7 +80,7 @@ text-spacing-attrs nil dwt/current-text-values) - children) + shape-with-children) text-spacing-attrs) valign-values @@ -89,7 +90,7 @@ text-valign-attrs nil dwt/current-root-values) - children) + shape-with-children) text-valign-attrs) decoration-values @@ -99,7 +100,7 @@ text-decoration-attrs nil dwt/current-text-values) - children) + shape-with-children) text-decoration-attrs) transform-values @@ -109,17 +110,17 @@ text-transform-attrs nil dwt/current-text-values) - children) + shape-with-children) text-transform-attrs)] [:* - [:& measures-menu {:ids [(:id shape)] + [:& measures-menu {:ids [id] :type type :values measure-values}] - [:& fill-menu {:ids child-ids + [:& fill-menu {:ids ids-with-children :type type :values fill-values}] (when-not (empty? other-ids) - [:& stroke-menu {:ids child-ids + [:& stroke-menu {:ids other-ids :type type :values stroke-values}]) (when-not (empty? text-ids)