Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions editor/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ pub const DEFAULT_STROKE_WIDTH: f64 = 2.;
pub const SELECTION_TOLERANCE: f64 = 5.;
pub const DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD: f64 = 15.;
pub const SELECTION_DRAG_ANGLE: f64 = 90.;
pub const LAYER_ORIGIN_CROSS_DIAMETER: f64 = 10.;
pub const LAYER_ORIGIN_CROSS_THICKNESS: f64 = 1.;

// PIVOT
pub const PIVOT_CROSSHAIR_THICKNESS: f64 = 1.;
Expand Down
19 changes: 19 additions & 0 deletions editor/src/messages/portfolio/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
OverlaysType::TransformCage => visibility_settings.transform_cage = visible,
OverlaysType::HoverOutline => visibility_settings.hover_outline = visible,
OverlaysType::SelectionOutline => visibility_settings.selection_outline = visible,
OverlaysType::LayerOriginCross => visibility_settings.layer_origin_cross = visible,
OverlaysType::Pivot => visibility_settings.pivot = visible,
OverlaysType::Origin => visibility_settings.origin = visible,
OverlaysType::Path => visibility_settings.path = visible,
Expand Down Expand Up @@ -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 {
widgets: vec![TextLabel::new("Pen & Path Tools").widget_instance()],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@ use std::sync::{Arc, Mutex, MutexGuard};
use vello::Scene;
use vello::peniko;

// TODO Remove duplicated definition of this in `utility_types_web.rs`
pub type OverlayProvider = fn(OverlayContext) -> Message;

// TODO Remove duplicated definition of this in `utility_types_web.rs`
pub fn empty_provider() -> OverlayProvider {
|_| 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.
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
pub enum OverlaysType {
Expand All @@ -41,13 +44,15 @@ pub enum OverlaysType {
TransformCage,
HoverOutline,
SelectionOutline,
LayerOriginCross,
Pivot,
Origin,
Path,
Anchors,
Handles,
}

// TODO Remove duplicated definition of this in `utility_types_web.rs`
#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
#[serde(default)]
pub struct OverlaysVisibilitySettings {
Expand All @@ -59,13 +64,15 @@ pub struct OverlaysVisibilitySettings {
pub transform_cage: bool,
pub hover_outline: bool,
pub selection_outline: bool,
pub layer_origin_cross: bool,
pub pivot: bool,
pub origin: bool,
pub path: bool,
pub anchors: bool,
pub handles: bool,
}

// TODO Remove duplicated definition of this in `utility_types_web.rs`
impl Default for OverlaysVisibilitySettings {
fn default() -> Self {
Self {
Expand All @@ -77,6 +84,7 @@ impl Default for OverlaysVisibilitySettings {
transform_cage: true,
hover_outline: true,
selection_outline: true,
layer_origin_cross: true,
pivot: true,
origin: true,
path: true,
Expand All @@ -86,6 +94,7 @@ impl Default for OverlaysVisibilitySettings {
}
}

// TODO Remove duplicated definition of this in `utility_types_web.rs`
impl OverlaysVisibilitySettings {
pub fn all(&self) -> bool {
self.all
Expand Down Expand Up @@ -119,6 +128,10 @@ impl OverlaysVisibilitySettings {
self.all && self.selection_outline
}

pub fn layer_origin_cross(&self) -> bool {
self.all && self.layer_origin_cross
}

pub fn pivot(&self) -> bool {
self.all && self.pivot
}
Expand Down Expand Up @@ -391,12 +404,14 @@ impl OverlayContext {
}
}

// TODO Remove duplicated definition of this in `utility_types_web.rs`
pub enum Pivot {
Start,
Middle,
End,
}

// TODO Remove duplicated definition of this in `utility_types_web.rs`
pub enum DrawHandles {
All,
SelectedAnchors(HashMap<LayerNodeIdentifier, Vec<SegmentId>>),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub enum OverlaysType {
TransformCage,
HoverOutline,
SelectionOutline,
LayerOriginCross,
Pivot,
Origin,
Path,
Expand All @@ -55,6 +56,7 @@ pub struct OverlaysVisibilitySettings {
pub transform_cage: bool,
pub hover_outline: bool,
pub selection_outline: bool,
pub layer_origin_cross: bool,
pub pivot: bool,
pub origin: bool,
pub path: bool,
Expand All @@ -73,6 +75,7 @@ impl Default for OverlaysVisibilitySettings {
transform_cage: true,
hover_outline: true,
selection_outline: true,
layer_origin_cross: true,
pivot: true,
origin: true,
path: true,
Expand Down Expand Up @@ -115,6 +118,10 @@ impl OverlaysVisibilitySettings {
self.all && self.selection_outline
}

pub fn layer_origin_cross(&self) -> bool {
self.all && self.layer_origin_cross
}

pub fn pivot(&self) -> bool {
self.all && self.pivot
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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));
}
}
}
1 change: 1 addition & 0 deletions editor/src/messages/tool/common_functionality/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod color_selector;
pub mod compass_rose;
pub mod gizmos;
pub mod graph_modification_utils;
pub mod layer_origin_cross;
pub mod measure;
pub mod pivot;
pub mod resize;
Expand Down
16 changes: 8 additions & 8 deletions editor/src/messages/tool/common_functionality/pivot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
.collect();

vec![
CheckboxInput::new(!state.disabled)
CheckboxInput::new(state.enabled)
.tooltip_label("Pivot Gizmo")
.tooltip_description(
"
Expand All @@ -74,11 +74,11 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
)
.on_update(move |optional_input: &CheckboxInput| match source {
PivotToolSource::Select => SelectToolMessage::SelectOptions {
options: SelectOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
options: SelectOptionsUpdate::SetPivotGizmoEnabled(optional_input.checked),
}
.into(),
PivotToolSource::Path => PathToolMessage::UpdateOptions {
options: PathOptionsUpdate::TogglePivotGizmoType(optional_input.checked),
options: PathOptionsUpdate::SetPivotGizmoEnabled(optional_input.checked),
}
.into(),
})
Expand All @@ -101,7 +101,7 @@ pub fn pivot_gizmo_type_widget(state: PivotGizmoState, source: PivotToolSource)
"
.trim(),
)
.disabled(state.disabled)
.disabled(!state.enabled)
.widget_instance(),
]
}
Expand All @@ -124,7 +124,7 @@ pub struct PivotGizmo {
impl PivotGizmo {
pub fn position(&self, document: &DocumentMessageHandler) -> DVec2 {
let network = &document.network_interface;
(!self.state.disabled)
(self.state.enabled)
.then_some({
match self.state.gizmo_type {
PivotGizmoType::Average => Some(network.selected_nodes().selected_visible_and_unlocked_layers_mean_average_origin(network)),
Expand Down Expand Up @@ -163,18 +163,18 @@ pub enum PivotGizmoType {

#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct PivotGizmoState {
pub disabled: bool,
pub enabled: bool,
pub gizmo_type: PivotGizmoType,
}

impl PivotGizmoState {
pub fn is_pivot_type(&self) -> bool {
// 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 {
self.gizmo_type == PivotGizmoType::Pivot && !self.disabled
self.gizmo_type == PivotGizmoType::Pivot && self.enabled
}
}

Expand Down
10 changes: 5 additions & 5 deletions editor/src/messages/tool/tool_messages/path_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ pub enum PathOptionsUpdate {
PointEditingMode { enabled: bool },
SegmentEditingMode { enabled: bool },
PivotGizmoType(PivotGizmoType),
TogglePivotGizmoType(bool),
SetPivotGizmoEnabled(bool),
TogglePivotPinned,
}

Expand Down Expand Up @@ -397,7 +397,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Path
responses.add(OverlaysMessage::Draw);
}
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;
responses.add(ToolMessage::UpdateHints);
let pivot_gizmo = self.tool_data.pivot_gizmo();
Expand All @@ -406,8 +406,8 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Path
self.send_layout(responses, LayoutTarget::ToolOptions);
}
}
PathOptionsUpdate::TogglePivotGizmoType(state) => {
self.tool_data.pivot_gizmo.state.disabled = !state;
PathOptionsUpdate::SetPivotGizmoEnabled(enabled) => {
self.tool_data.pivot_gizmo.state.enabled = enabled;
responses.add(ToolMessage::UpdateHints);
responses.add(NodeGraphMessage::RunDocumentGraph);
self.send_layout(responses, LayoutTarget::ToolOptions);
Expand Down Expand Up @@ -1571,7 +1571,7 @@ impl Fsm for PathToolFsmState {
let ToolMessage::Path(event) = event else { return self };

// 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) {
(_, PathToolMessage::SelectionChanged) => {
Expand Down
19 changes: 11 additions & 8 deletions editor/src/messages/tool/tool_messages/select_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct SelectOptions {
pub enum SelectOptionsUpdate {
NestedSelectionBehavior(NestedSelectionBehavior),
PivotGizmoType(PivotGizmoType),
TogglePivotGizmoType(bool),
SetPivotGizmoEnabled(bool),
TogglePivotPinned,
}

Expand Down Expand Up @@ -240,7 +240,7 @@ impl LayoutHolder for SelectTool {
widgets.push(Separator::new(SeparatorStyle::Related).widget_instance());

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 {
widgets.push(pin_pivot_widget(pin_active, pin_enabled, PivotToolSource::Select));
Expand Down Expand Up @@ -275,23 +275,23 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Sele
let mut redraw_reference_pivot = false;

if let ToolMessage::Select(SelectToolMessage::SelectOptions { options: ref option_update }) = message {
match option_update {
match *option_update {
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);
}
SelectOptionsUpdate::PivotGizmoType(gizmo_type) => {
if !self.tool_data.pivot_gizmo.state.disabled {
self.tool_data.pivot_gizmo.state.gizmo_type = *gizmo_type;
if !self.tool_data.pivot_gizmo.state.enabled {
self.tool_data.pivot_gizmo.state.gizmo_type = gizmo_type;
responses.add(ToolMessage::UpdateHints);
let pivot_gizmo = self.tool_data.pivot_gizmo();
responses.add(TransformLayerMessage::SetPivotGizmo { pivot_gizmo });
responses.add(NodeGraphMessage::RunDocumentGraph);
redraw_reference_pivot = true;
}
}
SelectOptionsUpdate::TogglePivotGizmoType(state) => {
self.tool_data.pivot_gizmo.state.disabled = !state;
SelectOptionsUpdate::SetPivotGizmoEnabled(enabled) => {
self.tool_data.pivot_gizmo.state.enabled = enabled;
responses.add(ToolMessage::UpdateHints);
responses.add(NodeGraphMessage::RunDocumentGraph);
redraw_reference_pivot = true;
Expand Down Expand Up @@ -610,6 +610,8 @@ impl Fsm for SelectToolFsmState {
(_, SelectToolMessage::Overlays { context: 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();
tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count;
tool_data.selected_layers_count = selected_layers_count;
Expand Down Expand Up @@ -731,6 +733,7 @@ impl Fsm for SelectToolFsmState {
if let Some(bounds) = bounds {
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.transform = transform;
bounding_box_manager.transform_tampered = transform_tampered;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ fn calculate_pivot(
});
gizmo.pivot.recalculate_pivot_for_layer(document, bounds);
let position = || {
(if !gizmo.state.disabled {
(if gizmo.state.enabled {
match gizmo.state.gizmo_type {
PivotGizmoType::Average => None,
PivotGizmoType::Active => gizmo.point.and_then(|p| get_location(&p)),
Expand Down
Loading
Loading