mirror of
https://github.com/penpot/penpot.git
synced 2025-03-15 17:21:17 -05:00
✨ Show measures on workspace when pressed "ALT"
This commit is contained in:
parent
3ccb52735f
commit
b3fee39433
7 changed files with 324 additions and 211 deletions
|
@ -20,7 +20,7 @@
|
|||
(if ref
|
||||
(let [target (dom/get-target event)
|
||||
parent (mf/ref-val ref)]
|
||||
(when-not (.contains parent target)
|
||||
(when-not (or (not parent) (.contains parent target))
|
||||
(on-close)))
|
||||
(on-close)))
|
||||
|
||||
|
|
256
frontend/src/app/main/ui/measurements.cljs
Normal file
256
frontend/src/app/main/ui/measurements.cljs
Normal file
|
@ -0,0 +1,256 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.measurements
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.main.store :as st]))
|
||||
|
||||
;; ------------------------------------------------
|
||||
;; CONSTANTS
|
||||
;; ------------------------------------------------
|
||||
|
||||
(def font-size 10)
|
||||
(def selection-rect-width 1)
|
||||
|
||||
(def select-color "#1FDEA7")
|
||||
(def select-guide-width 1)
|
||||
(def select-guide-dasharray 5)
|
||||
|
||||
(def hover-color "#DB00FF")
|
||||
(def hover-color-text "#FFF")
|
||||
(def hover-guide-width 1)
|
||||
|
||||
(def size-display-color "#FFF")
|
||||
(def size-display-opacity 0.7)
|
||||
(def size-display-text-color "#000")
|
||||
(def size-display-width-min 50)
|
||||
(def size-display-width-max 75)
|
||||
(def size-display-height 16)
|
||||
|
||||
(def distance-color "#DB00FF")
|
||||
(def distance-text-color "#FFF")
|
||||
(def distance-border-radius 2)
|
||||
(def distance-pill-width 40)
|
||||
(def distance-pill-height 16)
|
||||
(def distance-line-stroke 1)
|
||||
|
||||
;; ------------------------------------------------
|
||||
;; HELPERS
|
||||
;; ------------------------------------------------
|
||||
|
||||
(defn bound->selrect [bounds]
|
||||
{:x (:x bounds)
|
||||
:y (:y bounds)
|
||||
:x1 (:x bounds)
|
||||
:y1 (:y bounds)
|
||||
:x2 (+ (:x bounds) (:width bounds))
|
||||
:y2 (+ (:y bounds) (:height bounds))
|
||||
:width (:width bounds)
|
||||
:height (:height bounds)})
|
||||
|
||||
(defn calculate-guides
|
||||
"Calculates coordinates for the selection guides"
|
||||
[bounds selrect]
|
||||
(let [{bounds-width :width bounds-height :height} bounds
|
||||
{:keys [x y width height]} selrect]
|
||||
[[(:x bounds) y (+ (:x bounds) bounds-width) y]
|
||||
[(:x bounds) (+ y height) (+ (:x bounds) bounds-width) (+ y height)]
|
||||
[x (:y bounds) x (+ (:y bounds) bounds-height)]
|
||||
[(+ x width) (:y bounds) (+ x width) (+ (:y bounds) bounds-height)]]))
|
||||
|
||||
(defn calculate-distance-lines
|
||||
"Given a start/end from two shapes gives the distance lines"
|
||||
[from-s from-e to-s to-e]
|
||||
(let [ss (- to-s from-s)
|
||||
se (- to-e from-s)
|
||||
es (- to-s from-e)
|
||||
ee (- to-e from-e)]
|
||||
(cond-> []
|
||||
(or (and (neg? ss) (pos? se))
|
||||
(and (pos? ss) (neg? ee))
|
||||
(and (neg? ss) (> ss se)))
|
||||
(conj [ from-s (+ from-s ss) ])
|
||||
|
||||
(or (and (neg? se) (<= ss se)))
|
||||
(conj [ from-s (+ from-s se) ])
|
||||
|
||||
(or (and (pos? es) (<= es ee)))
|
||||
(conj [ from-e (+ from-e es) ])
|
||||
|
||||
(or (and (pos? ee) (neg? es))
|
||||
(and (neg? ee) (pos? ss))
|
||||
(and (pos? ee) (< ee es)))
|
||||
(conj [ from-e (+ from-e ee) ]))))
|
||||
|
||||
;; ------------------------------------------------
|
||||
;; COMPONENTS
|
||||
;; ------------------------------------------------
|
||||
|
||||
(mf/defc size-display [{:keys [type selrect zoom]}]
|
||||
(let [{:keys [x y width height]} selrect
|
||||
size-label (str/fmt "%s x %s" (mth/round width) (mth/round height))
|
||||
|
||||
rect-height (/ size-display-height zoom)
|
||||
rect-width (/ (if (<= (count size-label) 9)
|
||||
size-display-width-min
|
||||
size-display-width-max)
|
||||
zoom)
|
||||
text-padding (/ 4 zoom)]
|
||||
[:g.size-display
|
||||
[:rect {:x (+ x (/ width 2) (- (/ rect-width 2)))
|
||||
:y (- (+ y height) rect-height)
|
||||
:width rect-width
|
||||
:height rect-height
|
||||
:style {:fill size-display-color
|
||||
:fill-opacity size-display-opacity}}]
|
||||
|
||||
[:text {:x (+ (+ x (/ width 2) (- (/ rect-width 2))) (/ rect-width 2))
|
||||
:y (- (+ y height (+ text-padding (/ rect-height 2))) rect-height)
|
||||
:width rect-width
|
||||
:height rect-height
|
||||
:text-anchor "middle"
|
||||
:style {:fill size-display-text-color
|
||||
:font-size (/ font-size zoom)}}
|
||||
size-label]]))
|
||||
|
||||
(mf/defc distance-display-pill [{:keys [x y zoom distance bounds]}]
|
||||
(let [distance-pill-width (/ distance-pill-width zoom)
|
||||
distance-pill-height (/ distance-pill-height zoom)
|
||||
distance-line-stroke (/ distance-line-stroke zoom)
|
||||
font-size (/ font-size zoom)
|
||||
text-padding (/ 3 zoom)
|
||||
distance-border-radius (/ distance-border-radius zoom)
|
||||
|
||||
{bounds-width :width bounds-height :height} bounds
|
||||
|
||||
rect-x (- x (/ distance-pill-width 2))
|
||||
rect-y (- y (/ distance-pill-height 2))
|
||||
|
||||
text-x x
|
||||
text-y (+ y text-padding)
|
||||
|
||||
offset-x (cond (< rect-x (:x bounds)) (- (:x bounds) rect-x)
|
||||
(> (+ rect-x distance-pill-width) (+ (:x bounds) bounds-width))
|
||||
(- (+ (:x bounds) bounds-width) (+ rect-x distance-pill-width))
|
||||
:else 0)
|
||||
|
||||
offset-y (cond (< rect-y (:y bounds)) (- (:y bounds) rect-y)
|
||||
(> (+ rect-y distance-pill-height) (+ (:y bounds) bounds-height))
|
||||
(- (+ (:y bounds) bounds-height) (+ rect-y distance-pill-height))
|
||||
:else 0)]
|
||||
[:g.distance-pill
|
||||
[:rect {:x (+ rect-x offset-x)
|
||||
:y (+ rect-y offset-y)
|
||||
:rx distance-border-radius
|
||||
:ry distance-border-radius
|
||||
:width distance-pill-width
|
||||
:height distance-pill-height
|
||||
:style {:fill distance-color}}]
|
||||
|
||||
[:text {:x (+ text-x offset-x)
|
||||
:y (+ text-y offset-y)
|
||||
:rx distance-border-radius
|
||||
:ry distance-border-radius
|
||||
:text-anchor "middle"
|
||||
:width distance-pill-width
|
||||
:height distance-pill-height
|
||||
:style {:fill distance-text-color
|
||||
:font-size font-size}}
|
||||
distance]]))
|
||||
|
||||
(mf/defc selection-rect [{:keys [frame selrect zoom]}]
|
||||
(let [{:keys [x y width height]} selrect
|
||||
selection-rect-width (/ selection-rect-width zoom)]
|
||||
[:g.selection-rect
|
||||
[:rect {:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:style {:fill "transparent"
|
||||
:stroke hover-color
|
||||
:stroke-width selection-rect-width}}]]))
|
||||
|
||||
(mf/defc distance-display [{:keys [type from to zoom frame bounds]}]
|
||||
(let [fixed-x (if (gsh/fully-contained? from to)
|
||||
(+ (:x to) (/ (:width to) 2))
|
||||
(+ (:x from) (/ (:width from) 2)))
|
||||
fixed-y (if (gsh/fully-contained? from to)
|
||||
(+ (:y to) (/ (:height to) 2))
|
||||
(+ (:y from) (/ (:height from) 2)))
|
||||
|
||||
v-lines (->> (calculate-distance-lines (:y1 from) (:y2 from) (:y1 to) (:y2 to))
|
||||
(map (fn [[start end]] [fixed-x start fixed-x end])))
|
||||
|
||||
h-lines (->> (calculate-distance-lines (:x1 from) (:x2 from) (:x1 to) (:x2 to))
|
||||
(map (fn [[start end]] [start fixed-y end fixed-y])))
|
||||
|
||||
lines (d/concat [] v-lines h-lines)]
|
||||
|
||||
(for [[x1 y1 x2 y2] lines]
|
||||
(let [center-x (+ x1 (/ (- x2 x1) 2))
|
||||
center-y (+ y1 (/ (- y2 y1) 2))
|
||||
distance (gpt/distance (gpt/point x1 y1) (gpt/point x2 y2))]
|
||||
[:g.distance-line {:key (str "line-%s-%s-%s-%s" x1 y1 x2 y2)}
|
||||
[:line
|
||||
{:x1 x1
|
||||
:y1 y1
|
||||
:x2 x2
|
||||
:y2 y2
|
||||
:style {:stroke distance-color
|
||||
:stroke-width distance-line-stroke}}]
|
||||
|
||||
[:& distance-display-pill
|
||||
{:x center-x
|
||||
:y center-y
|
||||
:zoom zoom
|
||||
:distance (str (mth/round distance) "px")
|
||||
:bounds bounds}]]))))
|
||||
|
||||
(mf/defc selection-guides [{:keys [bounds selrect zoom]}]
|
||||
[:g.selection-guides
|
||||
(for [[x1 y1 x2 y2] (calculate-guides bounds selrect)]
|
||||
[:line {:x1 x1
|
||||
:y1 y1
|
||||
:x2 x2
|
||||
:y2 y2
|
||||
:style {:stroke select-color
|
||||
:stroke-width (/ select-guide-width zoom)
|
||||
:stroke-dasharray (/ select-guide-dasharray zoom)}}])])
|
||||
|
||||
(mf/defc measurement [{:keys [bounds frame selected-shapes hover-shape zoom]}]
|
||||
(let [selected-selrect (gsh/selection-rect selected-shapes)
|
||||
hover-selrect (:selrect hover-shape)
|
||||
bounds-selrect (bound->selrect bounds)]
|
||||
|
||||
(when (seq selected-shapes)
|
||||
[:g.measurement-feedback {:pointer-events "none"}
|
||||
[:& selection-guides {:selrect selected-selrect :bounds bounds :zoom zoom}]
|
||||
[:& size-display {:selrect selected-selrect :zoom zoom}]
|
||||
|
||||
(if (not hover-shape)
|
||||
(when frame
|
||||
[:g.hover-shapes
|
||||
[:& distance-display {:from (:selrect frame)
|
||||
:to selected-selrect
|
||||
:zoom zoom
|
||||
:bounds bounds-selrect}]])
|
||||
|
||||
[:g.hover-shapes
|
||||
[:& selection-rect {:type :hover :selrect hover-selrect :zoom zoom}]
|
||||
[:& size-display {:selrect hover-selrect :zoom zoom}]
|
||||
[:& distance-display {:from hover-selrect :to selected-selrect :zoom zoom :bounds bounds-selrect}]])])))
|
||||
|
||||
|
|
@ -16,36 +16,17 @@
|
|||
[app.common.math :as mth]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.main.store :as st]))
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.measurements :refer [selection-guides size-display measurement]]))
|
||||
|
||||
;; ------------------------------------------------
|
||||
;; CONSTANTS
|
||||
;; ------------------------------------------------
|
||||
|
||||
(def select-color "#1FDEA7")
|
||||
(def hover-color "#DB00FF")
|
||||
(def hover-color-text "#FFF")
|
||||
(def font-size 10)
|
||||
|
||||
(def selection-rect-width 1)
|
||||
|
||||
(def select-guide-width 1)
|
||||
(def select-guide-dasharray 5)
|
||||
(def hover-guide-width 1)
|
||||
|
||||
(def size-display-color "#FFF")
|
||||
(def size-display-opacity 0.7)
|
||||
(def size-display-text-color "#000")
|
||||
(def size-display-width-min 50)
|
||||
(def size-display-width-max 75)
|
||||
(def size-display-height 16)
|
||||
|
||||
(def distance-color "#DB00FF")
|
||||
(def distance-text-color "#FFF")
|
||||
(def distance-border-radius 2)
|
||||
(def distance-pill-width 40)
|
||||
(def distance-pill-height 16)
|
||||
(def distance-line-stroke 1)
|
||||
|
||||
;; ------------------------------------------------
|
||||
;; LENSES
|
||||
|
@ -87,182 +68,28 @@
|
|||
:width (:width frame)
|
||||
:height (:height frame)})
|
||||
|
||||
(defn calculate-guides
|
||||
"Calculates coordinates for the selection guides"
|
||||
[frame selrect]
|
||||
(let [{frame-width :width frame-height :height} frame
|
||||
{:keys [x y width height]} selrect]
|
||||
[[0 y frame-width y]
|
||||
[0 (+ y height) frame-width (+ y height)]
|
||||
[x 0 x frame-height]
|
||||
[(+ x width) 0 (+ x width) frame-height]]))
|
||||
|
||||
(defn calculate-distance-lines
|
||||
"Given a start/end from two shapes gives the distance lines"
|
||||
[from-s from-e to-s to-e]
|
||||
(let [ss (- to-s from-s)
|
||||
se (- to-e from-s)
|
||||
es (- to-s from-e)
|
||||
ee (- to-e from-e)]
|
||||
(cond-> []
|
||||
(or (and (neg? ss) (pos? se))
|
||||
(and (pos? ss) (neg? ee))
|
||||
(and (neg? ss) (> ss se)))
|
||||
(conj [ from-s (+ from-s ss) ])
|
||||
|
||||
(or (and (neg? se) (<= ss se)))
|
||||
(conj [ from-s (+ from-s se) ])
|
||||
|
||||
(or (and (pos? es) (<= es ee)))
|
||||
(conj [ from-e (+ from-e es) ])
|
||||
|
||||
(or (and (pos? ee) (neg? es))
|
||||
(and (neg? ee) (pos? ss))
|
||||
(and (pos? ee) (< ee es)))
|
||||
(conj [ from-e (+ from-e ee) ]))))
|
||||
|
||||
;; ------------------------------------------------
|
||||
;; COMPONENTS
|
||||
;; ------------------------------------------------
|
||||
|
||||
(mf/defc selection-guides [{:keys [frame selrect zoom]}]
|
||||
[:g.selection-guides
|
||||
(for [[x1 y1 x2 y2] (calculate-guides frame selrect)]
|
||||
[:line {:x1 x1
|
||||
:y1 y1
|
||||
:x2 x2
|
||||
:y2 y2
|
||||
:style {:stroke select-color
|
||||
:stroke-width (/ select-guide-width zoom)
|
||||
:stroke-dasharray (/ select-guide-dasharray zoom)}}])])
|
||||
|
||||
(mf/defc selection-rect [{:keys [type frame selrect zoom]}]
|
||||
(mf/defc selection-rect [{:keys [frame selrect zoom]}]
|
||||
(let [{:keys [x y width height]} selrect
|
||||
stroke-color (case type
|
||||
:selection select-color
|
||||
:hover hover-color)]
|
||||
selection-rect-width (/ selection-rect-width zoom)]
|
||||
[:g.selection-rect
|
||||
[:rect {:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:style {:fill "transparent"
|
||||
:stroke stroke-color
|
||||
:stroke-width (/ selection-rect-width zoom)}}]]))
|
||||
|
||||
(mf/defc size-display [{:keys [type selrect zoom]}]
|
||||
(let [{:keys [x y width height]} selrect
|
||||
size-label (str/fmt "%s x %s" (mth/round width) (mth/round height))
|
||||
|
||||
rect-height (/ size-display-height zoom)
|
||||
rect-width (/ (if (<= (count size-label) 9)
|
||||
size-display-width-min
|
||||
size-display-width-max)
|
||||
zoom)
|
||||
text-padding (/ 4 zoom)]
|
||||
[:g.size-display
|
||||
[:rect {:x (+ x (/ width 2) (- (/ rect-width 2)))
|
||||
:y (- (+ y height) rect-height)
|
||||
:width rect-width
|
||||
:height rect-height
|
||||
:style {:fill size-display-color
|
||||
:fill-opacity size-display-opacity}}]
|
||||
|
||||
[:text {:x (+ (+ x (/ width 2) (- (/ rect-width 2))) (/ rect-width 2))
|
||||
:y (- (+ y height (+ text-padding (/ rect-height 2))) rect-height)
|
||||
:width rect-width
|
||||
:height rect-height
|
||||
:text-anchor "middle"
|
||||
:style {:fill size-display-text-color
|
||||
:font-size (/ font-size zoom)}}
|
||||
size-label]]))
|
||||
|
||||
(mf/defc distance-display-pill [{:keys [x y zoom distance frame]}]
|
||||
(let [distance-pill-width (/ distance-pill-width zoom)
|
||||
distance-pill-height (/ distance-pill-height zoom)
|
||||
distance-line-stroke (/ distance-line-stroke zoom)
|
||||
font-size (/ font-size zoom)
|
||||
text-padding (/ 3 zoom)
|
||||
distance-border-radius (/ distance-border-radius zoom)
|
||||
|
||||
{frame-width :width frame-height :height} frame
|
||||
|
||||
rect-x (- x (/ distance-pill-width 2))
|
||||
rect-y (- y (/ distance-pill-height 2))
|
||||
|
||||
text-x x
|
||||
text-y (+ y text-padding)
|
||||
|
||||
offset-x (cond (< rect-x 0) (- rect-x)
|
||||
(> (+ rect-x distance-pill-width) frame-width) (- frame-width (+ rect-x distance-pill-width))
|
||||
:else 0)
|
||||
|
||||
offset-y (cond (< rect-y 0) (- rect-y)
|
||||
(> (+ rect-y distance-pill-height) frame-height) (- frame-height (+ rect-y distance-pill-height))
|
||||
:else 0)
|
||||
|
||||
]
|
||||
[:g.distance-pill
|
||||
[:rect {:x (+ rect-x offset-x)
|
||||
:y (+ rect-y offset-y)
|
||||
:rx distance-border-radius
|
||||
:ry distance-border-radius
|
||||
:width distance-pill-width
|
||||
:height distance-pill-height
|
||||
:style {:fill distance-color}}]
|
||||
|
||||
[:text {:x (+ text-x offset-x)
|
||||
:y (+ text-y offset-y)
|
||||
:rx distance-border-radius
|
||||
:ry distance-border-radius
|
||||
:text-anchor "middle"
|
||||
:width distance-pill-width
|
||||
:height distance-pill-height
|
||||
:style {:fill distance-text-color
|
||||
:font-size font-size}}
|
||||
distance]])
|
||||
)
|
||||
|
||||
(mf/defc distance-display [{:keys [type from to zoom frame]}]
|
||||
(let [fixed-x (if (gsh/fully-contained? from to)
|
||||
(+ (:x to) (/ (:width to) 2))
|
||||
(+ (:x from) (/ (:width from) 2)))
|
||||
fixed-y (if (gsh/fully-contained? from to)
|
||||
(+ (:y to) (/ (:height to) 2))
|
||||
(+ (:y from) (/ (:height from) 2)))
|
||||
|
||||
v-lines (->> (calculate-distance-lines (:y1 from) (:y2 from) (:y1 to) (:y2 to))
|
||||
(map (fn [[start end]] [fixed-x start fixed-x end])))
|
||||
|
||||
h-lines (->> (calculate-distance-lines (:x1 from) (:x2 from) (:x1 to) (:x2 to))
|
||||
(map (fn [[start end]] [start fixed-y end fixed-y])))
|
||||
|
||||
lines (d/concat [] v-lines h-lines)]
|
||||
|
||||
(for [[x1 y1 x2 y2] lines]
|
||||
(let [center-x (+ x1 (/ (- x2 x1) 2))
|
||||
center-y (+ y1 (/ (- y2 y1) 2))
|
||||
distance (gpt/distance (gpt/point x1 y1) (gpt/point x2 y2))]
|
||||
[:g.distance-line {:key (str "line-%s-%s-%s-%s" x1 y1 x2 y2)}
|
||||
[:line
|
||||
{:x1 x1
|
||||
:y1 y1
|
||||
:x2 x2
|
||||
:y2 y2
|
||||
:style {:stroke distance-color
|
||||
:stroke-width distance-line-stroke}}]
|
||||
|
||||
[:& distance-display-pill
|
||||
{:x center-x
|
||||
:y center-y
|
||||
:zoom zoom
|
||||
:distance (str (mth/round distance) "px")
|
||||
:frame frame}]]))))
|
||||
:stroke select-color
|
||||
:stroke-width selection-rect-width}}]]))
|
||||
|
||||
(mf/defc selection-feedback [{:keys [frame]}]
|
||||
(let [zoom (mf/deref selected-zoom)
|
||||
|
||||
hover-shapes-ref (mf/use-memo (make-hover-shapes-iref))
|
||||
hover-shape (mf/deref hover-shapes-ref)
|
||||
hover-shape (-> (mf/deref hover-shapes-ref)
|
||||
(gsh/translate-to-frame frame))
|
||||
|
||||
selected-shapes-ref (mf/use-memo (make-selected-shapes-iref))
|
||||
selected-shapes (->> (mf/deref selected-shapes-ref)
|
||||
|
@ -271,19 +98,13 @@
|
|||
selrect (gsh/selection-rect selected-shapes)]
|
||||
|
||||
(when (seq selected-shapes)
|
||||
[:g.measurement-feedback {:pointer-events "none"}
|
||||
[:g.selection-feedback {:pointer-events "none"}
|
||||
[:g.selected-shapes
|
||||
[:& selection-guides {:selrect selrect :frame frame :zoom zoom}]
|
||||
[:& selection-rect {:type :selection :selrect selrect :zoom zoom}]
|
||||
[:& selection-rect {:selrect selrect :zoom zoom}]
|
||||
[:& size-display {:selrect selrect :zoom zoom}]]
|
||||
|
||||
(if (and (not-empty selected-shapes) (not hover-shape))
|
||||
[:g.hover-shapes
|
||||
[:& distance-display {:from (frame->selrect frame) :to selrect :zoom zoom :frame frame}]]
|
||||
|
||||
(let [hover-selrect (-> hover-shape (gsh/translate-to-frame frame) :selrect)]
|
||||
[:g.hover-shapes
|
||||
[:& selection-rect {:type :hover :selrect hover-selrect :zoom zoom}]
|
||||
[:& size-display {:selrect hover-selrect :zoom zoom}]
|
||||
[:& distance-display {:from hover-selrect :to selrect :zoom zoom :frame frame}]]))])))
|
||||
|
||||
[:& measurement {:bounds frame
|
||||
:selected-shapes selected-shapes
|
||||
:hover-shape hover-shape
|
||||
:zoom zoom}]])))
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]
|
||||
[rumext.util :refer [map->obj]]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.util.data :as d]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -28,7 +30,8 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.util.debug :refer [debug?]]
|
||||
[app.main.ui.workspace.shapes.outline :refer [outline]]))
|
||||
[app.main.ui.workspace.shapes.outline :refer [outline]]
|
||||
[app.main.ui.measurements :as msr]))
|
||||
|
||||
(def rotation-handler-size 25)
|
||||
(def resize-point-radius 4)
|
||||
|
@ -138,8 +141,7 @@
|
|||
[:circle {:r (/ resize-point-radius zoom)
|
||||
:style {:fillOpacity "1"
|
||||
:strokeWidth "1px"
|
||||
:vectorEffect "non-scaling-stroke"
|
||||
}
|
||||
:vectorEffect "non-scaling-stroke"}
|
||||
:fill "#FFFFFF"
|
||||
:stroke (if (and (= position :bottom-right) overflow-text) "red" color)
|
||||
:cx cx'
|
||||
|
@ -266,9 +268,16 @@
|
|||
:fill "transparent"}}]]))
|
||||
|
||||
(mf/defc multiple-selection-handlers
|
||||
[{:keys [shapes selected zoom color] :as props}]
|
||||
[{:keys [shapes selected zoom color show-distances] :as props}]
|
||||
(let [shape (geom/selection-rect shapes)
|
||||
shape-center (geom/center shape)
|
||||
|
||||
hover-id (-> (mf/deref refs/current-hover) first)
|
||||
hover-id (when-not (d/seek #(= hover-id (:id %)) shapes) hover-id)
|
||||
hover-shape (mf/deref (refs/object-by-id hover-id))
|
||||
|
||||
vbox (mf/deref refs/vbox)
|
||||
|
||||
on-resize (fn [current-position initial-position event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dw/start-resize current-position initial-position selected shape)))
|
||||
|
@ -282,13 +291,29 @@
|
|||
:color color
|
||||
:on-resize on-resize
|
||||
:on-rotate on-rotate}]
|
||||
|
||||
(when show-distances
|
||||
[:& msr/measurement {:bounds vbox
|
||||
:selected-shapes shapes
|
||||
:hover-shape hover-shape
|
||||
:zoom zoom}])
|
||||
|
||||
(when (debug? :selection-center)
|
||||
[:circle {:cx (:x shape-center) :cy (:y shape-center) :r 5 :fill "yellow"}])]))
|
||||
|
||||
(mf/defc single-selection-handlers
|
||||
[{:keys [shape zoom color] :as props}]
|
||||
[{:keys [shape zoom color show-distances] :as props}]
|
||||
(let [shape-id (:id shape)
|
||||
shape (geom/transform-shape shape)
|
||||
|
||||
frame (mf/deref (refs/object-by-id (:frame-id shape)))
|
||||
frame (when-not (= (:id frame) uuid/zero) frame)
|
||||
vbox (mf/deref refs/vbox)
|
||||
|
||||
hover-id (-> (mf/deref refs/current-hover) first)
|
||||
hover-id (when-not (= shape-id hover-id) hover-id)
|
||||
hover-shape (mf/deref (refs/object-by-id hover-id))
|
||||
|
||||
shape' (if (debug? :simple-selection) (geom/selection-rect [shape]) shape)
|
||||
on-resize (fn [current-position initial-position event]
|
||||
(dom/stop-propagation event)
|
||||
|
@ -303,10 +328,17 @@
|
|||
:zoom zoom
|
||||
:color color
|
||||
:on-rotate on-rotate
|
||||
:on-resize on-resize}]]))
|
||||
:on-resize on-resize}]
|
||||
|
||||
(when show-distances
|
||||
[:& msr/measurement {:bounds vbox
|
||||
:frame frame
|
||||
:selected-shapes [shape]
|
||||
:hover-shape hover-shape
|
||||
:zoom zoom}])]))
|
||||
|
||||
(mf/defc selection-handlers
|
||||
[{:keys [selected edition zoom] :as props}]
|
||||
[{:keys [selected edition zoom show-distances] :as props}]
|
||||
(let [;; We need remove posible nil values because on shape
|
||||
;; deletion many shape will reamin selected and deleted
|
||||
;; in the same time for small instant of time
|
||||
|
@ -326,7 +358,8 @@
|
|||
[:& multiple-selection-handlers {:shapes shapes
|
||||
:selected selected
|
||||
:zoom zoom
|
||||
:color color}]
|
||||
:color color
|
||||
:show-distances show-distances}]
|
||||
|
||||
(and (= type :text)
|
||||
(= edition (:id shape)))
|
||||
|
@ -343,4 +376,5 @@
|
|||
:else
|
||||
[:& single-selection-handlers {:shape shape
|
||||
:zoom zoom
|
||||
:color color}])))
|
||||
:color color
|
||||
:show-distances show-distances}])))
|
||||
|
|
|
@ -216,7 +216,7 @@
|
|||
(filter #(show-distance? (distance-to-selrect %)))
|
||||
(map #(vector selrect (:selrect %))))
|
||||
|
||||
segments-to-display (concat other-shapes-segments selection-segments)]
|
||||
segments-to-display (d/concat #{} other-shapes-segments selection-segments)]
|
||||
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
|
|
|
@ -116,8 +116,9 @@
|
|||
;; can cause problems with react keys
|
||||
snap-points (into #{} (mapcat add-point-to-snaps) @state)
|
||||
|
||||
snap-lines (into (process-snap-lines @state :x)
|
||||
(process-snap-lines @state :y))]
|
||||
snap-lines (->> (into (process-snap-lines @state :x)
|
||||
(process-snap-lines @state :y))
|
||||
(into #{}))]
|
||||
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
|
|
|
@ -210,6 +210,7 @@
|
|||
(assoc :modifiers (:modifiers local))
|
||||
(gsh/transform-shape))
|
||||
|
||||
alt? (mf/use-state false)
|
||||
viewport-ref (mf/use-ref nil)
|
||||
zoom-view-ref (mf/use-ref nil)
|
||||
last-position (mf/use-var nil)
|
||||
|
@ -498,6 +499,7 @@
|
|||
(timers/schedule #(st/emit! (dw/initialize-viewport size))))))
|
||||
|
||||
(mf/use-layout-effect (mf/deps layout) on-resize)
|
||||
(hooks/use-stream ms/keyboard-alt #(reset! alt? %))
|
||||
|
||||
[:*
|
||||
(when picking-color?
|
||||
|
@ -513,9 +515,7 @@
|
|||
:zoom (:zoom local)
|
||||
:drawing drawing
|
||||
:page-id page-id
|
||||
:file-id (:id file)}
|
||||
])
|
||||
|
||||
:file-id (:id file)}])
|
||||
|
||||
[:svg.viewport
|
||||
{:preserveAspectRatio "xMidYMid meet"
|
||||
|
@ -569,7 +569,8 @@
|
|||
(when (seq selected)
|
||||
[:& selection-handlers {:selected selected
|
||||
:zoom zoom
|
||||
:edition edition}])
|
||||
:edition edition
|
||||
:show-distances (and (not (:transform local)) @alt?)}])
|
||||
|
||||
(when (= (count selected) 1)
|
||||
[:& gradient-handlers {:id (first selected)
|
||||
|
|
Loading…
Add table
Reference in a new issue