mirror of
https://github.com/penpot/penpot.git
synced 2025-07-06 10:07:19 +02:00
✨ Improved behaviour for horizontal/vertical lines
This commit is contained in:
parent
640723a4e7
commit
b5e965cf1a
6 changed files with 59 additions and 54 deletions
|
@ -981,7 +981,6 @@
|
||||||
(gpr/points->selrect))]
|
(gpr/points->selrect))]
|
||||||
[points selrect]))
|
[points selrect]))
|
||||||
|
|
||||||
|
|
||||||
(defn open-path?
|
(defn open-path?
|
||||||
[shape]
|
[shape]
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.path :as upg]
|
[app.common.geom.shapes.path :as upg]
|
||||||
[app.common.math :as mth]
|
|
||||||
[app.main.data.workspace.path.state :as state]
|
[app.main.data.workspace.path.state :as state]
|
||||||
[app.main.snap :as snap]
|
[app.main.snap :as snap]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
[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.pages.changes-builder :as pcb]
|
|
||||||
[app.common.pages :as cp]
|
[app.common.pages :as cp]
|
||||||
|
[app.common.pages.changes-builder :as pcb]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.spec :refer [max-safe-int min-safe-int]]
|
[app.common.spec :refer [max-safe-int min-safe-int]]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
|
|
@ -289,14 +289,6 @@
|
||||||
|
|
||||||
;; --- RESIZE UTILS
|
;; --- RESIZE UTILS
|
||||||
|
|
||||||
(defn update-overflow-text [id value]
|
|
||||||
(ptk/reify ::update-overflow-text
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(let [page-id (:current-page-id state)]
|
|
||||||
(update-in state [:workspace-data :pages-index page-id :objects id] assoc :overflow-text value)))))
|
|
||||||
|
|
||||||
|
|
||||||
(def start-edit-if-selected
|
(def start-edit-if-selected
|
||||||
(ptk/reify ::start-edit-if-selected
|
(ptk/reify ::start-edit-if-selected
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
|
@ -325,22 +317,13 @@
|
||||||
update-fn
|
update-fn
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [[new-width new-height] (get changes-map (:id shape))
|
(let [[new-width new-height] (get changes-map (:id shape))
|
||||||
{:keys [selrect grow-type overflow-text]} (gsh/transform-shape shape)
|
{:keys [selrect grow-type]} (gsh/transform-shape shape)
|
||||||
{shape-width :width shape-height :height} selrect
|
{shape-width :width shape-height :height} selrect
|
||||||
|
|
||||||
modifier-width (gsh/resize-modifiers shape :width new-width)
|
modifier-width (gsh/resize-modifiers shape :width new-width)
|
||||||
modifier-height (gsh/resize-modifiers shape :height new-height)]
|
modifier-height (gsh/resize-modifiers shape :height new-height)]
|
||||||
|
|
||||||
(cond-> shape
|
(cond-> shape
|
||||||
(and overflow-text (not= :fixed grow-type))
|
|
||||||
(assoc :overflow-text false)
|
|
||||||
|
|
||||||
(and (= :fixed grow-type) (not overflow-text) (> new-height shape-height))
|
|
||||||
(assoc :overflow-text true)
|
|
||||||
|
|
||||||
(and (= :fixed grow-type) overflow-text (<= new-height shape-height))
|
|
||||||
(assoc :overflow-text false)
|
|
||||||
|
|
||||||
(and (not-changed? shape-width new-width) (= grow-type :auto-width))
|
(and (not-changed? shape-width new-width) (= grow-type :auto-width))
|
||||||
(-> (assoc :modifiers modifier-width)
|
(-> (assoc :modifiers modifier-width)
|
||||||
(gsh/transform-shape))
|
(gsh/transform-shape))
|
||||||
|
|
|
@ -121,7 +121,7 @@
|
||||||
(set-modifiers ids modifiers false))
|
(set-modifiers ids modifiers false))
|
||||||
|
|
||||||
([ids modifiers ignore-constraints]
|
([ids modifiers ignore-constraints]
|
||||||
(set-modifiers ids modifiers false false))
|
(set-modifiers ids modifiers ignore-constraints false))
|
||||||
|
|
||||||
([ids modifiers ignore-constraints ignore-snap-pixel]
|
([ids modifiers ignore-constraints ignore-snap-pixel]
|
||||||
(us/verify (s/coll-of uuid?) ids)
|
(us/verify (s/coll-of uuid?) ids)
|
||||||
|
@ -264,8 +264,18 @@
|
||||||
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
|
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
|
||||||
flip-y? (neg? (get-in modifiers [:resize-vector :y]))
|
flip-y? (neg? (get-in modifiers [:resize-vector :y]))
|
||||||
|
|
||||||
target-width (max 1 (mth/round (:width raw-bounds)))
|
path? (= :path (:type shape))
|
||||||
target-height (max 1 (mth/round (:height raw-bounds)))
|
vertical-line? (and path? (<= (:width raw-bounds) 0.01))
|
||||||
|
horizontal-line? (and path? (<= (:height raw-bounds) 0.01))
|
||||||
|
|
||||||
|
target-width (if vertical-line?
|
||||||
|
(:width raw-bounds)
|
||||||
|
(max 1 (mth/round (:width raw-bounds))))
|
||||||
|
|
||||||
|
target-height (if horizontal-line?
|
||||||
|
(:height raw-bounds)
|
||||||
|
(max 1 (mth/round (:height raw-bounds))))
|
||||||
|
|
||||||
target-p (cond-> (gpt/round (gpt/point raw-bounds))
|
target-p (cond-> (gpt/round (gpt/point raw-bounds))
|
||||||
flip-x?
|
flip-x?
|
||||||
(update :x + target-width)
|
(update :x + target-width)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
(ns app.main.ui.workspace.viewport.selection
|
(ns app.main.ui.workspace.viewport.selection
|
||||||
"Selection handlers component."
|
"Selection handlers component."
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[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]
|
||||||
|
@ -18,7 +19,6 @@
|
||||||
[app.main.ui.workspace.shapes.path.editor :refer [path-editor]]
|
[app.main.ui.workspace.shapes.path.editor :refer [path-editor]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[cuerdas.core :as str]
|
|
||||||
[debug :refer [debug?]]
|
[debug :refer [debug?]]
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[rumext.util :refer [map->obj]]))
|
[rumext.util :refer [map->obj]]))
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
:y y
|
:y y
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:transform transform
|
:transform (str transform)
|
||||||
:on-mouse-down on-move-selected
|
:on-mouse-down on-move-selected
|
||||||
:on-context-menu on-context-menu
|
:on-context-menu on-context-menu
|
||||||
:style {:stroke color
|
:style {:stroke color
|
||||||
|
@ -93,7 +93,8 @@
|
||||||
:y y
|
:y y
|
||||||
:length length
|
:length length
|
||||||
:angle 0
|
:angle 0
|
||||||
:align align}}))
|
:align align
|
||||||
|
:show-handler? tiny-width?}}))
|
||||||
|
|
||||||
(when-not horizontal-line?
|
(when-not horizontal-line?
|
||||||
(let [x (if small-width? (+ x (/ (+ width threshold-small) 2)) (+ x width))
|
(let [x (if small-width? (+ x (/ (+ width threshold-small) 2)) (+ x width))
|
||||||
|
@ -104,7 +105,8 @@
|
||||||
:y (+ y height)
|
:y (+ y height)
|
||||||
:length length
|
:length length
|
||||||
:angle 180
|
:angle 180
|
||||||
:align align}}))
|
:align align
|
||||||
|
:show-handler? tiny-width?}}))
|
||||||
|
|
||||||
(when-not vertical-line?
|
(when-not vertical-line?
|
||||||
(let [y (if small-height? (+ y (/ (- height threshold-small) 2)) y)
|
(let [y (if small-height? (+ y (/ (- height threshold-small) 2)) y)
|
||||||
|
@ -115,7 +117,8 @@
|
||||||
:y y
|
:y y
|
||||||
:length length
|
:length length
|
||||||
:angle 90
|
:angle 90
|
||||||
:align align}}))
|
:align align
|
||||||
|
:show-handler? tiny-height?}}))
|
||||||
|
|
||||||
(when-not vertical-line?
|
(when-not vertical-line?
|
||||||
(let [y (if small-height? (+ y (/ (+ height threshold-small) 2)) (+ y height))
|
(let [y (if small-height? (+ y (/ (+ height threshold-small) 2)) (+ y height))
|
||||||
|
@ -126,7 +129,8 @@
|
||||||
:y y
|
:y y
|
||||||
:length length
|
:length length
|
||||||
:angle 270
|
:angle 270
|
||||||
:align align}}))
|
:align align
|
||||||
|
:show-handler? tiny-height?}}))
|
||||||
|
|
||||||
(when (and (not tiny-width?) (not tiny-height?))
|
(when (and (not tiny-width?) (not tiny-height?))
|
||||||
{:type :resize-point
|
{:type :resize-point
|
||||||
|
@ -166,11 +170,11 @@
|
||||||
:height size
|
:height size
|
||||||
:fill (if (debug? :handlers) "blue" "none")
|
:fill (if (debug? :handlers) "blue" "none")
|
||||||
:stroke-width 0
|
:stroke-width 0
|
||||||
:transform transform
|
:transform (str transform)
|
||||||
:on-mouse-down on-rotate}]))
|
:on-mouse-down on-rotate}]))
|
||||||
|
|
||||||
(mf/defc resize-point-handler
|
(mf/defc resize-point-handler
|
||||||
[{:keys [cx cy zoom position on-resize transform rotation color overflow-text align]}]
|
[{:keys [cx cy zoom position on-resize transform rotation color align]}]
|
||||||
(let [cursor (if (#{:top-left :bottom-right} position)
|
(let [cursor (if (#{:top-left :bottom-right} position)
|
||||||
(cur/resize-nesw rotation) (cur/resize-nwse rotation))
|
(cur/resize-nesw rotation) (cur/resize-nwse rotation))
|
||||||
{cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)]
|
{cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)]
|
||||||
|
@ -181,7 +185,7 @@
|
||||||
:strokeWidth "1px"
|
:strokeWidth "1px"
|
||||||
:vectorEffect "non-scaling-stroke"}
|
:vectorEffect "non-scaling-stroke"}
|
||||||
:fill "var(--color-white)"
|
:fill "var(--color-white)"
|
||||||
:stroke (if (and (= position :bottom-right) overflow-text) "red" color)
|
:stroke color
|
||||||
:cx cx'
|
:cx cx'
|
||||||
:cy cy'}]
|
:cy cy'}]
|
||||||
|
|
||||||
|
@ -196,7 +200,7 @@
|
||||||
:y cy'
|
:y cy'
|
||||||
:width resize-point-circle-radius
|
:width resize-point-circle-radius
|
||||||
:height resize-point-circle-radius
|
:height resize-point-circle-radius
|
||||||
:transform (when rotation (str/fmt "rotate(%s, %s, %s)" rotation cx' cy'))
|
:transform (when rotation (dm/fmt "rotate(%, %, %)" rotation cx' cy'))
|
||||||
:style {:fill (if (debug? :handlers) "red" "none")
|
:style {:fill (if (debug? :handlers) "red" "none")
|
||||||
:stroke-width 0
|
:stroke-width 0
|
||||||
:cursor cursor}
|
:cursor cursor}
|
||||||
|
@ -212,26 +216,37 @@
|
||||||
|
|
||||||
(mf/defc resize-side-handler
|
(mf/defc resize-side-handler
|
||||||
"The side handler is always rendered horizontally and then rotated"
|
"The side handler is always rendered horizontally and then rotated"
|
||||||
[{:keys [x y length align angle zoom position rotation transform on-resize]}]
|
[{:keys [x y length align angle zoom position rotation transform on-resize color show-handler?]}]
|
||||||
(let [res-point (if (#{:top :bottom} position)
|
(let [res-point (if (#{:top :bottom} position)
|
||||||
{:y y}
|
{:y y}
|
||||||
{:x x})
|
{:x x})
|
||||||
|
|
||||||
height (/ resize-side-height zoom)
|
height (/ resize-side-height zoom)
|
||||||
offset-y (if (= align :outside) (- height) (- (/ height 2)))
|
offset-y (if (= align :outside) (- height) (- (/ height 2)))
|
||||||
target-y (+ y offset-y)]
|
target-y (+ y offset-y)
|
||||||
[:rect {:x x
|
transform-str (str (gmt/multiply transform (gmt/rotate-matrix angle (gpt/point x y))))]
|
||||||
:y target-y
|
[:g.resize-handler
|
||||||
:width length
|
(when show-handler?
|
||||||
:height height
|
[:circle {:r (/ resize-point-radius zoom)
|
||||||
:transform (gmt/multiply transform
|
:style {:fillOpacity 1
|
||||||
(gmt/rotate-matrix angle (gpt/point x y)))
|
:stroke color
|
||||||
:on-mouse-down #(on-resize res-point %)
|
:strokeWidth "1px"
|
||||||
:style {:fill (if (debug? :handlers) "yellow" "none")
|
:fill "var(--color-white)"
|
||||||
:stroke-width 0
|
:vectorEffect "non-scaling-stroke"}
|
||||||
:cursor (if (#{:left :right} position)
|
:cx (+ x (/ length 2))
|
||||||
(cur/resize-ew rotation)
|
:cy y
|
||||||
(cur/resize-ns rotation)) }}]))
|
:transform transform-str}])
|
||||||
|
[:rect {:x x
|
||||||
|
:y target-y
|
||||||
|
:width length
|
||||||
|
:height height
|
||||||
|
:transform transform-str
|
||||||
|
:on-mouse-down #(on-resize res-point %)
|
||||||
|
:style {:fill (if (debug? :handlers) "yellow" "none")
|
||||||
|
:stroke-width 0
|
||||||
|
:cursor (if (#{:left :right} position)
|
||||||
|
(cur/resize-ew rotation)
|
||||||
|
(cur/resize-ns rotation)) }}]]))
|
||||||
|
|
||||||
(defn minimum-selrect [{:keys [x y width height] :as selrect}]
|
(defn minimum-selrect [{:keys [x y width height] :as selrect}]
|
||||||
(let [final-width (max width min-selrect-side)
|
(let [final-width (max width min-selrect-side)
|
||||||
|
@ -262,7 +277,7 @@
|
||||||
[:g.controls {:pointer-events (if disable-handlers "none" "visible")}
|
[:g.controls {:pointer-events (if disable-handlers "none" "visible")}
|
||||||
;; Selection rect
|
;; Selection rect
|
||||||
[:& selection-rect {:rect selrect
|
[:& selection-rect {:rect selrect
|
||||||
:transform transform
|
:transform (str transform)
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:color color
|
:color color
|
||||||
:on-move-selected on-move-selected
|
:on-move-selected on-move-selected
|
||||||
|
@ -271,7 +286,7 @@
|
||||||
(mf/defc controls-handlers
|
(mf/defc controls-handlers
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [{:keys [overflow-text] :as shape} (obj/get props "shape")
|
(let [shape (obj/get props "shape")
|
||||||
zoom (obj/get props "zoom")
|
zoom (obj/get props "zoom")
|
||||||
color (obj/get props "color")
|
color (obj/get props "color")
|
||||||
on-resize (obj/get props "on-resize")
|
on-resize (obj/get props "on-resize")
|
||||||
|
@ -291,15 +306,14 @@
|
||||||
[:g.controls {:pointer-events (if disable-handlers "none" "visible")}
|
[:g.controls {:pointer-events (if disable-handlers "none" "visible")}
|
||||||
;; Handlers
|
;; Handlers
|
||||||
(for [{:keys [type position props]} (handlers-for-selection selrect shape zoom)]
|
(for [{:keys [type position props]} (handlers-for-selection selrect shape zoom)]
|
||||||
(let [common-props {:key (str (name type) "-" (name position))
|
(let [common-props {:key (dm/str (name type) "-" (name position))
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:position position
|
:position position
|
||||||
:on-rotate on-rotate
|
:on-rotate on-rotate
|
||||||
:on-resize (partial on-resize position)
|
:on-resize (partial on-resize position)
|
||||||
:transform transform
|
:transform transform
|
||||||
:rotation rotation
|
:rotation rotation
|
||||||
:color color
|
:color color}
|
||||||
:overflow-text overflow-text}
|
|
||||||
props (map->obj (merge common-props props))]
|
props (map->obj (merge common-props props))]
|
||||||
(case type
|
(case type
|
||||||
:rotation (when (not= :frame (:type shape)) [:> rotation-handler props])
|
:rotation (when (not= :frame (:type shape)) [:> rotation-handler props])
|
||||||
|
@ -313,7 +327,7 @@
|
||||||
(let [{:keys [x y width height]} 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 (gsh/transform-matrix shape)
|
:transform (str (gsh/transform-matrix shape))
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:pointer-events "visible"
|
:pointer-events "visible"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue