mirror of
https://github.com/penpot/penpot.git
synced 2025-02-26 08:45:34 -05:00
🎉 Changed the user origin for shapes to their corner
This commit is contained in:
parent
db4e0fc314
commit
7ab3d86bc6
19 changed files with 195 additions and 182 deletions
|
@ -88,7 +88,3 @@
|
||||||
(when (= "main" (unchecked-get js/window app-sym))
|
(when (= "main" (unchecked-get js/window app-sym))
|
||||||
(reinit)))
|
(reinit)))
|
||||||
|
|
||||||
(defn ^:export toggle-debug
|
|
||||||
[]
|
|
||||||
(swap! st/*debug* not))
|
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,6 @@
|
||||||
(let [frame (get objects (:frame-id shape))
|
(let [frame (get objects (:frame-id shape))
|
||||||
{:keys [width height rotation]} shape
|
{:keys [width height rotation]} shape
|
||||||
|
|
||||||
center (gpt/center shape)
|
|
||||||
shapev (-> (gpt/point width height))
|
shapev (-> (gpt/point width height))
|
||||||
|
|
||||||
;; Vector modifiers depending on the handler
|
;; Vector modifiers depending on the handler
|
||||||
|
@ -140,7 +139,7 @@
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [stoper (rx/filter ms/mouse-up? stream)
|
(let [stoper (rx/filter ms/mouse-up? stream)
|
||||||
group (gsh/selection-rect shapes)
|
group (gsh/selection-rect shapes)
|
||||||
group-center (gpt/center group)
|
group-center (gsh/center group)
|
||||||
initial-angle (gpt/angle (apply-zoom @ms/mouse-position) group-center)
|
initial-angle (gpt/angle (apply-zoom @ms/mouse-position) group-center)
|
||||||
calculate-angle (fn [pos ctrl?]
|
calculate-angle (fn [pos ctrl?]
|
||||||
(let [angle (- (gpt/angle pos group-center) initial-angle)
|
(let [angle (- (gpt/angle pos group-center) initial-angle)
|
||||||
|
@ -161,7 +160,7 @@
|
||||||
(rx/with-latest vector ms/mouse-position-ctrl)
|
(rx/with-latest vector ms/mouse-position-ctrl)
|
||||||
(rx/map (fn [[pos ctrl?]]
|
(rx/map (fn [[pos ctrl?]]
|
||||||
(let [delta-angle (calculate-angle pos ctrl?)]
|
(let [delta-angle (calculate-angle pos ctrl?)]
|
||||||
(set-rotation delta-angle shapes))))
|
(set-rotation delta-angle shapes group-center))))
|
||||||
(rx/take-until stoper))
|
(rx/take-until stoper))
|
||||||
(rx/of (apply-modifiers (map :id shapes))))))))
|
(rx/of (apply-modifiers (map :id shapes))))))))
|
||||||
|
|
||||||
|
@ -275,7 +274,7 @@
|
||||||
|
|
||||||
;; Set-rotation is custom because applies different modifiers to each shape adjusting their position
|
;; Set-rotation is custom because applies different modifiers to each shape adjusting their position
|
||||||
(defn set-rotation
|
(defn set-rotation
|
||||||
[delta-rotation shapes]
|
[delta-rotation shapes center]
|
||||||
(ptk/reify ::set-rotation
|
(ptk/reify ::set-rotation
|
||||||
IUpdateGroup
|
IUpdateGroup
|
||||||
(get-ids [_] (map :id shapes))
|
(get-ids [_] (map :id shapes))
|
||||||
|
@ -293,8 +292,7 @@
|
||||||
(rotate-around-center [state angle center shapes]
|
(rotate-around-center [state angle center shapes]
|
||||||
(reduce #(rotate-shape %1 angle %2 center) state shapes))]
|
(reduce #(rotate-shape %1 angle %2 center) state shapes))]
|
||||||
|
|
||||||
(let [center (-> shapes gsh/selection-rect gpt/center)
|
(let [objects (get-in state [:workspace-data page-id :objects])
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
|
||||||
id->obj #(get objects %)
|
id->obj #(get objects %)
|
||||||
get-children (fn [shape] (map id->obj (helpers/get-children (:id shape) objects)))
|
get-children (fn [shape] (map id->obj (helpers/get-children (:id shape) objects)))
|
||||||
shapes (concat shapes (mapcat get-children shapes))]
|
shapes (concat shapes (mapcat get-children shapes))]
|
||||||
|
|
|
@ -57,6 +57,14 @@
|
||||||
(get-in % [:workspace-data page-id]))
|
(get-in % [:workspace-data page-id]))
|
||||||
(l/derived st/state)))
|
(l/derived st/state)))
|
||||||
|
|
||||||
|
(defn object-by-id
|
||||||
|
[id]
|
||||||
|
(letfn [(selector [state]
|
||||||
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
|
objects (get-in state [:workspace-data page-id :objects])]
|
||||||
|
(->> (get objects id))))]
|
||||||
|
(l/derived selector st/state =)))
|
||||||
|
|
||||||
(defn objects-by-id
|
(defn objects-by-id
|
||||||
[ids]
|
[ids]
|
||||||
(letfn [(selector [state]
|
(letfn [(selector [state]
|
||||||
|
|
|
@ -23,11 +23,10 @@
|
||||||
(when (debug? :bounding-boxes)
|
(when (debug? :bounding-boxes)
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
frame (unchecked-get props "frame")
|
frame (unchecked-get props "frame")
|
||||||
selrect (geom/transform-selrect frame shape)
|
selrect (-> shape
|
||||||
shape-path (-> shape
|
(geom/selection-rect-shape)
|
||||||
(geom/transform-apply-modifiers)
|
(geom/translate-to-frame frame))
|
||||||
(geom/translate-to-frame frame))
|
shape-center (geom/center selrect)]
|
||||||
shape-center (geom/center shape-path)]
|
|
||||||
[:g
|
[:g
|
||||||
[:text {:x (:x selrect)
|
[:text {:x (:x selrect)
|
||||||
:y (- (:y selrect) 5)
|
:y (- (:y selrect) 5)
|
||||||
|
@ -37,10 +36,12 @@
|
||||||
:stroke-width 0.1}
|
:stroke-width 0.1}
|
||||||
(str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fix (:x shape)) (fix (:y shape)))]
|
(str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fix (:x shape)) (fix (:y shape)))]
|
||||||
|
|
||||||
[:circle {:cx (:x shape-center) :cy (:y shape-center) :r 5 :fill "yellow"}]
|
|
||||||
|
|
||||||
[:rect {:x (:x selrect)
|
[:rect {:x (:x selrect)
|
||||||
:y (:y selrect)
|
:y (:y selrect)
|
||||||
:width (:width selrect)
|
:width (:width selrect)
|
||||||
:height (:height selrect)
|
:height (:height selrect)
|
||||||
:style {:stroke "red" :fill "transparent" :stroke-width "1px" :stroke-opacity 0.5}}]])))
|
:style {:stroke "red"
|
||||||
|
:fill "transparent"
|
||||||
|
:stroke-width "1px"
|
||||||
|
:stroke-opacity 0.5
|
||||||
|
:pointer-events "none"}}]])))
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
(declare circle-shape)
|
(declare circle-shape)
|
||||||
|
|
||||||
(mf/defc circle-wrapper
|
(mf/defc circle-wrapper
|
||||||
[{:keys [shape frame] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
(let [selected (mf/deref refs/selected-shapes)
|
(let [selected (mf/deref refs/selected-shapes)
|
||||||
selected? (contains? selected (:id shape))
|
selected? (contains? selected (:id shape))
|
||||||
on-mouse-down #(common/on-mouse-down % shape)
|
on-mouse-down #(common/on-mouse-down % shape)
|
||||||
|
@ -30,8 +30,7 @@
|
||||||
[:g.shape {:class (when selected? "selected")
|
[:g.shape {:class (when selected? "selected")
|
||||||
:on-mouse-down on-mouse-down
|
:on-mouse-down on-mouse-down
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
[:& circle-shape {:shape (geom/transform-shape frame shape)}]
|
[:& circle-shape {:shape shape}]]))
|
||||||
[:& bounding-box {:shape shape :frame frame}]]))
|
|
||||||
|
|
||||||
;; --- Circle Shape
|
;; --- Circle Shape
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
|
|
||||||
inv-zoom (/ 1 zoom)
|
inv-zoom (/ 1 zoom)
|
||||||
childs (mapv #(get objects %) (:shapes shape))
|
childs (mapv #(get objects %) (:shapes shape))
|
||||||
ds-modifier (:displacement-modifier shape)
|
ds-modifier (get-in shape [:modifiers :displacement])
|
||||||
|
|
||||||
label-pos (cond-> (gpt/point x (- y 10))
|
label-pos (cond-> (gpt/point x (- y 10))
|
||||||
(gmt/matrix? ds-modifier) (gpt/transform ds-modifier))
|
(gmt/matrix? ds-modifier) (gpt/transform ds-modifier))
|
||||||
|
|
|
@ -73,11 +73,9 @@
|
||||||
|
|
||||||
[:& group-shape
|
[:& group-shape
|
||||||
{:frame frame
|
{:frame frame
|
||||||
:shape (geom/transform-shape frame shape)
|
:shape shape
|
||||||
:children children
|
:children children
|
||||||
:is-child-selected? is-child-selected?}]
|
:is-child-selected? is-child-selected?}]]))))
|
||||||
(when (not is-child-selected?)
|
|
||||||
[:& bounding-box {:shape shape :frame frame}])]))))
|
|
||||||
|
|
||||||
(defn group-shape
|
(defn group-shape
|
||||||
[shape-wrapper]
|
[shape-wrapper]
|
||||||
|
|
|
@ -15,15 +15,14 @@
|
||||||
[uxbox.main.ui.shapes.attrs :as attrs]
|
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||||
[uxbox.main.ui.shapes.common :as common]
|
[uxbox.main.ui.shapes.common :as common]
|
||||||
[uxbox.util.interop :as itr]
|
[uxbox.util.interop :as itr]
|
||||||
[uxbox.util.geom.matrix :as gmt]
|
[uxbox.util.geom.matrix :as gmt]))
|
||||||
[uxbox.main.ui.shapes.bounding-box :refer [bounding-box]]))
|
|
||||||
|
|
||||||
;; --- Image Wrapper
|
;; --- Image Wrapper
|
||||||
|
|
||||||
(declare image-shape)
|
(declare image-shape)
|
||||||
|
|
||||||
(mf/defc image-wrapper
|
(mf/defc image-wrapper
|
||||||
[{:keys [shape frame] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
(let [selected (mf/deref refs/selected-shapes)
|
(let [selected (mf/deref refs/selected-shapes)
|
||||||
selected? (contains? selected (:id shape))
|
selected? (contains? selected (:id shape))
|
||||||
on-mouse-down (mf/use-callback
|
on-mouse-down (mf/use-callback
|
||||||
|
@ -37,8 +36,7 @@
|
||||||
[:g.shape {:class (when selected? "selected")
|
[:g.shape {:class (when selected? "selected")
|
||||||
:on-mouse-down on-mouse-down
|
:on-mouse-down on-mouse-down
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
[:& image-shape {:shape (geom/transform-shape frame shape)}]
|
[:& image-shape {:shape shape}]]))
|
||||||
[:& bounding-box {:shape shape :frame frame}]]))
|
|
||||||
|
|
||||||
;; --- Image Shape
|
;; --- Image Shape
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
(declare path-shape)
|
(declare path-shape)
|
||||||
|
|
||||||
(mf/defc path-wrapper
|
(mf/defc path-wrapper
|
||||||
[{:keys [shape frame] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
(let [selected (mf/deref refs/selected-shapes)
|
(let [selected (mf/deref refs/selected-shapes)
|
||||||
selected? (contains? selected (:id shape))
|
selected? (contains? selected (:id shape))
|
||||||
on-mouse-down (mf/use-callback
|
on-mouse-down (mf/use-callback
|
||||||
|
@ -42,8 +42,7 @@
|
||||||
[:g.shape {:on-double-click on-double-click
|
[:g.shape {:on-double-click on-double-click
|
||||||
:on-mouse-down on-mouse-down
|
:on-mouse-down on-mouse-down
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
[:& path-shape {:shape (geom/transform-shape frame shape) :background? true}]
|
[:& path-shape {:shape shape :background? true}]]))
|
||||||
[:& bounding-box {:shape shape :frame frame}]]))
|
|
||||||
|
|
||||||
;; --- Path Shape
|
;; --- Path Shape
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
[uxbox.main.ui.shapes.attrs :as attrs]
|
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||||
[uxbox.main.ui.shapes.common :as common]
|
[uxbox.main.ui.shapes.common :as common]
|
||||||
[uxbox.util.interop :as itr]
|
[uxbox.util.interop :as itr]
|
||||||
[uxbox.main.ui.shapes.bounding-box :refer [bounding-box]]
|
|
||||||
[uxbox.main.ui.shapes.custom-stroke :refer [shape-custom-stroke]]))
|
[uxbox.main.ui.shapes.custom-stroke :refer [shape-custom-stroke]]))
|
||||||
|
|
||||||
;; --- Rect Wrapper
|
;; --- Rect Wrapper
|
||||||
|
@ -26,7 +25,6 @@
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
frame (unchecked-get props "frame")
|
|
||||||
on-mouse-down (mf/use-callback
|
on-mouse-down (mf/use-callback
|
||||||
(mf/deps shape)
|
(mf/deps shape)
|
||||||
#(common/on-mouse-down % shape))
|
#(common/on-mouse-down % shape))
|
||||||
|
@ -35,8 +33,7 @@
|
||||||
#(common/on-context-menu % shape))]
|
#(common/on-context-menu % shape))]
|
||||||
[:g.shape {:on-mouse-down on-mouse-down
|
[:g.shape {:on-mouse-down on-mouse-down
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
[:& rect-shape {:shape (geom/transform-shape frame shape) }]
|
[:& rect-shape {:shape shape}]]))
|
||||||
[:& bounding-box {:shape shape :frame frame}]]))
|
|
||||||
|
|
||||||
;; --- Rect Shape
|
;; --- Rect Shape
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
[uxbox.main.ui.shapes.text :as text]
|
[uxbox.main.ui.shapes.text :as text]
|
||||||
[uxbox.main.ui.shapes.group :as group]
|
[uxbox.main.ui.shapes.group :as group]
|
||||||
[uxbox.main.ui.shapes.frame :as frame]
|
[uxbox.main.ui.shapes.frame :as frame]
|
||||||
|
[uxbox.main.ui.shapes.bounding-box :refer [bounding-box]]
|
||||||
|
[uxbox.util.geom.shapes :as gsh]
|
||||||
[uxbox.main.refs :as refs]))
|
[uxbox.main.refs :as refs]))
|
||||||
|
|
||||||
(defn- shape-wrapper-memo-equals?
|
(defn- shape-wrapper-memo-equals?
|
||||||
|
@ -42,21 +44,24 @@
|
||||||
[props]
|
[props]
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
frame (unchecked-get props "frame")
|
frame (unchecked-get props "frame")
|
||||||
opts #js {:shape shape :frame frame}]
|
opts #js {:shape (->> shape (gsh/transform-shape frame))
|
||||||
|
:frame frame}]
|
||||||
(when (and shape (not (:hidden shape)))
|
(when (and shape (not (:hidden shape)))
|
||||||
(case (:type shape)
|
[:*
|
||||||
:group [:> group-wrapper opts]
|
(case (:type shape)
|
||||||
:curve [:> path/path-wrapper opts]
|
:group [:> group-wrapper opts]
|
||||||
:text [:> text/text-wrapper opts]
|
:curve [:> path/path-wrapper opts]
|
||||||
:icon [:> icon/icon-wrapper opts]
|
:text [:> text/text-wrapper opts]
|
||||||
:rect [:> rect/rect-wrapper opts]
|
:icon [:> icon/icon-wrapper opts]
|
||||||
:path [:> path/path-wrapper opts]
|
:rect [:> rect/rect-wrapper opts]
|
||||||
:image [:> image/image-wrapper opts]
|
:path [:> path/path-wrapper opts]
|
||||||
:circle [:> circle/circle-wrapper opts]
|
:image [:> image/image-wrapper opts]
|
||||||
|
:circle [:> circle/circle-wrapper opts]
|
||||||
|
|
||||||
;; Only used when drawing a new frame.
|
;; Only used when drawing a new frame.
|
||||||
:frame [:> frame-wrapper opts]
|
:frame [:> frame-wrapper {:shape shape}]
|
||||||
nil))))
|
nil)
|
||||||
|
[:& bounding-box {:shape shape :frame frame}]])))
|
||||||
|
|
||||||
(def group-wrapper (group/group-wrapper shape-wrapper))
|
(def group-wrapper (group/group-wrapper shape-wrapper))
|
||||||
(def frame-wrapper (frame/frame-wrapper shape-wrapper))
|
(def frame-wrapper (frame/frame-wrapper shape-wrapper))
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
(declare text-shape)
|
(declare text-shape)
|
||||||
|
|
||||||
(mf/defc text-wrapper
|
(mf/defc text-wrapper
|
||||||
[{:keys [shape frame] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
(let [{:keys [id x1 y1 content group]} shape
|
(let [{:keys [id x1 y1 content group]} shape
|
||||||
selected (mf/deref refs/selected-shapes)
|
selected (mf/deref refs/selected-shapes)
|
||||||
edition (mf/deref refs/selected-edition)
|
edition (mf/deref refs/selected-edition)
|
||||||
|
@ -67,8 +67,8 @@
|
||||||
:on-mouse-down on-mouse-down
|
:on-mouse-down on-mouse-down
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
(if edition?
|
(if edition?
|
||||||
[:& text-shape-edit {:shape (geom/transform-shape frame shape)}]
|
[:& text-shape-edit {:shape shape}]
|
||||||
[:& text-shape {:shape (geom/transform-shape frame shape)
|
[:& text-shape {:shape shape
|
||||||
:selected? selected?}])]))
|
:selected? selected?}])]))
|
||||||
|
|
||||||
;; --- Text Rendering
|
;; --- Text Rendering
|
||||||
|
@ -284,7 +284,8 @@
|
||||||
|
|
||||||
(mf/use-effect on-mount)
|
(mf/use-effect on-mount)
|
||||||
|
|
||||||
[:foreignObject {:x x :y y :width width :height height :ref self-ref}
|
[:foreignObject {:transform (geom/transform-matrix shape)
|
||||||
|
:x x :y y :width width :height height :ref self-ref}
|
||||||
[:> rslate/Slate {:editor editor
|
[:> rslate/Slate {:editor editor
|
||||||
:value @state
|
:value @state
|
||||||
:on-change on-change}
|
:on-change on-change}
|
||||||
|
@ -305,13 +306,7 @@
|
||||||
|
|
||||||
(mf/defc text-shape
|
(mf/defc text-shape
|
||||||
[{:keys [shape selected?] :as props}]
|
[{:keys [shape selected?] :as props}]
|
||||||
(let [{:keys [id x y width height rotation content]} shape
|
(let [{:keys [id x y width height content]} shape
|
||||||
transform (when (and rotation (pos? rotation))
|
|
||||||
(str/format "rotate(%s %s %s)"
|
|
||||||
rotation
|
|
||||||
(+ x (/ width 2))
|
|
||||||
(+ y (/ height 2))))
|
|
||||||
|
|
||||||
content (parse-content content)
|
content (parse-content content)
|
||||||
editor (mf/use-memo #(rslate/withReact (slate/createEditor)))
|
editor (mf/use-memo #(rslate/withReact (slate/createEditor)))
|
||||||
|
|
||||||
|
@ -334,7 +329,7 @@
|
||||||
|
|
||||||
[:foreignObject {:x x
|
[:foreignObject {:x x
|
||||||
:y y
|
:y y
|
||||||
:transform transform
|
:transform (geom/transform-matrix shape)
|
||||||
:id (str id)
|
:id (str id)
|
||||||
:width width
|
:width width
|
||||||
:height height}
|
:height height}
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
(let [modifier (-> (gpt/point (:x frame) (:y frame))
|
(let [modifier (-> (gpt/point (:x frame) (:y frame))
|
||||||
(gpt/negate)
|
(gpt/negate)
|
||||||
(gmt/translate-matrix))
|
(gmt/translate-matrix))
|
||||||
frame (assoc frame :displacement-modifier modifier)
|
frame (assoc-in frame [:modifiers :displacement] modifier )
|
||||||
|
|
||||||
width (* (:width frame) zoom)
|
width (* (:width frame) zoom)
|
||||||
height (* (:height frame) zoom)
|
height (* (:height frame) zoom)
|
||||||
|
|
|
@ -305,7 +305,7 @@
|
||||||
|
|
||||||
(mf/defc generic-draw-area
|
(mf/defc generic-draw-area
|
||||||
[{:keys [shape zoom]}]
|
[{:keys [shape zoom]}]
|
||||||
(let [{:keys [x y width height]} (geom/transform-selrect nil shape)]
|
(let [{:keys [x y width height]} (geom/selection-rect-shape shape)]
|
||||||
(when (and x y)
|
(when (and x y)
|
||||||
[:g
|
[:g
|
||||||
[:& shapes/shape-wrapper {:shape shape}]
|
[:& shapes/shape-wrapper {:shape shape}]
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
[{:keys [shape zoom on-resize on-rotate] :as props}]
|
[{:keys [shape zoom on-resize on-rotate] :as props}]
|
||||||
(let [{:keys [x y width height rotation] :as shape} (geom/shape->rect-shape shape)
|
(let [{:keys [x y width height rotation] :as shape} (geom/shape->rect-shape shape)
|
||||||
radius (if (> (max width height) handler-size-threshold) 4.0 4.0)
|
radius (if (> (max width height) handler-size-threshold) 4.0 4.0)
|
||||||
|
|
||||||
transform (geom/transform-matrix shape)
|
transform (geom/transform-matrix shape)
|
||||||
|
|
||||||
resize-handlers {:top [(+ x (/ width 2 )) y]
|
resize-handlers {:top [(+ x (/ width 2 )) y]
|
||||||
|
@ -85,14 +86,12 @@
|
||||||
|
|
||||||
[:g.controls
|
[:g.controls
|
||||||
[:rect.main {:transform transform
|
[:rect.main {:transform transform
|
||||||
:x x :y y
|
:x (- x 1) :y (- y 1)
|
||||||
:width width
|
:width (+ width 2)
|
||||||
:height height
|
:height (+ height 2)
|
||||||
;;:stroke-dasharray (str (/ 8.0 zoom) "," (/ 5 zoom))
|
|
||||||
:vector-effect "non-scaling-stroke"
|
|
||||||
:style {:stroke "#1FDEA7"
|
:style {:stroke "#1FDEA7"
|
||||||
:fill "transparent"
|
:stroke-width "1"
|
||||||
:stroke-opacity "1"}}]
|
:fill "transparent"}}]
|
||||||
|
|
||||||
(for [[position [cx cy]] resize-handlers]
|
(for [[position [cx cy]] resize-handlers]
|
||||||
(let [tp (gpt/transform (gpt/point cx cy) transform)]
|
(let [tp (gpt/transform (gpt/point cx cy) transform)]
|
||||||
|
@ -156,12 +155,12 @@
|
||||||
|
|
||||||
(mf/defc text-edition-selection-handlers
|
(mf/defc text-edition-selection-handlers
|
||||||
[{:keys [shape zoom] :as props}]
|
[{:keys [shape zoom] :as props}]
|
||||||
(let [{:keys [x y width height] :as shape} shape]
|
(let [{:keys [x y width height]} shape]
|
||||||
[:g.controls
|
[:g.controls
|
||||||
[:rect.main {:x x :y y
|
[:rect.main {:x x :y y
|
||||||
|
:transform (geom/transform-matrix shape)
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
;; :stroke-dasharray (str (/ 5.0 zoom) "," (/ 5 zoom))
|
|
||||||
:style {:stroke "#1FDEA7"
|
:style {:stroke "#1FDEA7"
|
||||||
:stroke-width "0.5"
|
:stroke-width "0.5"
|
||||||
:stroke-opacity "1"
|
:stroke-opacity "1"
|
||||||
|
@ -170,16 +169,20 @@
|
||||||
(mf/defc multiple-selection-handlers
|
(mf/defc multiple-selection-handlers
|
||||||
[{:keys [shapes selected zoom objects] :as props}]
|
[{:keys [shapes selected zoom objects] :as props}]
|
||||||
(let [shape (geom/selection-rect shapes)
|
(let [shape (geom/selection-rect shapes)
|
||||||
|
shape-center (geom/center shape)
|
||||||
on-resize #(do (dom/stop-propagation %2)
|
on-resize #(do (dom/stop-propagation %2)
|
||||||
(st/emit! (dw/start-resize %1 selected shape objects)))
|
(st/emit! (dw/start-resize %1 selected shape objects)))
|
||||||
|
|
||||||
on-rotate #(do (dom/stop-propagation %)
|
on-rotate #(do (dom/stop-propagation %)
|
||||||
(st/emit! (dw/start-rotate shapes)))]
|
(st/emit! (dw/start-rotate shapes)))]
|
||||||
|
|
||||||
[:& controls {:shape shape
|
[:*
|
||||||
:zoom zoom
|
[:& controls {:shape shape
|
||||||
:on-resize on-resize
|
:zoom zoom
|
||||||
:on-rotate on-rotate}]))
|
:on-resize on-resize
|
||||||
|
:on-rotate on-rotate}]
|
||||||
|
(when (debug? :selection-center)
|
||||||
|
[:circle {:cx (:x shape-center) :cy (:y shape-center) :r 5 :fill "yellow"}])]))
|
||||||
|
|
||||||
(mf/defc single-selection-handlers
|
(mf/defc single-selection-handlers
|
||||||
[{:keys [shape zoom objects] :as props}]
|
[{:keys [shape zoom objects] :as props}]
|
||||||
|
|
|
@ -15,25 +15,43 @@
|
||||||
[uxbox.main.refs :as refs]
|
[uxbox.main.refs :as refs]
|
||||||
[uxbox.common.data :as d]
|
[uxbox.common.data :as d]
|
||||||
[uxbox.util.dom :as dom]
|
[uxbox.util.dom :as dom]
|
||||||
|
[uxbox.util.geom.shapes :as gsh]
|
||||||
|
[uxbox.util.geom.point :as gpt]
|
||||||
[uxbox.main.data.workspace :as udw]
|
[uxbox.main.data.workspace :as udw]
|
||||||
[uxbox.util.math :as math]
|
[uxbox.util.math :as math]
|
||||||
[uxbox.util.i18n :refer [t] :as i18n]))
|
[uxbox.util.i18n :refer [t] :as i18n]))
|
||||||
|
|
||||||
|
|
||||||
|
;; -- User/drawing coords
|
||||||
|
(defn user-coords-vector [shape]
|
||||||
|
(let [{sel-x :x sel-y :y :as selrect}
|
||||||
|
(-> shape
|
||||||
|
gsh/shape->path
|
||||||
|
(gsh/center-transform (:transform shape))
|
||||||
|
gsh/shape->rect-shape)
|
||||||
|
{rec-x :x rec-y :y} (-> shape gsh/shape->rect-shape)
|
||||||
|
|
||||||
|
dx (- rec-x sel-x)
|
||||||
|
dy (- rec-y sel-y)]
|
||||||
|
(gpt/point dx dy)))
|
||||||
|
|
||||||
|
(defn user->draw [{:keys [x y width height] :as shape}]
|
||||||
|
(let [dv (user-coords-vector shape)]
|
||||||
|
(-> shape (gsh/move dv))))
|
||||||
|
|
||||||
|
(defn draw->user [{:keys [x y width height] :as shape}]
|
||||||
|
(let [dv (user-coords-vector shape)]
|
||||||
|
(-> shape (gsh/move (gpt/negate dv)))))
|
||||||
|
|
||||||
(mf/defc measures-menu
|
(mf/defc measures-menu
|
||||||
[{:keys [shape options] :as props}]
|
[{:keys [shape options] :as props}]
|
||||||
(let [options (or options #{:size :position :rotation :radius})
|
(let [options (or options #{:size :position :rotation :radius})
|
||||||
locale (i18n/use-locale)
|
locale (i18n/use-locale)
|
||||||
|
frame (deref (refs/object-by-id (:frame-id shape)))
|
||||||
|
|
||||||
data (deref refs/workspace-data)
|
shape (->> shape
|
||||||
parent (get-in data [:objects (:frame-id shape)])
|
(gsh/transform-shape frame)
|
||||||
|
(draw->user))
|
||||||
x (cond
|
|
||||||
(:x shape) :x
|
|
||||||
(:cx shape) :cx)
|
|
||||||
|
|
||||||
y (cond
|
|
||||||
(:y shape) :y
|
|
||||||
(:cy shape) :cy)
|
|
||||||
|
|
||||||
on-size-change
|
on-size-change
|
||||||
(fn [event attr]
|
(fn [event attr]
|
||||||
|
@ -58,9 +76,12 @@
|
||||||
(fn [event attr]
|
(fn [event attr]
|
||||||
(let [value (-> (dom/get-target event)
|
(let [value (-> (dom/get-target event)
|
||||||
(dom/get-value)
|
(dom/get-value)
|
||||||
(d/parse-integer 0)
|
(d/parse-integer 0))
|
||||||
(+ (attr parent)))] ; Convert back to absolute position before update
|
new-shape (-> shape
|
||||||
(st/emit! (udw/update-position (:id shape) {attr value}))))
|
(assoc attr value)
|
||||||
|
(gsh/translate-from-frame frame)
|
||||||
|
(user->draw))]
|
||||||
|
(st/emit! (udw/update-position (:id shape) (select-keys new-shape [attr])))))
|
||||||
|
|
||||||
on-rotation-change
|
on-rotation-change
|
||||||
(fn [event]
|
(fn [event]
|
||||||
|
@ -89,31 +110,31 @@
|
||||||
|
|
||||||
;; WIDTH & HEIGHT
|
;; WIDTH & HEIGHT
|
||||||
(when (options :size)
|
(when (options :size)
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:span.element-set-subtitle (t locale "workspace.options.size")]
|
[:span.element-set-subtitle (t locale "workspace.options.size")]
|
||||||
[:div.lock-size {:class (when (:proportion-lock shape) "selected")
|
[:div.lock-size {:class (when (:proportion-lock shape) "selected")
|
||||||
:on-click on-proportion-lock-change}
|
:on-click on-proportion-lock-change}
|
||||||
(if (:proportion-lock shape)
|
(if (:proportion-lock shape)
|
||||||
i/lock
|
i/lock
|
||||||
i/unlock)]
|
i/unlock)]
|
||||||
[:div.input-element.pixels
|
[:div.input-element.pixels
|
||||||
[:input.input-text {:type "number"
|
[:input.input-text {:type "number"
|
||||||
:min "0"
|
:min "0"
|
||||||
:no-validate true
|
:no-validate true
|
||||||
:on-change on-width-change
|
:on-change on-width-change
|
||||||
:value (str (-> (:width shape)
|
:value (str (-> (:width shape)
|
||||||
(d/coalesce 0)
|
(d/coalesce 0)
|
||||||
(math/round)))}]]
|
(math/round)))}]]
|
||||||
|
|
||||||
|
|
||||||
[:div.input-element.pixels
|
[:div.input-element.pixels
|
||||||
[:input.input-text {:type "number"
|
[:input.input-text {:type "number"
|
||||||
:min "0"
|
:min "0"
|
||||||
:no-validate true
|
:no-validate true
|
||||||
:on-change on-height-change
|
:on-change on-height-change
|
||||||
:value (str (-> (:height shape)
|
:value (str (-> (:height shape)
|
||||||
(d/coalesce 0)
|
(d/coalesce 0)
|
||||||
(math/round)))}]]])
|
(math/round)))}]]])
|
||||||
|
|
||||||
;; Circle RX RY
|
;; Circle RX RY
|
||||||
(when (options :circle-size)
|
(when (options :circle-size)
|
||||||
|
@ -142,57 +163,61 @@
|
||||||
;; POSITION
|
;; POSITION
|
||||||
(when (options :position)
|
(when (options :position)
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:span.element-set-subtitle (t locale "workspace.options.position")]
|
[:span.element-set-subtitle (t locale "workspace.options.position")]
|
||||||
[:div.input-element.pixels
|
[:div.input-element.pixels
|
||||||
[:input.input-text {:placeholder "x"
|
[:input.input-text {:placeholder "x"
|
||||||
:type "number"
|
:type "number"
|
||||||
:no-validate true
|
:no-validate true
|
||||||
:on-change on-pos-x-change
|
:on-change on-pos-x-change
|
||||||
:value (str (-> (- (x shape) (:x parent)) ; Show to user position relative to frame
|
:value (:x shape)
|
||||||
(d/coalesce 0)
|
;;:value (str (-> (- (x shape) (:x parent)) ; Show to user position relative to frame
|
||||||
(math/round)))}]]
|
;; (d/coalesce 0)
|
||||||
[:div.input-element.pixels
|
;; (math/round)))
|
||||||
[:input.input-text {:placeholder "y"
|
}]]
|
||||||
:type "number"
|
[:div.input-element.pixels
|
||||||
:no-validate true
|
[:input.input-text {:placeholder "y"
|
||||||
:on-change on-pos-y-change
|
:type "number"
|
||||||
:value (str (-> (- (y shape) (:y parent))
|
:no-validate true
|
||||||
(d/coalesce 0)
|
:on-change on-pos-y-change
|
||||||
(math/round)))}]]])
|
:value (:y shape)
|
||||||
|
;;:value (str (-> (- (y shape) (:y parent))
|
||||||
|
;; (d/coalesce 0)
|
||||||
|
;; (math/round)))
|
||||||
|
}]]])
|
||||||
|
|
||||||
(when (options :rotation)
|
(when (options :rotation)
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:span.element-set-subtitle (t locale "workspace.options.rotation")]
|
[:span.element-set-subtitle (t locale "workspace.options.rotation")]
|
||||||
[:div.input-element.degrees
|
[:div.input-element.degrees
|
||||||
[:input.input-text
|
[:input.input-text
|
||||||
{:placeholder ""
|
{:placeholder ""
|
||||||
:type "number"
|
:type "number"
|
||||||
:no-validate true
|
:no-validate true
|
||||||
|
:min "0"
|
||||||
|
:max "360"
|
||||||
|
:on-change on-rotation-change
|
||||||
|
:value (str (-> (:rotation shape)
|
||||||
|
(d/coalesce 0)
|
||||||
|
(math/round)))}]]
|
||||||
|
[:input.slidebar
|
||||||
|
{:type "range"
|
||||||
:min "0"
|
:min "0"
|
||||||
:max "360"
|
:max "360"
|
||||||
|
:step "1"
|
||||||
|
:no-validate true
|
||||||
:on-change on-rotation-change
|
:on-change on-rotation-change
|
||||||
:value (str (-> (:rotation shape)
|
:value (str (-> (:rotation shape)
|
||||||
(d/coalesce 0)
|
(d/coalesce 0)))}]])
|
||||||
(math/round)))}]]
|
|
||||||
[:input.slidebar
|
|
||||||
{:type "range"
|
|
||||||
:min "0"
|
|
||||||
:max "360"
|
|
||||||
:step "1"
|
|
||||||
:no-validate true
|
|
||||||
:on-change on-rotation-change
|
|
||||||
:value (str (-> (:rotation shape)
|
|
||||||
(d/coalesce 0)))}]])
|
|
||||||
|
|
||||||
(when (options :radius)
|
(when (options :radius)
|
||||||
[:div.row-flex
|
[:div.row-flex
|
||||||
[:span.element-set-subtitle (t locale "workspace.options.radius")]
|
[:span.element-set-subtitle (t locale "workspace.options.radius")]
|
||||||
[:div.input-element.pixels
|
[:div.input-element.pixels
|
||||||
[:input.input-text
|
[:input.input-text
|
||||||
{:placeholder "rx"
|
{:placeholder "rx"
|
||||||
:type "number"
|
:type "number"
|
||||||
:on-change on-radius-change
|
:on-change on-radius-change
|
||||||
:value (str (-> (:rx shape)
|
:value (str (-> (:rx shape)
|
||||||
(d/coalesce 0)
|
(d/coalesce 0)
|
||||||
(math/round)))}]]
|
(math/round)))}]]
|
||||||
[:div.input-element]])]]))
|
[:div.input-element]])]]))
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
(ns uxbox.util.debug
|
(ns uxbox.util.debug
|
||||||
"Debugging utils"
|
"Debugging utils")
|
||||||
(:require
|
|
||||||
[uxbox.main.store :as store]))
|
|
||||||
|
|
||||||
(def debug-options #{:bounding-boxes :group :events :rotation-handler #_:simple-selection })
|
(def debug-options #{:bounding-boxes :group :events :rotation-handler :selection-center #_:simple-selection })
|
||||||
|
|
||||||
(defonce ^:dynamic *debug* (atom #{}))
|
(defonce ^:dynamic *debug* (atom #{}))
|
||||||
|
|
||||||
|
@ -13,6 +11,13 @@
|
||||||
(defn -debug! [option] (swap! *debug* disj option))
|
(defn -debug! [option] (swap! *debug* disj option))
|
||||||
(defn debug? [option] (@*debug* option))
|
(defn debug? [option] (@*debug* option))
|
||||||
|
|
||||||
|
|
||||||
|
(defn ^:export toggle-debug [name] (let [option (keyword name)]
|
||||||
|
(if (debug? option)
|
||||||
|
(-debug! option)
|
||||||
|
(debug! option))))
|
||||||
|
(defn ^:export debug-all [name] (debug-all!))
|
||||||
|
|
||||||
(defn tap
|
(defn tap
|
||||||
"Transducer function that can execute a side-effect `effect-fn` per input"
|
"Transducer function that can execute a side-effect `effect-fn` per input"
|
||||||
[effect-fn]
|
[effect-fn]
|
||||||
|
@ -31,9 +36,4 @@
|
||||||
(js/console.log str (clj->js val))
|
(js/console.log str (clj->js val))
|
||||||
val))
|
val))
|
||||||
|
|
||||||
(defn dump-state []
|
|
||||||
(logjs "state" @store/state))
|
|
||||||
|
|
||||||
(defn dump-objects []
|
|
||||||
(let [page-id (get @store/state :current-page-id)]
|
|
||||||
(logjs "state" (get-in @store/state [:workspace-data page-id :objects]))))
|
|
||||||
|
|
|
@ -40,11 +40,6 @@
|
||||||
(throw (ex-info "Invalid arguments" {:v v}))))
|
(throw (ex-info "Invalid arguments" {:v v}))))
|
||||||
([x y] (Point. x y)))
|
([x y] (Point. x y)))
|
||||||
|
|
||||||
(defn center
|
|
||||||
[{:keys [x y width height]}]
|
|
||||||
(point (+ x (/ width 2))
|
|
||||||
(+ y (/ height 2))))
|
|
||||||
|
|
||||||
(defn add
|
(defn add
|
||||||
"Returns the addition of the supplied value to both
|
"Returns the addition of the supplied value to both
|
||||||
coordinates of the point as a new point."
|
coordinates of the point as a new point."
|
||||||
|
|
|
@ -376,6 +376,7 @@
|
||||||
maxx (transduce (map :x) max segments)
|
maxx (transduce (map :x) max segments)
|
||||||
maxy (transduce (map :y) max segments)]
|
maxy (transduce (map :y) max segments)]
|
||||||
(assoc shape
|
(assoc shape
|
||||||
|
:type :rect
|
||||||
:x1 minx
|
:x1 minx
|
||||||
:y1 miny
|
:y1 miny
|
||||||
:x2 maxx
|
:x2 maxx
|
||||||
|
@ -495,7 +496,7 @@
|
||||||
|
|
||||||
(defn translate-from-frame
|
(defn translate-from-frame
|
||||||
[shape {:keys [x y] :as frame}]
|
[shape {:keys [x y] :as frame}]
|
||||||
(move shape (gpt/point (+ x) (+ y))))
|
(move shape (gpt/point x y)))
|
||||||
|
|
||||||
;; --- Alignment
|
;; --- Alignment
|
||||||
|
|
||||||
|
@ -736,13 +737,6 @@
|
||||||
(gpt/divide (gpt/point (:width shape-path-temp-rec) (:height shape-path-temp-rec))
|
(gpt/divide (gpt/point (:width shape-path-temp-rec) (:height shape-path-temp-rec))
|
||||||
(gpt/point (:width shape-path-temp-dim) (:height shape-path-temp-dim)))))
|
(gpt/point (:width shape-path-temp-dim) (:height shape-path-temp-dim)))))
|
||||||
|
|
||||||
(defn transform-selrect
|
|
||||||
[frame shape]
|
|
||||||
(-> shape
|
|
||||||
(transform-apply-modifiers)
|
|
||||||
(translate-to-frame frame)
|
|
||||||
(shape->rect-shape)))
|
|
||||||
|
|
||||||
(defn transform-rect-shape
|
(defn transform-rect-shape
|
||||||
[shape]
|
[shape]
|
||||||
(let [;; Apply modifiers to the rect as a path so we have the end shape expected
|
(let [;; Apply modifiers to the rect as a path so we have the end shape expected
|
||||||
|
@ -788,6 +782,8 @@
|
||||||
|
|
||||||
new-shape (-> shape
|
new-shape (-> shape
|
||||||
(merge rec)
|
(merge rec)
|
||||||
|
(update :x #(mth/precision % 2))
|
||||||
|
(update :y #(mth/precision % 2))
|
||||||
(update :transform #(gmt/multiply (or % (gmt/matrix)) stretch-matrix))
|
(update :transform #(gmt/multiply (or % (gmt/matrix)) stretch-matrix))
|
||||||
(update :transform-inverse #(gmt/multiply stretch-matrix-inverse (or % (gmt/matrix)))))]
|
(update :transform-inverse #(gmt/multiply stretch-matrix-inverse (or % (gmt/matrix)))))]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue