0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-15 09:11:21 -05:00

Allows rotation for shapes

This commit is contained in:
alonso.torres 2020-12-22 17:44:51 +01:00
parent 5636881463
commit 84007e6ad1
10 changed files with 105 additions and 49 deletions

View file

@ -293,7 +293,9 @@
"Function that checks if a number is nil or nan. Will return 0 when not
valid and the number otherwise."
[v]
(if (or (not v) (mth/nan? v)) 0 v))
(if (or (not v)
(not (mth/finite? v))
(mth/nan? v)) 0 v))
(defmacro export

View file

@ -48,7 +48,7 @@
(us/assert #{:width :height} attr)
(us/assert number? value)
(let [{:keys [proportion proportion-lock]} shape
size (select-keys shape [:width :height])
size (select-keys (:selrect shape) [:width :height])
new-size (if-not proportion-lock
(assoc size attr value)
(if (= attr :width)
@ -260,6 +260,7 @@
(d/export gco/center-shape)
(d/export gco/center-selrect)
(d/export gco/center-rect)
(d/export gco/center-points)
(d/export gpr/rect->selrect)
(d/export gpr/rect->points)
(d/export gpr/points->selrect)
@ -268,7 +269,9 @@
(d/export gtr/transform-point-center)
(d/export gtr/transform-rect)
(d/export gtr/update-group-selrect)
(d/export gtr/transform-points)
;; PATHS
(d/export gsp/content->points)
(d/export gsp/content->selrect)
(d/export gsp/transform-content)

View file

@ -14,7 +14,13 @@
[app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.path :as gpa]
[app.common.geom.shapes.rect :as gpr]
[app.common.math :as mth]))
[app.common.math :as mth]
[app.common.data :as d]))
(defn- modif-rotation [shape]
(let [cur-rotation (d/check-num (:rotation shape))
delta-angle (d/check-num (get-in shape [:modifiers :rotation]))]
(mod (+ cur-rotation delta-angle) 360)))
(defn transform-matrix
"Returns a transformation matrix without changing the shape properties.
@ -191,18 +197,23 @@
(defn apply-transform-path
[shape transform]
(let [content (gpa/transform-content (:content shape) transform)
selrect (gpa/content->selrect content)
points (gpr/rect->points selrect)
;;rotation (mod (+ (:rotation shape 0)
;; (or (get-in shape [:modifiers :rotation]) 0))
;; 360)
]
;; Calculate the new selrect by "unrotate" the shape
rotation (modif-rotation shape)
center (gpt/transform (gco/center-shape shape) transform)
content-rotated (gpa/transform-content content (gmt/rotate-matrix (- rotation) center))
selrect (gpa/content->selrect content-rotated)
;; Transform the points
points (-> (:points shape)
(transform-points transform))]
(assoc shape
:content content
:points points
:selrect selrect
;;:rotation rotation
)))
:transform (gmt/rotate-matrix rotation)
:transform-inverse (gmt/rotate-matrix (- rotation))
:rotation rotation)))
(defn apply-transform-rect
"Given a new set of points transformed, set up the rectangle so it keeps

View file

@ -1038,9 +1038,12 @@
(let [page-id (:current-page-id state)
objects (dwc/lookup-page-objects state page-id)
shape (get objects id)
cpos (gpt/point (:x shape) (:y shape))
pos (gpt/point (or (:x position) (:x shape))
(or (:y position) (:y shape)))
bbox (-> shape :points gsh/points->selrect)
cpos (gpt/point (:x bbox) (:y bbox))
pos (gpt/point (or (:x position) (:x bbox))
(or (:y position) (:y bbox)))
displ (gmt/translate-matrix (gpt/subtract pos cpos))]
(rx/of (dwt/set-modifiers [id] {:displacement displ})
(dwt/apply-modifiers [id]))))))
@ -1544,6 +1547,7 @@
(d/export dwt/start-move-selected)
(d/export dwt/move-selected)
(d/export dwt/set-rotation)
(d/export dwt/increase-rotation)
(d/export dwt/set-modifiers)
(d/export dwt/apply-modifiers)
(d/export dwt/update-dimensions)

