diff --git a/common/src/app/common/types/interactions.cljc b/common/src/app/common/types/interactions.cljc index 287b4b30d..aa28a6425 100644 --- a/common/src/app/common/types/interactions.cljc +++ b/common/src/app/common/types/interactions.cljc @@ -45,6 +45,14 @@ :open-url}) (s/def ::destination (s/nilable ::us/uuid)) +(s/def ::overlay-pos-type #{:manual + :center + :top-left + :top-right + :top-center + :bottom-left + :bottom-right + :bottom-center}) (s/def ::overlay-position ::point) (s/def ::url ::us/string) @@ -55,7 +63,8 @@ (defmethod action-opts-spec :open-overlay [_] (s/keys :req-un [::destination - ::overlay-position])) + ::overlay-position + ::overlay-pos-type])) (defmethod action-opts-spec :close-overlay [_] (s/keys :req-un [::destination])) @@ -92,6 +101,8 @@ ;; -- Helpers +(declare calc-overlay-position) + (defn set-event-type [interaction event-type] (us/verify ::interaction interaction) @@ -110,7 +121,7 @@ (defn set-action-type - [interaction action-type] + [interaction action-type shape objects] (us/verify ::interaction interaction) (us/verify ::action-type action-type) (if (= (:action-type interaction) action-type) @@ -123,10 +134,21 @@ :destination (get interaction :destination)) :open-overlay - (assoc interaction - :action-type action-type - :destination (get interaction :destination) - :overlay-position (get interaction :overlay-position (gpt/point 0 0))) + (let [destination (get interaction :destination) + overlay-pos-type (get interaction :overlay-pos-type :center) + overlay-position (get interaction + :overlay-position + (calc-overlay-position + destination + interaction + shape + objects + overlay-pos-type))] + (assoc interaction + :action-type action-type + :destination destination + :overlay-pos-type overlay-pos-type + :overlay-position overlay-position)) :close-overlay (assoc interaction @@ -142,7 +164,6 @@ :action-type action-type :url (get interaction :url ""))))) - (defn set-destination [interaction destination shape objects] (us/verify ::interaction interaction) @@ -150,33 +171,95 @@ (assert (or (nil? destination) (some? (get objects destination)))) (assert #(:navigate :open-overlay :close-overlay) (:action-type interaction)) - (let [calc-overlay-position - (fn [] - (if (nil? destination) - (gpt/point 0 0) - (let [dest-frame (get objects destination) - overlay-size (:selrect dest-frame) + (cond-> interaction + :always + (assoc :destination destination) - orig-frame (if (= (:type shape) :frame) - shape - (get objects (:frame-id shape))) - frame-size (:selrect orig-frame) + (= (:action-type interaction) :open-overlay) + (assoc :overlay-pos-type :center + :overlay-position (calc-overlay-position destination + interaction + shape + objects + :center)))) - x (/ (- (:width frame-size) (:width overlay-size)) 2) - y (/ (- (:height frame-size) (:height overlay-size)) 2)] - (gpt/point x y))))] - - (cond-> interaction - :always - (assoc :destination destination) - - (= (:action-type interaction) :open-overlay) - (assoc :overlay-position (calc-overlay-position))))) +(defn set-overlay-pos-type + [interaction overlay-pos-type shape objects] + (us/verify ::interaction interaction) + (us/verify ::overlay-pos-type overlay-pos-type) + (assert #(= :open-overlay (:action-type interaction))) + (assoc interaction + :overlay-pos-type overlay-pos-type + :overlay-position (calc-overlay-position (:destination interaction) + interaction + shape + objects + overlay-pos-type))) +(defn toggle-overlay-pos-type + [interaction overlay-pos-type shape objects] + (us/verify ::interaction interaction) + (us/verify ::overlay-pos-type overlay-pos-type) + (assert #(= :open-overlay (:action-type interaction))) + (let [new-pos-type (if (= (:overlay-pos-type interaction) overlay-pos-type) + :manual + overlay-pos-type)] + (assoc interaction + :overlay-pos-type new-pos-type + :overlay-position (calc-overlay-position (:destination interaction) + interaction + shape + objects + new-pos-type)))) (defn set-overlay-position [interaction overlay-position] (us/verify ::interaction interaction) (us/verify ::overlay-position overlay-position) - (assoc interaction :overlay-position overlay-position)) + (assert #(= :open-overlay (:action-type interaction))) + (assoc interaction + :overlay-pos-type :manual + :overlay-position overlay-position)) + +(defn- calc-overlay-position + [destination interaction shape objects overlay-pos-type] + (if (nil? destination) + (gpt/point 0 0) + (let [dest-frame (get objects destination) + overlay-size (:selrect dest-frame) + orig-frame (if (= (:type shape) :frame) + shape + (get objects (:frame-id shape))) + frame-size (:selrect orig-frame)] + (case overlay-pos-type + + :center + (gpt/point (/ (- (:width frame-size) (:width overlay-size)) 2) + (/ (- (:height frame-size) (:height overlay-size)) 2)) + + :top-left + (gpt/point 0 0) + + :top-right + (gpt/point (- (:width frame-size) (:width overlay-size)) + 0) + + :top-center + (gpt/point (/ (- (:width frame-size) (:width overlay-size)) 2) + 0) + + :bottom-left + (gpt/point 0 + (- (:height frame-size) (:height overlay-size))) + + :bottom-right + (gpt/point (- (:width frame-size) (:width overlay-size)) + (- (:height frame-size) (:height overlay-size))) + + :bottom-center + (gpt/point (/ (- (:width frame-size) (:width overlay-size)) 2) + (- (:height frame-size) (:height overlay-size))) + + :manual + (:overlay-position interaction))))) diff --git a/frontend/resources/images/icons/position-bottom-center.svg b/frontend/resources/images/icons/position-bottom-center.svg new file mode 100644 index 000000000..002466ead --- /dev/null +++ b/frontend/resources/images/icons/position-bottom-center.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/resources/images/icons/position-bottom-left.svg b/frontend/resources/images/icons/position-bottom-left.svg new file mode 100644 index 000000000..4811b74a9 --- /dev/null +++ b/frontend/resources/images/icons/position-bottom-left.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/resources/images/icons/position-bottom-right.svg b/frontend/resources/images/icons/position-bottom-right.svg new file mode 100644 index 000000000..ebf861dcf --- /dev/null +++ b/frontend/resources/images/icons/position-bottom-right.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/resources/images/icons/position-center.svg b/frontend/resources/images/icons/position-center.svg new file mode 100644 index 000000000..ce6695ba7 --- /dev/null +++ b/frontend/resources/images/icons/position-center.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/resources/images/icons/position-top-center.svg b/frontend/resources/images/icons/position-top-center.svg new file mode 100644 index 000000000..5a971d427 --- /dev/null +++ b/frontend/resources/images/icons/position-top-center.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/resources/images/icons/position-top-left.svg b/frontend/resources/images/icons/position-top-left.svg new file mode 100644 index 000000000..0285e444e --- /dev/null +++ b/frontend/resources/images/icons/position-top-left.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/resources/images/icons/position-top-right.svg b/frontend/resources/images/icons/position-top-right.svg new file mode 100644 index 000000000..838f63602 --- /dev/null +++ b/frontend/resources/images/icons/position-top-right.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index f1845e3d9..5eee36b8d 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -945,11 +945,15 @@ width: 12px; height: 12px; fill: $color-gray-20; + stroke: $color-gray-20; } - &:hover svg { + &:hover svg, + &.active svg { fill: $color-primary; + stroke: $color-primary; } + &.actions-inside { position: absolute; right: 0; diff --git a/frontend/resources/styles/main/partials/sidebar-interactions.scss b/frontend/resources/styles/main/partials/sidebar-interactions.scss index c8ea87266..d2c9cb1dc 100644 --- a/frontend/resources/styles/main/partials/sidebar-interactions.scss +++ b/frontend/resources/styles/main/partials/sidebar-interactions.scss @@ -47,3 +47,13 @@ width: 64px; } } + +.interactions-pos-buttons { + margin-top: $small; + justify-content: space-around; + + svg { + width: 18px; + height: 18px; + } +} diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index dbff3982c..a53fdcee3 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1827,8 +1827,8 @@ frame)] ;; Update or create interaction (if index - (update-in interactions [index] - #(cti/set-destination % (:id frame) shape objects)) + (update interactions index + #(cti/set-destination % (:id frame) shape objects)) (conj (or interactions []) (cti/set-destination cti/default-interaction (:id frame) @@ -1870,11 +1870,11 @@ (rx/concat (->> ms/mouse-position (rx/take-until stopper) - (rx/map #(move-overlay-pos % overlay-pos frame-pos offset))) - (rx/of (finish-move-overlay-pos index overlay-pos frame-pos offset))))))))) + (rx/map #(move-overlay-pos % frame-pos offset))) + (rx/of (finish-move-overlay-pos index frame-pos offset))))))))) (defn move-overlay-pos - [pos overlay-pos frame-pos offset] + [pos frame-pos offset] (ptk/reify ::move-overlay-pos ptk/UpdateEvent (update [_ state] @@ -1884,7 +1884,7 @@ (assoc-in state [:workspace-local :move-overlay-to] pos))))) (defn finish-move-overlay-pos - [index overlay-pos frame-pos offset] + [index frame-pos offset] (ptk/reify ::finish-move-overlay-pos ptk/UpdateEvent (update [_ state] diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index 47738e45a..abf60ef6e 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -101,6 +101,13 @@ (def play (icon-xref :play)) (def plus (icon-xref :plus)) (def pointer-inner (icon-xref :pointer-inner)) +(def position-bottom-center (icon-xref :position-bottom-center)) +(def position-bottom-left (icon-xref :position-bottom-left)) +(def position-bottom-right (icon-xref :position-bottom-right)) +(def position-center (icon-xref :position-center)) +(def position-top-center (icon-xref :position-top-center)) +(def position-top-left (icon-xref :position-top-left)) +(def position-top-right (icon-xref :position-top-right)) (def radius (icon-xref :radius)) (def radius-1 (icon-xref :radius-1)) (def radius-4 (icon-xref :radius-4)) diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index b55016671..99fa30d33 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -146,8 +146,8 @@ {:style {:width (:width size-over) :height (:height size-over) :position "absolute" - :left (:x (:position overlay)) - :top (:y (:position overlay))}} + :left (* (:x (:position overlay)) zoom) + :top (* (:y (:position overlay)) zoom)}} [:& interactions/viewport {:frame (:frame overlay) :size size-over diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index c8dc7c2e7..3bdd854d1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -31,7 +31,8 @@ [] {:navigate (tr "workspace.options.interaction-navigate-to") :open-overlay (tr "workspace.options.interaction-open-overlay") - :close-overlay (tr "workspace.options.interaction-close-overlay")}) + :close-overlay (tr "workspace.options.interaction-close-overlay") + :prev-screen (tr "workspace.options.interaction-prev-screen")}) (defn- action-summary [interaction destination] @@ -44,6 +45,17 @@ (get destination :name (tr "workspace.options.interaction-self"))) "--")) +(defn- overlay-pos-type-names + [] + {:manual (tr "workspace.options.interaction-pos-manual") + :center (tr "workspace.options.interaction-pos-center") + :top-left (tr "workspace.options.interaction-pos-top-left") + :top-right (tr "workspace.options.interaction-pos-top-right") + :top-center (tr "workspace.options.interaction-pos-top-center") + :bottom-left (tr "workspace.options.interaction-pos-bottom-left") + :bottom-right (tr "workspace.options.interaction-pos-bottom-right") + :bottom-center (tr "workspace.options.interaction-pos-bottom-center")}) + (mf/defc interaction-entry [{:keys [index shape interaction update-interaction remove-interaction]}] (let [objects (deref refs/workspace-page-objects) @@ -51,6 +63,9 @@ frames (mf/use-memo (mf/deps objects) #(cp/select-frames objects)) + action-type (:action-type interaction) + overlay-pos-type (:overlay-pos-type interaction) + extended-open? (mf/use-state false) change-event-type @@ -61,13 +76,22 @@ change-action-type (fn [event] (let [value (-> event dom/get-target dom/get-value d/read-string)] - (update-interaction index #(cti/set-action-type % value)))) + (update-interaction index #(cti/set-action-type % value shape objects)))) change-destination (fn [event] (let [value (-> event dom/get-target dom/get-value) value (when (not= value "") (uuid/uuid value))] - (update-interaction index #(cti/set-destination % value shape objects))))] + (update-interaction index #(cti/set-destination % value shape objects)))) + + change-overlay-pos-type + (fn [event] + (let [value (-> event dom/get-target dom/get-value d/read-string)] + (update-interaction index #(cti/set-overlay-pos-type % value shape objects)))) + + toggle-overlay-pos-type + (fn [pos-type] + (update-interaction index #(cti/toggle-overlay-pos-type % pos-type shape objects)))] [:* [:div.element-set-options-group @@ -95,7 +119,8 @@ :on-change change-action-type} (for [[value name] (action-type-names)] [:option {:value (str value)} name])]] - [:div.interactions-element + (when (#{:navigate :open-overlay :close-overlay} action-type) + [:div.interactions-element [:span.element-set-subtitle.wide (tr "workspace.options.interaction-destination")] [:select.input-select {:value (str (:destination interaction)) @@ -104,7 +129,45 @@ (for [frame frames] (when (and (not= (:id frame) (:id shape)) ; A frame cannot navigate to itself (not= (:id frame) (:frame-id shape))) ; nor a shape to its container frame - [:option {:value (str (:id frame))} (:name frame)]))]]]])])) + [:option {:value (str (:id frame))} (:name frame)]))]]) + (when (= action-type :open-overlay) + [:* + [:div.interactions-element + [:span.element-set-subtitle.wide (tr "workspace.options.interaction-position")] + [:select.input-select + {:value (str (:overlay-pos-type interaction)) + :on-change change-overlay-pos-type} + (for [[value name] (overlay-pos-type-names)] + [:option {:value (str value)} name])]] + [:div.interactions-element.interactions-pos-buttons + [:div.element-set-actions-button + {:class (dom/classnames :active (= overlay-pos-type :center)) + :on-click #(toggle-overlay-pos-type :center)} + i/position-center] + [:div.element-set-actions-button + {:class (dom/classnames :active (= overlay-pos-type :top-left)) + :on-click #(toggle-overlay-pos-type :top-left)} + i/position-top-left] + [:div.element-set-actions-button + {:class (dom/classnames :active (= overlay-pos-type :top-right)) + :on-click #(toggle-overlay-pos-type :top-right)} + i/position-top-right] + [:div.element-set-actions-button + {:class (dom/classnames :active (= overlay-pos-type :top-center)) + :on-click #(toggle-overlay-pos-type :top-center)} + i/position-top-center] + [:div.element-set-actions-button + {:class (dom/classnames :active (= overlay-pos-type :bottom-left)) + :on-click #(toggle-overlay-pos-type :bottom-left)} + i/position-bottom-left] + [:div.element-set-actions-button + {:class (dom/classnames :active (= overlay-pos-type :bottom-right)) + :on-click #(toggle-overlay-pos-type :bottom-right)} + i/position-bottom-right] + [:div.element-set-actions-button + {:class (dom/classnames :active (= overlay-pos-type :bottom-center)) + :on-click #(toggle-overlay-pos-type :bottom-center)} + i/position-bottom-center]]])]])])) (mf/defc interactions-menu [{:keys [shape] :as props}] diff --git a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs index 404431856..a5ec3e378 100644 --- a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs @@ -194,9 +194,9 @@ (mf/defc overlay-marker - [{:keys [index orig-shape dest-shape position objects zoom] :as props}] + [{:keys [index orig-shape dest-shape position objects] :as props}] (let [start-move-position - (fn [event] + (fn [_] (st/emit! (dw/start-move-overlay-pos index)))] (when dest-shape @@ -287,15 +287,13 @@ :orig-shape shape :dest-shape dest-shape :position move-overlay-to - :objects objects - :zoom zoom}] + :objects objects}] [:& overlay-marker {:key (str "pos" (:id shape) "-" index) :index index :orig-shape shape :dest-shape dest-shape :position (:overlay-position interaction) - :objects objects - :zoom zoom}]))]))) + :objects objects}]))]))) (when (not (#{:move :rotate} current-transform)) [:& interaction-handle {:key (:id shape) :index nil diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 0ed54d467..a49fdf5a1 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -2441,6 +2441,42 @@ msgstr "Open overlay" msgid "workspace.options.interaction-open-overlay-dest" msgstr "Open overlay: %s" +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-manual" +msgstr "Manual" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-center" +msgstr "Center" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-top-left" +msgstr "Top left" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-top-right" +msgstr "Top right" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-top-center" +msgstr "Top center" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-bottom-left" +msgstr "Bottom left" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-bottom-right" +msgstr "Bottom right" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-bottom-center" +msgstr "Bottom center" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-position" +msgstr "Position" + #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs msgid "workspace.options.interaction-self" msgstr "self" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 83b47aefe..1e48f671a 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2324,6 +2324,42 @@ msgstr "Open overlay" msgid "workspace.options.interaction-open-overlay-dest" msgstr "Open overlay: %s" +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-manual" +msgstr "Manual" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-center" +msgstr "Centro" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-top-left" +msgstr "Arriba izquierda" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-top-right" +msgstr "Arriba derecha" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-top-center" +msgstr "Arriba centro" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-bottom-left" +msgstr "Abajo izquierda" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-bottom-right" +msgstr "Abajo derecha" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-pos-bottom-center" +msgstr "Abajo centro" + +#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +msgid "workspace.options.interaction-position" +msgstr "PosiciĆ³n" + #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs msgid "workspace.options.interaction-self" msgstr "self"