diff --git a/frontend/src/uxbox/main/ui/workspace/layout_display.cljs b/frontend/src/uxbox/main/ui/workspace/layout_display.cljs index 01fe1e6c2e..9702b0e1ec 100644 --- a/frontend/src/uxbox/main/ui/workspace/layout_display.cljs +++ b/frontend/src/uxbox/main/ui/workspace/layout_display.cljs @@ -10,11 +10,12 @@ (ns uxbox.main.ui.workspace.layout-display (:require [rumext.alpha :as mf] - [uxbox.main.refs :as refs])) + [uxbox.main.refs :as refs] + [uxbox.util.geom.layout :as ula])) -(mf/defc grid-layout [{:keys [frame zoom params] :as props}] - (let [{:keys [color size]} params - {color-value :value color-opacity :opacity} (:color params) +(mf/defc grid-layout [{:keys [frame zoom layout] :as props}] + (let [{:keys [color size] :as params} (-> layout :params) + {color-value :value color-opacity :opacity} color {frame-width :width frame-height :height :keys [x y]} frame] [:g.grid [:* @@ -37,49 +38,13 @@ :stroke-opacity color-opacity :stroke-width (str (/ 1 zoom))}}])]])) -(defn calculate-column-layout [frame size gutter margin item-width layout-type] - (let [{:keys [width height x y]} frame - parts (/ width size) - item-width (or item-width (+ parts (- gutter) (/ gutter size) (- (/ (* margin 2) size)))) - item-height height - initial-offset (case layout-type - :right (- width (* item-width size) (* gutter (dec size)) margin) - :center (/ (- width (* item-width size) (* gutter (dec size))) 2) - margin) - gutter (if (= :stretch layout-type) (/ (- width (* item-width size) (* margin 2)) (dec size)) gutter) - next-x (fn [cur-val] (+ initial-offset x (* (+ item-width gutter) cur-val))) - next-y (fn [cur-val] y)] - [parts item-width item-height next-x next-y])) - -(defn calculate-row-layout [frame size gutter margin item-height layout-type] - (let [{:keys [width height x y]} frame - parts (/ height size) - item-width width - item-height (or item-height (+ parts (- gutter) (/ gutter size) (- (/ (* margin 2) size)))) - initial-offset (case layout-type - :right (- height (* item-height size) (* gutter (dec size)) margin) - :center (/ (- height (* item-height size) (* gutter (dec size))) 2) - margin) - gutter (if (= :stretch layout-type) (/ (- height (* item-height size) (* margin 2)) (dec size)) gutter) - next-x (fn [cur-val] x) - next-y (fn [cur-val] (+ initial-offset y (* (+ item-height gutter) cur-val)))] - [parts item-width item-height next-x next-y])) - -(mf/defc flex-layout [{:keys [frame zoom params orientation]}] - (let [{:keys [color size type gutter margin item-width item-height]} params - {color-value :value color-opacity :opacity} (:color params) - - ;; calculates the layout configuration - [parts item-width item-height next-x next-y] - (if (= orientation :column) - (calculate-column-layout frame size gutter margin item-width type) - (calculate-row-layout frame size gutter margin item-height type))] - - (for [cur-val (range 0 size)] - [:rect {:x (next-x cur-val) - :y (next-y cur-val) - :width item-width - :height item-height +(mf/defc flex-layout [{:keys [frame zoom layout]}] + (let [{color-value :value color-opacity :opacity} (-> layout :params :color)] + (for [{:keys [x y width height]} (ula/layout-rects frame layout)] + [:rect {:x x + :y y + :width width + :height height :style {:pointer-events "none" :fill color-value :opacity color-opacity}}]))) @@ -87,14 +52,11 @@ (mf/defc layout-display [{:keys [frame]}] (let [zoom (mf/deref refs/selected-zoom) layouts (:layouts frame)] - (for [[index {:keys [type display params]}] (map-indexed vector layouts)] + (for [[index {:keys [type display] :as layout}] (map-indexed vector layouts)] (let [props #js {:key (str (:id frame) "-layout-" index) :frame frame :zoom zoom - :params params - :orientation (cond (= type :column) :column - (= type :row) :row - :else nil) }] + :layout layout}] (when display (case type :square [:> grid-layout props] 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 19df4cba4d..af6051a39e 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame.cljs @@ -22,7 +22,7 @@ [uxbox.main.ui.components.dropdown :refer [dropdown]] [uxbox.main.ui.workspace.sidebar.options.fill :refer [fill-menu]] [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]] - [uxbox.main.ui.workspace.sidebar.options.grid-options :refer [grid-options]])) + [uxbox.main.ui.workspace.sidebar.options.frame-layouts :refer [frame-layouts]])) (declare +size-presets+) @@ -204,4 +204,4 @@ [:& measures-menu {:shape shape}] [:& fill-menu {:shape shape}] [:& stroke-menu {:shape shape}] - [:& grid-options {:shape shape}]]) + [:& frame-layouts {:shape shape}]]) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/grid_options.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame_layouts.cljs similarity index 94% rename from frontend/src/uxbox/main/ui/workspace/sidebar/options/grid_options.cljs rename to frontend/src/uxbox/main/ui/workspace/sidebar/options/frame_layouts.cljs index 756184d411..9f8ea3125b 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/grid_options.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/frame_layouts.cljs @@ -7,7 +7,7 @@ ;; ;; Copyright (c) 2020 UXBOX Labs SL -(ns uxbox.main.ui.workspace.sidebar.options.grid-options +(ns uxbox.main.ui.workspace.sidebar.options.frame-layouts (:require [rumext.alpha :as mf] [uxbox.util.dom :as dom] @@ -49,7 +49,7 @@ :color {:value "#DE4762" :opacity 0.1}}}) -(mf/defc grid-option [{:keys [layout on-change on-remove]}] +(mf/defc layout-options [{:keys [layout on-change on-remove]}] (let [state (mf/use-state {:show-advanced-options false :changes {}}) {:keys [type display params] :as layout} (d/deep-merge layout (:changes @state)) @@ -169,7 +169,7 @@ [:button.btn-options "Use default"] [:button.btn-options "Set as default"]]]])) -(mf/defc grid-options [{:keys [shape]}] +(mf/defc frame-layouts [{:keys [shape]}] (let [id (:id shape) handle-create-layout #(st/emit! (dw/add-frame-layout id)) handle-remove-layout (fn [index] #(st/emit! (dw/remove-frame-layout id index))) @@ -181,8 +181,8 @@ [:div.element-set-content (for [[index layout] (map-indexed vector (:layouts shape))] - [:& grid-option {:key (str (:id shape) "-" index) - :layout layout - :on-change (handle-edit-layout index) - :on-remove (handle-remove-layout index)}])]])) + [:& layout-options {:key (str (:id shape) "-" index) + :layout layout + :on-change (handle-edit-layout index) + :on-remove (handle-remove-layout index)}])]])) diff --git a/frontend/src/uxbox/util/geom/layout.cljs b/frontend/src/uxbox/util/geom/layout.cljs new file mode 100644 index 0000000000..164edea37d --- /dev/null +++ b/frontend/src/uxbox/util/geom/layout.cljs @@ -0,0 +1,49 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns uxbox.util.geom.layout) + +(defn calculate-column-layout [{:keys [width height x y] :as frame} {:keys [size gutter margin item-width type] :as params}] + (let [parts (/ width size) + item-width (or item-width (+ parts (- gutter) (/ gutter size) (- (/ (* margin 2) size)))) + item-height height + initial-offset (case type + :right (- width (* item-width size) (* gutter (dec size)) margin) + :center (/ (- width (* item-width size) (* gutter (dec size))) 2) + margin) + gutter (if (= :stretch type) (/ (- width (* item-width size) (* margin 2)) (dec size)) gutter) + next-x (fn [cur-val] (+ initial-offset x (* (+ item-width gutter) cur-val))) + next-y (fn [cur-val] y)] + [item-width item-height next-x next-y])) + +(defn calculate-row-layout [{:keys [width height x y] :as frame} {:keys [size gutter margin item-height type] :as params}] + (let [{:keys [width height x y]} frame + parts (/ height size) + item-width width + item-height (or item-height (+ parts (- gutter) (/ gutter size) (- (/ (* margin 2) size)))) + initial-offset (case type + :right (- height (* item-height size) (* gutter (dec size)) margin) + :center (/ (- height (* item-height size) (* gutter (dec size))) 2) + margin) + gutter (if (= :stretch type) (/ (- height (* item-height size) (* margin 2)) (dec size)) gutter) + next-x (fn [cur-val] x) + next-y (fn [cur-val] (+ initial-offset y (* (+ item-height gutter) cur-val)))] + [item-width item-height next-x next-y])) + +(defn layout-rects [frame layout] + (let [[item-width item-height next-x next-y] + (case (-> layout :type) + :column (calculate-column-layout frame (-> layout :params)) + :row (calculate-row-layout frame (-> layout :params)))] + (->> + (range 0 (-> layout :params :size)) + (map #(hash-map :x (next-x %) + :y (next-y %) + :width item-width + :height item-height))))) diff --git a/frontend/src/uxbox/util/geom/snap_points.cljs b/frontend/src/uxbox/util/geom/snap_points.cljs index a8274a5662..609b06cc95 100644 --- a/frontend/src/uxbox/util/geom/snap_points.cljs +++ b/frontend/src/uxbox/util/geom/snap_points.cljs @@ -12,38 +12,31 @@ [cljs.spec.alpha :as s] [clojure.set :as set] [uxbox.util.geom.shapes :as gsh] - [uxbox.util.geom.point :as gpt])) + [uxbox.util.geom.point :as gpt] + [uxbox.util.geom.layout :as gla])) -(defn- frame-snap-points [{:keys [x y width height]}] +(defn- layout-rect-snaps [{:keys [x y width height]}] #{(gpt/point x y) - (gpt/point (+ x (/ width 2)) y) (gpt/point (+ x width) y) - (gpt/point (+ x width) (+ y (/ height 2))) (gpt/point (+ x width) (+ y height)) - (gpt/point (+ x (/ width 2)) (+ y height)) - (gpt/point x (+ y height)) - (gpt/point x (+ y (/ height 2)))}) + (gpt/point x (+ y height))}) -(defn- frame-snap-points-resize [{:keys [x y width height]} handler] - (case handler - :top-left (gpt/point x y) - :top (gpt/point (+ x (/ width 2)) y) - :top-right (gpt/point (+ x width) y) - :right (gpt/point (+ x width) (+ y (/ height 2))) - :bottom-right (gpt/point (+ x width) (+ y height)) - :bottom (gpt/point (+ x (/ width 2)) (+ y height)) - :bottom-left (gpt/point x (+ y height)) - :left (gpt/point x (+ y (/ height 2))))) +(defn- layout-snap-points [frame {:keys [type] :as layout}] + (mapcat layout-rect-snaps (gla/layout-rects frame layout))) -(def ^:private handler->point-idx - {:top-left 0 - :top 0 - :top-right 1 - :right 1 - :bottom-right 2 - :bottom 2 - :bottom-left 3 - :left 3}) +(defn- frame-snap-points [{:keys [x y width height layouts] :as frame}] + (into #{(gpt/point x y) + (gpt/point (+ x (/ width 2)) y) + (gpt/point (+ x width) y) + (gpt/point (+ x width) (+ y (/ height 2))) + (gpt/point (+ x width) (+ y height)) + (gpt/point (+ x (/ width 2)) (+ y height)) + (gpt/point x (+ y height)) + (gpt/point x (+ y (/ height 2)))} + (->> + layouts + (filter #(and (not= :grid (:type %)) (:display %))) + (mapcat #(layout-snap-points frame %))))) (defn shape-snap-points [shape]