Add a Select tool overlay for the layer origin (#3471)
* Add blue layer origin cross overlay * Apply suggestion from @Keavon * Skip layers without local transforms * Disable the Custom Pivot by default --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
20a595db39
commit
c46060db44
|
|
@ -56,6 +56,8 @@ pub const DEFAULT_STROKE_WIDTH: f64 = 2.;
|
||||||
pub const SELECTION_TOLERANCE: f64 = 5.;
|
pub const SELECTION_TOLERANCE: f64 = 5.;
|
||||||
pub const DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD: f64 = 15.;
|
pub const DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD: f64 = 15.;
|
||||||
pub const SELECTION_DRAG_ANGLE: f64 = 90.;
|
pub const SELECTION_DRAG_ANGLE: f64 = 90.;
|
||||||
|
pub const LAYER_ORIGIN_CROSS_DIAMETER: f64 = 10.;
|
||||||
|
pub const LAYER_ORIGIN_CROSS_THICKNESS: f64 = 1.;
|
||||||
|
|
||||||
// PIVOT
|
// PIVOT
|
||||||
pub const PIVOT_CROSSHAIR_THICKNESS: f64 = 1.;
|
pub const PIVOT_CROSSHAIR_THICKNESS: f64 = 1.;
|
||||||
|
|
|
||||||
|
|
@ -1262,6 +1262,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
||||||
OverlaysType::TransformCage => visibility_settings.transform_cage = visible,
|
OverlaysType::TransformCage => visibility_settings.transform_cage = visible,
|
||||||
OverlaysType::HoverOutline => visibility_settings.hover_outline = visible,
|
OverlaysType::HoverOutline => visibility_settings.hover_outline = visible,
|
||||||
OverlaysType::SelectionOutline => visibility_settings.selection_outline = visible,
|
OverlaysType::SelectionOutline => visibility_settings.selection_outline = visible,
|
||||||
|
OverlaysType::LayerOriginCross => visibility_settings.layer_origin_cross = visible,
|
||||||
OverlaysType::Pivot => visibility_settings.pivot = visible,
|
OverlaysType::Pivot => visibility_settings.pivot = visible,
|
||||||
OverlaysType::Origin => visibility_settings.origin = visible,
|
OverlaysType::Origin => visibility_settings.origin = visible,
|
||||||
OverlaysType::Path => visibility_settings.path = visible,
|
OverlaysType::Path => visibility_settings.path = visible,
|
||||||
|
|
@ -2394,6 +2395,24 @@ impl DocumentMessageHandler {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
LayoutGroup::Row {
|
||||||
|
widgets: {
|
||||||
|
let checkbox_id = CheckboxId::new();
|
||||||
|
vec![
|
||||||
|
CheckboxInput::new(self.overlays_visibility_settings.layer_origin_cross)
|
||||||
|
.on_update(|optional_input: &CheckboxInput| {
|
||||||
|
DocumentMessage::SetOverlaysVisibility {
|
||||||
|
visible: optional_input.checked,
|
||||||
|
overlays_type: Some(OverlaysType::LayerOriginCross),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.for_label(checkbox_id)
|
||||||
|
.widget_instance(),
|
||||||
|
TextLabel::new("Layer Origin".to_string()).for_checkbox(checkbox_id).widget_instance(),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
LayoutGroup::Row {
|
LayoutGroup::Row {
|
||||||
widgets: vec![TextLabel::new("Pen & Path Tools").widget_instance()],
|
widgets: vec![TextLabel::new("Pen & Path Tools").widget_instance()],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,15 @@ use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use vello::Scene;
|
use vello::Scene;
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
pub type OverlayProvider = fn(OverlayContext) -> Message;
|
pub type OverlayProvider = fn(OverlayContext) -> Message;
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
pub fn empty_provider() -> OverlayProvider {
|
pub fn empty_provider() -> OverlayProvider {
|
||||||
|_| Message::NoOp
|
|_| Message::NoOp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
/// Types of overlays used by DocumentMessage to enable/disable the selected set of viewport overlays.
|
/// Types of overlays used by DocumentMessage to enable/disable the selected set of viewport overlays.
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub enum OverlaysType {
|
pub enum OverlaysType {
|
||||||
|
|
@ -41,6 +44,7 @@ pub enum OverlaysType {
|
||||||
TransformCage,
|
TransformCage,
|
||||||
HoverOutline,
|
HoverOutline,
|
||||||
SelectionOutline,
|
SelectionOutline,
|
||||||
|
LayerOriginCross,
|
||||||
Pivot,
|
Pivot,
|
||||||
Origin,
|
Origin,
|
||||||
Path,
|
Path,
|
||||||
|
|
@ -48,6 +52,7 @@ pub enum OverlaysType {
|
||||||
Handles,
|
Handles,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct OverlaysVisibilitySettings {
|
pub struct OverlaysVisibilitySettings {
|
||||||
|
|
@ -59,6 +64,7 @@ pub struct OverlaysVisibilitySettings {
|
||||||
pub transform_cage: bool,
|
pub transform_cage: bool,
|
||||||
pub hover_outline: bool,
|
pub hover_outline: bool,
|
||||||
pub selection_outline: bool,
|
pub selection_outline: bool,
|
||||||
|
pub layer_origin_cross: bool,
|
||||||
pub pivot: bool,
|
pub pivot: bool,
|
||||||
pub origin: bool,
|
pub origin: bool,
|
||||||
pub path: bool,
|
pub path: bool,
|
||||||
|
|
@ -66,6 +72,7 @@ pub struct OverlaysVisibilitySettings {
|
||||||
pub handles: bool,
|
pub handles: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
impl Default for OverlaysVisibilitySettings {
|
impl Default for OverlaysVisibilitySettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -77,6 +84,7 @@ impl Default for OverlaysVisibilitySettings {
|
||||||
transform_cage: true,
|
transform_cage: true,
|
||||||
hover_outline: true,
|
hover_outline: true,
|
||||||
selection_outline: true,
|
selection_outline: true,
|
||||||
|
layer_origin_cross: true,
|
||||||
pivot: true,
|
pivot: true,
|
||||||
origin: true,
|
origin: true,
|
||||||
path: true,
|
path: true,
|
||||||
|
|
@ -86,6 +94,7 @@ impl Default for OverlaysVisibilitySettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
impl OverlaysVisibilitySettings {
|
impl OverlaysVisibilitySettings {
|
||||||
pub fn all(&self) -> bool {
|
pub fn all(&self) -> bool {
|
||||||
self.all
|
self.all
|
||||||
|
|
@ -119,6 +128,10 @@ impl OverlaysVisibilitySettings {
|
||||||
self.all && self.selection_outline
|
self.all && self.selection_outline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn layer_origin_cross(&self) -> bool {
|
||||||
|
self.all && self.layer_origin_cross
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pivot(&self) -> bool {
|
pub fn pivot(&self) -> bool {
|
||||||
self.all && self.pivot
|
self.all && self.pivot
|
||||||
}
|
}
|
||||||
|
|
@ -391,12 +404,14 @@ impl OverlayContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
pub enum Pivot {
|
pub enum Pivot {
|
||||||
Start,
|
Start,
|
||||||
Middle,
|
Middle,
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove duplicated definition of this in `utility_types_web.rs`
|
||||||
pub enum DrawHandles {
|
pub enum DrawHandles {
|
||||||
All,
|
All,
|
||||||
SelectedAnchors(HashMap<LayerNodeIdentifier, Vec<SegmentId>>),
|
SelectedAnchors(HashMap<LayerNodeIdentifier, Vec<SegmentId>>),
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ pub enum OverlaysType {
|
||||||
TransformCage,
|
TransformCage,
|
||||||
HoverOutline,
|
HoverOutline,
|
||||||
SelectionOutline,
|
SelectionOutline,
|
||||||
|
LayerOriginCross,
|
||||||
Pivot,
|
Pivot,
|
||||||
Origin,
|
Origin,
|
||||||
Path,
|
Path,
|
||||||
|
|
@ -55,6 +56,7 @@ pub struct OverlaysVisibilitySettings {
|
||||||
pub transform_cage: bool,
|
pub transform_cage: bool,
|
||||||
pub hover_outline: bool,
|
pub hover_outline: bool,
|
||||||
pub selection_outline: bool,
|
pub selection_outline: bool,
|
||||||
|
pub layer_origin_cross: bool,
|
||||||
pub pivot: bool,
|
pub pivot: bool,
|
||||||
pub origin: bool,
|
pub origin: bool,
|
||||||
pub path: bool,
|
pub path: bool,
|
||||||
|
|
@ -73,6 +75,7 @@ impl Default for OverlaysVisibilitySettings {
|
||||||
transform_cage: true,
|
transform_cage: true,
|
||||||
hover_outline: true,
|
hover_outline: true,
|
||||||
selection_outline: true,
|
selection_outline: true,
|
||||||
|
layer_origin_cross: true,
|
||||||
pivot: true,
|
pivot: true,
|
||||||
origin: true,
|
origin: true,
|
||||||
path: true,
|
path: true,
|
||||||
|
|
@ -115,6 +118,10 @@ impl OverlaysVisibilitySettings {
|
||||||
self.all && self.selection_outline
|
self.all && self.selection_outline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn layer_origin_cross(&self) -> bool {
|
||||||
|
self.all && self.layer_origin_cross
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pivot(&self) -> bool {
|
pub fn pivot(&self) -> bool {
|
||||||
self.all && self.pivot
|
self.all && self.pivot
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
use crate::consts::{COLOR_OVERLAY_BLUE, LAYER_ORIGIN_CROSS_DIAMETER, LAYER_ORIGIN_CROSS_THICKNESS};
|
||||||
|
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||||
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
|
use crate::messages::tool::tool_messages::tool_prelude::DocumentMessageHandler;
|
||||||
|
use glam::DVec2;
|
||||||
|
|
||||||
|
/// Draws a cross overlay at the origin point of the layers in layer space.
|
||||||
|
/// This cross is orientated based on the +X vector of the layer.
|
||||||
|
pub fn draw_for_selected_layers(overlay_context: &mut OverlayContext, document: &DocumentMessageHandler) {
|
||||||
|
// Don't draw if it is a disabled overlay
|
||||||
|
if !overlay_context.visibility_settings.layer_origin_cross() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only show for layers that are visible, unlocked, and selected
|
||||||
|
for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
|
||||||
|
// Don't show for artboards
|
||||||
|
if document.network_interface.is_artboard(&layer.to_node(), &[]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't crash if we accidentally have the root
|
||||||
|
if layer == LayerNodeIdentifier::ROOT_PARENT {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some layers such as groups don't have a local transform (although we'll likely design a fix for that fact later)
|
||||||
|
if !document.metadata().local_transforms.contains_key(&layer.to_node()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A transformation from the layer's local space to the viewport space (where overlays are drawn)
|
||||||
|
let transform_to_viewport = document.metadata().transform_to_viewport(layer);
|
||||||
|
|
||||||
|
// The origin of the layer in viewport space which is the center of the origin cross
|
||||||
|
let origin_viewport = transform_to_viewport.transform_point2(DVec2::ZERO);
|
||||||
|
// The forward +X direction vector from layer space (used to orient the origin cross)
|
||||||
|
let forward = transform_to_viewport.transform_vector2(DVec2::X).normalize_or_zero();
|
||||||
|
|
||||||
|
// Draw the origin cross
|
||||||
|
let offsets = [forward + forward.perp(), forward - forward.perp()].map(|offset| offset * core::f64::consts::FRAC_1_SQRT_2 * LAYER_ORIGIN_CROSS_DIAMETER / 2.);
|
||||||
|
for offset in offsets {
|
||||||
|
overlay_context.line(origin_viewport - offset, origin_viewport + offset, Some(COLOR_OVERLAY_BLUE), Some(LAYER_ORIGIN_CROSS_THICKNESS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ pub mod color_selector;
|
||||||
pub mod compass_rose;
|
pub mod compass_rose;
|
||||||
pub mod gizmos;
|
pub mod gizmos;
|
||||||
pub mod graph_modification_utils;
|
pub mod graph_modification_utils;
|
||||||
|
pub mod layer_origin_cross;
|
||||||
pub mod measure;
|
pub mod measure;
|
||||||
pub mod pivot;
|
pub mod pivot;
|
||||||
pub mod resize;
|
pub mod resize;
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
CheckboxInput::new(!state.disabled)
|
CheckboxInput::new(state.enabled)
|
||||||
.tooltip_label("Pivot Gizmo")
|
.tooltip_label("Pivot Gizmo")
|
||||||
.tooltip_description(
|
.tooltip_description(
|
||||||
"
|
"
|
||||||
|
|
@ -74,11 +74,11 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
|
||||||
)
|
)
|
||||||
.on_update(move |optional_input: &CheckboxInput| match source {
|
.on_update(move |optional_input: &CheckboxInput| match source {
|
||||||
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
PivotToolSource::Select => SelectToolMessage::SelectOptions {
|
||||||
options: SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
|
options: SelectOptionsUpdate::SetPivotGizmoEnabled(optional_input.checked),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
PivotToolSource::Path => PathToolMessage::UpdateOptions {
|
PivotToolSource::Path => PathToolMessage::UpdateOptions {
|
||||||
options: PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
|
options: PathOptionsUpdate::SetPivotGizmoEnabled(optional_input.checked),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
})
|
})
|
||||||
|
|
@ -101,7 +101,7 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
|
||||||
"
|
"
|
||||||
.trim(),
|
.trim(),
|
||||||
)
|
)
|
||||||
.disabled(state.disabled)
|
.disabled(!state.enabled)
|
||||||
.widget_instance(),
|
.widget_instance(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ pub struct PivotGizmo {
|
||||||
impl PivotGizmo {
|
impl PivotGizmo {
|
||||||
pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 {
|
pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 {
|
||||||
let network = &document.network_interface;
|
let network = &document.network_interface;
|
||||||
(!self.state.disabled)
|
(self.state.enabled)
|
||||||
.then_some({
|
.then_some({
|
||||||
match self.state.gizmo_type {
|
match self.state.gizmo_type {
|
||||||
PivotGizmoType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)),
|
PivotGizmoType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)),
|
||||||
|
|
@ -163,18 +163,18 @@ pub enum PivotGizmoType {
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct PivotGizmoState {
|
pub struct PivotGizmoState {
|
||||||
pub disabled: bool,
|
pub enabled: bool,
|
||||||
pub gizmo_type: PivotGizmoType,
|
pub gizmo_type: PivotGizmoType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PivotGizmoState {
|
impl PivotGizmoState {
|
||||||
pub fn is_pivot_type(&self) -> bool {
|
pub fn is_pivot_type(&self) -> bool {
|
||||||
// A disabled pivot is considered a pivot-type gizmo that is always centered
|
// A disabled pivot is considered a pivot-type gizmo that is always centered
|
||||||
self.gizmo_type == PivotGizmoType::Pivot || self.disabled
|
self.gizmo_type == PivotGizmoType::Pivot || !self.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_pivot(&self) -> bool {
|
pub fn is_pivot(&self) -> bool {
|
||||||
self.gizmo_type == PivotGizmoType::Pivot && !self.disabled
|
self.gizmo_type == PivotGizmoType::Pivot && self.enabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ pub enum PathOptionsUpdate {
|
||||||
PointEditingMode { enabled: bool },
|
PointEditingMode { enabled: bool },
|
||||||
SegmentEditingMode { enabled: bool },
|
SegmentEditingMode { enabled: bool },
|
||||||
PivotGizmoType(PivotGizmoType),
|
PivotGizmoType(PivotGizmoType),
|
||||||
TogglePivotGizmoType(bool),
|
SetPivotGizmoEnabled(bool),
|
||||||
TogglePivotPinned,
|
TogglePivotPinned,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -397,7 +397,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Path
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
}
|
}
|
||||||
PathOptionsUpdate::PivotGizmoType(gizmo_type) => {
|
PathOptionsUpdate::PivotGizmoType(gizmo_type) => {
|
||||||
if !self.tool_data.pivot_gizmo.state.disabled {
|
if !self.tool_data.pivot_gizmo.state.enabled {
|
||||||
self.tool_data.pivot_gizmo.state.gizmo_type = gizmo_type;
|
self.tool_data.pivot_gizmo.state.gizmo_type = gizmo_type;
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
let pivot_gizmo = self.tool_data.pivot_gizmo();
|
let pivot_gizmo = self.tool_data.pivot_gizmo();
|
||||||
|
|
@ -406,8 +406,8 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Path
|
||||||
self.send_layout(responses, LayoutTarget::ToolOptions);
|
self.send_layout(responses, LayoutTarget::ToolOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PathOptionsUpdate::TogglePivotGizmoType(state) => {
|
PathOptionsUpdate::SetPivotGizmoEnabled(enabled) => {
|
||||||
self.tool_data.pivot_gizmo.state.disabled = !state;
|
self.tool_data.pivot_gizmo.state.enabled = enabled;
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
self.send_layout(responses, LayoutTarget::ToolOptions);
|
self.send_layout(responses, LayoutTarget::ToolOptions);
|
||||||
|
|
@ -1571,7 +1571,7 @@ impl Fsm for PathToolFsmState {
|
||||||
let ToolMessage::Path(event) = event else { return self };
|
let ToolMessage::Path(event) = event else { return self };
|
||||||
|
|
||||||
// TODO(mTvare6): Remove once gizmos are implemented for path_tool
|
// TODO(mTvare6): Remove once gizmos are implemented for path_tool
|
||||||
tool_data.pivot_gizmo.state.disabled = true;
|
tool_data.pivot_gizmo.state.enabled = false;
|
||||||
|
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(_, PathToolMessage::SelectionChanged) => {
|
(_, PathToolMessage::SelectionChanged) => {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ pub struct SelectOptions {
|
||||||
pub enum SelectOptionsUpdate {
|
pub enum SelectOptionsUpdate {
|
||||||
NestedSelectionBehavior(NestedSelectionBehavior),
|
NestedSelectionBehavior(NestedSelectionBehavior),
|
||||||
PivotGizmoType(PivotGizmoType),
|
PivotGizmoType(PivotGizmoType),
|
||||||
TogglePivotGizmoType(bool),
|
SetPivotGizmoEnabled(bool),
|
||||||
TogglePivotPinned,
|
TogglePivotPinned,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,7 +240,7 @@ impl LayoutHolder for SelectTool {
|
||||||
widgets.push(Separator::new(SeparatorStyle::Related).widget_instance());
|
widgets.push(Separator::new(SeparatorStyle::Related).widget_instance());
|
||||||
|
|
||||||
let pin_active = self.tool_data.pivot_gizmo.pin_active();
|
let pin_active = self.tool_data.pivot_gizmo.pin_active();
|
||||||
let pin_enabled = self.tool_data.pivot_gizmo.pivot.old_pivot_position == ReferencePoint::None && !self.tool_data.pivot_gizmo.state.disabled;
|
let pin_enabled = self.tool_data.pivot_gizmo.pivot.old_pivot_position == ReferencePoint::None && self.tool_data.pivot_gizmo.state.enabled;
|
||||||
|
|
||||||
if pin_active || pin_enabled {
|
if pin_active || pin_enabled {
|
||||||
widgets.push(pin_pivot_widget(pin_active, pin_enabled, PivotToolSource::Select));
|
widgets.push(pin_pivot_widget(pin_active, pin_enabled, PivotToolSource::Select));
|
||||||
|
|
@ -275,14 +275,14 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Sele
|
||||||
let mut redraw_reference_pivot = false;
|
let mut redraw_reference_pivot = false;
|
||||||
|
|
||||||
if let ToolMessage::Select(SelectToolMessage::SelectOptions { options: ref option_update }) = message {
|
if let ToolMessage::Select(SelectToolMessage::SelectOptions { options: ref option_update }) = message {
|
||||||
match option_update {
|
match *option_update {
|
||||||
SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior) => {
|
SelectOptionsUpdate::NestedSelectionBehavior(nested_selection_behavior) => {
|
||||||
self.tool_data.nested_selection_behavior = *nested_selection_behavior;
|
self.tool_data.nested_selection_behavior = nested_selection_behavior;
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
}
|
}
|
||||||
SelectOptionsUpdate::PivotGizmoType(gizmo_type) => {
|
SelectOptionsUpdate::PivotGizmoType(gizmo_type) => {
|
||||||
if !self.tool_data.pivot_gizmo.state.disabled {
|
if !self.tool_data.pivot_gizmo.state.enabled {
|
||||||
self.tool_data.pivot_gizmo.state.gizmo_type = *gizmo_type;
|
self.tool_data.pivot_gizmo.state.gizmo_type = gizmo_type;
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
let pivot_gizmo = self.tool_data.pivot_gizmo();
|
let pivot_gizmo = self.tool_data.pivot_gizmo();
|
||||||
responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
|
responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
|
||||||
|
|
@ -290,8 +290,8 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Sele
|
||||||
redraw_reference_pivot = true;
|
redraw_reference_pivot = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SelectOptionsUpdate::TogglePivotGizmoType(state) => {
|
SelectOptionsUpdate::SetPivotGizmoEnabled(enabled) => {
|
||||||
self.tool_data.pivot_gizmo.state.disabled = !state;
|
self.tool_data.pivot_gizmo.state.enabled = enabled;
|
||||||
responses.add(ToolMessage::UpdateHints);
|
responses.add(ToolMessage::UpdateHints);
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
redraw_reference_pivot = true;
|
redraw_reference_pivot = true;
|
||||||
|
|
@ -610,6 +610,8 @@ impl Fsm for SelectToolFsmState {
|
||||||
(_, SelectToolMessage::Overlays { context: mut overlay_context }) => {
|
(_, SelectToolMessage::Overlays { context: mut overlay_context }) => {
|
||||||
tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
|
tool_data.snap_manager.draw_overlays(SnapData::new(document, input, viewport), &mut overlay_context);
|
||||||
|
|
||||||
|
crate::messages::tool::common_functionality::layer_origin_cross::draw_for_selected_layers(&mut overlay_context, document);
|
||||||
|
|
||||||
let selected_layers_count = document.network_interface.selected_nodes().selected_unlocked_layers(&document.network_interface).count();
|
let selected_layers_count = document.network_interface.selected_nodes().selected_unlocked_layers(&document.network_interface).count();
|
||||||
tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count;
|
tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count;
|
||||||
tool_data.selected_layers_count = selected_layers_count;
|
tool_data.selected_layers_count = selected_layers_count;
|
||||||
|
|
@ -731,6 +733,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
if let Some(bounds) = bounds {
|
if let Some(bounds) = bounds {
|
||||||
let bounding_box_manager = tool_data.bounding_box_manager.get_or_insert(BoundingBoxManager::default());
|
let bounding_box_manager = tool_data.bounding_box_manager.get_or_insert(BoundingBoxManager::default());
|
||||||
|
|
||||||
|
// TODO: Don't perform bounding box calculations here because the user can disable overlays which breaks bbox-based resizing
|
||||||
bounding_box_manager.bounds = bounds;
|
bounding_box_manager.bounds = bounds;
|
||||||
bounding_box_manager.transform = transform;
|
bounding_box_manager.transform = transform;
|
||||||
bounding_box_manager.transform_tampered = transform_tampered;
|
bounding_box_manager.transform_tampered = transform_tampered;
|
||||||
|
|
|
||||||
|
|
@ -686,7 +686,7 @@ fn calculate_pivot(
|
||||||
});
|
});
|
||||||
gizmo.pivot.recalculate_pivot_for_layer(document, bounds);
|
gizmo.pivot.recalculate_pivot_for_layer(document, bounds);
|
||||||
let position = || {
|
let position = || {
|
||||||
(if !gizmo.state.disabled {
|
(if gizmo.state.enabled {
|
||||||
match gizmo.state.gizmo_type {
|
match gizmo.state.gizmo_type {
|
||||||
PivotGizmoType::Average => None,
|
PivotGizmoType::Average => None,
|
||||||
PivotGizmoType::Active => gizmo.point.and_then(|p| get_location(&p)),
|
PivotGizmoType::Active => gizmo.point.and_then(|p| get_location(&p)),
|
||||||
|
|
|
||||||
|
|
@ -121,8 +121,8 @@ mod test_centroid {
|
||||||
#[test]
|
#[test]
|
||||||
fn centroid_rect() {
|
fn centroid_rect() {
|
||||||
let rect = Subpath::<PointId>::new_rectangle(DVec2::new(100., 100.), DVec2::new(300., 200.));
|
let rect = Subpath::<PointId>::new_rectangle(DVec2::new(100., 100.), DVec2::new(300., 200.));
|
||||||
let (centre, area) = rect.area_centroid_and_area(Some(1e-3), Some(1e-3)).unwrap();
|
let (center, area) = rect.area_centroid_and_area(Some(1e-3), Some(1e-3)).unwrap();
|
||||||
assert_eq!(area, 200. * 100.);
|
assert_eq!(area, 200. * 100.);
|
||||||
assert_eq!(centre, DVec2::new(200., 150.))
|
assert_eq!(center, DVec2::new(200., 150.))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue