0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-05 03:21:26 -05:00

Adapt the application to use the new point abstraction.

This commit is contained in:
Andrey Antukh 2016-02-06 12:29:00 +02:00
parent b102c19ea7
commit 5d5b84a0a1
9 changed files with 126 additions and 105 deletions

View file

@ -10,6 +10,7 @@
[uxbox.time :as time]
[uxbox.xforms :as xf]
[uxbox.shapes :as sh]
[uxbox.util.geom.point :as gpt]
[uxbox.util.data :refer (index-of)]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -156,7 +157,8 @@
(defn move-shape
"Mark a shape selected for drawing in the canvas."
[sid [dx dy :as delta]]
[sid delta]
{:pre [(gpt/point? delta)]}
(reify
rs/UpdateEvent
(-apply-update [_ state]

View file

@ -116,14 +116,16 @@
;; Resize
(defmethod -resize :builtin/line
[shape {:keys [x2 y2] :as pos}]
[shape {:keys [x y] :as pos}]
(assoc shape
:x2 x2 :y2 y2))
:x2 x :y2 x))
(defmethod -resize :builtin/circle
[{:keys [cx cy rx ry] :as shape} {:keys [x2 y2 lock] :as pos}]
[{:keys [cx cy rx ry] :as shape} {:keys [x y lock] :as pos}]
(let [x1 (- cx rx)
y1 (- cy ry)
x2 x
y2 y
width (- x2 x1)
height (if lock
@ -140,15 +142,14 @@
(assoc shape :rx rx :ry ry :cx cx :cy cy))))
(defmethod -resize :builtin/rect
[shape {:keys [x2 y2 lock] :as pos}]
(let [{:keys [x y]} shape]
(if lock
(assoc shape
:width (- x2 x)
:height (- x2 x))
(assoc shape
:width (- x2 x)
:height (- y2 y)))))
[shape {:keys [x y lock] :as pos}]
(if lock
(assoc shape
:width (- x (:x shape))
:height (- x (:x shape)))
(assoc shape
:width (- x (:x shape))
:height (- y (:y shape)))))
(defmethod -resize :default
[shape _]
@ -167,19 +168,19 @@
;; Move
(defmethod -move ::rect
[shape [dx dy]]
[shape {dx :x dy :y}]
(assoc shape
:x (+ (:x shape) dx)
:y (+ (:y shape) dy)))
(defmethod -move :builtin/group
[shape [dx dy]]
[shape {dx :x dy :y}]
(assoc shape
:dx (+ (:dx shape 0) dx)
:dy (+ (:dy shape 0) dy)))
(defmethod -move :builtin/line
[shape [dx dy]]
[shape {dx :x dy :y}]
(assoc shape
:x1 (+ (:x1 shape) dx)
:y1 (+ (:y1 shape) dy)
@ -187,7 +188,7 @@
:y2 (+ (:y2 shape) dy)))
(defmethod -move :builtin/circle
[shape [dx dy]]
[shape {dx :x dy :y}]
(assoc shape
:cx (+ (:cx shape) dx)
:cy (+ (:cy shape) dy)))

View file

@ -25,7 +25,7 @@
(defn- coordenates-render
[own]
(let [[x y] (rum/react wb/mouse-position)]
(let [{:keys [x y]} (rum/react wb/mouse-position)]
(html
[:div {:style {:position "absolute" :left "80px" :top "20px"}}
[:table

View file

@ -6,6 +6,7 @@
[uxbox.state :as st]
[uxbox.data.projects :as dp]
[uxbox.data.workspace :as dw]
[uxbox.util.geom.point :as gpt]
[uxbox.util.lens :as ul]
[goog.events :as events])
(:import goog.events.EventType))
@ -51,25 +52,15 @@
;; Scroll Stream
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defonce ^:private scroll-b (rx/bus))
(defonce scroll-b (rx/bus))
(defonce scroll-s
(as-> scroll-b $
(rx/merge $ (rx/of {:top 0 :left 0}))
(rx/merge $ (rx/of (gpt/point)))
(rx/dedupe $)))
(defonce scroll-top-s
(->> scroll-s
(rx/map :top)
(rx/dedupe)))
(defonce scroll-left-s
(->> scroll-s
(rx/map :left)
(rx/dedupe)))
(defonce scroll-top (rx/to-atom scroll-top-s))
(defonce scroll-left (rx/to-atom scroll-left-s))
(defonce scroll
(rx/to-atom scroll-s))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Interactions
@ -107,10 +98,7 @@
(defn- coords-delta
[[old new]]
(let [[oldx oldy] old
[newx newy] new]
[(- newx oldx)
(- newy oldy)]))
(gpt/subtract new old))
(defonce mouse-delta-s
(->> mouse-s
@ -135,4 +123,3 @@
(def document-start-x 50)
(def document-start-y 50)

View file

@ -14,6 +14,7 @@
[uxbox.data.projects :as dp]
[uxbox.data.workspace :as dw]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom]
[uxbox.ui.keyboard :as kbd]
[uxbox.ui.workspace.base :as wb]
@ -109,19 +110,19 @@
(defn- canvas-did-mount
[own]
(letfn [(on-mousemove [event page [offset-x offset-y]]
(let [x (.-clientX event)
y (.-clientY event)
(letfn [(on-mousemove [event page offset-pt]
(let [wpt (gpt/point (.-clientX event) (.-clientY event))
cpt (gpt/subtract wpt offset-pt)
event {:id (:id page)
:ctrl (kbd/ctrl? event)
:window-coords [x y]
:canvas-coords [(- x offset-x)
(- y offset-y)]}]
:shift (kbd/shift? event)
:window-coords wpt
:canvas-coords cpt}]
(rx/push! wb/mouse-b event)))]
(let [[page] (:rum/props own)
canvas (mx/get-ref-dom own (str "canvas" (:id page)))
brect (.getBoundingClientRect canvas)
brect [(.-left brect) (.-top brect)]
brect (gpt/point (.-left brect) (.-top brect))
key (events/listen js/document EventType.MOUSEMOVE
#(on-mousemove % page brect))]
(swap! wb/bounding-rect assoc (:id page) brect)

View file

@ -10,6 +10,7 @@
[uxbox.data.workspace :as dw]
[uxbox.ui.workspace.base :as wb]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom]))
(defonce +drawing-shape+ (atom nil))
@ -37,13 +38,13 @@
;; Subscriptions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FIXME: this works for now, but should be refactored when advanced rendering
;; is introduced such as polyline, polygon and path.
(define-once :drawing-subscriptions
(letfn [(init-shape [shape]
(let [[x y :as mpos] @wb/mouse-position
stop @wb/scroll-top
y (+ stop y)
(let [{:keys [x y]} (gpt/subtract @wb/mouse-position @wb/scroll)
shape (sh/-initialize shape {:x1 x :y1 y :x2 x :y2 y})]
(reset! +drawing-shape+ shape)
(reset! +drawing-position+ {:x2 x :y2 y :lock false})
@ -54,10 +55,9 @@
(rx/with-latest-from vector wb/mouse-ctrl-s $)
(rx/subscribe $ on-value nil on-complete))))
(on-value [[[x y :as pos] ctrl?]]
(let [stop @wb/scroll-top]
(reset! +drawing-position+
{:x2 x :y2 (+ y stop) :lock ctrl?})))
(on-value [[pos ctrl?]]
(let [{:keys [x y] :as pos} (gpt/subtract pos @wb/scroll)]
(reset! +drawing-position+ {:x2 x :y2 y :lock ctrl?})))
(on-complete []
(let [shape @+drawing-shape+
@ -69,9 +69,7 @@
(reset! +drawing-shape+ nil)))
(init-icon [shape]
(let [[x y] @wb/mouse-position
stop @wb/scroll-top
y (+ stop y)
(let [{:keys [x y]} (gpt/subtract @wb/mouse-position @wb/scroll)
props {:x1 x :y1 y :x2 (+ x 100) :y2 (+ y 100)}
shape (sh/-initialize shape props)]
(rs/emit! (dw/add-shape shape)

View file

@ -11,6 +11,7 @@
[uxbox.util.math :as mth]
[uxbox.ui.workspace.base :as wb]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -18,17 +19,17 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- resolve-position
[own [x y]]
[own pt]
(let [overlay (mx/get-ref-dom own "overlay")
brect (.getBoundingClientRect overlay)]
[(- x (.-left brect))
(- y (.-top brect))]))
brect (.getBoundingClientRect overlay)
bpt (gpt/point (.-left brect) (.-top brect))]
(gpt/subtract pt bpt)))
(defn- get-position
[own event]
(let [x (.-clientX event)
y (.-clientY event)]
(resolve-position own [x y])))
(->> (gpt/point (.-clientX event)
(.-clientY event))
(resolve-position own)))
(defn- on-mouse-down
[own local event]
@ -41,41 +42,77 @@
(dom/stop-propagation event)
(swap! local assoc :active false))
(defn- overlay-line-render
[own center pt]
(let [distance (-> (gpt/distance pt center)
(mth/precision 4))
angle (-> (gpt/angle pt center)
(mth/precision 4))
{x1 :x y1 :y} center
{x2 :x y2 :y} pt]
(html
[:g
[:line {:x1 x1 :y1 y1
:x2 x2 :y2 y2
:style {:cursor "cell"}
:stroke-width "2"
:stroke "red"}]
[:text
{:transform (str "translate(" (+ x2 15) "," (- y2 10) ")")}
[:tspan {:x "0" :dy="1.2em"}
(str "distance=" distance)]
[:tspan {:x "0" :y "20" :dy="1.2em"}
(str "angle=" angle)]]])))
(defn- overlay-render
[own local]
(let [[x1 y1 :as p1] (:pos1 @local)
[x2 y2 :as p2] (:pos2 @local)
distance (mth/distance p1 p2)]
(let [p1 (:pos1 @local)
p2 (:pos2 @local)]
(html
[:svg {:on-mouse-down #(on-mouse-down own local %)
:on-mouse-up #(on-mouse-up own local %)
:ref "overlay"}
[:rect {:style {:fill "transparent" :stroke "transparent" :cursor "cell"}
[:rect {:style {:fill "transparent"
:stroke "transparent"
:cursor "cell"}
:width wb/viewport-width
:height wb/viewport-height}]
(if (and x1 x2)
[:g
[:line {:x1 x1 :y1 y1 :x2 x2 :y2 y2
:style {:cursor "cell"}
:stroke-width "2"
:stroke "red"}]
[:text {:x (+ x2 15) :y y2}
[:tspan (str distance)]]])])))
(if (and p1 p2)
(overlay-line-render own p1 p2))])))
(def ^:private ^:static +immanted-zones+
(let [transform #(vector (- % 7) (+ % 7) %)]
(concat
(mapv transform (range 0 181 10))
(mapv (comp transform -) (range 0 181 10)))))
(defn- overlay-will-mount
[own local]
(letfn [(on-value [[[x y :as pos] ctrl?]]
(letfn [(align-position [angle pos]
(reduce (fn [pos [a1 a2 v]]
(if (< a1 angle a2)
(reduced (gpt/update-angle pos v))
pos))
pos
+immanted-zones+))
(on-value-aligned [pos2]
(let [center (:pos1 @local)]
(as-> pos2 $
(gpt/subtract $ center)
(align-position (gpt/angle $) $)
(gpt/add $ center)
(swap! local assoc :pos2 $))))
(on-value-simple [pos2]
(swap! local assoc :pos2 pos2))
(on-value [[pos ctrl?]]
(if ctrl?
(let [[sx sy] (:pos1 @local)
dx (mth/abs (- x sx))
dy (mth/abs (- y sy))]
(cond
(> dx dy) (swap! local assoc :pos2 [x sy])
(> dy dx) (swap! local assoc :pos2 [sx y])
:else (swap! local assoc :pos2 pos)))
(swap! local assoc :pos2 pos)))]
(on-value-aligned pos)
(on-value-simple pos)))]
(as-> wb/mouse-absolute-s $
(rx/dedupe $)
(rx/filter #(:active @local) $)
(rx/map #(resolve-position own %) $)
(rx/with-latest-from vector wb/mouse-ctrl-s $)

View file

@ -11,6 +11,7 @@
[uxbox.data.workspace :as dw]
[uxbox.ui.workspace.base :as wb]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom]))
(defonce selrect-pos (atom nil))
@ -46,10 +47,10 @@
[data]
(let [start (:start data)
current (:current data )
start-x (min (first start) (first current))
start-y (min (second start) (second current))
current-x (max (first start) (first current))
current-y (max (second start) (second current))
start-x (min (:x start) (:x current))
start-y (min (:y start) (:y current))
current-x (max (:x start) (:x current))
current-y (max (:y start) (:y current))
width (- current-x start-x)
height (- current-y start-y)]
{:x start-x
@ -58,9 +59,8 @@
:height (- current-y start-y)}))
(define-once :selrect-subscriptions
(letfn [(on-value [[x y :as pos]]
(let [scroll (or @wb/scroll-top 0)
pos [x (+ y scroll)]]
(letfn [(on-value [pos]
(let [pos (gpt/subtract pos @wb/scroll)]
(if (nil? @selrect-pos)
(reset! selrect-pos {:start pos :current pos})
(swap! selrect-pos assoc :current pos))))

View file

@ -7,6 +7,7 @@
[uxbox.data.workspace :as dw]
[uxbox.ui.icons :as i]
[uxbox.ui.mixins :as mx]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom]
[uxbox.ui.colorpicker :refer (colorpicker)]
[uxbox.ui.workspace.recent-colors :refer (recent-colors)]
@ -53,19 +54,12 @@
;; Helpers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- viewportcoord->clientcoord
[pageid viewport-x viewport-y]
(let [[offset-x offset-y] (get @wb/bounding-rect pageid)
new-x (+ viewport-x offset-x)
new-y (+ viewport-y offset-y)]
[new-x new-y]))
(defn- get-position
[{:keys [page] :as shape}]
(let [{:keys [x y width]} (sh/-outer-rect shape)
vx (+ x width 50)
vy (- y 50)]
(viewportcoord->clientcoord page vx vy)))
bpt (get @wb/bounding-rect page)
vpt (gpt/point (+ x width 50) (- y 50))]
(gpt/add vpt bpt)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Implementation
@ -496,16 +490,17 @@
(defn element-opts-render
[own shape]
(let [local (:rum/local own)
shape (rum/react shape)
[popup-x popup-y] (get-position shape)
scroll (or (rum/react wb/scroll-top) 0)
zoom 1
shape (rum/react shape)
scroll (rum/react wb/scroll)
pos (-> (get-position shape)
(gpt/subtract scroll)) ;; and multiply by zoom in future
menus (get +menus-map+ (:type shape))
active-menu (:menu @local (first menus))]
(when (seq menus)
(html
[:div#element-options.element-options
{:style {:left (* popup-x zoom) :top (- (* popup-y zoom) scroll)}}
{:style {:left (:x pos) :top (:y pos)}}
[:ul.element-icons
(for [menu-id (get +menus-map+ (:type shape))
:let [menu (get +menus-by-id+ menu-id)