View file

@ -16,6 +16,7 @@
[app.common.math :as mth]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.geom.matrix :as gmt]
[app.util.data :as ud]
[app.common.data :as cd]
[app.util.geom.path :as ugp]
@ -87,12 +88,37 @@
[:workspace-drawing :object])
path)))
(defn- points->components [shape content]
(let [rotation (:rotation shape 0)
center (gsh/center-shape shape)
content-rotated (gsh/transform-content content (gmt/rotate-matrix (- rotation) center))
;; Calculates the new selrect with points given the old center
points (-> (gsh/content->selrect content-rotated)
(gsh/rect->points)
(gsh/transform-points center (:transform shape (gmt/matrix))))
points-center (gsh/center-points points)
;; Points is now the selrect but the center is different so we can create the selrect
;; through points
selrect (-> points
(gsh/transform-points points-center (:transform-inverse shape (gmt/matrix)))
(gsh/points->selrect))]
[points selrect]))
(defn update-selrect
"Updates the selrect and points for a path"
[shape]
(let [selrect (gsh/content->selrect (:content shape))
points (gsh/rect->points selrect)]
(assoc shape :points points :selrect selrect)))
(if (= (:rotation shape 0) 0)
(let [content (:content shape)
selrect (gsh/content->selrect content)
points (gsh/rect->points selrect)]
(assoc shape :points points :selrect selrect))
(let [content (:content shape)
[points selrect] (points->components shape content)]
(assoc shape :points points :selrect selrect))))
(defn closest-angle [angle]
(cond
@ -157,13 +183,12 @@
;; TODO: Enter now finish path but can finish drawing/editing as well
(= enter-keycode (:key event)))))
(defn generate-path-changes [page-id shape-id old-content new-content]
(defn generate-path-changes [page-id shape old-content new-content]
(us/verify ::content old-content)
(us/verify ::content new-content)
(let [old-selrect (gsh/content->selrect old-content)
old-points (gsh/rect->points old-selrect)
new-selrect (gsh/content->selrect new-content)
new-points (gsh/rect->points new-selrect)
(let [shape-id (:id shape)
[old-points old-selrect] (points->components shape old-content)
[new-points new-selrect] (points->components shape new-content)
rch [{:type :mod-obj
:id shape-id
@ -393,7 +418,7 @@
shape (get-in state (get-path state))
selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{})
new-content (reduce ugp/make-corner-point (:content shape) selected-points)
[rch uch] (generate-path-changes page-id id (:content shape) new-content)]
[rch uch] (generate-path-changes page-id shape (:content shape) new-content)]
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
(defn make-curve []
@ -405,7 +430,7 @@
shape (get-in state (get-path state))
selected-points (get-in state [:workspace-local :edit-path id :selected-points] #{})
new-content (reduce ugp/make-curve-point (:content shape) selected-points)
[rch uch] (generate-path-changes page-id id (:content shape) new-content)]
[rch uch] (generate-path-changes page-id shape (:content shape) new-content)]
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
(defn path-handler-enter [index prefix]
@ -552,7 +577,7 @@
shape (get-in state (get-path state))
content-modifiers (get-in state [:workspace-local :edit-path id :content-modifiers])
new-content (ugp/apply-content-modifiers (:content shape) content-modifiers)
[rch uch] (generate-path-changes page-id (:id shape) (:content shape) new-content)]
[rch uch] (generate-path-changes page-id shape (:content shape) new-content)]
(rx/of (dwc/commit-changes rch uch {:commit-local? true})
(fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers)))))))
@ -573,7 +598,7 @@
shape (get-in state (get-path state))
page-id (:current-page-id state)
old-content (get-in state [:workspace-local :edit-path id :old-content])
[rch uch] (generate-path-changes page-id id old-content (:content shape))]
[rch uch] (generate-path-changes page-id shape old-content (:content shape))]
(rx/of (dwc/commit-changes rch uch {:commit-local? true}))))))
(declare start-draw-mode)

View file

