From c31dc94496d77640ea25db3b671c20663ea0457f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 11 May 2023 15:41:58 +0200 Subject: [PATCH] :sparkles: Align items in grid layout --- .../geom/shapes/grid_layout/positions.cljc | 50 ++++++++++++++++++- common/src/app/common/geom/shapes/points.cljc | 21 +++++++- .../options/menus/layout_container.cljs | 2 +- .../sidebar/options/shapes/grid_cell.cljs | 5 +- .../viewport/grid_layout_editor.cljs | 40 +++++++++++++++ 5 files changed, 113 insertions(+), 5 deletions(-) diff --git a/common/src/app/common/geom/shapes/grid_layout/positions.cljc b/common/src/app/common/geom/shapes/grid_layout/positions.cljc index aae5e7e30..e4f480499 100644 --- a/common/src/app/common/geom/shapes/grid_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/positions.cljc @@ -104,8 +104,54 @@ (defn child-modifiers [parent parent-bounds child child-bounds layout-data cell-data] - (let [fill-modifiers (fill-modifiers parent parent-bounds child child-bounds layout-data cell-data) - position-delta (gpt/subtract (:start-p cell-data) (gpo/origin child-bounds))] + (let [cell-bounds (cell-bounds layout-data cell-data) + + fill-modifiers (fill-modifiers parent parent-bounds child child-bounds layout-data cell-data) + + align (:layout-align-items parent) + justify (:layout-justify-items parent) + align-self (:align-self cell-data) + justify-self (:justify-self cell-data) + + align-self (when (and align-self (not= align-self :auto)) align-self) + justify-self (when (and justify-self (not= justify-self :auto)) justify-self) + + align (or align-self align) + justify (or justify-self justify) + + position-delta (gpt/point) + + ;; Adjust alignment/justify + [from-h to-h] + (case justify + :end + [(gpo/project-point cell-bounds :h (nth child-bounds 1)) + (nth cell-bounds 1)] + + :center + [(gpo/project-point cell-bounds :h (gpo/center child-bounds)) + (gpo/project-point cell-bounds :h (gpo/center cell-bounds))] + + [(gpo/project-point cell-bounds :h (first child-bounds)) + (first cell-bounds)]) + + [from-v to-v] + (case align + :end + [(gpo/project-point cell-bounds :v (nth child-bounds 3)) + (nth cell-bounds 3)] + + :center + [(gpo/project-point cell-bounds :v (gpo/center child-bounds)) + (gpo/project-point cell-bounds :v (gpo/center cell-bounds))] + + [(gpo/project-point cell-bounds :v (first child-bounds)) + (first cell-bounds)]) + + position-delta + (-> position-delta + (gpt/add (gpt/to-vec from-h to-h)) + (gpt/add (gpt/to-vec from-v to-v)))] (-> (ctm/empty) (ctm/add-modifiers fill-modifiers) (ctm/move position-delta)))) diff --git a/common/src/app/common/geom/shapes/points.cljc b/common/src/app/common/geom/shapes/points.cljc index ff6bd15df..e2403b76b 100644 --- a/common/src/app/common/geom/shapes/points.cljc +++ b/common/src/app/common/geom/shapes/points.cljc @@ -80,7 +80,7 @@ "Given a point and a line returns the parametric t the cross point with the line going through the other axis projected" [point [start end] other-axis-vec] - (let [line-vec (gpt/to-vec start end) + (let [line-vec (gpt/to-vec start end) pr-point (gsi/line-line-intersect point (gpt/add point other-axis-vec) start end)] (cond (not (mth/almost-zero? (:x line-vec))) @@ -93,6 +93,15 @@ :else 0))) +(defn project-point + "Project the point into the given axis: `:h` or `:v` means horizontal or vertical axis" + [[p0 p1 _ p3 :as bounds] axis point] + (let [[other-vec start end] + (if (= axis :h) + [(gpt/to-vec p0 p3) p0 p1] + [(gpt/to-vec p0 p1) p0 p3])] + (gsi/line-line-intersect point (gpt/add point other-vec) start end))) + (defn parent-coords-bounds [child-bounds [p1 p2 _ p4 :as parent-bounds]] @@ -154,3 +163,13 @@ [bounds vector] (->> bounds (map #(gpt/add % vector)))) + +(defn center + [bounds] + (let [width (width-points bounds) + height (height-points bounds) + half-h (start-hv bounds (/ width 2)) + half-v (start-vv bounds (/ height 2))] + (-> (origin bounds) + (gpt/add half-h) + (gpt/add half-v)))) 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 a4e9979e4..cc61a2c07 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 @@ -390,7 +390,7 @@ [{:keys [is-col? align-items set-align] :as props}] (let [type (if is-col? :column :row)] [:div.align-items-style - (for [align [:start :center :end :stretch :baseline]] + (for [align [:start :center :end]] [:button.align-start.tooltip {:class (dom/classnames :active (= align-items align) :tooltip-bottom-left (not= align :start) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs index 752eaaea7..9250d9a39 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/grid_cell.cljs @@ -96,7 +96,10 @@ (mf/use-callback (mf/deps (:id shape) (:id cell)) (fn [mode] - (st/emit! (dwsl/update-grid-cell (:id shape) (:id cell) {:mode mode}))))] + (let [props (cond-> {:mode mode} + (not= mode :area) + (assoc :area-name nil))] + (st/emit! (dwsl/update-grid-cell (:id shape) (:id cell) props)))))] [:div.element-set [:div.element-set-title 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 index c8143f11c..1a10b91b1 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -226,6 +226,40 @@ :on-lost-pointer-capture handle-lost-pointer-capture :on-pointer-move handle-pointer-move}])) +(mf/defc grid-cell-area-label + {::mf/wrap-props false} + [props] + + (let [cell-origin (unchecked-get props "origin") + cell-width (unchecked-get props "width") + zoom (unchecked-get props "zoom") + text (unchecked-get props "text") + + area-width (/ (* 10 (count text)) zoom) + area-height (/ 25 zoom) + area-x (- (+ (:x cell-origin) cell-width) area-width) + area-y (:y cell-origin) + + area-text-x (+ area-x (/ area-width 2)) + area-text-y (+ area-y (/ area-height 2))] + + [:g {:pointer-events "none"} + [:rect {:x area-x + :y area-y + :width area-width + :height area-height + :style {:fill "var(--color-distance)" + :fill-opacity 0.3}}] + [:text {:x area-text-x + :y area-text-y + :style {:fill "var(--color-distance)" + :font-family "worksans" + :font-weight 600 + :font-size (/ 14 zoom) + :alignment-baseline "central" + :text-anchor "middle"}} + text]])) + (mf/defc grid-cell {::mf/wrap-props false} [props] @@ -271,6 +305,12 @@ :on-pointer-leave handle-pointer-leave :on-pointer-down handle-pointer-down}] + (when (:area-name cell) + [:& grid-cell-area-label {:origin cell-origin + :width cell-width + :zoom zoom + :text (:area-name cell)}]) + (when selected? (let [handlers ;; Handlers positions, size and cursor