mirror of
https://github.com/penpot/penpot.git
synced 2025-02-18 21:06:11 -05:00
Merge pull request #624 from penpot/feature/flip
Adds flip vertical/horizontal commands
This commit is contained in:
commit
8e5fd5892e
13 changed files with 181 additions and 120 deletions
|
@ -7,6 +7,7 @@
|
||||||
- Add images lock proportions by default [#541](https://github.com/penpot/penpot/discussions/541), [#609](https://github.com/penpot/penpot/issues/609)
|
- Add images lock proportions by default [#541](https://github.com/penpot/penpot/discussions/541), [#609](https://github.com/penpot/penpot/issues/609)
|
||||||
- Shows a pixel grid when zoom greater than 800% [#519](https://github.com/penpot/penpot/discussions/519)
|
- Shows a pixel grid when zoom greater than 800% [#519](https://github.com/penpot/penpot/discussions/519)
|
||||||
- Increase default deletion delay to 7 days.
|
- Increase default deletion delay to 7 days.
|
||||||
|
- Flip horizontal/vertical
|
||||||
- Zstd+nippy based blob storage format
|
- Zstd+nippy based blob storage format
|
||||||
- Improved component testing
|
- Improved component testing
|
||||||
- Add user feedback form
|
- Add user feedback form
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
### Bugs fixed
|
### Bugs fixed
|
||||||
|
|
||||||
- Make the team deletion defferred (in the same way other objects).
|
- Make the team deletion defferred (in the same way other objects).
|
||||||
|
- Problems when transforming path shapes
|
||||||
- Fix 500 when requestion password reset
|
- Fix 500 when requestion password reset
|
||||||
- Fix ldap function called on login click
|
- Fix ldap function called on login click
|
||||||
- Fix issues when moving shapes outside groups
|
- Fix issues when moving shapes outside groups
|
||||||
|
|
|
@ -12,6 +12,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.math :refer [close?]]
|
||||||
[app.common.pages :refer [make-minimal-shape]]
|
[app.common.pages :refer [make-minimal-shape]]
|
||||||
[clojure.test :as t]))
|
[clojure.test :as t]))
|
||||||
|
|
||||||
|
@ -32,7 +33,9 @@
|
||||||
:points points)))
|
:points points)))
|
||||||
|
|
||||||
(defn add-rect-data [shape]
|
(defn add-rect-data [shape]
|
||||||
(let [selrect (gsh/rect->selrect shape)
|
(let [shape (-> shape
|
||||||
|
(assoc :width 20 :height 20))
|
||||||
|
selrect (gsh/rect->selrect shape)
|
||||||
points (gsh/rect->points selrect)]
|
points (gsh/rect->points selrect)]
|
||||||
(assoc shape
|
(assoc shape
|
||||||
:selrect selrect
|
:selrect selrect
|
||||||
|
@ -64,16 +67,16 @@
|
||||||
shape-after (gsh/transform-shape shape-before)]
|
shape-after (gsh/transform-shape shape-before)]
|
||||||
(t/is (not= shape-before shape-after))
|
(t/is (not= shape-before shape-after))
|
||||||
|
|
||||||
(t/is (== (get-in shape-before [:selrect :x])
|
(t/is (close? (get-in shape-before [:selrect :x])
|
||||||
(- 10 (get-in shape-after [:selrect :x]))))
|
(- 10 (get-in shape-after [:selrect :x]))))
|
||||||
|
|
||||||
(t/is (== (get-in shape-before [:selrect :y])
|
(t/is (close? (get-in shape-before [:selrect :y])
|
||||||
(+ 10 (get-in shape-after [:selrect :y]))))
|
(+ 10 (get-in shape-after [:selrect :y]))))
|
||||||
|
|
||||||
(t/is (== (get-in shape-before [:selrect :width])
|
(t/is (close? (get-in shape-before [:selrect :width])
|
||||||
(get-in shape-after [:selrect :width])))
|
(get-in shape-after [:selrect :width])))
|
||||||
|
|
||||||
(t/is (== (get-in shape-before [:selrect :height])
|
(t/is (close? (get-in shape-before [:selrect :height])
|
||||||
(get-in shape-after [:selrect :height])))))
|
(get-in shape-after [:selrect :height])))))
|
||||||
|
|
||||||
:rect :path))
|
:rect :path))
|
||||||
|
@ -84,7 +87,7 @@
|
||||||
shape-before (create-test-shape type {:modifiers modifiers})
|
shape-before (create-test-shape type {:modifiers modifiers})
|
||||||
shape-after (gsh/transform-shape shape-before)]
|
shape-after (gsh/transform-shape shape-before)]
|
||||||
(t/are [prop]
|
(t/are [prop]
|
||||||
(t/is (== (get-in shape-before [:selrect prop])
|
(t/is (close? (get-in shape-before [:selrect prop])
|
||||||
(get-in shape-after [:selrect prop])))
|
(get-in shape-after [:selrect prop])))
|
||||||
:x :y :width :height :x1 :y1 :x2 :y2))
|
:x :y :width :height :x1 :y1 :x2 :y2))
|
||||||
:rect :path))
|
:rect :path))
|
||||||
|
@ -98,16 +101,16 @@
|
||||||
shape-after (gsh/transform-shape shape-before)]
|
shape-after (gsh/transform-shape shape-before)]
|
||||||
(t/is (not= shape-before shape-after))
|
(t/is (not= shape-before shape-after))
|
||||||
|
|
||||||
(t/is (== (get-in shape-before [:selrect :x])
|
(t/is (close? (get-in shape-before [:selrect :x])
|
||||||
(get-in shape-after [:selrect :x])))
|
(get-in shape-after [:selrect :x])))
|
||||||
|
|
||||||
(t/is (== (get-in shape-before [:selrect :y])
|
(t/is (close? (get-in shape-before [:selrect :y])
|
||||||
(get-in shape-after [:selrect :y])))
|
(get-in shape-after [:selrect :y])))
|
||||||
|
|
||||||
(t/is (== (* 2 (get-in shape-before [:selrect :width]))
|
(t/is (close? (* 2 (get-in shape-before [:selrect :width]))
|
||||||
(get-in shape-after [:selrect :width])))
|
(get-in shape-after [:selrect :width])))
|
||||||
|
|
||||||
(t/is (== (* 2 (get-in shape-before [:selrect :height]))
|
(t/is (close? (* 2 (get-in shape-before [:selrect :height]))
|
||||||
(get-in shape-after [:selrect :height]))))
|
(get-in shape-after [:selrect :height]))))
|
||||||
:rect :path))
|
:rect :path))
|
||||||
|
|
||||||
|
@ -119,7 +122,7 @@
|
||||||
shape-before (create-test-shape type {:modifiers modifiers})
|
shape-before (create-test-shape type {:modifiers modifiers})
|
||||||
shape-after (gsh/transform-shape shape-before)]
|
shape-after (gsh/transform-shape shape-before)]
|
||||||
(t/are [prop]
|
(t/are [prop]
|
||||||
(t/is (== (get-in shape-before [:selrect prop])
|
(t/is (close? (get-in shape-before [:selrect prop])
|
||||||
(get-in shape-after [:selrect prop])))
|
(get-in shape-after [:selrect prop])))
|
||||||
:x :y :width :height :x1 :y1 :x2 :y2))
|
:x :y :width :height :x1 :y1 :x2 :y2))
|
||||||
:rect :path))
|
:rect :path))
|
||||||
|
@ -145,13 +148,23 @@
|
||||||
(let [modifiers {:rotation 30}
|
(let [modifiers {:rotation 30}
|
||||||
shape-before (create-test-shape type {:modifiers modifiers})
|
shape-before (create-test-shape type {:modifiers modifiers})
|
||||||
shape-after (gsh/transform-shape shape-before)]
|
shape-after (gsh/transform-shape shape-before)]
|
||||||
|
|
||||||
(t/is (not= shape-before shape-after))
|
(t/is (not= shape-before shape-after))
|
||||||
|
|
||||||
(t/is (not (== (get-in shape-before [:selrect :x])
|
;; Selrect won't change with a rotation, but points will
|
||||||
(get-in shape-after [:selrect :x]))))
|
(t/is (close? (get-in shape-before [:selrect :x])
|
||||||
|
(get-in shape-after [:selrect :x])))
|
||||||
|
|
||||||
(t/is (not (== (get-in shape-before [:selrect :y])
|
(t/is (close? (get-in shape-before [:selrect :y])
|
||||||
(get-in shape-after [:selrect :y])))))
|
(get-in shape-after [:selrect :y])))
|
||||||
|
|
||||||
|
(t/is (= (count (:points shape-before)) (count (:points shape-after))))
|
||||||
|
|
||||||
|
(for [idx (range 0 (count (:point shape-before)))]
|
||||||
|
(do (t/is (not (close? (get-in shape-before [:points idx :x])
|
||||||
|
(get-in shape-after [:points idx :x]))))
|
||||||
|
(t/is (not (close? (get-in shape-before [:points idx :y])
|
||||||
|
(get-in shape-after [:points idx :y])))))))
|
||||||
:rect :path))
|
:rect :path))
|
||||||
|
|
||||||
(t/testing "Transform shape with rotation = 0 should leave equal selrect"
|
(t/testing "Transform shape with rotation = 0 should leave equal selrect"
|
||||||
|
@ -160,7 +173,7 @@
|
||||||
shape-before (create-test-shape type {:modifiers modifiers})
|
shape-before (create-test-shape type {:modifiers modifiers})
|
||||||
shape-after (gsh/transform-shape shape-before)]
|
shape-after (gsh/transform-shape shape-before)]
|
||||||
(t/are [prop]
|
(t/are [prop]
|
||||||
(t/is (== (get-in shape-before [:selrect prop])
|
(t/is (close? (get-in shape-before [:selrect prop])
|
||||||
(get-in shape-after [:selrect prop])))
|
(get-in shape-after [:selrect prop])))
|
||||||
:x :y :width :height :x1 :y1 :x2 :y2))
|
:x :y :width :height :x1 :y1 :x2 :y2))
|
||||||
:rect :path))
|
:rect :path))
|
||||||
|
|
|
@ -134,3 +134,9 @@
|
||||||
(th-eq m1f m2f))))
|
(th-eq m1f m2f))))
|
||||||
|
|
||||||
(defmethod pp/simple-dispatch Matrix [obj] (pr obj))
|
(defmethod pp/simple-dispatch Matrix [obj] (pr obj))
|
||||||
|
|
||||||
|
(defn transform-in [pt mtx]
|
||||||
|
(-> (matrix)
|
||||||
|
(translate pt)
|
||||||
|
(multiply mtx)
|
||||||
|
(translate (gpt/negate pt))))
|
||||||
|
|
|
@ -43,10 +43,13 @@
|
||||||
(let [shape-center (or (gco/center-shape shape)
|
(let [shape-center (or (gco/center-shape shape)
|
||||||
(gpt/point 0 0))]
|
(gpt/point 0 0))]
|
||||||
(inverse-transform-matrix shape shape-center)))
|
(inverse-transform-matrix shape shape-center)))
|
||||||
([shape center]
|
([{:keys [flip-x flip-y] :as shape} center]
|
||||||
(let []
|
(let []
|
||||||
(-> (gmt/matrix)
|
(-> (gmt/matrix)
|
||||||
(gmt/translate center)
|
(gmt/translate center)
|
||||||
|
(cond->
|
||||||
|
flip-x (gmt/scale (gpt/point -1 1))
|
||||||
|
flip-y (gmt/scale (gpt/point 1 -1)))
|
||||||
(gmt/multiply (:transform-inverse shape (gmt/matrix)))
|
(gmt/multiply (:transform-inverse shape (gmt/matrix)))
|
||||||
(gmt/translate (gpt/negate center))))))
|
(gmt/translate (gpt/negate center))))))
|
||||||
|
|
||||||
|
@ -203,29 +206,7 @@
|
||||||
(gmt/rotate (- rotation-angle)))]
|
(gmt/rotate (- rotation-angle)))]
|
||||||
[stretch-matrix stretch-matrix-inverse]))
|
[stretch-matrix stretch-matrix-inverse]))
|
||||||
|
|
||||||
|
(defn apply-transform
|
||||||
(defn apply-transform-path
|
|
||||||
[shape transform]
|
|
||||||
(let [content (gpa/transform-content (:content shape) transform)
|
|
||||||
|
|
||||||
;; 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
|
|
||||||
: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
|
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||||
its properties. We adjust de x,y,width,height and create a custom transform"
|
its properties. We adjust de x,y,width,height and create a custom transform"
|
||||||
[shape transform]
|
[shape transform]
|
||||||
|
@ -246,13 +227,21 @@
|
||||||
(:height points-temp-dim))
|
(:height points-temp-dim))
|
||||||
rect-points (gpr/rect->points rect-shape)
|
rect-points (gpr/rect->points rect-shape)
|
||||||
|
|
||||||
[matrix matrix-inverse] (calculate-adjust-matrix points-temp rect-points (:flip-x shape) (:flip-y shape))]
|
[matrix matrix-inverse] (calculate-adjust-matrix points-temp rect-points (:flip-x shape) (:flip-y shape))
|
||||||
|
|
||||||
|
shape (cond
|
||||||
|
(= :path (:type shape))
|
||||||
|
(-> shape
|
||||||
|
(update :content #(gpa/transform-content % transform)))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(-> shape
|
||||||
|
(merge rect-shape)
|
||||||
|
(update :x #(mth/precision % 0))
|
||||||
|
(update :y #(mth/precision % 0))
|
||||||
|
(update :width #(mth/precision % 0))
|
||||||
|
(update :height #(mth/precision % 0))))]
|
||||||
(as-> shape $
|
(as-> shape $
|
||||||
(merge $ rect-shape)
|
|
||||||
(update $ :x #(mth/precision % 0))
|
|
||||||
(update $ :y #(mth/precision % 0))
|
|
||||||
(update $ :width #(mth/precision % 0))
|
|
||||||
(update $ :height #(mth/precision % 0))
|
|
||||||
(update $ :transform #(gmt/multiply (or % (gmt/matrix)) matrix))
|
(update $ :transform #(gmt/multiply (or % (gmt/matrix)) matrix))
|
||||||
(update $ :transform-inverse #(gmt/multiply matrix-inverse (or % (gmt/matrix))))
|
(update $ :transform-inverse #(gmt/multiply matrix-inverse (or % (gmt/matrix))))
|
||||||
(assoc $ :points (into [] points))
|
(assoc $ :points (into [] points))
|
||||||
|
@ -260,37 +249,6 @@
|
||||||
(update $ :rotation #(mod (+ (or % 0)
|
(update $ :rotation #(mod (+ (or % 0)
|
||||||
(or (get-in $ [:modifiers :rotation]) 0)) 360)))))
|
(or (get-in $ [:modifiers :rotation]) 0)) 360)))))
|
||||||
|
|
||||||
(defn apply-transform [shape transform]
|
|
||||||
(let [apply-transform-fn
|
|
||||||
(case (:type shape)
|
|
||||||
:path apply-transform-path
|
|
||||||
apply-transform-rect)]
|
|
||||||
(apply-transform-fn shape transform)))
|
|
||||||
|
|
||||||
(defn transform-gradients [shape modifiers]
|
|
||||||
(let [angle (d/check-num (get modifiers :rotation))
|
|
||||||
;; Gradients are represented with unit vectors so its center is 0.5, 0.5
|
|
||||||
center (gpt/point 0.5 0.5)
|
|
||||||
transform (gmt/rotate-matrix angle center)
|
|
||||||
transform-gradient
|
|
||||||
(fn [{:keys [start-x start-y end-x end-y] :as gradient}]
|
|
||||||
(let [start-point (gpt/point start-x start-y)
|
|
||||||
end-point (gpt/point end-x end-y)
|
|
||||||
{start-x :x start-y :y} (gpt/transform start-point transform)
|
|
||||||
{end-x :x end-y :y} (gpt/transform end-point transform)]
|
|
||||||
|
|
||||||
(assoc gradient
|
|
||||||
:start-x start-x
|
|
||||||
:start-y start-y
|
|
||||||
:end-x end-x
|
|
||||||
:end-y end-y)))]
|
|
||||||
(cond-> shape
|
|
||||||
(:fill-color-gradient shape)
|
|
||||||
(update :fill-color-gradient transform-gradient)
|
|
||||||
|
|
||||||
(:stroke-color-gradient shape)
|
|
||||||
(update :stroke-color-gradient transform-gradient))))
|
|
||||||
|
|
||||||
(defn set-flip [shape modifiers]
|
(defn set-flip [shape modifiers]
|
||||||
(let [rx (get-in modifiers [:resize-vector :x])
|
(let [rx (get-in modifiers [:resize-vector :x])
|
||||||
ry (get-in modifiers [:resize-vector :y])]
|
ry (get-in modifiers [:resize-vector :y])]
|
||||||
|
@ -305,12 +263,13 @@
|
||||||
(-> shape
|
(-> shape
|
||||||
(set-flip (:modifiers shape))
|
(set-flip (:modifiers shape))
|
||||||
(apply-transform transform)
|
(apply-transform transform)
|
||||||
(transform-gradients (:modifiers shape))
|
|
||||||
(dissoc :modifiers)))
|
(dissoc :modifiers)))
|
||||||
shape)))
|
shape)))
|
||||||
|
|
||||||
(defn update-group-selrect [group children]
|
(defn update-group-selrect [group children]
|
||||||
(let [shape-center (gco/center-shape group)
|
(let [shape-center (gco/center-shape group)
|
||||||
|
transform (:transform group (gmt/matrix))
|
||||||
|
transform-inverse (:transform-inverse group (gmt/matrix))
|
||||||
|
|
||||||
;; Points for every shape inside the group
|
;; Points for every shape inside the group
|
||||||
points (->> children (mapcat :points))
|
points (->> children (mapcat :points))
|
||||||
|
@ -330,5 +289,10 @@
|
||||||
(-> group
|
(-> group
|
||||||
(assoc :selrect new-selrect)
|
(assoc :selrect new-selrect)
|
||||||
(assoc :points new-points)
|
(assoc :points new-points)
|
||||||
(apply-transform-rect (gmt/matrix)))))
|
|
||||||
|
;; We're regenerating the selrect from its children so we
|
||||||
|
;; need to remove the flip flags
|
||||||
|
(assoc :flip-x false)
|
||||||
|
(assoc :flip-y false)
|
||||||
|
(apply-transform (gmt/matrix)))))
|
||||||
|
|
||||||
|
|
|
@ -142,3 +142,10 @@
|
||||||
|
|
||||||
(defn almost-zero? [num]
|
(defn almost-zero? [num]
|
||||||
(< (abs num) 1e-8))
|
(< (abs num) 1e-8))
|
||||||
|
|
||||||
|
(defonce float-equal-precision 0.001)
|
||||||
|
|
||||||
|
(defn close?
|
||||||
|
"Equality for float numbers. Check if the difference is within a range"
|
||||||
|
[num1 num2]
|
||||||
|
(<= (abs (- num1 num2)) float-equal-precision))
|
||||||
|
|
|
@ -4805,5 +4805,19 @@
|
||||||
"es" : "Pulsar para cerrar la ruta"
|
"es" : "Pulsar para cerrar la ruta"
|
||||||
},
|
},
|
||||||
"unused" : true
|
"unused" : true
|
||||||
|
},
|
||||||
|
"workspace.shape.menu.flip-horizontal" : {
|
||||||
|
"used-in" : [ "src/app/main/ui/workspace/context_menu.cljs:146" ],
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Flip horizontal",
|
||||||
|
"es" : "Voltear horizontal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspace.shape.menu.flip-vertical" : {
|
||||||
|
"used-in" : [ "src/app/main/ui/workspace/context_menu.cljs:143" ],
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Flip vertical",
|
||||||
|
"es" : "Voltear vertical"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1799,6 +1799,8 @@
|
||||||
(d/export dwt/set-modifiers)
|
(d/export dwt/set-modifiers)
|
||||||
(d/export dwt/apply-modifiers)
|
(d/export dwt/apply-modifiers)
|
||||||
(d/export dwt/update-dimensions)
|
(d/export dwt/update-dimensions)
|
||||||
|
(d/export dwt/flip-horizontal-selected)
|
||||||
|
(d/export dwt/flip-vertical-selected)
|
||||||
|
|
||||||
;; Persistence
|
;; Persistence
|
||||||
|
|
||||||
|
|
|
@ -90,12 +90,15 @@
|
||||||
path)))
|
path)))
|
||||||
|
|
||||||
(defn- points->components [shape content]
|
(defn- points->components [shape content]
|
||||||
(let [rotation (:rotation shape 0)
|
(let [transform (:transform shape)
|
||||||
|
transform-inverse (:transform-inverse shape)
|
||||||
center (gsh/center-shape shape)
|
center (gsh/center-shape shape)
|
||||||
content-rotated (gsh/transform-content content (gmt/rotate-matrix (- rotation) center))
|
base-content (gsh/transform-content
|
||||||
|
content
|
||||||
|
(gmt/transform-in center transform-inverse))
|
||||||
|
|
||||||
;; Calculates the new selrect with points given the old center
|
;; Calculates the new selrect with points given the old center
|
||||||
points (-> (gsh/content->selrect content-rotated)
|
points (-> (gsh/content->selrect base-content)
|
||||||
(gsh/rect->points)
|
(gsh/rect->points)
|
||||||
(gsh/transform-points center (:transform shape (gmt/matrix))))
|
(gsh/transform-points center (:transform shape (gmt/matrix))))
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,14 @@
|
||||||
:command (ds/c-mod "k")
|
:command (ds/c-mod "k")
|
||||||
:fn #(st/emit! dwl/add-component)}
|
:fn #(st/emit! dwl/add-component)}
|
||||||
|
|
||||||
|
:flip-vertical {:tooltip (ds/shift "V")
|
||||||
|
:command "shift+v"
|
||||||
|
:fn #(st/emit! (dw/flip-vertical-selected))}
|
||||||
|
|
||||||
|
:flip-horizontal {:tooltip (ds/shift "V")
|
||||||
|
:command "shift+h"
|
||||||
|
:fn #(st/emit! (dw/flip-horizontal-selected))}
|
||||||
|
|
||||||
:reset-zoom {:tooltip (ds/shift "0")
|
:reset-zoom {:tooltip (ds/shift "0")
|
||||||
:command "shift+0"
|
:command "shift+0"
|
||||||
:fn #(st/emit! dw/reset-zoom)}
|
:fn #(st/emit! dw/reset-zoom)}
|
||||||
|
|
|
@ -82,8 +82,6 @@
|
||||||
{:keys [rotation]} shape
|
{:keys [rotation]} shape
|
||||||
shapev (-> (gpt/point width height))
|
shapev (-> (gpt/point width height))
|
||||||
|
|
||||||
rotation (if (= :path (:type shape)) 0 rotation)
|
|
||||||
|
|
||||||
;; Vector modifiers depending on the handler
|
;; Vector modifiers depending on the handler
|
||||||
handler-modif (let [[x y] (handler-modifiers handler)] (gpt/point x y))
|
handler-modif (let [[x y] (handler-modifiers handler)] (gpt/point x y))
|
||||||
|
|
||||||
|
@ -125,15 +123,7 @@
|
||||||
;; lock flag that can be activated on element options.
|
;; lock flag that can be activated on element options.
|
||||||
(normalize-proportion-lock [[point shift?]]
|
(normalize-proportion-lock [[point shift?]]
|
||||||
(let [proportion-lock? (:proportion-lock shape)]
|
(let [proportion-lock? (:proportion-lock shape)]
|
||||||
[point (or proportion-lock? shift?)]))
|
[point (or proportion-lock? shift?)]))]
|
||||||
|
|
||||||
;; Applies alginment to point if it is currently
|
|
||||||
;; activated on the current workspace
|
|
||||||
;; (apply-grid-alignment [point]
|
|
||||||
;; (if @refs/selected-alignment
|
|
||||||
;; (uwrk/align-point point)
|
|
||||||
;; (rx/of point)))
|
|
||||||
]
|
|
||||||
(reify
|
(reify
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
@ -142,8 +132,7 @@
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [current-pointer @ms/mouse-position
|
(let [initial-position @ms/mouse-position
|
||||||
initial-position (merge current-pointer initial)
|
|
||||||
stoper (rx/filter ms/mouse-up? stream)
|
stoper (rx/filter ms/mouse-up? stream)
|
||||||
layout (:workspace-layout state)
|
layout (:workspace-layout state)
|
||||||
page-id (:current-page-id state)
|
page-id (:current-page-id state)
|
||||||
|
@ -541,3 +530,37 @@
|
||||||
objects (dwc/lookup-page-objects state page-id)
|
objects (dwc/lookup-page-objects state page-id)
|
||||||
ids (d/concat [] ids (mapcat #(cp/get-children % objects) ids))]
|
ids (d/concat [] ids (mapcat #(cp/get-children % objects) ids))]
|
||||||
(rx/of (apply-modifiers ids))))))
|
(rx/of (apply-modifiers ids))))))
|
||||||
|
|
||||||
|
(defn flip-horizontal-selected []
|
||||||
|
(ptk/reify ::flip-horizontal-selected
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [objects (dwc/lookup-page-objects state)
|
||||||
|
selected (get-in state [:workspace-local :selected])
|
||||||
|
shapes (map #(get objects %) selected)
|
||||||
|
selrect (gsh/selection-rect (->> shapes (map gsh/transform-shape)))
|
||||||
|
origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2)))]
|
||||||
|
|
||||||
|
(rx/of (set-modifiers selected
|
||||||
|
{:resize-vector (gpt/point -1.0 1.0)
|
||||||
|
:resize-origin origin
|
||||||
|
:displacement (gmt/translate-matrix (gpt/point (- (:width selrect)) 0))}
|
||||||
|
false)
|
||||||
|
(apply-modifiers selected))))))
|
||||||
|
|
||||||
|
(defn flip-vertical-selected []
|
||||||
|
(ptk/reify ::flip-vertical-selected
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [objects (dwc/lookup-page-objects state)
|
||||||
|
selected (get-in state [:workspace-local :selected])
|
||||||
|
shapes (map #(get objects %) selected)
|
||||||
|
selrect (gsh/selection-rect (->> shapes (map gsh/transform-shape)))
|
||||||
|
origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect))]
|
||||||
|
|
||||||
|
(rx/of (set-modifiers selected
|
||||||
|
{:resize-vector (gpt/point 1.0 -1.0)
|
||||||
|
:resize-origin origin
|
||||||
|
:displacement (gmt/translate-matrix (gpt/point 0 (- (:height selrect))))}
|
||||||
|
false)
|
||||||
|
(apply-modifiers selected))))))
|
||||||
|
|
|
@ -20,15 +20,13 @@
|
||||||
|
|
||||||
(mf/defc linear-gradient [{:keys [id gradient shape]}]
|
(mf/defc linear-gradient [{:keys [id gradient shape]}]
|
||||||
(let [{:keys [x y width height]} (:selrect shape)
|
(let [{:keys [x y width height]} (:selrect shape)
|
||||||
transform (case (:type shape)
|
transform (when (= :path (:type shape)) (gsh/transform-matrix shape nil (gpt/point 0.5 0.5)))]
|
||||||
:path (gmt/matrix)
|
|
||||||
(gsh/inverse-transform-matrix shape (gpt/point 0.5 0.5)))]
|
|
||||||
[:linearGradient {:id id
|
[:linearGradient {:id id
|
||||||
:x1 (:start-x gradient)
|
:x1 (:start-x gradient)
|
||||||
:y1 (:start-y gradient)
|
:y1 (:start-y gradient)
|
||||||
:x2 (:end-x gradient)
|
:x2 (:end-x gradient)
|
||||||
:y2 (:end-y gradient)
|
:y2 (:end-y gradient)
|
||||||
:gradient-transform transform}
|
:gradientTransform transform}
|
||||||
(for [{:keys [offset color opacity]} (:stops gradient)]
|
(for [{:keys [offset color opacity]} (:stops gradient)]
|
||||||
[:stop {:key (str id "-stop-" offset)
|
[:stop {:key (str id "-stop-" offset)
|
||||||
:offset (or offset 0)
|
:offset (or offset 0)
|
||||||
|
@ -37,9 +35,8 @@
|
||||||
|
|
||||||
(mf/defc radial-gradient [{:keys [id gradient shape]}]
|
(mf/defc radial-gradient [{:keys [id gradient shape]}]
|
||||||
(let [{:keys [x y width height]} (:selrect shape)
|
(let [{:keys [x y width height]} (:selrect shape)
|
||||||
transform (case (:type shape)
|
center (gsh/center-shape shape)
|
||||||
:path (gmt/matrix)
|
transform (when (= :path (:type shape)) (gsh/transform-matrix shape))]
|
||||||
(gsh/inverse-transform-matrix shape))]
|
|
||||||
(let [[x y] (if (= (:type shape) :frame) [0 0] [x y])
|
(let [[x y] (if (= (:type shape) :frame) [0 0] [x y])
|
||||||
translate-vec (gpt/point (+ x (* width (:start-x gradient)))
|
translate-vec (gpt/point (+ x (* width (:start-x gradient)))
|
||||||
(+ y (* height (:start-y gradient))))
|
(+ y (* height (:start-y gradient))))
|
||||||
|
|
|
@ -72,6 +72,8 @@
|
||||||
do-remove-group (st/emitf dw/ungroup-selected)
|
do-remove-group (st/emitf dw/ungroup-selected)
|
||||||
do-mask-group (st/emitf dw/mask-group)
|
do-mask-group (st/emitf dw/mask-group)
|
||||||
do-unmask-group (st/emitf dw/unmask-group)
|
do-unmask-group (st/emitf dw/unmask-group)
|
||||||
|
do-flip-vertical (st/emitf (dw/flip-vertical-selected))
|
||||||
|
do-flip-horizontal (st/emitf (dw/flip-horizontal-selected))
|
||||||
do-add-component (st/emitf dwl/add-component)
|
do-add-component (st/emitf dwl/add-component)
|
||||||
do-detach-component (st/emitf (dwl/detach-component id))
|
do-detach-component (st/emitf (dwl/detach-component id))
|
||||||
do-reset-component (st/emitf (dwl/reset-component id))
|
do-reset-component (st/emitf (dwl/reset-component id))
|
||||||
|
@ -133,7 +135,18 @@
|
||||||
:on-click do-create-group}]
|
:on-click do-create-group}]
|
||||||
[:& menu-entry {:title (t locale "workspace.shape.menu.mask")
|
[:& menu-entry {:title (t locale "workspace.shape.menu.mask")
|
||||||
:shortcut (sc/get-tooltip :mask)
|
:shortcut (sc/get-tooltip :mask)
|
||||||
:on-click do-mask-group}]])
|
:on-click do-mask-group}]
|
||||||
|
[:& menu-separator]])
|
||||||
|
|
||||||
|
(when (>= (count selected) 1)
|
||||||
|
[:*
|
||||||
|
[:& menu-entry {:title (t locale "workspace.shape.menu.flip-vertical")
|
||||||
|
:shortcut (sc/get-tooltip :flip-vertical)
|
||||||
|
:on-click do-flip-vertical}]
|
||||||
|
[:& menu-entry {:title (t locale "workspace.shape.menu.flip-horizontal")
|
||||||
|
:shortcut (sc/get-tooltip :flip-horizontal)
|
||||||
|
:on-click do-flip-horizontal}]
|
||||||
|
[:& menu-separator]])
|
||||||
|
|
||||||
(when (and (= (count selected) 1) (= (:type shape) :group))
|
(when (and (= (count selected) 1) (= (:type shape) :group))
|
||||||
[:*
|
[:*
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
@ -238,16 +239,22 @@
|
||||||
gradient (mf/deref current-gradient-ref)
|
gradient (mf/deref current-gradient-ref)
|
||||||
editing-spot (mf/deref editing-spot-ref)
|
editing-spot (mf/deref editing-spot-ref)
|
||||||
|
|
||||||
|
transform (gsh/transform-matrix shape)
|
||||||
|
transform-inverse (gsh/inverse-transform-matrix shape)
|
||||||
|
|
||||||
{:keys [x y width height] :as sr} (:selrect shape)
|
{:keys [x y width height] :as sr} (:selrect shape)
|
||||||
|
|
||||||
[{start-color :color start-opacity :opacity}
|
[{start-color :color start-opacity :opacity}
|
||||||
{end-color :color end-opacity :opacity}] (:stops gradient)
|
{end-color :color end-opacity :opacity}] (:stops gradient)
|
||||||
|
|
||||||
from-p (gpt/point (+ x (* width (:start-x gradient)))
|
from-p (-> (gpt/point (+ x (* width (:start-x gradient)))
|
||||||
(+ y (* height (:start-y gradient))))
|
(+ y (* height (:start-y gradient))))
|
||||||
|
|
||||||
to-p (gpt/point (+ x (* width (:end-x gradient)))
|
(gpt/transform transform))
|
||||||
|
|
||||||
|
to-p (-> (gpt/point (+ x (* width (:end-x gradient)))
|
||||||
(+ y (* height (:end-y gradient))))
|
(+ y (* height (:end-y gradient))))
|
||||||
|
(gpt/transform transform))
|
||||||
|
|
||||||
gradient-vec (gpt/to-vec from-p to-p)
|
gradient-vec (gpt/to-vec from-p to-p)
|
||||||
gradient-length (gpt/length gradient-vec)
|
gradient-length (gpt/length gradient-vec)
|
||||||
|
@ -263,14 +270,16 @@
|
||||||
(st/emit! (dc/update-gradient changes)))
|
(st/emit! (dc/update-gradient changes)))
|
||||||
|
|
||||||
on-change-start (fn [point]
|
on-change-start (fn [point]
|
||||||
(let [start-x (/ (- (:x point) x) width)
|
(let [point (gpt/transform point transform-inverse)
|
||||||
|
start-x (/ (- (:x point) x) width)
|
||||||
start-y (/ (- (:y point) y) height)
|
start-y (/ (- (:y point) y) height)
|
||||||
start-x (mth/precision start-x 2)
|
start-x (mth/precision start-x 2)
|
||||||
start-y (mth/precision start-y 2)]
|
start-y (mth/precision start-y 2)]
|
||||||
(change! {:start-x start-x :start-y start-y})))
|
(change! {:start-x start-x :start-y start-y})))
|
||||||
|
|
||||||
on-change-finish (fn [point]
|
on-change-finish (fn [point]
|
||||||
(let [end-x (/ (- (:x point) x) width)
|
(let [point (gpt/transform point transform-inverse)
|
||||||
|
end-x (/ (- (:x point) x) width)
|
||||||
end-y (/ (- (:y point) y) height)
|
end-y (/ (- (:y point) y) height)
|
||||||
|
|
||||||
end-x (mth/precision end-x 2)
|
end-x (mth/precision end-x 2)
|
||||||
|
|
Loading…
Add table
Reference in a new issue