@ -431,6 +431,20 @@
(let [page-id (:current-page-id state)]
(d/update-in-when state [:workspace-data :pages-index page-id :objects] set-rotation)))))))
(defn increase-rotation [ids rotation]
(ptk/reify ::increase-rotation
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (dwc/lookup-page-objects state page-id)
rotate-shape (fn [shape]
(let [delta (- rotation (:rotation shape))]
(set-rotation delta [shape])))]
(rx/concat
(rx/from (->> ids (map #(get objects %)) (map rotate-shape)))
(rx/of (apply-modifiers ids)))))))
(defn apply-modifiers
[ids]
(us/verify (s/coll-of uuid?) ids)

View file

@ -13,7 +13,6 @@
[rumext.alpha :as mf]
[app.main.ui.shapes.attrs :as attrs]
[app.main.ui.shapes.custom-stroke :refer [shape-custom-stroke]]
[app.common.geom.shapes :as geom]
[app.util.object :as obj]
[app.util.geom.path :as ugp]))
@ -24,14 +23,11 @@
[props]
(let [shape (unchecked-get props "shape")
background? (unchecked-get props "background?")
;; {:keys [id x y width height]} (geom/shape->rect-shape shape)
{:keys [id x y width height]} (:selrect shape)
transform (geom/transform-matrix shape)
pdata (ugp/content->path (:content shape))
props (-> (attrs/extract-style-attrs shape)
(obj/merge!
#js {:transform transform
:d pdata}))]
#js {:d pdata}))]
(if background?
[:g
[:path {:stroke "transparent"

View file

@ -44,16 +44,17 @@
(def selection-rect-width 1)
(mf/defc selection-rect [{:keys [transform rect zoom color]}]
(let [{:keys [x y width height]} rect]
[:rect.main
{:x x
:y y
:width width
:height height
:transform transform
:style {:stroke color
:stroke-width (/ selection-rect-width zoom)
:fill "transparent"}}]))
(when rect
(let [{:keys [x y width height]} rect]
[:rect.main
{:x x
:y y
:width width
:height height
:transform transform
:style {:stroke color
:stroke-width (/ selection-rect-width zoom)
:fill "transparent"}}])))
(defn- handlers-for-selection [{:keys [x y width height]}]
[;; TOP-LEFT
@ -181,9 +182,7 @@
current-transform (mf/deref refs/current-transform)
selrect (:selrect shape)
transform (geom/transform-matrix shape {:no-flip true})
tr-shape (geom/transform-shape shape)]
transform (geom/transform-matrix shape {:no-flip true})]
(when (not (#{:move :rotate} current-transform))
[:g.controls
@ -193,7 +192,7 @@
:transform transform
:zoom zoom
:color color}]
[:& outline {:shape tr-shape :color color}]
[:& outline {:shape shape :color color}]
;; Handlers
(for [{:keys [type position props]} (handlers-for-selection selrect)]

View file

@ -35,11 +35,12 @@
:stroke-width "1px"
:stroke-opacity 0.5}]]))
(mf/defc render-rect [{{:keys [x y width height]} :rect :keys [color]}]
(mf/defc render-rect [{{:keys [x y width height]} :rect :keys [color transform]}]
[:rect {:x x
:y y
:width width
:height height
:transform (or transform "none")
:style {:stroke color
:fill "transparent"
:stroke-width "1px"
@ -76,7 +77,7 @@
:fill line-color
:stroke "white"
:stroke-width 0.1}
(str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x shape)) (fixed (:y shape)))]
(str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x selrect)) (fixed (:y selrect)))]
[:& cross-point {:point shape-center
:zoom zoom
@ -87,7 +88,7 @@
:zoom zoom
:color line-color}])
[:& render-rect-points {:rect selrect
[:& render-rect-points {:points (:points shape)
:color line-color}]
[:& render-rect {:rect selrect

View file

@ -45,7 +45,8 @@
:ry (/ height 2)}
:path
{:d (ugp/content->path (:content shape))}
{:d (ugp/content->path (:content shape))
:transform nil}
{:x x
:y y