diff --git a/common/src/app/common/geom/shapes/grid_layout.cljc b/common/src/app/common/geom/shapes/grid_layout.cljc index 2588b0e53..36f927081 100644 --- a/common/src/app/common/geom/shapes/grid_layout.cljc +++ b/common/src/app/common/geom/shapes/grid_layout.cljc @@ -12,5 +12,4 @@ (dm/export glld/calc-layout-data) (dm/export glld/get-cell-data) -(dm/export glld/get-child-coordinates) (dm/export glp/child-modifiers) diff --git a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc index ae6ee4bfb..aba5d9f87 100644 --- a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc @@ -6,66 +6,144 @@ (ns app.common.geom.shapes.grid-layout.layout-data (:require + [app.common.data :as d] + [app.common.uuid :as uuid] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes.points :as gpo])) +(defn set-sample-data + [parent children] + + (let [parent (assoc parent + :layout-grid-columns + [{:type :percent :value 25} + {:type :percent :value 25} + {:type :fixed :value 100} + ;;{:type :auto} + ;;{:type :fr :value 1} + ] + + :layout-grid-rows + [{:type :percent :value 50} + {:type :percent :value 50} + ;;{:type :fixed :value 100} + ;;{:type :auto} + ;;{:type :fr :value 1} + ]) + + num-rows (count (:layout-grid-rows parent)) + num-columns (count (:layout-grid-columns parent)) + + layout-grid-cells + (into + {} + (for [[row-idx row] (d/enumerate (:layout-grid-rows parent)) + [col-idx col] (d/enumerate (:layout-grid-columns parent))] + (let [[_bounds shape] (nth children (+ (* row-idx num-columns) col-idx) nil) + cell-data {:id (uuid/next) + :row (inc row-idx) + :column (inc col-idx) + :row-span 1 + :col-span 1 + :shapes (when shape [(:id shape)])}] + [(:id cell-data) cell-data]))) + + parent (assoc parent :layout-grid-cells layout-grid-cells)] + + [parent children])) + +(defn calculate-initial-track-values + [{:keys [type value]} total-value] + + (case type + :percent + (let [value (/ (* total-value value) 100) ] + value) + + :fixed + value + + :auto + 0 + )) + (defn calc-layout-data - [_parent _children transformed-parent-bounds] - (let [num-columns 3 - num-rows 2 + [parent children transformed-parent-bounds] + + (let [ + + ;; TODO: Delete when there is UI + [parent children] (set-sample-data parent children) height (gpo/height-points transformed-parent-bounds) width (gpo/width-points transformed-parent-bounds) - row-lines - (->> (range 0 num-rows) - (reduce (fn [[result start-dist] _] - (let [height (/ height num-rows)] - [(conj result {:distance start-dist - :height height}) - (+ start-dist height)])) + ;; Initialize tracks + column-tracks + (->> (:layout-grid-columns parent) + (map (fn [track] + (let [initial (calculate-initial-track-values track width)] + (assoc track :value initial))))) - [[] 0]) + row-tracks + (->> (:layout-grid-rows parent) + (map (fn [track] + (let [initial (calculate-initial-track-values track height)] + (assoc track :value initial))))) + + ;; Go through cells to adjust auto sizes + + + ;; Once auto sizes have been calculated we get calculate the `fr` with the remainining size and adjust the size + + + ;; Adjust final distances + + acc-track-distance + (fn [[result next-distance] data] + (let [result (conj result (assoc data :distance next-distance)) + next-distance (+ next-distance (:value data))] + [result next-distance])) + + column-tracks + (->> column-tracks + (reduce acc-track-distance [[] 0]) first) - column-lines - (->> (range 0 num-columns) - (reduce (fn [[result start-dist] _] - (let [width (/ width num-columns)] - [(conj result {:distance start-dist - :width width}) - (+ start-dist width)])) - [[] 0]) - first)] - {:columns 3 - :rows 3 - :row-lines row-lines - :column-lines column-lines})) + row-tracks + (->> row-tracks + (reduce acc-track-distance [[] 0]) + first) -(defn get-child-coordinates - [{:keys [columns]} _child child-idx] - [;; Row - (quot child-idx columns) - ;; column - (mod child-idx columns)]) + shape-cells + (into {} + (mapcat (fn [[_ cell]] + (->> (:shapes cell) + (map #(vector % cell))))) + (:layout-grid-cells parent)) + ] + + {:row-tracks row-tracks + :column-tracks column-tracks + :shape-cells shape-cells})) (defn get-cell-data - [grid-data transformed-parent-bounds row col] + [{:keys [row-tracks column-tracks shape-cells]} transformed-parent-bounds [child-bounds child]] (let [origin (gpo/origin transformed-parent-bounds) - hv #(gpo/start-hv transformed-parent-bounds %) - vv #(gpo/start-vv transformed-parent-bounds %) + hv #(gpo/start-hv transformed-parent-bounds %) + vv #(gpo/start-vv transformed-parent-bounds %) - {col-dist :distance width :width} (dm/get-in grid-data [:column-lines col]) - {row-dist :distance height :height} (dm/get-in grid-data [:row-lines row]) + grid-cell (get shape-cells (:id child))] - start-p - (-> origin - (gpt/add (hv col-dist)) - (gpt/add (vv row-dist)))] - {:start-p start-p - :width width - :height height - :row row - :col col})) + (when (some? grid-cell) + (let [column (nth column-tracks (dec (:column grid-cell)) nil) + row (nth row-tracks (dec (:row grid-cell)) nil) + + start-p (-> origin + (gpt/add (hv (:distance column))) + (gpt/add (vv (:distance row)))) + ] + + (assoc grid-cell :start-p start-p))))) diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index f0c247229..29fe313ed 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -218,14 +218,14 @@ (map apply-modifiers)) grid-data (gcgl/calc-layout-data parent children @transformed-parent-bounds)] (loop [modif-tree modif-tree - child-idx 0 child (first children) pending (rest children)] (if (some? child) - (let [[row col] (gcgl/get-child-coordinates grid-data child child-idx) - cell-data (gcgl/get-cell-data grid-data @transformed-parent-bounds row col) - modif-tree (set-child-modifiers modif-tree cell-data child)] - (recur modif-tree (inc child-idx) (first pending) (rest pending))) + (let [cell-data (gcgl/get-cell-data grid-data @transformed-parent-bounds child) + modif-tree (cond-> modif-tree + (some? cell-data) + (set-child-modifiers cell-data child))] + (recur modif-tree (first pending) (rest pending))) modif-tree))))) (defn- calc-auto-modifiers diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index f3317e214..e201ad54c 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -68,6 +68,7 @@ (defn get-layout-initializer [type from-frame?] + (prn "??type" type) (let [initial-layout-data (case type :flex initial-flex-layout @@ -156,6 +157,7 @@ (defn create-layout-from-id [ids type from-frame?] + (.trace js/console "create-layout-from-id" type) (ptk/reify ::create-layout-from-id ptk/WatchEvent (watch [_ state _] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 9d941d190..925d0a84c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -403,7 +403,7 @@ :active (= :grid layout-type))} "Grid"]] [:button.remove-layout {:on-click on-remove-layout} i/minus]] - [:button.add-page {:on-click on-add-layout} i/close])]] + [:button.add-page {:on-click #(on-add-layout :flex)} i/close])]] (when (:layout values) (when (not= :multiple layout-type) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index d4f4ce663..d9102d9f9 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.workspace.viewport (:require + [app.main.ui.workspace.viewport.grid-layout-editor :as grid-layout] [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] @@ -476,6 +477,11 @@ :disabled-guides? disabled-guides? :modifiers modifiers}]) + [:& grid-layout/editor + {:zoom zoom + :objects base-objects + :shape (first selected-shapes)}] + ;; DEBUG LAYOUT DROP-ZONES (when (debug? :layout-drop-zones) [:& wvd/debug-drop-zones {:selected-shapes selected-shapes diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index ada80994d..8cd73894c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -215,7 +215,8 @@ (when (and (some? parent) (not= uuid/zero (:id parent))) (let [children (->> (cph/get-immediate-children objects (:id parent)) - (remove :hidden)) + (remove :hidden) + (map #(vector (gpo/parent-coords-bounds (:points %) (:points parent)) %))) hv #(gpo/start-hv parent-bounds %) vv #(gpo/start-vv parent-bounds %) @@ -224,10 +225,11 @@ height (gpo/height-points parent-bounds) origin (gpo/origin parent-bounds) - grid-layout (gsg/calc-layout-data parent children parent-bounds)] + {:keys [row-tracks column-tracks shape-cells]} + (gsg/calc-layout-data parent children parent-bounds)] [:* - (for [row-data (:row-lines grid-layout)] + (for [row-data row-tracks] (let [start-p (gpt/add origin (vv (:distance row-data))) end-p (gpt/add start-p (hv width))] [:line {:x1 (:x start-p) @@ -236,7 +238,7 @@ :y2 (:y end-p) :style {:stroke "red"}}])) - (for [column-data (:column-lines grid-layout)] + (for [column-data column-tracks] (let [start-p (gpt/add origin (hv (:distance column-data))) end-p (gpt/add start-p (vv height))] [:line {:x1 (:x start-p) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs new file mode 100644 index 000000000..77732e1a6 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -0,0 +1,197 @@ +;; 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/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.main.ui.workspace.viewport.grid-layout-editor + (:require + [app.main.ui.icons :as i] + [app.common.geom.shapes.grid-layout.layout-data :refer [set-sample-data] ] + + [cuerdas.core :as str] + [app.common.geom.point :as gpt] + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.geom.shapes.grid-layout :as gsg] + [app.common.geom.shapes.points :as gpo] + [app.common.pages.helpers :as cph] + [app.common.types.shape.layout :as ctl] + [app.main.refs :as refs] + [app.main.store :as st] + [rumext.v2 :as mf])) + + +(mf/defc track-marker + {::mf/wrap-props false} + [props] + + (let [center (unchecked-get props "center") + value (unchecked-get props "value") + zoom (unchecked-get props "zoom") + + p1 (-> center + (update :x - (/ 13 zoom)) + (update :y - (/ 16 zoom))) + + p2 (-> p1 + (update :x + (/ 26 zoom))) + + p3 (-> p2 + (update :y + (/ 24 zoom))) + + p4 (-> p3 + (update :x - (/ 13 zoom)) + (update :y + (/ 8 zoom))) + + p5 (-> p4 + (update :x - (/ 13 zoom)) + (update :y - (/ 8 zoom))) + + text-x (:x center) + text-y (:y center)] + [:g.grid-track-marker + [:polygon {:points (->> [p1 p2 p3 p4 p5] + (map #(dm/fmt "%,%" (:x %) (:y %))) + (str/join " ")) + + :style {:fill "#DB00FF" + :fill-opacity 0.3}}] + [:text {:x text-x + :y text-y + :width (/ 26.26 zoom) + :height (/ 32 zoom) + :font-size (/ 16 zoom) + :text-anchor "middle" + :dominant-baseline "middle" + :style {:fill "#DB00FF"}} + (dm/str value)]])) + +(mf/defc editor + {::mf/wrap-props false} + [props] + + (let [shape (unchecked-get props "shape") + objects (unchecked-get props "objects") + zoom (unchecked-get props "zoom") + bounds (:points shape)] + + (when (ctl/grid-layout? shape) + (let [children (->> (cph/get-immediate-children objects (:id shape)) + (remove :hidden) + (map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %))) + + hv #(gpo/start-hv bounds %) + vv #(gpo/start-vv bounds %) + + width (gpo/width-points bounds) + height (gpo/height-points bounds) + origin (gpo/origin bounds) + + {:keys [row-tracks column-tracks shape-cells]} + (gsg/calc-layout-data shape children bounds) + + [shape children] (set-sample-data shape children)] + + [:g.grid-editor + [:polygon {:points (->> [origin + (-> origin + (gpt/add (hv width))) + (-> origin + (gpt/add (hv width)) + (gpt/subtract (vv (/ 40 zoom)))) + + (-> origin + (gpt/add (hv width)) + (gpt/subtract (vv (/ 40 zoom))) + (gpt/subtract (hv (+ width (/ 40 zoom))))) + + (-> origin + (gpt/add (hv width)) + (gpt/subtract (vv (/ 40 zoom))) + (gpt/subtract (hv (+ width (/ 40 zoom)))) + (gpt/add (vv (+ height (/ 40 zoom))))) + (-> origin + (gpt/add (hv width)) + (gpt/subtract (vv (/ 40 zoom))) + (gpt/subtract (hv (+ width (/ 40 zoom)))) + (gpt/add (vv (+ height (/ 40 zoom)))) + (gpt/add (hv (/ 40 zoom))))] + (map #(dm/fmt "%,%" (:x %) (:y %))) + (str/join " ")) + :style {:stroke "#DB00FF" + :stroke-width (/ 1 zoom)}}] + + (let [start-p (-> origin (gpt/add (hv width)))] + [:* + [:rect {:x (:x start-p) + :y (- (:y start-p) (/ 40 zoom)) + :width (/ 40 zoom) + :height (/ 40 zoom) + :style {:fill "#DB00FF" + :stroke "#DB00FF" + :stroke-width (/ 1 zoom)}}] + + [:use {:x (+ (:x start-p) (/ 12 zoom)) + :y (- (:y start-p) (/ 28 zoom)) + :width (/ 16 zoom) + :height (/ 16 zoom) + :href (dm/str "#icon-plus") + :fill "white"}]]) + + (let [start-p (-> origin (gpt/add (vv height)))] + [:rect {:x (- (:x start-p) (/ 40 zoom)) + :y (:y start-p) + :width (/ 40 zoom) + :height (/ 40 zoom) + :style {:fill "#DB00FF" + :stroke "#DB00FF" + :stroke-width (/ 1 zoom)}}]) + + (for [[idx column-data] (d/enumerate column-tracks)] + (let [start-p (-> origin + (gpt/add (hv (:distance column-data))) + (gpt/subtract (vv (/ 20 zoom))))] + [:& track-marker {:center start-p + :value (dm/str (inc idx)) + :zoom zoom}])) + + (for [[idx row-data] (d/enumerate row-tracks)] + (let [start-p (-> origin + (gpt/add (vv (:distance row-data))) + (gpt/subtract (hv (/ 20 zoom))))] + [:g {:transform (dm/fmt "rotate(-90 % %)" (:x start-p) (:y start-p))} + [:& track-marker {:center start-p + :value (dm/str (inc idx)) + :zoom zoom}]])) + + (for [[_ grid-cell] (:layout-grid-cells shape)] + (let [column (nth column-tracks (dec (:column grid-cell)) nil) + row (nth row-tracks (dec (:row grid-cell)) nil) + + start-p (-> origin + (gpt/add (hv (:distance column))) + (gpt/add (vv (:distance row)))) + + end-p (-> start-p + (gpt/add (hv (:value column))) + (gpt/add (vv (:value row))))] + + [:* + #_[:rect {:x (:x start-p) + :y (- (:y start-p) (/ 32 zoom) (/ 8 zoom)) + :width (/ 26.26 zoom) + :height (/ 32 zoom) + :style {:fill "#DB00FF" + :fill-opacity 0.3} + }] + + [:rect.cell-editor {:x (:x start-p) + :y (:y start-p) + :width (- (:x end-p) (:x start-p)) + :height (- (:y end-p) (:y start-p)) + :style {:stroke "#DB00FF" + :stroke-dasharray (str/join " " (map #(/ % zoom) [0 8]) ) + :stroke-linecap "round" + :stroke-width (/ 2 zoom)} + }]]))]))))