mirror of
https://github.com/penpot/penpot.git
synced 2025-07-29 03:37:21 +02:00
✨ Move auto-layout children
This commit is contained in:
parent
025cac0228
commit
c3ed46d3ab
22 changed files with 457 additions and 329 deletions
|
@ -5,7 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.common.geom.point
|
(ns app.common.geom.point
|
||||||
(:refer-clojure :exclude [divide min max])
|
(:refer-clojure :exclude [divide min max abs])
|
||||||
(:require
|
(:require
|
||||||
#?(:cljs [cljs.pprint :as pp]
|
#?(:cljs [cljs.pprint :as pp]
|
||||||
:clj [clojure.pprint :as pp])
|
:clj [clojure.pprint :as pp])
|
||||||
|
@ -328,6 +328,13 @@
|
||||||
(update :x #(if (mth/almost-zero? %) 0.001 %))
|
(update :x #(if (mth/almost-zero? %) 0.001 %))
|
||||||
(update :y #(if (mth/almost-zero? %) 0.001 %))))
|
(update :y #(if (mth/almost-zero? %) 0.001 %))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn abs
|
||||||
|
[point]
|
||||||
|
(-> point
|
||||||
|
(update :x mth/abs)
|
||||||
|
(update :y mth/abs)))
|
||||||
|
|
||||||
;; --- Debug
|
;; --- Debug
|
||||||
|
|
||||||
(defmethod pp/simple-dispatch Point [obj] (pr obj))
|
(defmethod pp/simple-dispatch Point [obj] (pr obj))
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
(dm/export gpr/join-rects)
|
(dm/export gpr/join-rects)
|
||||||
(dm/export gpr/join-selrects)
|
(dm/export gpr/join-selrects)
|
||||||
(dm/export gpr/contains-selrect?)
|
(dm/export gpr/contains-selrect?)
|
||||||
|
(dm/export gpr/contains-point?)
|
||||||
|
|
||||||
(dm/export gtr/move)
|
(dm/export gtr/move)
|
||||||
(dm/export gtr/absolute-move)
|
(dm/export gtr/absolute-move)
|
||||||
|
|
|
@ -288,7 +288,9 @@
|
||||||
(defn calc-child-modifiers
|
(defn calc-child-modifiers
|
||||||
[parent child modifiers ignore-constraints transformed-parent]
|
[parent child modifiers ignore-constraints transformed-parent]
|
||||||
|
|
||||||
(let [constraints-h
|
(let [modifiers (select-keys modifiers [:v2])
|
||||||
|
|
||||||
|
constraints-h
|
||||||
(if-not ignore-constraints
|
(if-not ignore-constraints
|
||||||
(:constraints-h child (default-constraints-h child))
|
(:constraints-h child (default-constraints-h child))
|
||||||
:scale)
|
:scale)
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
(ns app.common.geom.shapes.layout
|
(ns app.common.geom.shapes.layout
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.common.geom.shapes.common :as gco]
|
||||||
[app.common.geom.shapes.rect :as gsr]
|
[app.common.geom.shapes.rect :as gsr]
|
||||||
[app.common.geom.shapes.transforms :as gst]))
|
[app.common.geom.shapes.transforms :as gst]
|
||||||
|
[app.common.pages.helpers :as cph]))
|
||||||
|
|
||||||
;; :layout ;; true if active, false if not
|
;; :layout ;; true if active, false if not
|
||||||
;; :layout-dir ;; :right, :left, :top, :bottom
|
;; :layout-dir ;; :right, :left, :top, :bottom
|
||||||
|
@ -213,6 +216,8 @@
|
||||||
layout-height (height-points layout-bounds)
|
layout-height (height-points layout-bounds)
|
||||||
row? (row? parent)
|
row? (row? parent)
|
||||||
col? (col? parent)
|
col? (col? parent)
|
||||||
|
space-between? (= :space-between (:layout-type parent))
|
||||||
|
space-around? (= :space-around (:layout-type parent))
|
||||||
h-center? (h-center? parent)
|
h-center? (h-center? parent)
|
||||||
h-end? (h-end? parent)
|
h-end? (h-end? parent)
|
||||||
v-center? (v-center? parent)
|
v-center? (v-center? parent)
|
||||||
|
@ -258,11 +263,11 @@
|
||||||
start-p
|
start-p
|
||||||
(cond-> base-p
|
(cond-> base-p
|
||||||
;; X AXIS
|
;; X AXIS
|
||||||
(and col? h-center?)
|
(and col? h-center? (not space-around?) (not space-between?))
|
||||||
(-> (gpt/add (xv (/ layout-width 2)))
|
(-> (gpt/add (xv (/ layout-width 2)))
|
||||||
(gpt/subtract (xv (/ (+ line-width children-gap) 2))))
|
(gpt/subtract (xv (/ (+ line-width children-gap) 2))))
|
||||||
|
|
||||||
(and col? h-end?)
|
(and col? h-end? (not space-around?) (not space-between?))
|
||||||
(-> (gpt/add (xv layout-width))
|
(-> (gpt/add (xv layout-width))
|
||||||
(gpt/subtract (xv (+ line-width children-gap))))
|
(gpt/subtract (xv (+ line-width children-gap))))
|
||||||
|
|
||||||
|
@ -273,11 +278,11 @@
|
||||||
(gpt/add (xv line-width))
|
(gpt/add (xv line-width))
|
||||||
|
|
||||||
;; Y AXIS
|
;; Y AXIS
|
||||||
(and row? v-center?)
|
(and row? v-center? (not space-around?) (not space-between?))
|
||||||
(-> (gpt/add (yv (/ layout-height 2)))
|
(-> (gpt/add (yv (/ layout-height 2)))
|
||||||
(gpt/subtract (yv (/ (+ line-height children-gap) 2))))
|
(gpt/subtract (yv (/ (+ line-height children-gap) 2))))
|
||||||
|
|
||||||
(and row? v-end?)
|
(and row? v-end? (not space-around?) (not space-between?))
|
||||||
(-> (gpt/add (yv layout-height))
|
(-> (gpt/add (yv layout-height))
|
||||||
(gpt/subtract (yv (+ line-height children-gap))))
|
(gpt/subtract (yv (+ line-height children-gap))))
|
||||||
|
|
||||||
|
@ -385,17 +390,10 @@
|
||||||
(let [row? (row? parent)
|
(let [row? (row? parent)
|
||||||
col? (col? parent)
|
col? (col? parent)
|
||||||
|
|
||||||
layout-type (:layout-type parent)
|
h-center? (h-center? parent)
|
||||||
space-around? (= :space-around layout-type)
|
h-end? (h-end? parent)
|
||||||
space-between? (= :space-between layout-type)
|
v-center? (v-center? parent)
|
||||||
|
v-end? (v-end? parent)
|
||||||
stretch-h? (and row? (or space-around? space-between?))
|
|
||||||
stretch-v? (and col? (or space-around? space-between?))
|
|
||||||
|
|
||||||
h-center? (and (h-center? parent) (not stretch-h?))
|
|
||||||
h-end? (and (h-end? parent) (not stretch-h?))
|
|
||||||
v-center? (and (v-center? parent) (not stretch-v?))
|
|
||||||
v-end? (and (v-end? parent) (not stretch-v?))
|
|
||||||
points (:points parent)
|
points (:points parent)
|
||||||
|
|
||||||
xv (partial start-hv points)
|
xv (partial start-hv points)
|
||||||
|
@ -409,10 +407,10 @@
|
||||||
(and row? h-end?)
|
(and row? h-end?)
|
||||||
(gpt/add (xv (- child-width)))
|
(gpt/add (xv (- child-width)))
|
||||||
|
|
||||||
(and col? v-center? (not space-around?))
|
(and col? v-center?)
|
||||||
(gpt/add (yv (- (/ child-height 2))))
|
(gpt/add (yv (- (/ child-height 2))))
|
||||||
|
|
||||||
(and col? v-end? (not space-around?))
|
(and col? v-end?)
|
||||||
(gpt/add (yv (- child-height)))
|
(gpt/add (yv (- child-height)))
|
||||||
|
|
||||||
(some? margin-x)
|
(some? margin-x)
|
||||||
|
@ -584,21 +582,27 @@
|
||||||
v-center? (and col? (v-center? frame))
|
v-center? (and col? (v-center? frame))
|
||||||
v-end? (and row? (v-end? frame))
|
v-end? (and row? (v-end? frame))
|
||||||
layout-gap (:layout-gap frame 0)
|
layout-gap (:layout-gap frame 0)
|
||||||
|
reverse? (:reverse? layout-data)
|
||||||
|
|
||||||
children (vec (cond->> children
|
children (vec (cond->> (d/enumerate children)
|
||||||
(:reverse? layout-data) reverse))
|
reverse? reverse))
|
||||||
|
|
||||||
redfn-child
|
redfn-child
|
||||||
(fn [[result parent-rect prev-x prev-y] [child next]]
|
(fn [[result parent-rect prev-x prev-y] [[index child] next]]
|
||||||
(let [prev-x (or prev-x (:x parent-rect))
|
(let [prev-x (or prev-x (:x parent-rect))
|
||||||
prev-y (or prev-y (:y parent-rect))
|
prev-y (or prev-y (:y parent-rect))
|
||||||
|
|
||||||
last? (nil? next)
|
last? (nil? next)
|
||||||
|
|
||||||
box-x (-> child :selrect :x)
|
start-p (gpt/point (:selrect child))
|
||||||
box-y (-> child :selrect :y)
|
start-p (-> start-p
|
||||||
box-width (-> child :selrect :width)
|
(gmt/transform-point-center (gco/center-shape child) (:transform frame))
|
||||||
box-height(-> child :selrect :height)
|
(gmt/transform-point-center (gco/center-shape frame) (:transform-inverse frame)))
|
||||||
|
|
||||||
|
box-x (:x start-p)
|
||||||
|
box-y (:y start-p)
|
||||||
|
box-width (-> child :selrect :width)
|
||||||
|
box-height (-> child :selrect :height)
|
||||||
|
|
||||||
x (if row? (:x parent-rect) prev-x)
|
x (if row? (:x parent-rect) prev-x)
|
||||||
y (if col? (:y parent-rect) prev-y)
|
y (if col? (:y parent-rect) prev-y)
|
||||||
|
@ -623,14 +627,35 @@
|
||||||
:else
|
:else
|
||||||
(+ box-height (- box-y prev-y) (/ layout-gap 2)))
|
(+ box-height (- box-y prev-y) (/ layout-gap 2)))
|
||||||
|
|
||||||
line-area (gsr/make-rect x y width height)
|
[line-area-1 line-area-2]
|
||||||
result (conj result line-area)]
|
(if col?
|
||||||
|
(let [half-point-width (+ (- box-x x) (/ box-width 2))]
|
||||||
|
[(-> (gsr/make-rect x y half-point-width height)
|
||||||
|
(assoc :index (if reverse? (inc index) index)))
|
||||||
|
(-> (gsr/make-rect (+ x half-point-width) y (- width half-point-width) height)
|
||||||
|
(assoc :index (if reverse? index (inc index))))])
|
||||||
|
(let [half-point-height (+ (- box-y y) (/ box-height 2))]
|
||||||
|
[(-> (gsr/make-rect x y width half-point-height)
|
||||||
|
(assoc :index (if reverse? (inc index) index)))
|
||||||
|
(-> (gsr/make-rect x (+ y half-point-height) width (- height half-point-height))
|
||||||
|
(assoc :index (if reverse? index (inc index))))]))
|
||||||
|
|
||||||
|
result (conj result line-area-1 line-area-2)
|
||||||
|
|
||||||
|
;;line-area
|
||||||
|
;;(-> (gsr/make-rect x y width height)
|
||||||
|
;; (assoc :index (if reverse? (inc index) index)))
|
||||||
|
;;result (conj result line-area)
|
||||||
|
;;result (conj result (gsr/make-rect box-x box-y box-width box-height))
|
||||||
|
]
|
||||||
|
|
||||||
[result parent-rect (+ x width) (+ y height)]))
|
[result parent-rect (+ x width) (+ y height)]))
|
||||||
|
|
||||||
redfn-lines
|
redfn-lines
|
||||||
(fn [[result from-idx prev-x prev-y] [{:keys [start-p layout-gap num-children line-width line-height]} next]]
|
(fn [[result from-idx prev-x prev-y] [{:keys [start-p layout-gap num-children line-width line-height]} next]]
|
||||||
(let [prev-x (or prev-x (:x frame))
|
(let [start-p (gmt/transform-point-center start-p (gco/center-shape frame) (:transform-inverse frame))
|
||||||
|
|
||||||
|
prev-x (or prev-x (:x frame))
|
||||||
prev-y (or prev-y (:y frame))
|
prev-y (or prev-y (:y frame))
|
||||||
last? (nil? next)
|
last? (nil? next)
|
||||||
|
|
||||||
|
@ -695,13 +720,16 @@
|
||||||
|
|
||||||
result (first (reduce redfn-child [result line-area] (d/with-next children)))]
|
result (first (reduce redfn-child [result line-area] (d/with-next children)))]
|
||||||
|
|
||||||
[result (+ from-idx num-children) (+ x width) (+ y height)]))
|
[result (+ from-idx num-children) (+ x width) (+ y height)]))]
|
||||||
|
|
||||||
ret (first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data))))
|
(first (reduce redfn-lines [[] 0] (d/with-next (:layout-lines layout-data))))))
|
||||||
]
|
|
||||||
|
|
||||||
|
(defn get-drop-index
|
||||||
;;(.log js/console "RET" (clj->js ret))
|
[frame-id objects position]
|
||||||
ret
|
(let [frame (get objects frame-id)
|
||||||
|
position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame))
|
||||||
))
|
children (cph/get-immediate-children objects frame-id)
|
||||||
|
layout-data (calc-layout-data frame children)
|
||||||
|
drop-areas (drop-areas frame layout-data children)
|
||||||
|
area (d/seek #(gsr/contains-point? % position) drop-areas)]
|
||||||
|
(:index area)))
|
||||||
|
|
|
@ -166,9 +166,9 @@
|
||||||
|
|
||||||
[layout-line modif-tree]))]
|
[layout-line modif-tree]))]
|
||||||
|
|
||||||
(let [children (map (d/getf objects) (:shapes parent))
|
(let [modifiers (get-in modif-tree [(:id parent) :modifiers])
|
||||||
modifiers (get-in modif-tree [(:id parent) :modifiers])
|
|
||||||
transformed-parent (gtr/transform-shape parent modifiers)
|
transformed-parent (gtr/transform-shape parent modifiers)
|
||||||
|
children (map (d/getf objects) (:shapes transformed-parent))
|
||||||
|
|
||||||
modif-tree (reduce (partial normalize-child transformed-parent _snap-pixel?) modif-tree children)
|
modif-tree (reduce (partial normalize-child transformed-parent _snap-pixel?) modif-tree children)
|
||||||
|
|
||||||
|
@ -343,27 +343,26 @@
|
||||||
(assoc id {:modifiers modifiers}))))
|
(assoc id {:modifiers modifiers}))))
|
||||||
|
|
||||||
modif-tree (reduce set-modifiers {} ids)
|
modif-tree (reduce set-modifiers {} ids)
|
||||||
|
|
||||||
shapes-tree (resolve-tree-sequence ids objects)
|
shapes-tree (resolve-tree-sequence ids objects)
|
||||||
|
|
||||||
modif-tree
|
modif-tree
|
||||||
(->> shapes-tree
|
(->> shapes-tree
|
||||||
(reduce
|
(reduce
|
||||||
(fn [modif-tree shape]
|
(fn [modif-tree shape]
|
||||||
(let [has-modifiers? (some? (get-in modif-tree [(:id shape) :modifiers]))
|
(let [modifiers (get-in modif-tree [(:id shape) :modifiers])
|
||||||
|
has-modifiers? (some? modifiers)
|
||||||
is-layout? (layout? shape)
|
is-layout? (layout? shape)
|
||||||
is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape))))
|
is-parent? (or (group? shape) (and (frame? shape) (not (layout? shape))))
|
||||||
|
root? (= uuid/zero (:id shape))
|
||||||
;; If the current child is inside the layout we ignore the constraints
|
;; If the current child is inside the layout we ignore the constraints
|
||||||
is-inside-layout? (inside-layout? objects shape)]
|
is-inside-layout? (inside-layout? objects shape)]
|
||||||
|
|
||||||
(cond-> modif-tree
|
(cond-> modif-tree
|
||||||
(and has-modifiers? is-parent?)
|
(and has-modifiers? is-parent? (not root?))
|
||||||
(set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?)
|
(set-children-modifiers objects shape (or ignore-constraints is-inside-layout?) snap-pixel?)
|
||||||
|
|
||||||
is-layout?
|
is-layout?
|
||||||
(set-layout-modifiers objects shape snap-pixel?)
|
(set-layout-modifiers objects shape snap-pixel?))))
|
||||||
)))
|
|
||||||
|
|
||||||
modif-tree))]
|
modif-tree))]
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,21 @@
|
||||||
[app.common.math :as mth]))
|
[app.common.math :as mth]))
|
||||||
|
|
||||||
(defn make-rect
|
(defn make-rect
|
||||||
[x y width height]
|
([p1 p2]
|
||||||
(when (d/num? x y width height)
|
(let [x1 (min (:x p1) (:x p2))
|
||||||
(let [width (max width 0.01)
|
y1 (min (:y p1) (:y p2))
|
||||||
height (max height 0.01)]
|
x2 (max (:x p1) (:x p2))
|
||||||
{:x x
|
y2 (max (:y p1) (:y p2))]
|
||||||
:y y
|
(make-rect x1 y1 (- x2 x1) (- y2 y1))))
|
||||||
:width width
|
|
||||||
:height height})))
|
([x y width height]
|
||||||
|
(when (d/num? x y width height)
|
||||||
|
(let [width (max width 0.01)
|
||||||
|
height (max height 0.01)]
|
||||||
|
{:x x
|
||||||
|
:y y
|
||||||
|
:width width
|
||||||
|
:height height}))))
|
||||||
|
|
||||||
(defn make-selrect
|
(defn make-selrect
|
||||||
[x y width height]
|
[x y width height]
|
||||||
|
|
|
@ -14,8 +14,10 @@
|
||||||
[app.common.geom.shapes.path :as gpa]
|
[app.common.geom.shapes.path :as gpa]
|
||||||
[app.common.geom.shapes.rect :as gpr]
|
[app.common.geom.shapes.rect :as gpr]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
[app.common.types.modifiers :as ctm]))
|
[app.common.types.modifiers :as ctm]
|
||||||
|
[app.common.uuid :as uuid]))
|
||||||
|
|
||||||
(def ^:dynamic *skip-adjust* false)
|
(def ^:dynamic *skip-adjust* false)
|
||||||
|
|
||||||
|
@ -436,13 +438,46 @@
|
||||||
%)))
|
%)))
|
||||||
shape))
|
shape))
|
||||||
|
|
||||||
|
(defn- apply-structure-modifiers
|
||||||
|
[shape modifiers]
|
||||||
|
|
||||||
|
(let [remove-children
|
||||||
|
(fn [shapes children-to-remove]
|
||||||
|
(let [remove? (set children-to-remove)]
|
||||||
|
(d/removev remove? shapes)))
|
||||||
|
|
||||||
|
apply-modifier
|
||||||
|
(fn [shape {:keys [type value index]}]
|
||||||
|
(cond-> shape
|
||||||
|
(and (= type :add-children) (some? index))
|
||||||
|
(update :shapes
|
||||||
|
(fn [shapes]
|
||||||
|
(if (vector? shapes)
|
||||||
|
(cph/insert-at-index shapes index value)
|
||||||
|
(d/concat-vec shapes value))))
|
||||||
|
|
||||||
|
(and (= type :add-children) (nil? index))
|
||||||
|
(update :shapes d/concat-vec value)
|
||||||
|
|
||||||
|
(= type :remove-children)
|
||||||
|
(update :shapes remove-children value)))]
|
||||||
|
|
||||||
|
(reduce apply-modifier shape (:v3 modifiers))))
|
||||||
|
|
||||||
(defn apply-modifiers
|
(defn apply-modifiers
|
||||||
[shape modifiers]
|
[shape modifiers]
|
||||||
(let [center (gco/center-shape shape)
|
(let [center (gco/center-shape shape)
|
||||||
transform (ctm/modifiers->transform center modifiers)]
|
transform (ctm/modifiers->transform center modifiers)]
|
||||||
(-> shape
|
|
||||||
#_(set-flip-2 transform)
|
(cond-> shape
|
||||||
(apply-transform transform))))
|
#_(set-flip-2 transform)
|
||||||
|
(and (some? transform)
|
||||||
|
;; Never transform the root frame
|
||||||
|
(not= uuid/zero (:id shape)))
|
||||||
|
(apply-transform transform)
|
||||||
|
|
||||||
|
:always
|
||||||
|
(apply-structure-modifiers modifiers))))
|
||||||
|
|
||||||
(defn apply-objects-modifiers
|
(defn apply-objects-modifiers
|
||||||
[objects modifiers]
|
[objects modifiers]
|
||||||
|
|
|
@ -174,3 +174,8 @@
|
||||||
(defn max-abs
|
(defn max-abs
|
||||||
[a b]
|
[a b]
|
||||||
(max (abs a) (abs b)))
|
(max (abs a) (abs b)))
|
||||||
|
|
||||||
|
(defn sign
|
||||||
|
"Get the sign (+1 / -1) for the number"
|
||||||
|
[n]
|
||||||
|
(if (neg? n) -1 1))
|
||||||
|
|
|
@ -33,6 +33,12 @@
|
||||||
([{:keys [type]}]
|
([{:keys [type]}]
|
||||||
(= type :frame)))
|
(= type :frame)))
|
||||||
|
|
||||||
|
(defn layout-shape?
|
||||||
|
([objects id]
|
||||||
|
(layout-shape? (get objects id)))
|
||||||
|
([{:keys [type layout]}]
|
||||||
|
(and (= type :frame) layout)))
|
||||||
|
|
||||||
(defn group-shape?
|
(defn group-shape?
|
||||||
[{:keys [type]}]
|
[{:keys [type]}]
|
||||||
(= type :group))
|
(= type :group))
|
||||||
|
|
|
@ -162,9 +162,6 @@
|
||||||
:move
|
:move
|
||||||
(gmt/multiply (gmt/translate-matrix vector) matrix)
|
(gmt/multiply (gmt/translate-matrix vector) matrix)
|
||||||
|
|
||||||
;;:transform
|
|
||||||
;;(gmt/multiply transform matrix)
|
|
||||||
|
|
||||||
:resize
|
:resize
|
||||||
(gmt/multiply
|
(gmt/multiply
|
||||||
(-> (gmt/matrix)
|
(-> (gmt/matrix)
|
||||||
|
@ -178,7 +175,7 @@
|
||||||
matrix)
|
matrix)
|
||||||
|
|
||||||
:rotation
|
:rotation
|
||||||
;; TODO LAYOUT: Comprobar que pasa si no hay centro
|
;; TODO LAYOUT: Maybe an issue when no center data
|
||||||
(gmt/multiply
|
(gmt/multiply
|
||||||
(-> (gmt/matrix)
|
(-> (gmt/matrix)
|
||||||
(gmt/translate center)
|
(gmt/translate center)
|
||||||
|
|
|
@ -234,6 +234,7 @@
|
||||||
(if (nil? child-frame-id)
|
(if (nil? child-frame-id)
|
||||||
(or current-id uuid/zero)
|
(or current-id uuid/zero)
|
||||||
(recur child-frame-id))))))
|
(recur child-frame-id))))))
|
||||||
|
|
||||||
(defn top-nested-frame-ids
|
(defn top-nested-frame-ids
|
||||||
"Search the top nested frame in a list of ids"
|
"Search the top nested frame in a list of ids"
|
||||||
[objects ids]
|
[objects ids]
|
||||||
|
@ -246,8 +247,7 @@
|
||||||
(-> (:shapes current-shape) reverse))]
|
(-> (:shapes current-shape) reverse))]
|
||||||
(if (nil? child-frame-id)
|
(if (nil? child-frame-id)
|
||||||
(or current-id uuid/zero)
|
(or current-id uuid/zero)
|
||||||
(recur child-frame-id)))))
|
(recur child-frame-id))))))
|
||||||
)
|
|
||||||
|
|
||||||
(defn get-viewer-frames
|
(defn get-viewer-frames
|
||||||
([objects]
|
([objects]
|
||||||
|
|
|
@ -21,27 +21,37 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
(defn truncate-zero [num default]
|
(defn adjust-ratio
|
||||||
(if (mth/almost-zero? num) default num))
|
[point initial]
|
||||||
|
(let [v (gpt/to-vec point initial)
|
||||||
|
dx (mth/abs (:x v))
|
||||||
|
dy (mth/abs (:y v))
|
||||||
|
sx (mth/sign (:x v))
|
||||||
|
sy (mth/sign (:y v))]
|
||||||
|
|
||||||
|
(cond-> point
|
||||||
|
(> dx dy)
|
||||||
|
(assoc :y (- (:y point) (* sy (- dx dy))))
|
||||||
|
|
||||||
|
(> dy dx)
|
||||||
|
(assoc :x (- (:x point) (* sx (- dy dx)))))))
|
||||||
|
|
||||||
|
(defn resize-shape [{:keys [x y width height] :as shape} initial point lock?]
|
||||||
|
(let [draw-rect (gsh/make-rect initial (cond-> point lock? (adjust-ratio initial)))
|
||||||
|
shape-rect (gsh/make-rect x y width height)
|
||||||
|
|
||||||
|
scalev (gpt/point (/ (:width draw-rect) (:width shape-rect))
|
||||||
|
(/ (:height draw-rect) (:height shape-rect)))
|
||||||
|
|
||||||
|
movev (gpt/to-vec (gpt/point shape-rect) (gpt/point draw-rect))]
|
||||||
|
|
||||||
(defn resize-shape [{:keys [x y width height] :as shape} point lock?]
|
|
||||||
(let [;; The new shape behaves like a resize on the bottom-right corner
|
|
||||||
initial (gpt/point (+ x width) (+ y height))
|
|
||||||
shapev (gpt/point width height)
|
|
||||||
deltav (gpt/to-vec initial point)
|
|
||||||
scalev (-> (gpt/divide (gpt/add shapev deltav) shapev)
|
|
||||||
(update :x truncate-zero 0.01)
|
|
||||||
(update :y truncate-zero 0.01))
|
|
||||||
scalev (if lock?
|
|
||||||
(let [v (max (:x scalev) (:y scalev))]
|
|
||||||
(gpt/point v v))
|
|
||||||
scalev)]
|
|
||||||
(-> shape
|
(-> shape
|
||||||
(assoc :click-draw? false)
|
(assoc :click-draw? false)
|
||||||
(gsh/transform-shape (ctm/resize scalev (gpt/point x y))))))
|
(gsh/transform-shape (ctm/resize scalev (gpt/point x y)))
|
||||||
|
(gsh/transform-shape (ctm/move movev)))))
|
||||||
|
|
||||||
(defn update-drawing [state point lock?]
|
(defn update-drawing [state initial point lock?]
|
||||||
(update-in state [:workspace-drawing :object] resize-shape point lock?))
|
(update-in state [:workspace-drawing :object] resize-shape initial point lock?))
|
||||||
|
|
||||||
(defn move-drawing
|
(defn move-drawing
|
||||||
[{:keys [x y]}]
|
[{:keys [x y]}]
|
||||||
|
@ -57,8 +67,7 @@
|
||||||
layout (get state :workspace-layout)
|
layout (get state :workspace-layout)
|
||||||
snap-pixel? (contains? layout :snap-pixel-grid)
|
snap-pixel? (contains? layout :snap-pixel-grid)
|
||||||
|
|
||||||
initial (cond-> @ms/mouse-position
|
initial (cond-> @ms/mouse-position snap-pixel? gpt/round)
|
||||||
snap-pixel? gpt/round)
|
|
||||||
|
|
||||||
page-id (:current-page-id state)
|
page-id (:current-page-id state)
|
||||||
objects (wsh/lookup-page-objects state page-id)
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
|
@ -96,7 +105,7 @@
|
||||||
(rx/map #(conj current %)))))
|
(rx/map #(conj current %)))))
|
||||||
(rx/map
|
(rx/map
|
||||||
(fn [[_ shift? point]]
|
(fn [[_ shift? point]]
|
||||||
#(update-drawing % (cond-> point snap-pixel? gpt/round) shift?)))
|
#(update-drawing % initial (cond-> point snap-pixel? gpt/round) shift?)))
|
||||||
|
|
||||||
(rx/take-until stoper))
|
(rx/take-until stoper))
|
||||||
(rx/of (common/handle-finish-drawing)))))))
|
(rx/of (common/handle-finish-drawing)))))))
|
||||||
|
|
|
@ -51,8 +51,7 @@
|
||||||
|
|
||||||
(and click-draw? (not text?))
|
(and click-draw? (not text?))
|
||||||
(-> (assoc :width min-side :height min-side)
|
(-> (assoc :width min-side :height min-side)
|
||||||
(gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2))))
|
(gsh/transform-shape (ctm/move (- (/ min-side 2)) (- (/ min-side 2)))))
|
||||||
#_(ctm/add-move (- (/ min-side 2)) (- (/ min-side 2))))
|
|
||||||
|
|
||||||
(and click-draw? text?)
|
(and click-draw? text?)
|
||||||
(assoc :height 17 :width 4 :grow-type :auto-width)
|
(assoc :height 17 :width 4 :grow-type :auto-width)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
[app.main.data.workspace.edition :as dwe]
|
[app.main.data.workspace.edition :as dwe]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
[app.main.data.workspace.shape-layout :as dwsl]
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
|
@ -146,6 +147,10 @@
|
||||||
ids (cph/clean-loops objects ids)
|
ids (cph/clean-loops objects ids)
|
||||||
lookup (d/getf objects)
|
lookup (d/getf objects)
|
||||||
|
|
||||||
|
layout-ids (->> ids
|
||||||
|
(mapcat (partial cph/get-parent-ids objects))
|
||||||
|
(filter (partial cph/layout-shape? objects)))
|
||||||
|
|
||||||
components-v2 (features/active-feature? state :components-v2)
|
components-v2 (features/active-feature? state :components-v2)
|
||||||
|
|
||||||
groups-to-unmask
|
groups-to-unmask
|
||||||
|
@ -266,7 +271,8 @@
|
||||||
|
|
||||||
(rx/of (dc/detach-comment-thread ids)
|
(rx/of (dc/detach-comment-thread ids)
|
||||||
(dwsl/update-layout-positions all-parents)
|
(dwsl/update-layout-positions all-parents)
|
||||||
(dch/commit-changes changes)))))))
|
(dch/commit-changes changes)
|
||||||
|
(dwsl/update-layout-positions layout-ids)))))))
|
||||||
|
|
||||||
(defn- viewport-center
|
(defn- viewport-center
|
||||||
[state]
|
[state]
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.geom.shapes.layout :as gsl]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.common.pages.changes-builder :as pcb]
|
[app.common.pages.changes-builder :as pcb]
|
||||||
[app.common.pages.common :as cpc]
|
[app.common.pages.common :as cpc]
|
||||||
|
@ -137,8 +138,20 @@
|
||||||
snap-pixel? (and (not ignore-snap-pixel)
|
snap-pixel? (and (not ignore-snap-pixel)
|
||||||
(contains? (:workspace-layout state) :snap-pixel-grid))
|
(contains? (:workspace-layout state) :snap-pixel-grid))
|
||||||
|
|
||||||
|
workspace-modifiers (:workspace-modifiers state)
|
||||||
|
|
||||||
modif-tree
|
modif-tree
|
||||||
(gsh/set-objects-modifiers ids objects (constantly modifiers) ignore-constraints snap-pixel?)]
|
(gsh/set-objects-modifiers
|
||||||
|
;; TODO LAYOUT: I don't like this
|
||||||
|
(concat (keys workspace-modifiers) ids)
|
||||||
|
objects
|
||||||
|
(fn [shape]
|
||||||
|
(let [modifiers (if (contains? ids (:id shape)) modifiers {})
|
||||||
|
old-modifiers-v3 (get-in state [:workspace-modifiers (:id shape) :modifiers :v3])]
|
||||||
|
(cond-> modifiers
|
||||||
|
(some? old-modifiers-v3)
|
||||||
|
(assoc :v3 old-modifiers-v3))))
|
||||||
|
ignore-constraints snap-pixel?)]
|
||||||
|
|
||||||
(update state :workspace-modifiers merge modif-tree))))))
|
(update state :workspace-modifiers merge modif-tree))))))
|
||||||
|
|
||||||
|
@ -619,6 +632,40 @@
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/map #(start-move from-position))))))
|
(rx/map #(start-move from-position))))))
|
||||||
|
|
||||||
|
(defn set-change-frame-modifiers
|
||||||
|
[selected target-frame position]
|
||||||
|
|
||||||
|
(ptk/reify ::set-change-frame-modifiers
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
|
|
||||||
|
origin-frame-ids (->> selected (group-by #(get-in objects [% :frame-id])))
|
||||||
|
|
||||||
|
layout? (get-in objects [target-frame :layout])
|
||||||
|
|
||||||
|
drop-index
|
||||||
|
(when layout? (gsl/get-drop-index target-frame objects position))
|
||||||
|
|
||||||
|
modif-tree
|
||||||
|
(into {}
|
||||||
|
(mapcat
|
||||||
|
(fn [original-frame]
|
||||||
|
(let [shapes (->> (get origin-frame-ids original-frame)
|
||||||
|
(d/removev #(= target-frame %)))]
|
||||||
|
(cond
|
||||||
|
(not= original-frame target-frame)
|
||||||
|
[[original-frame {:modifiers {:v3 [{:type :remove-children :value shapes}]}}]
|
||||||
|
[target-frame {:modifiers {:v3 [{:type :add-children
|
||||||
|
:value shapes
|
||||||
|
:index drop-index}]}}]]
|
||||||
|
layout?
|
||||||
|
[[target-frame {:modifiers {:v3 [{:type :add-children
|
||||||
|
:value shapes
|
||||||
|
:index drop-index}]}}]]))))
|
||||||
|
(keys origin-frame-ids))]
|
||||||
|
(assoc state :workspace-modifiers modif-tree)))))
|
||||||
|
|
||||||
(defn- start-move
|
(defn- start-move
|
||||||
([from-position] (start-move from-position nil))
|
([from-position] (start-move from-position nil))
|
||||||
([from-position ids]
|
([from-position ids]
|
||||||
|
@ -664,17 +711,25 @@
|
||||||
(if (empty? shapes)
|
(if (empty? shapes)
|
||||||
(rx/of (finish-transform))
|
(rx/of (finish-transform))
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(->> position
|
(rx/merge
|
||||||
;; We ask for the snap position but we continue even if the result is not available
|
(->> position
|
||||||
(rx/with-latest vector snap-delta)
|
(rx/map (fn [delta]
|
||||||
;; We try to use the previous snap so we don't have to wait for the result of the new
|
(let [position (gpt/add from-position delta)
|
||||||
(rx/map snap/correct-snap-point)
|
target-frame (ctst/top-nested-frame objects position)]
|
||||||
|
(set-change-frame-modifiers selected target-frame position))))
|
||||||
|
(rx/take-until stopper))
|
||||||
|
|
||||||
#_(rx/map #(hash-map :displacement (gmt/translate-matrix %)))
|
(->> position
|
||||||
(rx/map #(array-map :v2 [{:type :move :vector %}]))
|
;; We ask for the snap position but we continue even if the result is not available
|
||||||
|
(rx/with-latest vector snap-delta)
|
||||||
|
|
||||||
(rx/map (partial set-modifiers ids))
|
;; We try to use the previous snap so we don't have to wait for the result of the new
|
||||||
(rx/take-until stopper))
|
(rx/map snap/correct-snap-point)
|
||||||
|
|
||||||
|
(rx/map (fn [move-vec] {:v2 [{:type :move :vector move-vec}]}))
|
||||||
|
|
||||||
|
(rx/map (partial set-modifiers ids))
|
||||||
|
(rx/take-until stopper)))
|
||||||
|
|
||||||
(rx/of (dwu/start-undo-transaction)
|
(rx/of (dwu/start-undo-transaction)
|
||||||
(calculate-frame-for-move ids)
|
(calculate-frame-for-move ids)
|
||||||
|
@ -767,18 +822,22 @@
|
||||||
page-id (:current-page-id state)
|
page-id (:current-page-id state)
|
||||||
objects (wsh/lookup-page-objects state page-id)
|
objects (wsh/lookup-page-objects state page-id)
|
||||||
frame-id (ctst/top-nested-frame objects position)
|
frame-id (ctst/top-nested-frame objects position)
|
||||||
|
layout? (get-in objects [frame-id :layout])
|
||||||
lookup (d/getf objects)
|
lookup (d/getf objects)
|
||||||
|
|
||||||
|
shapes (->> ids (cph/clean-loops objects) (keep lookup))
|
||||||
|
|
||||||
moving-shapes
|
moving-shapes
|
||||||
(->> ids
|
(cond->> shapes
|
||||||
(cph/clean-loops objects)
|
(not layout?)
|
||||||
(keep lookup)
|
(remove #(= (:frame-id %) frame-id)))
|
||||||
(remove #(= (:frame-id %) frame-id)))
|
|
||||||
|
drop-index (when layout? (gsl/get-drop-index frame-id objects position))
|
||||||
|
|
||||||
changes
|
changes
|
||||||
(-> (pcb/empty-changes it page-id)
|
(-> (pcb/empty-changes it page-id)
|
||||||
(pcb/with-objects objects)
|
(pcb/with-objects objects)
|
||||||
(pcb/change-parent frame-id moving-shapes))]
|
(pcb/change-parent frame-id moving-shapes drop-index))]
|
||||||
|
|
||||||
(when-not (empty? changes)
|
(when-not (empty? changes)
|
||||||
(rx/of (dch/commit-changes changes)
|
(rx/of (dch/commit-changes changes)
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
others are defined using a generic wrapper implemented in
|
others are defined using a generic wrapper implemented in
|
||||||
common."
|
common."
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.shapes.circle :as circle]
|
[app.main.ui.shapes.circle :as circle]
|
||||||
[app.main.ui.shapes.image :as image]
|
[app.main.ui.shapes.image :as image]
|
||||||
|
@ -55,33 +57,36 @@
|
||||||
(mf/deps objects)
|
(mf/deps objects)
|
||||||
#(cph/objects-by-frame objects))]
|
#(cph/objects-by-frame objects))]
|
||||||
|
|
||||||
[:& (mf/provider ctx/active-frames) {:value active-frames}
|
[:g {:id (dm/str "shape-" uuid/zero)}
|
||||||
;; Render font faces only for shapes that are part of the root
|
[:& (mf/provider ctx/active-frames) {:value active-frames}
|
||||||
;; frame but don't belongs to any other frame.
|
;; Render font faces only for shapes that are part of the root
|
||||||
(let [xform (comp
|
;; frame but don't belongs to any other frame.
|
||||||
(remove cph/frame-shape?)
|
(let [xform (comp
|
||||||
(mapcat #(cph/get-children-with-self objects (:id %))))]
|
(remove cph/frame-shape?)
|
||||||
[:& ff/fontfaces-style {:shapes (into [] xform shapes)}])
|
(mapcat #(cph/get-children-with-self objects (:id %))))]
|
||||||
|
[:& ff/fontfaces-style {:shapes (into [] xform shapes)}])
|
||||||
|
|
||||||
(for [shape shapes]
|
[:g.frame-children
|
||||||
(cond
|
(for [shape shapes]
|
||||||
(not (cph/frame-shape? shape))
|
[:g.ws-shape-wrapper
|
||||||
[:& shape-wrapper
|
(cond
|
||||||
{:shape shape
|
(not (cph/frame-shape? shape))
|
||||||
:key (:id shape)}]
|
[:& shape-wrapper
|
||||||
|
{:shape shape
|
||||||
|
:key (:id shape)}]
|
||||||
|
|
||||||
(cph/root-frame? shape)
|
(cph/root-frame? shape)
|
||||||
[:& root-frame-wrapper
|
[:& root-frame-wrapper
|
||||||
{:shape shape
|
{:shape shape
|
||||||
:key (:id shape)
|
:key (:id shape)
|
||||||
:objects (get frame-objects (:id shape))
|
:objects (get frame-objects (:id shape))
|
||||||
:thumbnail? (not (contains? active-frames (:id shape)))}]
|
:thumbnail? (not (contains? active-frames (:id shape)))}]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[:& nested-frame-wrapper
|
[:& nested-frame-wrapper
|
||||||
{:shape shape
|
{:shape shape
|
||||||
:key (:id shape)
|
:key (:id shape)
|
||||||
:objects (get frame-objects (:id shape))}]))]))
|
:objects (get frame-objects (:id shape))}])])]]]))
|
||||||
|
|
||||||
(mf/defc shape-wrapper
|
(mf/defc shape-wrapper
|
||||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))]
|
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))]
|
||||||
|
@ -98,20 +103,21 @@
|
||||||
|
|
||||||
opts #js {:shape shape :thumbnail? thumbnail?}]
|
opts #js {:shape shape :thumbnail? thumbnail?}]
|
||||||
(when (and (some? shape) (not (:hidden shape)))
|
(when (and (some? shape) (not (:hidden shape)))
|
||||||
(case (:type shape)
|
[:g.ws-shape-wrapper
|
||||||
:path [:> path/path-wrapper opts]
|
(case (:type shape)
|
||||||
:text [:> text/text-wrapper opts]
|
:path [:> path/path-wrapper opts]
|
||||||
:group [:> group-wrapper opts]
|
:text [:> text/text-wrapper opts]
|
||||||
:rect [:> rect-wrapper opts]
|
:group [:> group-wrapper opts]
|
||||||
:image [:> image-wrapper opts]
|
:rect [:> rect-wrapper opts]
|
||||||
:circle [:> circle-wrapper opts]
|
:image [:> image-wrapper opts]
|
||||||
:svg-raw [:> svg-raw-wrapper opts]
|
:circle [:> circle-wrapper opts]
|
||||||
:bool [:> bool-wrapper opts]
|
:svg-raw [:> svg-raw-wrapper opts]
|
||||||
|
:bool [:> bool-wrapper opts]
|
||||||
|
|
||||||
;; Only used when drawing a new frame.
|
;; Only used when drawing a new frame.
|
||||||
:frame [:> nested-frame-wrapper opts]
|
:frame [:> nested-frame-wrapper opts]
|
||||||
|
|
||||||
nil))))
|
nil)])))
|
||||||
|
|
||||||
(def group-wrapper (group/group-wrapper-factory shape-wrapper))
|
(def group-wrapper (group/group-wrapper-factory shape-wrapper))
|
||||||
(def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper))
|
(def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper))
|
||||||
|
|
|
@ -24,87 +24,7 @@
|
||||||
[app.main.ui.workspace.shapes.frame.node-store :as fns]
|
[app.main.ui.workspace.shapes.frame.node-store :as fns]
|
||||||
[app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr]
|
[app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[rumext.v2 :as mf]
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
[app.common.geom.shapes :as gsh]
|
|
||||||
[app.common.geom.shapes.layout :as gsl]
|
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
|
||||||
[app.main.store :as st]))
|
|
||||||
|
|
||||||
(mf/defc debug-layout
|
|
||||||
{::mf/wrap-props false}
|
|
||||||
[props]
|
|
||||||
|
|
||||||
(let [shape (unchecked-get props "shape")
|
|
||||||
children (-> (wsh/lookup-page-objects @st/state)
|
|
||||||
(cph/get-immediate-children (:id shape)))
|
|
||||||
|
|
||||||
layout-data (gsl/calc-layout-data shape children)
|
|
||||||
|
|
||||||
drop-areas
|
|
||||||
(gsl/drop-areas shape layout-data children)
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
[:g.debug-layout {:pointer-events "none"}
|
|
||||||
(for [[idx drop-area] (d/enumerate drop-areas)]
|
|
||||||
[:rect {:x (:x drop-area)
|
|
||||||
:y (:y drop-area)
|
|
||||||
:width (:width drop-area)
|
|
||||||
:height (:height drop-area)
|
|
||||||
:style {:fill "blue"
|
|
||||||
:fill-opacity 0.3
|
|
||||||
:stroke "red"
|
|
||||||
:stroke-width 1
|
|
||||||
:stroke-dasharray "3 6"}}])
|
|
||||||
|
|
||||||
|
|
||||||
#_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))]
|
|
||||||
(let [col? (gsl/col? shape)
|
|
||||||
row? (gsl/row? shape)
|
|
||||||
h-center? (and row? (gsl/h-center? shape))
|
|
||||||
h-end? (and row? (gsl/h-end? shape))
|
|
||||||
v-center? (and col? (gsl/v-center? shape))
|
|
||||||
v-end? (and row? (gsl/v-end? shape))
|
|
||||||
|
|
||||||
line-width
|
|
||||||
(+ (-> layout-line :line-width)
|
|
||||||
(:margin-x shape)
|
|
||||||
(if col?
|
|
||||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
|
||||||
0))
|
|
||||||
|
|
||||||
line-height
|
|
||||||
(+ (-> layout-line :line-height)
|
|
||||||
(:margin-y shape)
|
|
||||||
(if row?
|
|
||||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
|
||||||
0))
|
|
||||||
]
|
|
||||||
[:g {:key (dm/str "line-" idx)}
|
|
||||||
[:rect {:x (- (-> layout-line :start-p :x)
|
|
||||||
(cond
|
|
||||||
h-center? (/ line-width 2)
|
|
||||||
h-end? line-width
|
|
||||||
:else 0))
|
|
||||||
:y (- (-> layout-line :start-p :y)
|
|
||||||
(cond
|
|
||||||
v-center? (/ line-height 2)
|
|
||||||
v-end? line-height
|
|
||||||
:else 0))
|
|
||||||
:width line-width
|
|
||||||
:height line-height
|
|
||||||
:style {:fill "blue"
|
|
||||||
:fill-opacity 0.3}
|
|
||||||
}]
|
|
||||||
#_[:line {:x1 (-> layout-line :start-p :x)
|
|
||||||
:y1 (-> layout-line :start-p :y)
|
|
||||||
:x2 (+ (-> layout-line :start-p :x) (if col? line-width 0))
|
|
||||||
:y2 (+ (-> layout-line :start-p :y) (if row? line-height 0))
|
|
||||||
:transform (gsh/transform-str shape)
|
|
||||||
:style {:fill "none"
|
|
||||||
:stroke "red"
|
|
||||||
:stroke-width 2}}]]))]))
|
|
||||||
|
|
||||||
(defn frame-shape-factory
|
(defn frame-shape-factory
|
||||||
[shape-wrapper]
|
[shape-wrapper]
|
||||||
|
@ -119,12 +39,9 @@
|
||||||
childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape)))
|
childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape)))
|
||||||
childs (mf/deref childs-ref)]
|
childs (mf/deref childs-ref)]
|
||||||
|
|
||||||
[:*
|
[:& (mf/provider embed/context) {:value true}
|
||||||
[:& (mf/provider embed/context) {:value true}
|
[:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)}
|
||||||
[:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)}
|
[:& frame-shape {:shape shape :childs childs} ]]]))))
|
||||||
[:& frame-shape {:shape shape :childs childs} ]]]
|
|
||||||
|
|
||||||
#_[:& debug-layout {:shape shape}]]))))
|
|
||||||
|
|
||||||
(defn check-props
|
(defn check-props
|
||||||
[new-props old-props]
|
[new-props old-props]
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.workspace.viewport.utils :as vwu]
|
[app.main.ui.workspace.viewport.utils :as vwu]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
[app.util.globals :as globals]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(defn- transform-no-resize
|
(defn- transform-no-resize
|
||||||
|
@ -78,13 +80,20 @@
|
||||||
|
|
||||||
[result width height]))
|
[result width height]))
|
||||||
|
|
||||||
|
(defn get-shape-node
|
||||||
|
([id]
|
||||||
|
(get-shape-node js/document id))
|
||||||
|
|
||||||
|
([base-node id]
|
||||||
|
(if (= (.-id base-node) (dm/str "shape-" id))
|
||||||
|
base-node
|
||||||
|
(dom/query base-node (dm/str "#shape-" id)))))
|
||||||
|
|
||||||
(defn get-nodes
|
(defn get-nodes
|
||||||
"Retrieve the DOM nodes to apply the matrix transformation"
|
"Retrieve the DOM nodes to apply the matrix transformation"
|
||||||
[base-node {:keys [id type masked-group?] :as shape}]
|
[base-node {:keys [id type masked-group?] :as shape}]
|
||||||
(when (some? base-node)
|
(when (some? base-node)
|
||||||
(let [shape-node (if (= (.-id base-node) (dm/str "shape-" id))
|
(let [shape-node (get-shape-node base-node id)
|
||||||
base-node
|
|
||||||
(dom/query base-node (dm/str "#shape-" id)))
|
|
||||||
|
|
||||||
frame? (= :frame type)
|
frame? (= :frame type)
|
||||||
group? (= :group type)
|
group? (= :group type)
|
||||||
|
@ -269,6 +278,33 @@
|
||||||
(ctm/modifiers->transform center modifiers)))
|
(ctm/modifiers->transform center modifiers)))
|
||||||
modifiers))))
|
modifiers))))
|
||||||
|
|
||||||
|
structure-changes
|
||||||
|
(mf/use-memo
|
||||||
|
(mf/deps modifiers)
|
||||||
|
(fn []
|
||||||
|
(into {}
|
||||||
|
(comp (filter (fn [[_ val]] (-> val :modifiers :v3 some?)))
|
||||||
|
(map (fn [[key val]]
|
||||||
|
[key (-> val :modifiers :v3)])))
|
||||||
|
|
||||||
|
modifiers)))
|
||||||
|
|
||||||
|
structure-changes (hooks/use-equal-memo structure-changes)
|
||||||
|
|
||||||
|
add-children
|
||||||
|
(mf/use-memo
|
||||||
|
(mf/deps structure-changes)
|
||||||
|
(fn []
|
||||||
|
(into []
|
||||||
|
(mapcat (fn [[frame-id changes]]
|
||||||
|
(->> changes
|
||||||
|
(filter (fn [{:keys [type]}] (= type :add-children)))
|
||||||
|
(mapcat (fn [{:keys [value]}]
|
||||||
|
(->> value (map (fn [id] {:frame frame-id :shape id}))))))))
|
||||||
|
structure-changes)))
|
||||||
|
|
||||||
|
add-children-prev (hooks/use-previous add-children)
|
||||||
|
|
||||||
shapes
|
shapes
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
(mf/deps transforms)
|
(mf/deps transforms)
|
||||||
|
@ -280,6 +316,31 @@
|
||||||
prev-modifiers (mf/use-var nil)
|
prev-modifiers (mf/use-var nil)
|
||||||
prev-transforms (mf/use-var nil)]
|
prev-transforms (mf/use-var nil)]
|
||||||
|
|
||||||
|
(mf/use-effect
|
||||||
|
(mf/deps add-children)
|
||||||
|
(fn []
|
||||||
|
(doseq [{:keys [frame shape]} add-children-prev]
|
||||||
|
(let [frame-node (get-shape-node node frame)
|
||||||
|
shape-node (get-shape-node shape)
|
||||||
|
mirror-node (dom/query frame-node (dm/fmt ".mirror-shape[href='#shape-%'" shape))]
|
||||||
|
(when mirror-node (.remove mirror-node))
|
||||||
|
(dom/remove-attribute! (dom/get-parent shape-node) "display")))
|
||||||
|
|
||||||
|
(doseq [{:keys [frame shape]} add-children]
|
||||||
|
(let [frame-node (get-shape-node node frame)
|
||||||
|
shape-node (get-shape-node shape)
|
||||||
|
|
||||||
|
use-node
|
||||||
|
(.createElementNS globals/document "http://www.w3.org/2000/svg" "use")
|
||||||
|
|
||||||
|
contents-node
|
||||||
|
(or (dom/query frame-node ".frame-children") frame-node)]
|
||||||
|
|
||||||
|
(dom/set-attribute! use-node "href" (dm/fmt "#shape-%" shape))
|
||||||
|
(dom/add-class! use-node "mirror-shape")
|
||||||
|
(dom/append-child! contents-node use-node)
|
||||||
|
(dom/set-attribute! (dom/get-parent shape-node) "display" "none")))))
|
||||||
|
|
||||||
(mf/use-layout-effect
|
(mf/use-layout-effect
|
||||||
(mf/deps transforms)
|
(mf/deps transforms)
|
||||||
(fn []
|
(fn []
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
[app.main.ui.workspace.shapes.text.viewport-texts-html :as stvh]
|
[app.main.ui.workspace.shapes.text.viewport-texts-html :as stvh]
|
||||||
[app.main.ui.workspace.viewport.actions :as actions]
|
[app.main.ui.workspace.viewport.actions :as actions]
|
||||||
[app.main.ui.workspace.viewport.comments :as comments]
|
[app.main.ui.workspace.viewport.comments :as comments]
|
||||||
|
[app.main.ui.workspace.viewport.debug :as wvd]
|
||||||
[app.main.ui.workspace.viewport.drawarea :as drawarea]
|
[app.main.ui.workspace.viewport.drawarea :as drawarea]
|
||||||
[app.main.ui.workspace.viewport.frame-grid :as frame-grid]
|
[app.main.ui.workspace.viewport.frame-grid :as frame-grid]
|
||||||
[app.main.ui.workspace.viewport.gradients :as gradients]
|
[app.main.ui.workspace.viewport.gradients :as gradients]
|
||||||
|
@ -41,85 +42,7 @@
|
||||||
[app.main.ui.workspace.viewport.widgets :as widgets]
|
[app.main.ui.workspace.viewport.widgets :as widgets]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[debug :refer [debug?]]
|
[debug :refer [debug?]]
|
||||||
[rumext.v2 :as mf]
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.common.geom.shapes :as gsh]
|
|
||||||
[app.common.geom.shapes.layout :as gsl]
|
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
|
||||||
[app.main.store :as st]
|
|
||||||
|
|
||||||
))
|
|
||||||
|
|
||||||
(mf/defc debug-layout
|
|
||||||
{::mf/wrap-props false}
|
|
||||||
[props]
|
|
||||||
|
|
||||||
(let [shape (unchecked-get props "shape")
|
|
||||||
objects (unchecked-get props "objects")
|
|
||||||
children (cph/get-immediate-children objects (:id shape))
|
|
||||||
layout-data (gsl/calc-layout-data shape children)
|
|
||||||
drop-areas (gsl/drop-areas shape layout-data children)]
|
|
||||||
|
|
||||||
[:g.debug-layout {:pointer-events "none"}
|
|
||||||
(for [[idx drop-area] (d/enumerate drop-areas)]
|
|
||||||
[:rect {:x (:x drop-area)
|
|
||||||
:y (:y drop-area)
|
|
||||||
:width (:width drop-area)
|
|
||||||
:height (:height drop-area)
|
|
||||||
:style {:fill "blue"
|
|
||||||
:fill-opacity 0.3
|
|
||||||
:stroke "red"
|
|
||||||
:stroke-width 1
|
|
||||||
:stroke-dasharray "3 6"}}])
|
|
||||||
|
|
||||||
|
|
||||||
#_(for [[idx layout-line] (d/enumerate (:layout-lines layout-data))]
|
|
||||||
(let [col? (gsl/col? shape)
|
|
||||||
row? (gsl/row? shape)
|
|
||||||
h-center? (and row? (gsl/h-center? shape))
|
|
||||||
h-end? (and row? (gsl/h-end? shape))
|
|
||||||
v-center? (and col? (gsl/v-center? shape))
|
|
||||||
v-end? (and row? (gsl/v-end? shape))
|
|
||||||
|
|
||||||
line-width
|
|
||||||
(+ (-> layout-line :line-width)
|
|
||||||
(:margin-x shape)
|
|
||||||
(if col?
|
|
||||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
|
||||||
0))
|
|
||||||
|
|
||||||
line-height
|
|
||||||
(+ (-> layout-line :line-height)
|
|
||||||
(:margin-y shape)
|
|
||||||
(if row?
|
|
||||||
(* (:layout-gap layout-line) (dec (-> layout-line :num-children)))
|
|
||||||
0))
|
|
||||||
]
|
|
||||||
[:g {:key (dm/str "line-" idx)}
|
|
||||||
[:rect {:x (- (-> layout-line :start-p :x)
|
|
||||||
(cond
|
|
||||||
h-center? (/ line-width 2)
|
|
||||||
h-end? line-width
|
|
||||||
:else 0))
|
|
||||||
:y (- (-> layout-line :start-p :y)
|
|
||||||
(cond
|
|
||||||
v-center? (/ line-height 2)
|
|
||||||
v-end? line-height
|
|
||||||
:else 0))
|
|
||||||
:width line-width
|
|
||||||
:height line-height
|
|
||||||
:style {:fill "blue"
|
|
||||||
:fill-opacity 0.3}
|
|
||||||
}]
|
|
||||||
#_[:line {:x1 (-> layout-line :start-p :x)
|
|
||||||
:y1 (-> layout-line :start-p :y)
|
|
||||||
:x2 (+ (-> layout-line :start-p :x) (if col? line-width 0))
|
|
||||||
:y2 (+ (-> layout-line :start-p :y) (if row? line-height 0))
|
|
||||||
:transform (gsh/transform-str shape)
|
|
||||||
:style {:fill "none"
|
|
||||||
:stroke "red"
|
|
||||||
:stroke-width 2}}]]))]))
|
|
||||||
|
|
||||||
;; --- Viewport
|
;; --- Viewport
|
||||||
|
|
||||||
|
@ -493,15 +416,12 @@
|
||||||
:hover-frame frame-parent
|
:hover-frame frame-parent
|
||||||
:disabled-guides? disabled-guides?}])
|
:disabled-guides? disabled-guides?}])
|
||||||
|
|
||||||
(let [selected-frame (when (= 1 (count selected-shapes))
|
;; DEBUG LAYOUT DROP-ZONES
|
||||||
(let [selected-shape (get objects-modified (first selected))]
|
(when (debug? :layout-drop-zones)
|
||||||
(when (= :frame (:type selected-shape))
|
[:& wvd/debug-layout {:selected-shapes selected-shapes
|
||||||
selected-shape)))
|
:objects objects-modified
|
||||||
|
:hover-top-frame-id @hover-top-frame-id}])
|
||||||
|
|
||||||
top-frame (or selected-frame (get objects-modified @hover-top-frame-id))]
|
|
||||||
(when (and top-frame (not= uuid/zero top-frame) (:layout top-frame))
|
|
||||||
[:& debug-layout {:shape top-frame
|
|
||||||
:objects objects-modified}]))
|
|
||||||
|
|
||||||
(when show-selection-handlers?
|
(when show-selection-handlers?
|
||||||
[:g.selection-handlers {:clipPath "url(#clip-handlers)"}
|
[:g.selection-handlers {:clipPath "url(#clip-handlers)"}
|
||||||
|
|
54
frontend/src/app/main/ui/workspace/viewport/debug.cljs
Normal file
54
frontend/src/app/main/ui/workspace/viewport/debug.cljs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
;; 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.debug
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.geom.shapes.layout :as gsl]
|
||||||
|
[app.common.pages.helpers :as cph]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(mf/defc debug-layout
|
||||||
|
"Debug component to show the auto-layout drop areas"
|
||||||
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
|
||||||
|
(let [objects (unchecked-get props "objects")
|
||||||
|
selected-shapes (unchecked-get props "selected-shapes")
|
||||||
|
hover-top-frame-id (unchecked-get props "hover-top-frame-id")
|
||||||
|
|
||||||
|
selected-frame
|
||||||
|
(when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type)))
|
||||||
|
(first selected-shapes))
|
||||||
|
|
||||||
|
shape (or selected-frame (get objects hover-top-frame-id))]
|
||||||
|
|
||||||
|
(when (and shape (:layout shape))
|
||||||
|
(let [children (cph/get-immediate-children objects (:id shape))
|
||||||
|
layout-data (gsl/calc-layout-data shape children)
|
||||||
|
drop-areas (gsl/drop-areas shape layout-data children)]
|
||||||
|
[:g.debug-layout {:pointer-events "none"
|
||||||
|
:transform (gsh/transform-str shape)}
|
||||||
|
(for [[idx drop-area] (d/enumerate drop-areas)]
|
||||||
|
[:g.drop-area {:key (dm/str "drop-area-" idx)}
|
||||||
|
[:rect {:x (:x drop-area)
|
||||||
|
:y (:y drop-area)
|
||||||
|
:width (:width drop-area)
|
||||||
|
:height (:height drop-area)
|
||||||
|
:style {:fill "blue"
|
||||||
|
:fill-opacity 0.3
|
||||||
|
:stroke "red"
|
||||||
|
:stroke-width 1
|
||||||
|
:stroke-dasharray "3 6"}}]
|
||||||
|
[:text {:x (:x drop-area)
|
||||||
|
:y (:y drop-area)
|
||||||
|
:width (:width drop-area)
|
||||||
|
:height (:height drop-area)
|
||||||
|
:alignment-baseline "hanging"
|
||||||
|
:fill "black"}
|
||||||
|
(:index drop-area)]])]))))
|
|
@ -11,6 +11,7 @@
|
||||||
[app.common.pages :as cp]
|
[app.common.pages :as cp]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.types.shape-tree :as ctt]
|
[app.common.types.shape-tree :as ctt]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.shortcuts :as dsc]
|
[app.main.data.shortcuts :as dsc]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.path.shortcuts :as psc]
|
[app.main.data.workspace.path.shortcuts :as psc]
|
||||||
|
@ -28,8 +29,7 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[debug :refer [debug?]]
|
[debug :refer [debug?]]
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
[rumext.v2 :as mf]
|
[rumext.v2 :as mf])
|
||||||
[app.common.types.shape-tree :as ctst])
|
|
||||||
(:import goog.events.EventType))
|
(:import goog.events.EventType))
|
||||||
|
|
||||||
(defn setup-dom-events [viewport-ref zoom disable-paste in-viewport?]
|
(defn setup-dom-events [viewport-ref zoom disable-paste in-viewport?]
|
||||||
|
@ -217,7 +217,7 @@
|
||||||
(get objects))]
|
(get objects))]
|
||||||
(reset! hover hover-shape)
|
(reset! hover hover-shape)
|
||||||
(reset! hover-ids ids)
|
(reset! hover-ids ids)
|
||||||
(reset! hover-top-frame-id (ctst/top-nested-frame objects (deref last-point-ref))))))))
|
(reset! hover-top-frame-id (ctt/top-nested-frame objects (deref last-point-ref))))))))
|
||||||
|
|
||||||
(defn setup-viewport-modifiers
|
(defn setup-viewport-modifiers
|
||||||
[modifiers objects]
|
[modifiers objects]
|
||||||
|
@ -225,7 +225,7 @@
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
(mf/deps objects)
|
(mf/deps objects)
|
||||||
#(ctt/get-root-shapes-ids objects))
|
#(ctt/get-root-shapes-ids objects))
|
||||||
modifiers (select-keys modifiers root-frame-ids)]
|
modifiers (select-keys modifiers (conj root-frame-ids uuid/zero))]
|
||||||
(sfd/use-dynamic-modifiers objects globals/document modifiers)))
|
(sfd/use-dynamic-modifiers objects globals/document modifiers)))
|
||||||
|
|
||||||
(defn inside-vbox [vbox objects frame-id]
|
(defn inside-vbox [vbox objects frame-id]
|
||||||
|
|
|
@ -67,6 +67,9 @@
|
||||||
|
|
||||||
;; Disable frame thumbnails
|
;; Disable frame thumbnails
|
||||||
:disable-frame-thumbnails
|
:disable-frame-thumbnails
|
||||||
|
|
||||||
|
;; Enable a widget to show the auto-layout drop-zones
|
||||||
|
:layout-drop-zones
|
||||||
})
|
})
|
||||||
|
|
||||||
;; These events are excluded when we activate the :events flag
|
;; These events are excluded when we activate the :events flag
|
||||||
|
@ -294,9 +297,16 @@
|
||||||
num-nodes (->> (dom/seq-nodes root-node) count)]
|
num-nodes (->> (dom/seq-nodes root-node) count)]
|
||||||
#js {:number num-nodes}))
|
#js {:number num-nodes}))
|
||||||
|
|
||||||
#_(defn modif->js
|
(defn modif->js
|
||||||
[modif-tree objects]
|
[modif-tree objects]
|
||||||
(clj->js (into {}
|
(clj->js (into {}
|
||||||
(map (fn [[k v]]
|
(map (fn [[k v]]
|
||||||
[(get-in objects [k :name]) v]))
|
[(get-in objects [k :name]) v]))
|
||||||
modif-tree)))
|
modif-tree)))
|
||||||
|
|
||||||
|
(defn ^:export dump-modifiers
|
||||||
|
[]
|
||||||
|
(let [page-id (get @st/state :current-page-id)
|
||||||
|
objects (get-in @st/state [:workspace-data :pages-index page-id :objects])]
|
||||||
|
(.log js/console (modif->js (:workspace-modifiers @st/state) objects)))
|
||||||
|
nil)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue