Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::consts::{UI_SCALE_DEFAULT, UI_SCALE_MAX, UI_SCALE_MIN, VIEWPORT_ZOOM_WHEEL_RATE, VIEWPORT_ZOOM_WHEEL_RATE_CHANGE};
use crate::consts::{VIEWPORT_ZOOM_WHEEL_RATE, VIEWPORT_ZOOM_WHEEL_RATE_CHANGE};
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::wires::GraphWireStyle;
use crate::messages::preferences::SelectionMode;
Expand Down Expand Up @@ -155,14 +155,14 @@ impl PreferencesDialogMessageHandler {
rows.extend_from_slice(&[header, selection_label, selection_mode]);
}

// ==========
// UI
// ==========
// =========
// INTERFACE
// =========
#[cfg(not(target_family = "wasm"))]
{
let header = vec![TextLabel::new("UI").italic(true).widget_instance()];
let header = vec![TextLabel::new("Interface").italic(true).widget_instance()];

let scale_description = "Adjust the scale of the user interface (100 is default).";
let scale_description = "Adjust the scale of the entire user interface (100% is default).";
let scale_label = vec![
Separator::new(SeparatorType::Unrelated).widget_instance(),
Separator::new(SeparatorType::Unrelated).widget_instance(),
Expand All @@ -176,15 +176,18 @@ impl PreferencesDialogMessageHandler {
.tooltip_description(scale_description)
.mode_range()
.int()
.min(ui_scale_to_display(UI_SCALE_MIN))
.max(ui_scale_to_display(UI_SCALE_MAX))
.min(ui_scale_to_display(crate::consts::UI_SCALE_MIN))
.max(ui_scale_to_display(crate::consts::UI_SCALE_MAX))
.unit("%")
.on_update(|number_input: &NumberInput| {
if let Some(display_value) = number_input.value {
let scale = map_display_to_ui_scale(display_value);
PreferencesMessage::UIScale { scale }.into()
} else {
PreferencesMessage::UIScale { scale: UI_SCALE_DEFAULT }.into()
PreferencesMessage::UIScale {
scale: crate::consts::UI_SCALE_DEFAULT,
}
.into()
}
})
.widget_instance(),
Expand Down Expand Up @@ -376,11 +379,13 @@ fn map_zoom_rate_to_display(rate: f64) -> f64 {
}

/// Maps display values in percent to actual ui scale.
#[cfg(not(target_family = "wasm"))]
fn map_display_to_ui_scale(display: f64) -> f64 {
display / 100.
}

/// Maps actual ui scale back to display values in percent.
#[cfg(not(target_family = "wasm"))]
fn ui_scale_to_display(scale: f64) -> f64 {
scale * 100.
}
19 changes: 15 additions & 4 deletions editor/src/messages/portfolio/document/document_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ pub enum DocumentMessage {
},
DeleteSelectedLayers,
DeselectAllLayers,
DocumentHistoryBackward,
DocumentHistoryForward,
DocumentStructureChanged,
DrawArtboardOverlays {
context: OverlayContext,
Expand Down Expand Up @@ -110,7 +108,6 @@ pub enum DocumentMessage {
mouse: Option<(f64, f64)>,
parent_and_insert_index: Option<(LayerNodeIdentifier, usize)>,
},
Redo,
RenameDocument {
new_name: String,
},
Expand Down Expand Up @@ -179,12 +176,27 @@ pub enum DocumentMessage {
SetRenderMode {
render_mode: RenderMode,
},
Undo,
Redo,
DocumentHistoryBackward,
DocumentHistoryForward,
// TODO: Rename to HistoryStepPush
/// Create a snapshot of the document at this point in time, by immediately starting and committing a transaction.
AddTransaction,
// TODO: Rename to HistoryTransactionStart
/// Take a snapshot of the document to an intermediate state, and then depending on what we do next, we might either commit or abort it.
StartTransaction,
// TODO: Rename to HistoryTransactionEnd
/// Either commit (creating a new history step) or cancel (removing the last history step, as if it never happened) the last transaction started with `StartTransaction`.
EndTransaction,
// TODO: Remove this, make it into a private function
CommitTransaction,
// TODO: Remove this, make it into a private function
CancelTransaction,
/// Cause the document to revert back to the state when the transaction was started. For example, the user may be dragging
/// something around and hits Escape to abort the drag. This jumps the document back to the point before the drag began.
AbortTransaction,
/// The same as `AbortTransaction` with one step back, but it can also be called with multiple steps back in the history of undos.
RepeatedAbortTransaction {
undo_count: usize,
},
Expand All @@ -208,7 +220,6 @@ pub enum DocumentMessage {
UpdateClipTargets {
clip_targets: HashSet<NodeId>,
},
Undo,
UngroupSelectedLayers,
UngroupLayer {
layer: LayerNodeIdentifier,
Expand Down
86 changes: 49 additions & 37 deletions editor/src/messages/portfolio/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
self.layer_range_selection_reference = None;
}
DocumentMessage::DocumentHistoryBackward => self.undo_with_history(viewport, responses),
DocumentMessage::DocumentHistoryForward => self.redo_with_history(viewport, responses),
DocumentMessage::DocumentStructureChanged => {
if layers_panel_open {
self.network_interface.load_structure();
Expand Down Expand Up @@ -953,15 +951,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
responses.add(ToolMessage::ActivateTool { tool_type: ToolType::Select });
}
DocumentMessage::Redo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(SelectToolMessage::Abort);
responses.add(DocumentMessage::DocumentHistoryForward);
responses.add(ToolMessage::Redo);
responses.add(OverlaysMessage::Draw);
}
DocumentMessage::RenameDocument { new_name } => {
self.name = new_name.clone();

Expand Down Expand Up @@ -1291,6 +1280,27 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
self.render_mode = render_mode;
responses.add_front(NodeGraphMessage::RunDocumentGraph);
}
DocumentMessage::Undo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(ToolMessage::PreUndo);
responses.add(DocumentMessage::DocumentHistoryBackward);
responses.add(OverlaysMessage::Draw);
responses.add(ToolMessage::Undo);
}
DocumentMessage::Redo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(SelectToolMessage::Abort);
responses.add(DocumentMessage::DocumentHistoryForward);
responses.add(ToolMessage::Redo);
responses.add(OverlaysMessage::Draw);
}
DocumentMessage::DocumentHistoryBackward => self.undo_with_history(viewport, responses),
DocumentMessage::DocumentHistoryForward => self.redo_with_history(viewport, responses),
// Create a snapshot of the document at this point in time, by immediately starting and committing a transaction.
DocumentMessage::AddTransaction => {
// Reverse order since they are added to the front
responses.add_front(DocumentMessage::CommitTransaction);
Expand All @@ -1307,20 +1317,18 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
}
// Commits the transaction if the network was mutated since the transaction started, otherwise it cancels the transaction
// Either commit (creating a new history step) or cancel (removing the last history step, as if it never happened) the last transaction started with `StartTransaction`.
DocumentMessage::EndTransaction => match self.network_interface.transaction_status() {
TransactionStatus::Started => {
responses.add_front(DocumentMessage::CancelTransaction);
}
TransactionStatus::Modified => {
responses.add_front(DocumentMessage::CommitTransaction);
}
// This is used if, between the start and end of the transaction, the changes were undone by the user.
// For example, dragging something around and then dropping it back at its exact original position.
// So we cancel the transaction to return to the point before the transaction was started.
TransactionStatus::Started => responses.add_front(DocumentMessage::CancelTransaction),
// This is used if, between the start and end of the transaction, actual changes did occur and we want to keep them as part of a history step that the user can undo/redo.
TransactionStatus::Modified => responses.add_front(DocumentMessage::CommitTransaction),
// This is an erroneous state indicating that a transaction is being ended without having ever been started.
TransactionStatus::Finished => {}
},
DocumentMessage::CancelTransaction => {
self.network_interface.finish_transaction();
self.document_undo_history.pop_back();
}
// Add a history step so the user can undo/redo to the point when the transaction was started.
DocumentMessage::CommitTransaction => {
if self.network_interface.transaction_status() == TransactionStatus::Finished {
return;
Expand All @@ -1329,25 +1337,38 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
self.document_redo_history.clear();
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
}
// Retroactively undoes the start of the transaction, as if the transaction was never started. This is useful, for example, if the user
// might have begun performing some action that ends up not changing anything, like dragging something back to its exact original position.
DocumentMessage::CancelTransaction => {
self.network_interface.finish_transaction();
self.document_undo_history.pop_back();
}
// Cause the document to revert back to the state when the transaction was started. For example, the user may be dragging
// something around and hits Escape to abort the drag. This jumps the document back to the point before the drag began.
DocumentMessage::AbortTransaction => match self.network_interface.transaction_status() {
TransactionStatus::Started => {
responses.add_front(DocumentMessage::CancelTransaction);
}
TransactionStatus::Modified => {
responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: 1 });
}
// If we abort a transaction without any changes having been made, we simply remove the transaction as if it never occurred.
TransactionStatus::Started => responses.add_front(DocumentMessage::CancelTransaction),
// If we abort a transaction after changes have been made, we need to undo those changes.
TransactionStatus::Modified => responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: 1 }),
// This is an erroneous state indicating that a transaction is being aborted without having ever been started.
TransactionStatus::Finished => {}
},
// The same as `AbortTransaction` with one step back, but it can also be called with multiple steps back in the history of undos.
DocumentMessage::RepeatedAbortTransaction { undo_count } => {
// This prevents us from aborting a transaction multiple times in a row, which would be erroneous.
if self.network_interface.transaction_status() == TransactionStatus::Finished {
return;
}

// Sometimes (like successive G/R/S transformations) we may need to undo multiple steps to fully abort the transaction, before we finish.
for _ in 0..undo_count {
self.undo(viewport, responses);
}

// Finally finish the transaction, ensuring that any future operations are not erroneously redone as part of this aborted transaction.
self.network_interface.finish_transaction();

// Refresh state
responses.add(OverlaysMessage::Draw);
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
}
Expand Down Expand Up @@ -1419,15 +1440,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
DocumentMessage::UpdateClipTargets { clip_targets } => {
self.network_interface.update_clip_targets(clip_targets);
}
DocumentMessage::Undo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
}
responses.add(ToolMessage::PreUndo);
responses.add(DocumentMessage::DocumentHistoryBackward);
responses.add(OverlaysMessage::Draw);
responses.add(ToolMessage::Undo);
}
DocumentMessage::UngroupSelectedLayers => {
if !self.selection_network_path.is_empty() {
log::error!("Ungrouping selected layers is only supported for the Document Network");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::messages::prelude::*;
use graph_craft::wasm_application_io::EditorPreferences;

#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type, ExtractField)]
#[serde(default)]
pub struct PreferencesMessageHandler {
pub selection_mode: SelectionMode,
pub zoom_with_scroll: bool,
Expand Down
1 change: 1 addition & 0 deletions editor/src/messages/tool/common_functionality/pivot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ pub struct PivotGizmoState {

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
}

Expand Down
7 changes: 5 additions & 2 deletions frontend/src/components/layout/FloatingMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,9 @@
// Start with the parent of the spawner for this floating menu and keep widening the search for any other valid spawners that are hover-transferrable
let currentAncestor = (targetSpawner && ownSpawner?.parentElement) || undefined;
while (currentAncestor) {
// If the current ancestor blocks hover transfer, stop searching
if (currentAncestor.hasAttribute("data-block-hover-transfer")) break;

const ownSpawnerDepthFromCurrentAncestor = ownSpawner && getDepthFromAncestor(ownSpawner, currentAncestor);
const currentAncestor2 = currentAncestor; // This duplicate variable avoids an ESLint warning

Expand All @@ -382,8 +385,8 @@
const notOurself = !ownDescendantMenuSpawners.includes(item);
// And filter away unequal depths from the current ancestor
const notUnequalDepths = notOurself && getDepthFromAncestor(item, currentAncestor2) === ownSpawnerDepthFromCurrentAncestor;
// And filter away elements that explicitly disable hover transfer
return notUnequalDepths && !(item as HTMLElement).getAttribute?.("data-floating-menu-spawner")?.includes("no-hover-transfer");
// And filter away descendants that explicitly disable hover transfer
return notUnequalDepths && !(item instanceof HTMLElement && item.hasAttribute("data-block-hover-transfer"));
});

// If none were found, widen the search by a level and keep trying (or stop looping if the root was reached)
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/views/Graph.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
style:--layer-area-width={layerAreaWidth}
style:--node-chain-area-left-extension={layerChainWidth !== 0 ? layerChainWidth + 0.5 : 0}
data-tooltip-label={node.displayName === node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-label={node.displayName === node.reference || !node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-description={`
${(description || "").trim()}${editor.handle.inDevelopmentMode() ? `\n\nID: ${node.id}. Position: (${node.position.x}, ${node.position.y}).` : ""}
`.trim()}
Expand Down Expand Up @@ -651,7 +651,7 @@
style:--clip-path-id={`url(#${clipPathId})`}
style:--data-color={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()})`}
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
data-tooltip-label={node.displayName === node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-label={node.displayName === node.reference || !node.reference ? node.displayName : `${node.displayName} (${node.reference})`}
data-tooltip-description={`
${(description || "").trim()}${editor.handle.inDevelopmentMode() ? `\n\nID: ${node.id}. Position: (${node.position.x}, ${node.position.y}).` : ""}
`.trim()}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/widgets/WidgetSection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
/>
</button>
{#if expanded}
<LayoutCol class="body">
<LayoutCol class="body" data-block-hover-transfer>
{#each widgetData.layout as layoutGroup}
{#if isWidgetSpanRow(layoutGroup)}
<WidgetSpan widgetData={layoutGroup} {layoutTarget} />
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/widgets/buttons/TextButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@
data-disabled={disabled || undefined}
data-text-button
tabindex={disabled ? -1 : 0}
data-floating-menu-spawner={menuListChildrenExists ? "" : "no-hover-transfer"}
data-floating-menu-spawner
data-block-hover-transfer={menuListChildrenExists ? undefined : ""}
on:click={onClick}
>
{#if icon}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

<LayoutCol class="working-colors-button">
<LayoutRow class="primary swatch">
<button on:click={clickPrimarySwatch} class:open={primaryOpen} style:--swatch-color={primary.toRgbaCSS()} data-floating-menu-spawner="no-hover-transfer" tabindex="0"></button>
<button on:click={clickPrimarySwatch} class:open={primaryOpen} style:--swatch-color={primary.toRgbaCSS()} data-floating-menu-spawner data-block-hover-transfer tabindex="0"></button>
<ColorPicker
open={primaryOpen}
on:open={({ detail }) => (primaryOpen = detail)}
Expand All @@ -47,7 +47,7 @@
/>
</LayoutRow>
<LayoutRow class="secondary swatch">
<button on:click={clickSecondarySwatch} class:open={secondaryOpen} style:--swatch-color={secondary.toRgbaCSS()} data-floating-menu-spawner="no-hover-transfer" tabindex="0"></button>
<button on:click={clickSecondarySwatch} class:open={secondaryOpen} style:--swatch-color={secondary.toRgbaCSS()} data-floating-menu-spawner data-block-hover-transfer tabindex="0"></button>
<ColorPicker
open={secondaryOpen}
on:open={({ detail }) => (secondaryOpen = detail)}
Expand Down
2 changes: 1 addition & 1 deletion node-graph/libraries/vector-types/src/vector/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use glam::DVec2;
use kurbo::{BezPath, CubicBez, Line, ParamCurve, PathSeg, Point, QuadBez};
use std::ops::Sub;

/// Represents different ways of calculating the centroid.
/// Represents different geometric interpretations of calculating the centroid (center of mass).
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
#[widget(Radio)]
pub enum CentroidType {
Expand Down
1 change: 0 additions & 1 deletion node-graph/libraries/vector-types/src/vector/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ impl From<Fill> for FillChoice {
}
}

/// Enum describing the type of [Fill].
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, PartialEq, serde::Serialize, serde::Deserialize, DynAny, Hash, specta::Type, node_macro::ChoiceType)]
#[widget(Radio)]
Expand Down
Loading