mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 19:18:13 +08:00
Retire layer paths used throughout the code (#1531)
* Part 1 * Part 2 * Part 3 * Part 4 * Part 5 * Part 6 * Part 7 * Part 8
This commit is contained in:
@@ -38,10 +38,9 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
|
|||||||
PropertiesPanelMessageDiscriminant::Refresh,
|
PropertiesPanelMessageDiscriminant::Refresh,
|
||||||
))),
|
))),
|
||||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)),
|
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)),
|
||||||
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure),
|
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerStructure),
|
||||||
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
|
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
|
||||||
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::DocumentIsDirty)),
|
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::DocumentIsDirty)),
|
||||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::InputFrameRasterizeRegionBelowLayer)),
|
|
||||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::Overlays(OverlaysMessageDiscriminant::Draw))),
|
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::Overlays(OverlaysMessageDiscriminant::Draw))),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -262,6 +261,7 @@ mod test {
|
|||||||
use crate::messages::tool::tool_messages::tool_prelude::ToolType;
|
use crate::messages::tool::tool_messages::tool_prelude::ToolType;
|
||||||
use crate::test_utils::EditorTestUtils;
|
use crate::test_utils::EditorTestUtils;
|
||||||
|
|
||||||
|
use graph_craft::document::NodeId;
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_core::raster::color::Color;
|
||||||
|
|
||||||
fn init_logger() {
|
fn init_logger() {
|
||||||
@@ -359,7 +359,7 @@ mod test {
|
|||||||
fn copy_paste_folder() {
|
fn copy_paste_folder() {
|
||||||
let mut editor = create_editor_with_three_layers();
|
let mut editor = create_editor_with_three_layers();
|
||||||
|
|
||||||
const FOLDER_ID: u64 = 3;
|
const FOLDER_ID: NodeId = 3;
|
||||||
|
|
||||||
editor.handle_message(GraphOperationMessage::NewCustomLayer {
|
editor.handle_message(GraphOperationMessage::NewCustomLayer {
|
||||||
id: FOLDER_ID,
|
id: FOLDER_ID,
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ impl LayoutHolder for ExportDialogMessageHandler {
|
|||||||
NumberInput::new(Some(self.scale_factor))
|
NumberInput::new(Some(self.scale_factor))
|
||||||
.unit("")
|
.unit("")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.disabled(self.file_type == FileType::Svg)
|
.disabled(self.file_type == FileType::Svg)
|
||||||
.on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor(number_input.value.unwrap()).into())
|
.on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor(number_input.value.unwrap()).into())
|
||||||
.min_width(200)
|
.min_width(200)
|
||||||
|
|||||||
+2
-2
@@ -95,7 +95,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
|||||||
.label("W")
|
.label("W")
|
||||||
.unit(" px")
|
.unit(" px")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.is_integer(true)
|
.is_integer(true)
|
||||||
.disabled(self.infinite)
|
.disabled(self.infinite)
|
||||||
.min_width(100)
|
.min_width(100)
|
||||||
@@ -106,7 +106,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
|||||||
.label("H")
|
.label("H")
|
||||||
.unit(" px")
|
.unit(" px")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.is_integer(true)
|
.is_integer(true)
|
||||||
.disabled(self.infinite)
|
.disabled(self.infinite)
|
||||||
.min_width(100)
|
.min_width(100)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ impl PreferencesDialogMessageHandler {
|
|||||||
NumberInput::new(Some(preferences.imaginate_refresh_frequency))
|
NumberInput::new(Some(preferences.imaginate_refresh_frequency))
|
||||||
.unit(" seconds")
|
.unit(" seconds")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.min_width(200)
|
.min_width(200)
|
||||||
.on_update(|number_input: &NumberInput| PreferencesMessage::ImaginateRefreshFrequency { seconds: number_input.value.unwrap() }.into())
|
.on_update(|number_input: &NumberInput| PreferencesMessage::ImaginateRefreshFrequency { seconds: number_input.value.unwrap() }.into())
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::messages::prelude::*;
|
|||||||
/// A dialog for confirming the closing a document with unsaved changes.
|
/// A dialog for confirming the closing a document with unsaved changes.
|
||||||
pub struct CloseDocumentDialog {
|
pub struct CloseDocumentDialog {
|
||||||
pub document_name: String,
|
pub document_name: String,
|
||||||
pub document_id: u64,
|
pub document_id: DocumentId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DialogLayoutHolder for CloseDocumentDialog {
|
impl DialogLayoutHolder for CloseDocumentDialog {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ pub enum FrontendMessage {
|
|||||||
TriggerImport,
|
TriggerImport,
|
||||||
TriggerIndexedDbRemoveDocument {
|
TriggerIndexedDbRemoveDocument {
|
||||||
#[serde(rename = "documentId")]
|
#[serde(rename = "documentId")]
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
TriggerIndexedDbWriteDocument {
|
TriggerIndexedDbWriteDocument {
|
||||||
document: String,
|
document: String,
|
||||||
@@ -111,7 +111,7 @@ pub enum FrontendMessage {
|
|||||||
// Update prefix: give the frontend a new value or state for it to use
|
// Update prefix: give the frontend a new value or state for it to use
|
||||||
UpdateActiveDocument {
|
UpdateActiveDocument {
|
||||||
#[serde(rename = "documentId")]
|
#[serde(rename = "documentId")]
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
UpdateDialogButtons {
|
UpdateDialogButtons {
|
||||||
#[serde(rename = "layoutTarget")]
|
#[serde(rename = "layoutTarget")]
|
||||||
@@ -139,11 +139,11 @@ pub enum FrontendMessage {
|
|||||||
UpdateDocumentLayerDetails {
|
UpdateDocumentLayerDetails {
|
||||||
data: LayerPanelEntry,
|
data: LayerPanelEntry,
|
||||||
},
|
},
|
||||||
UpdateDocumentLayerTreeStructure {
|
UpdateDocumentLayerStructure {
|
||||||
#[serde(rename = "dataBuffer")]
|
#[serde(rename = "dataBuffer")]
|
||||||
data_buffer: RawBuffer,
|
data_buffer: RawBuffer,
|
||||||
},
|
},
|
||||||
UpdateDocumentLayerTreeStructureJs {
|
UpdateDocumentLayerStructureJs {
|
||||||
#[serde(rename = "dataBuffer")]
|
#[serde(rename = "dataBuffer")]
|
||||||
data_buffer: JsRawBuffer,
|
data_buffer: JsRawBuffer,
|
||||||
},
|
},
|
||||||
@@ -180,7 +180,7 @@ pub enum FrontendMessage {
|
|||||||
},
|
},
|
||||||
UpdateImageData {
|
UpdateImageData {
|
||||||
#[serde(rename = "documentId")]
|
#[serde(rename = "documentId")]
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
#[serde(rename = "imageData")]
|
#[serde(rename = "imageData")]
|
||||||
image_data: Vec<FrontendImageData>,
|
image_data: Vec<FrontendImageData>,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -10,18 +10,14 @@ pub struct FrontendDocumentDetails {
|
|||||||
#[serde(rename = "isSaved")]
|
#[serde(rename = "isSaved")]
|
||||||
pub is_saved: bool,
|
pub is_saved: bool,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: u64,
|
pub id: DocumentId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)]
|
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)]
|
||||||
pub struct FrontendImageData {
|
pub struct FrontendImageData {
|
||||||
pub path: Vec<LayerId>,
|
|
||||||
pub mime: String,
|
pub mime: String,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub image_data: std::sync::Arc<Vec<u8>>,
|
pub image_data: std::sync::Arc<Vec<u8>>,
|
||||||
pub transform: Option<[f64; 6]>,
|
|
||||||
#[serde(rename = "nodeId")]
|
|
||||||
pub node_id: Option<graph_craft::document::NodeId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize, specta::Type)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize, specta::Type)]
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
|
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis};
|
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis};
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use graph_craft::document::{NodeId, NodeNetwork};
|
use graph_craft::document::{NodeId, NodeNetwork};
|
||||||
@@ -42,14 +41,14 @@ pub enum DocumentMessage {
|
|||||||
BackupDocument {
|
BackupDocument {
|
||||||
network: NodeNetwork,
|
network: NodeNetwork,
|
||||||
},
|
},
|
||||||
ClearLayerTree,
|
ClearLayersPanel,
|
||||||
CommitTransaction,
|
CommitTransaction,
|
||||||
CreateEmptyFolder {
|
CreateEmptyFolder {
|
||||||
parent: LayerNodeIdentifier,
|
parent: LayerNodeIdentifier,
|
||||||
},
|
},
|
||||||
DebugPrintDocument,
|
DebugPrintDocument,
|
||||||
DeleteLayer {
|
DeleteLayer {
|
||||||
layer_path: Vec<LayerId>,
|
id: NodeId,
|
||||||
},
|
},
|
||||||
DeleteSelectedLayers,
|
DeleteSelectedLayers,
|
||||||
DeselectAllLayers,
|
DeselectAllLayers,
|
||||||
@@ -61,20 +60,11 @@ pub enum DocumentMessage {
|
|||||||
flip_axis: FlipAxis,
|
flip_axis: FlipAxis,
|
||||||
},
|
},
|
||||||
GroupSelectedLayers,
|
GroupSelectedLayers,
|
||||||
ImaginateClear {
|
ImaginateGenerate,
|
||||||
layer_path: Vec<LayerId>,
|
|
||||||
},
|
|
||||||
ImaginateGenerate {
|
|
||||||
layer_path: Vec<LayerId>,
|
|
||||||
},
|
|
||||||
ImaginateRandom {
|
ImaginateRandom {
|
||||||
layer_path: Vec<LayerId>,
|
|
||||||
imaginate_node: Vec<NodeId>,
|
imaginate_node: Vec<NodeId>,
|
||||||
then_generate: bool,
|
then_generate: bool,
|
||||||
},
|
},
|
||||||
InputFrameRasterizeRegionBelowLayer {
|
|
||||||
layer_path: Vec<LayerId>,
|
|
||||||
},
|
|
||||||
MoveSelectedLayersTo {
|
MoveSelectedLayersTo {
|
||||||
parent: LayerNodeIdentifier,
|
parent: LayerNodeIdentifier,
|
||||||
insert_index: isize,
|
insert_index: isize,
|
||||||
@@ -106,7 +96,7 @@ pub enum DocumentMessage {
|
|||||||
relative_index_offset: isize,
|
relative_index_offset: isize,
|
||||||
},
|
},
|
||||||
SelectLayer {
|
SelectLayer {
|
||||||
layer_path: Vec<LayerId>,
|
id: NodeId,
|
||||||
ctrl: bool,
|
ctrl: bool,
|
||||||
shift: bool,
|
shift: bool,
|
||||||
},
|
},
|
||||||
@@ -132,7 +122,7 @@ pub enum DocumentMessage {
|
|||||||
},
|
},
|
||||||
StartTransaction,
|
StartTransaction,
|
||||||
ToggleLayerExpansion {
|
ToggleLayerExpansion {
|
||||||
layer: NodeId,
|
id: NodeId,
|
||||||
},
|
},
|
||||||
Undo,
|
Undo,
|
||||||
UndoFinished,
|
UndoFinished,
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
|||||||
use crate::messages::portfolio::document::utility_types::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier};
|
use crate::messages::portfolio::document::utility_types::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier};
|
||||||
use crate::messages::portfolio::document::utility_types::layer_panel::RawBuffer;
|
use crate::messages::portfolio::document::utility_types::layer_panel::RawBuffer;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ};
|
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ};
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::portfolio::utility_types::PersistentData;
|
use crate::messages::portfolio::utility_types::PersistentData;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
|
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
|
||||||
@@ -224,7 +223,7 @@ fn root_network() -> NodeNetwork {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct DocumentInputs<'a> {
|
pub struct DocumentInputs<'a> {
|
||||||
pub document_id: u64,
|
pub document_id: DocumentId,
|
||||||
pub ipp: &'a InputPreprocessorMessageHandler,
|
pub ipp: &'a InputPreprocessorMessageHandler,
|
||||||
pub persistent_data: &'a PersistentData,
|
pub persistent_data: &'a PersistentData,
|
||||||
pub executor: &'a mut NodeGraphExecutor,
|
pub executor: &'a mut NodeGraphExecutor,
|
||||||
@@ -324,7 +323,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
};
|
};
|
||||||
let translation = (aggregated - center) * axis;
|
let translation = (aggregated - center) * axis;
|
||||||
responses.add(GraphOperationMessage::TransformChange {
|
responses.add(GraphOperationMessage::TransformChange {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: DAffine2::from_translation(translation),
|
transform: DAffine2::from_translation(translation),
|
||||||
transform_in: TransformIn::Viewport,
|
transform_in: TransformIn::Viewport,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
@@ -333,10 +332,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
}
|
}
|
||||||
BackupDocument { network } => self.backup_with_document(network, responses),
|
BackupDocument { network } => self.backup_with_document(network, responses),
|
||||||
ClearLayerTree => {
|
ClearLayersPanel => {
|
||||||
// Send an empty layer tree
|
// Send an empty layer list
|
||||||
let data_buffer: RawBuffer = Self::default().serialize_root().as_slice().into();
|
let data_buffer: RawBuffer = Self::default().serialize_root();
|
||||||
responses.add(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer });
|
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
||||||
|
|
||||||
// Clear the options bar
|
// Clear the options bar
|
||||||
responses.add(LayoutMessage::SendLayout {
|
responses.add(LayoutMessage::SendLayout {
|
||||||
@@ -359,8 +358,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
DebugPrintDocument => {
|
DebugPrintDocument => {
|
||||||
info!("{:#?}", self.network);
|
info!("{:#?}", self.network);
|
||||||
}
|
}
|
||||||
DeleteLayer { layer_path } => {
|
DeleteLayer { id } => {
|
||||||
responses.add(GraphOperationMessage::DeleteLayer { id: layer_path[0] });
|
responses.add(GraphOperationMessage::DeleteLayer { id });
|
||||||
responses.add_front(BroadcastEvent::ToolAbort);
|
responses.add_front(BroadcastEvent::ToolAbort);
|
||||||
}
|
}
|
||||||
DeleteSelectedLayers => {
|
DeleteSelectedLayers => {
|
||||||
@@ -368,9 +367,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
|
|
||||||
responses.add_front(BroadcastEvent::SelectionChanged);
|
responses.add_front(BroadcastEvent::SelectionChanged);
|
||||||
for path in self.metadata().shallowest_unique_layers(self.metadata().selected_layers()) {
|
for path in self.metadata().shallowest_unique_layers(self.metadata().selected_layers()) {
|
||||||
responses.add_front(DocumentMessage::DeleteLayer {
|
responses.add_front(DocumentMessage::DeleteLayer { id: path.last().unwrap().to_node() });
|
||||||
layer_path: path.last().unwrap().to_path(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
@@ -384,8 +381,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
DocumentStructureChanged => {
|
DocumentStructureChanged => {
|
||||||
self.update_layers_panel_options_bar_widgets(responses);
|
self.update_layers_panel_options_bar_widgets(responses);
|
||||||
|
|
||||||
let data_buffer: RawBuffer = self.serialize_root().as_slice().into();
|
let data_buffer: RawBuffer = self.serialize_root();
|
||||||
responses.add(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer })
|
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer })
|
||||||
}
|
}
|
||||||
DuplicateSelectedLayers => {
|
DuplicateSelectedLayers => {
|
||||||
// TODO: Reimplement selected layer duplication
|
// TODO: Reimplement selected layer duplication
|
||||||
@@ -406,7 +403,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
let bbox_trans = DAffine2::from_translation(-center);
|
let bbox_trans = DAffine2::from_translation(-center);
|
||||||
for layer in self.metadata().selected_layers() {
|
for layer in self.metadata().selected_layers() {
|
||||||
responses.add(GraphOperationMessage::TransformChange {
|
responses.add(GraphOperationMessage::TransformChange {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: DAffine2::from_scale(scale),
|
transform: DAffine2::from_scale(scale),
|
||||||
transform_in: TransformIn::Scope { scope: bbox_trans },
|
transform_in: TransformIn::Scope { scope: bbox_trans },
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
@@ -438,13 +435,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
|
|
||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder_id] });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder_id] });
|
||||||
}
|
}
|
||||||
ImaginateClear { layer_path } => responses.add(InputFrameRasterizeRegionBelowLayer { layer_path }),
|
ImaginateGenerate => responses.add(PortfolioMessage::SubmitGraphRender { document_id }),
|
||||||
ImaginateGenerate { layer_path } => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path }),
|
ImaginateRandom { imaginate_node, then_generate } => {
|
||||||
ImaginateRandom {
|
|
||||||
layer_path,
|
|
||||||
imaginate_node,
|
|
||||||
then_generate,
|
|
||||||
} => {
|
|
||||||
// Generate a random seed. We only want values between -2^53 and 2^53, because integer values
|
// Generate a random seed. We only want values between -2^53 and 2^53, because integer values
|
||||||
// outside of this range can get rounded in f64
|
// outside of this range can get rounded in f64
|
||||||
let random_bits = generate_uuid();
|
let random_bits = generate_uuid();
|
||||||
@@ -459,10 +451,9 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
|
|
||||||
// Generate the image
|
// Generate the image
|
||||||
if then_generate {
|
if then_generate {
|
||||||
responses.add(DocumentMessage::ImaginateGenerate { layer_path });
|
responses.add(DocumentMessage::ImaginateGenerate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputFrameRasterizeRegionBelowLayer { layer_path } => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path }),
|
|
||||||
MoveSelectedLayersTo { parent, insert_index } => {
|
MoveSelectedLayersTo { parent, insert_index } => {
|
||||||
let selected_layers = self.metadata().selected_layers().collect::<Vec<_>>();
|
let selected_layers = self.metadata().selected_layers().collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -496,7 +487,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
// Nudge translation
|
// Nudge translation
|
||||||
if !ipp.keyboard.key(resize) {
|
if !ipp.keyboard.key(resize) {
|
||||||
responses.add(GraphOperationMessage::TransformChange {
|
responses.add(GraphOperationMessage::TransformChange {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: DAffine2::from_translation(delta),
|
transform: DAffine2::from_translation(delta),
|
||||||
transform_in: TransformIn::Local,
|
transform_in: TransformIn::Local,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
@@ -525,7 +516,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
let original_transform = self.metadata().upstream_transform(layer.to_node());
|
let original_transform = self.metadata().upstream_transform(layer.to_node());
|
||||||
let new = to.inverse() * transformation * to * original_transform;
|
let new = to.inverse() * transformation * to * original_transform;
|
||||||
responses.add(GraphOperationMessage::TransformSet {
|
responses.add(GraphOperationMessage::TransformSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: new,
|
transform: new,
|
||||||
transform_in: TransformIn::Local,
|
transform_in: TransformIn::Local,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
@@ -561,7 +552,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::TransformSet {
|
responses.add(GraphOperationMessage::TransformSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform,
|
transform,
|
||||||
transform_in: TransformIn::Local,
|
transform_in: TransformIn::Local,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
@@ -655,16 +646,15 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
SelectedLayersReorder { relative_index_offset } => {
|
SelectedLayersReorder { relative_index_offset } => {
|
||||||
self.selected_layers_reorder(relative_index_offset, responses);
|
self.selected_layers_reorder(relative_index_offset, responses);
|
||||||
}
|
}
|
||||||
SelectLayer { layer_path, ctrl, shift } => {
|
SelectLayer { id, ctrl, shift } => {
|
||||||
let clicked_node = *layer_path.last().expect("Cannot select root");
|
let layer = LayerNodeIdentifier::new(id, self.network());
|
||||||
let layer = LayerNodeIdentifier::new(clicked_node, self.network());
|
|
||||||
|
|
||||||
let mut nodes = vec![];
|
let mut nodes = vec![];
|
||||||
|
|
||||||
// If we have shift pressed and a layer already selected then fill the range
|
// If we have shift pressed and a layer already selected then fill the range
|
||||||
if let Some(last_selected) = self.layer_range_selection_reference.filter(|_| shift) {
|
if let Some(last_selected) = self.layer_range_selection_reference.filter(|_| shift) {
|
||||||
nodes.push(last_selected.to_node());
|
nodes.push(last_selected.to_node());
|
||||||
nodes.push(clicked_node);
|
nodes.push(id);
|
||||||
|
|
||||||
// Fill the selection range
|
// Fill the selection range
|
||||||
self.metadata()
|
self.metadata()
|
||||||
@@ -677,13 +667,13 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
if ctrl {
|
if ctrl {
|
||||||
// Toggle selection when holding ctrl
|
// Toggle selection when holding ctrl
|
||||||
if self.metadata().selected_layers_contains(layer) {
|
if self.metadata().selected_layers_contains(layer) {
|
||||||
responses.add_front(NodeGraphMessage::SelectedNodesRemove { nodes: vec![clicked_node] });
|
responses.add_front(NodeGraphMessage::SelectedNodesRemove { nodes: vec![id] });
|
||||||
} else {
|
} else {
|
||||||
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![clicked_node] });
|
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
||||||
}
|
}
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
} else {
|
} else {
|
||||||
nodes.push(clicked_node);
|
nodes.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set our last selection reference
|
// Set our last selection reference
|
||||||
@@ -703,7 +693,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
SetBlendModeForSelectedLayers { blend_mode } => {
|
SetBlendModeForSelectedLayers { blend_mode } => {
|
||||||
self.backup(responses);
|
self.backup(responses);
|
||||||
for layer in self.metadata().selected_layers_except_artboards() {
|
for layer in self.metadata().selected_layers_except_artboards() {
|
||||||
responses.add(GraphOperationMessage::BlendModeSet { layer: layer.to_path(), blend_mode });
|
responses.add(GraphOperationMessage::BlendModeSet { layer, blend_mode });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetOpacityForSelectedLayers { opacity } => {
|
SetOpacityForSelectedLayers { opacity } => {
|
||||||
@@ -711,7 +701,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
let opacity = opacity.clamp(0., 1.) as f32;
|
let opacity = opacity.clamp(0., 1.) as f32;
|
||||||
|
|
||||||
for layer in self.metadata().selected_layers_except_artboards() {
|
for layer in self.metadata().selected_layers_except_artboards() {
|
||||||
responses.add(GraphOperationMessage::OpacitySet { layer: layer.to_path(), opacity });
|
responses.add(GraphOperationMessage::OpacitySet { layer, opacity });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetOverlaysVisibility { visible } => {
|
SetOverlaysVisibility { visible } => {
|
||||||
@@ -742,8 +732,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
responses.add_front(NodeGraphMessage::RunDocumentGraph);
|
responses.add_front(NodeGraphMessage::RunDocumentGraph);
|
||||||
}
|
}
|
||||||
StartTransaction => self.backup(responses),
|
StartTransaction => self.backup(responses),
|
||||||
ToggleLayerExpansion { layer } => {
|
ToggleLayerExpansion { id } => {
|
||||||
let layer = LayerNodeIdentifier::new(layer, self.network());
|
let layer = LayerNodeIdentifier::new(id, self.network());
|
||||||
if self.collapsed.contains(&layer) {
|
if self.collapsed.contains(&layer) {
|
||||||
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer);
|
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer);
|
||||||
} else {
|
} else {
|
||||||
@@ -908,23 +898,23 @@ impl DocumentMessageHandler {
|
|||||||
std::iter::empty()
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_structure(&self, folder: LayerNodeIdentifier, structure: &mut Vec<u64>, data: &mut Vec<LayerId>, path: &mut Vec<LayerId>) {
|
fn serialize_structure(&self, folder: LayerNodeIdentifier, structure: &mut Vec<LayerNodeIdentifier>, data: &mut Vec<LayerNodeIdentifier>, path: &mut Vec<LayerNodeIdentifier>) {
|
||||||
let mut space = 0;
|
let mut space = 0;
|
||||||
for layer_node in folder.children(self.metadata()) {
|
for layer_node in folder.children(self.metadata()) {
|
||||||
data.push(layer_node.to_node());
|
data.push(layer_node);
|
||||||
space += 1;
|
space += 1;
|
||||||
if layer_node.has_children(self.metadata()) && !self.collapsed.contains(&layer_node) {
|
if layer_node.has_children(self.metadata()) && !self.collapsed.contains(&layer_node) {
|
||||||
path.push(layer_node.to_node());
|
path.push(layer_node);
|
||||||
|
|
||||||
// TODO: Skip if folder is not expanded.
|
// TODO: Skip if folder is not expanded.
|
||||||
structure.push(space);
|
structure.push(LayerNodeIdentifier::new_unchecked(space));
|
||||||
self.serialize_structure(layer_node, structure, data, path);
|
self.serialize_structure(layer_node, structure, data, path);
|
||||||
space = 0;
|
space = 0;
|
||||||
|
|
||||||
path.pop();
|
path.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
structure.push(space | 1 << 63);
|
structure.push(LayerNodeIdentifier::new_unchecked(space | 1 << 63));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes the layer structure into a condensed 1D structure.
|
/// Serializes the layer structure into a condensed 1D structure.
|
||||||
@@ -959,13 +949,15 @@ impl DocumentMessageHandler {
|
|||||||
/// [3427872634365736244,18115028555707261608,15878401910454357952]
|
/// [3427872634365736244,18115028555707261608,15878401910454357952]
|
||||||
/// [3427872634365736244,18115028555707261608,449479075714955186]
|
/// [3427872634365736244,18115028555707261608,449479075714955186]
|
||||||
/// ```
|
/// ```
|
||||||
pub fn serialize_root(&self) -> Vec<u64> {
|
pub fn serialize_root(&self) -> RawBuffer {
|
||||||
let (mut structure, mut data) = (vec![0], Vec::new());
|
let mut structure = vec![LayerNodeIdentifier::ROOT];
|
||||||
|
let mut data = Vec::new();
|
||||||
self.serialize_structure(self.metadata().root(), &mut structure, &mut data, &mut vec![]);
|
self.serialize_structure(self.metadata().root(), &mut structure, &mut data, &mut vec![]);
|
||||||
structure[0] = structure.len() as u64 - 1;
|
|
||||||
|
structure[0] = LayerNodeIdentifier::new_unchecked(structure.len() as NodeId - 1);
|
||||||
structure.extend(data);
|
structure.extend(data);
|
||||||
|
|
||||||
structure
|
structure.iter().map(|id| id.to_node()).collect::<Vec<_>>().as_slice().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Places a document into the history system
|
/// Places a document into the history system
|
||||||
@@ -1064,10 +1056,9 @@ impl DocumentMessageHandler {
|
|||||||
///
|
///
|
||||||
/// This function updates the insert index so that it points to the same place after the specified `layers` are deleted.
|
/// This function updates the insert index so that it points to the same place after the specified `layers` are deleted.
|
||||||
fn update_insert_index(&self, layers: &[LayerNodeIdentifier], parent: LayerNodeIdentifier, insert_index: isize) -> isize {
|
fn update_insert_index(&self, layers: &[LayerNodeIdentifier], parent: LayerNodeIdentifier, insert_index: isize) -> isize {
|
||||||
let layer_ids_above = parent.children(self.metadata()).take(if insert_index < 0 { usize::MAX } else { insert_index as usize });
|
let take_amount = if insert_index < 0 { usize::MAX } else { insert_index as usize };
|
||||||
let new_insert_index = layer_ids_above.filter(|layer_id| !layers.contains(layer_id)).count() as isize;
|
let layer_ids_above = parent.children(self.metadata()).take(take_amount);
|
||||||
|
layer_ids_above.filter(|layer_id| !layers.contains(layer_id)).count() as isize
|
||||||
new_insert_index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_layer_parent(&self) -> LayerNodeIdentifier {
|
pub fn new_layer_parent(&self) -> LayerNodeIdentifier {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use bezier_rs::Subpath;
|
use bezier_rs::Subpath;
|
||||||
@@ -16,56 +15,54 @@ use graphene_core::{Artboard, Color};
|
|||||||
|
|
||||||
use glam::{DAffine2, DVec2, IVec2};
|
use glam::{DAffine2, DVec2, IVec2};
|
||||||
|
|
||||||
pub type LayerIdentifier = Vec<LayerId>;
|
|
||||||
|
|
||||||
#[impl_message(Message, DocumentMessage, GraphOperation)]
|
#[impl_message(Message, DocumentMessage, GraphOperation)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum GraphOperationMessage {
|
pub enum GraphOperationMessage {
|
||||||
FillSet {
|
FillSet {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
fill: Fill,
|
fill: Fill,
|
||||||
},
|
},
|
||||||
OpacitySet {
|
OpacitySet {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
},
|
},
|
||||||
BlendModeSet {
|
BlendModeSet {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
blend_mode: BlendMode,
|
blend_mode: BlendMode,
|
||||||
},
|
},
|
||||||
UpdateBounds {
|
UpdateBounds {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
old_bounds: [DVec2; 2],
|
old_bounds: [DVec2; 2],
|
||||||
new_bounds: [DVec2; 2],
|
new_bounds: [DVec2; 2],
|
||||||
},
|
},
|
||||||
StrokeSet {
|
StrokeSet {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
stroke: Stroke,
|
stroke: Stroke,
|
||||||
},
|
},
|
||||||
|
|
||||||
TransformChange {
|
TransformChange {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
transform_in: TransformIn,
|
transform_in: TransformIn,
|
||||||
skip_rerender: bool,
|
skip_rerender: bool,
|
||||||
},
|
},
|
||||||
TransformSet {
|
TransformSet {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
transform_in: TransformIn,
|
transform_in: TransformIn,
|
||||||
skip_rerender: bool,
|
skip_rerender: bool,
|
||||||
},
|
},
|
||||||
TransformSetPivot {
|
TransformSetPivot {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
pivot: DVec2,
|
pivot: DVec2,
|
||||||
},
|
},
|
||||||
|
|
||||||
Vector {
|
Vector {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
modification: VectorDataModification,
|
modification: VectorDataModification,
|
||||||
},
|
},
|
||||||
Brush {
|
Brush {
|
||||||
layer: LayerIdentifier,
|
layer: LayerNodeIdentifier,
|
||||||
strokes: Vec<BrushStroke>,
|
strokes: Vec<BrushStroke>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+25
-33
@@ -1,6 +1,5 @@
|
|||||||
use super::{resolve_document_node_type, VectorDataModification};
|
use super::{resolve_document_node_type, VectorDataModification};
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use bezier_rs::Subpath;
|
use bezier_rs::Subpath;
|
||||||
@@ -26,7 +25,6 @@ struct ModifyInputsContext<'a> {
|
|||||||
document_network: &'a mut NodeNetwork,
|
document_network: &'a mut NodeNetwork,
|
||||||
node_graph: &'a mut NodeGraphMessageHandler,
|
node_graph: &'a mut NodeGraphMessageHandler,
|
||||||
responses: &'a mut VecDeque<Message>,
|
responses: &'a mut VecDeque<Message>,
|
||||||
layer: &'a [LayerId],
|
|
||||||
outwards_links: HashMap<NodeId, Vec<NodeId>>,
|
outwards_links: HashMap<NodeId, Vec<NodeId>>,
|
||||||
layer_node: Option<NodeId>,
|
layer_node: Option<NodeId>,
|
||||||
}
|
}
|
||||||
@@ -38,27 +36,25 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
document_network,
|
document_network,
|
||||||
node_graph,
|
node_graph,
|
||||||
responses,
|
responses,
|
||||||
layer: &[],
|
|
||||||
layer_node: None,
|
layer_node: None,
|
||||||
document_metadata,
|
document_metadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_with_layer(
|
fn new_with_layer(
|
||||||
layer: &'a [LayerId],
|
id: NodeId,
|
||||||
document_network: &'a mut NodeNetwork,
|
document_network: &'a mut NodeNetwork,
|
||||||
document_metadata: &'a mut DocumentMetadata,
|
document_metadata: &'a mut DocumentMetadata,
|
||||||
node_graph: &'a mut NodeGraphMessageHandler,
|
node_graph: &'a mut NodeGraphMessageHandler,
|
||||||
responses: &'a mut VecDeque<Message>,
|
responses: &'a mut VecDeque<Message>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let mut document = Self::new(document_network, document_metadata, node_graph, responses);
|
let mut document = Self::new(document_network, document_metadata, node_graph, responses);
|
||||||
let Some(mut id) = layer.last().copied() else {
|
|
||||||
error!("Tried to modify root layer");
|
let mut id = id;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
while !document.document_network.nodes.get(&id)?.is_layer() {
|
while !document.document_network.nodes.get(&id)?.is_layer() {
|
||||||
id = document.outwards_links.get(&id)?.first().copied()?;
|
id = document.outwards_links.get(&id)?.first().copied()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.layer_node = Some(id);
|
document.layer_node = Some(id);
|
||||||
Some(document)
|
Some(document)
|
||||||
}
|
}
|
||||||
@@ -325,10 +321,9 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
|
|
||||||
self.node_graph.network.clear();
|
self.node_graph.network.clear();
|
||||||
self.responses.add(PropertiesPanelMessage::Refresh);
|
self.responses.add(PropertiesPanelMessage::Refresh);
|
||||||
let layer_path = self.layer.to_vec();
|
|
||||||
|
|
||||||
if !skip_rerender {
|
if !skip_rerender {
|
||||||
self.responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
self.responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
} else {
|
} else {
|
||||||
// Code was removed from here which cleared the frame
|
// Code was removed from here which cleared the frame
|
||||||
}
|
}
|
||||||
@@ -354,10 +349,9 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.responses.add(PropertiesPanelMessage::Refresh);
|
self.responses.add(PropertiesPanelMessage::Refresh);
|
||||||
let layer_path = self.layer.to_vec();
|
|
||||||
|
|
||||||
if !skip_rerender {
|
if !skip_rerender {
|
||||||
self.responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
self.responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
} else {
|
} else {
|
||||||
// Code was removed from here which cleared the frame
|
// Code was removed from here which cleared the frame
|
||||||
}
|
}
|
||||||
@@ -509,8 +503,8 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
|
|
||||||
self.update_bounds([old_bounds_min, old_bounds_max], [new_bounds_min, new_bounds_max]);
|
self.update_bounds([old_bounds_min, old_bounds_max], [new_bounds_min, new_bounds_max]);
|
||||||
if empty {
|
if empty {
|
||||||
if let Some(layer) = self.layer_node {
|
if let Some(id) = self.layer_node {
|
||||||
self.responses.add(DocumentMessage::DeleteLayer { layer_path: vec![layer] })
|
self.responses.add(DocumentMessage::DeleteLayer { id })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -594,27 +588,27 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
|
|||||||
) {
|
) {
|
||||||
match message {
|
match message {
|
||||||
GraphOperationMessage::FillSet { layer, fill } => {
|
GraphOperationMessage::FillSet { layer, fill } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.fill_set(fill);
|
modify_inputs.fill_set(fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::OpacitySet { layer, opacity } => {
|
GraphOperationMessage::OpacitySet { layer, opacity } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.opacity_set(opacity);
|
modify_inputs.opacity_set(opacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::BlendModeSet { layer, blend_mode } => {
|
GraphOperationMessage::BlendModeSet { layer, blend_mode } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.blend_mode_set(blend_mode);
|
modify_inputs.blend_mode_set(blend_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds } => {
|
GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.update_bounds(old_bounds, new_bounds);
|
modify_inputs.update_bounds(old_bounds, new_bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::StrokeSet { layer, stroke } => {
|
GraphOperationMessage::StrokeSet { layer, stroke } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.stroke_set(stroke);
|
modify_inputs.stroke_set(stroke);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -624,10 +618,9 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
|
|||||||
transform_in,
|
transform_in,
|
||||||
skip_rerender,
|
skip_rerender,
|
||||||
} => {
|
} => {
|
||||||
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
let parent_transform = document_metadata.downstream_transform_to_viewport(layer);
|
||||||
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
|
let bounds = LayerBounds::new(document_metadata, layer);
|
||||||
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
|
||||||
modify_inputs.transform_change(transform, transform_in, parent_transform, bounds, skip_rerender);
|
modify_inputs.transform_change(transform, transform_in, parent_transform, bounds, skip_rerender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,28 +630,27 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
|
|||||||
transform_in,
|
transform_in,
|
||||||
skip_rerender,
|
skip_rerender,
|
||||||
} => {
|
} => {
|
||||||
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
let parent_transform = document_metadata.downstream_transform_to_viewport(layer);
|
||||||
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
|
|
||||||
|
|
||||||
let current_transform = Some(document_metadata.transform_to_viewport(layer_identifier));
|
let current_transform = Some(document_metadata.transform_to_viewport(layer));
|
||||||
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
let bounds = LayerBounds::new(document_metadata, layer);
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender);
|
modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::TransformSetPivot { layer, pivot } => {
|
GraphOperationMessage::TransformSetPivot { layer, pivot } => {
|
||||||
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
let bounds = LayerBounds::new(document_metadata, layer);
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.pivot_set(pivot, bounds);
|
modify_inputs.pivot_set(pivot, bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::Vector { layer, modification } => {
|
GraphOperationMessage::Vector { layer, modification } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.vector_modify(modification);
|
modify_inputs.vector_modify(modification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::Brush { layer, strokes } => {
|
GraphOperationMessage::Brush { layer, strokes } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.brush_modify(strokes);
|
modify_inputs.brush_modify(strokes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -744,7 +736,7 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
|
|||||||
load_network_structure(document_network, document_metadata, collapsed);
|
load_network_structure(document_network, document_metadata, collapsed);
|
||||||
}
|
}
|
||||||
GraphOperationMessage::ResizeArtboard { id, location, dimensions } => {
|
GraphOperationMessage::ResizeArtboard { id, location, dimensions } => {
|
||||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&[id], document_network, document_metadata, node_graph, responses) {
|
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(id, document_network, document_metadata, node_graph, responses) {
|
||||||
modify_inputs.resize_artboard(location, dimensions);
|
modify_inputs.resize_artboard(location, dimensions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -2,7 +2,6 @@ use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
|||||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||||
|
|
||||||
use bezier_rs::{ManipulatorGroup, Subpath};
|
use bezier_rs::{ManipulatorGroup, Subpath};
|
||||||
use graph_craft::document::NodeNetwork;
|
|
||||||
use graph_craft::document::{value::TaggedValue, NodeInput};
|
use graph_craft::document::{value::TaggedValue, NodeInput};
|
||||||
use graphene_core::uuid::ManipulatorGroupId;
|
use graphene_core::uuid::ManipulatorGroupId;
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||||
@@ -53,8 +52,7 @@ pub struct LayerBounds {
|
|||||||
|
|
||||||
impl LayerBounds {
|
impl LayerBounds {
|
||||||
/// Extract the layer bounds and their transform for a layer.
|
/// Extract the layer bounds and their transform for a layer.
|
||||||
pub fn new(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: &[u64]) -> Self {
|
pub fn new(document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier) -> Self {
|
||||||
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
|
||||||
Self {
|
Self {
|
||||||
bounds: document_metadata.nonzero_bounding_box(layer),
|
bounds: document_metadata.nonzero_bounding_box(layer),
|
||||||
bounds_transform: DAffine2::IDENTITY,
|
bounds_transform: DAffine2::IDENTITY,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
@@ -11,14 +10,13 @@ pub enum NodeGraphMessage {
|
|||||||
Init,
|
Init,
|
||||||
SelectedNodesUpdated,
|
SelectedNodesUpdated,
|
||||||
ConnectNodesByLink {
|
ConnectNodesByLink {
|
||||||
output_node: u64,
|
output_node: NodeId,
|
||||||
output_node_connector_index: usize,
|
output_node_connector_index: usize,
|
||||||
input_node: u64,
|
input_node: NodeId,
|
||||||
input_node_connector_index: usize,
|
input_node_connector_index: usize,
|
||||||
},
|
},
|
||||||
Copy,
|
Copy,
|
||||||
CreateNode {
|
CreateNode {
|
||||||
// Having the caller generate the id means that we don't have to return it. This can be a random u64.
|
|
||||||
node_id: Option<NodeId>,
|
node_id: Option<NodeId>,
|
||||||
node_type: String,
|
node_type: String,
|
||||||
x: i32,
|
x: i32,
|
||||||
@@ -83,7 +81,6 @@ pub enum NodeGraphMessage {
|
|||||||
input: NodeInput,
|
input: NodeInput,
|
||||||
},
|
},
|
||||||
SetQualifiedInputValue {
|
SetQualifiedInputValue {
|
||||||
layer_path: Vec<LayerId>,
|
|
||||||
node_path: Vec<NodeId>,
|
node_path: Vec<NodeId>,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
value: TaggedValue,
|
value: TaggedValue,
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ use super::load_network_structure;
|
|||||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::node_graph_executor::GraphIdentifier;
|
|
||||||
|
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
|
use graph_craft::document::{DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
|
||||||
@@ -99,13 +97,13 @@ pub struct FrontendNode {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct FrontendNodeLink {
|
pub struct FrontendNodeLink {
|
||||||
#[serde(rename = "linkStart")]
|
#[serde(rename = "linkStart")]
|
||||||
pub link_start: u64,
|
pub link_start: NodeId,
|
||||||
#[serde(rename = "linkStartOutputIndex")]
|
#[serde(rename = "linkStartOutputIndex")]
|
||||||
pub link_start_output_index: usize,
|
pub link_start_output_index: usize,
|
||||||
#[serde(rename = "linkEnd")]
|
#[serde(rename = "linkEnd")]
|
||||||
pub link_end: u64,
|
pub link_end: NodeId,
|
||||||
#[serde(rename = "linkEndInputIndex")]
|
#[serde(rename = "linkEndInputIndex")]
|
||||||
pub link_end_input_index: u64,
|
pub link_end_input_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
@@ -124,10 +122,9 @@ impl FrontendNodeType {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct NodeGraphMessageHandler {
|
pub struct NodeGraphMessageHandler {
|
||||||
pub layer_path: Option<Vec<LayerId>>,
|
|
||||||
pub network: Vec<NodeId>,
|
pub network: Vec<NodeId>,
|
||||||
has_selection: bool,
|
has_selection: bool,
|
||||||
pub widgets: [LayoutGroup; 2],
|
widgets: [LayoutGroup; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NodeGraphMessageHandler {
|
impl Default for NodeGraphMessageHandler {
|
||||||
@@ -137,7 +134,6 @@ impl Default for NodeGraphMessageHandler {
|
|||||||
let add_nodes_label_row = LayoutGroup::Row { widgets: vec![add_nodes_label] };
|
let add_nodes_label_row = LayoutGroup::Row { widgets: vec![add_nodes_label] };
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
layer_path: None,
|
|
||||||
network: Vec::new(),
|
network: Vec::new(),
|
||||||
has_selection: false,
|
has_selection: false,
|
||||||
widgets: [add_nodes_label_row, LayoutGroup::default()],
|
widgets: [add_nodes_label_row, LayoutGroup::default()],
|
||||||
@@ -261,15 +257,13 @@ impl NodeGraphMessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_graph(network: &NodeNetwork, layer_path: &Option<Vec<LayerId>>, graph_view_overlay_open: bool, responses: &mut VecDeque<Message>) {
|
fn send_graph(network: &NodeNetwork, graph_view_overlay_open: bool, responses: &mut VecDeque<Message>) {
|
||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
|
|
||||||
if !graph_view_overlay_open {
|
if !graph_view_overlay_open {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let layer_id = layer_path.as_ref().and_then(|path| path.last().copied());
|
|
||||||
|
|
||||||
// List of links in format (link_start, link_end, link_end_input_index)
|
// List of links in format (link_start, link_end, link_end_input_index)
|
||||||
let links = network
|
let links = network
|
||||||
.nodes
|
.nodes
|
||||||
@@ -278,16 +272,16 @@ impl NodeGraphMessageHandler {
|
|||||||
.filter_map(|(input, &link_end, link_end_input_index)| {
|
.filter_map(|(input, &link_end, link_end_input_index)| {
|
||||||
if let NodeInput::Node {
|
if let NodeInput::Node {
|
||||||
node_id: link_start,
|
node_id: link_start,
|
||||||
output_index: link_start_index,
|
output_index: link_start_output_index,
|
||||||
// TODO: add ui for lambdas
|
// TODO: add ui for lambdas
|
||||||
lambda: _,
|
lambda: _,
|
||||||
} = *input
|
} = *input
|
||||||
{
|
{
|
||||||
Some(FrontendNodeLink {
|
Some(FrontendNodeLink {
|
||||||
link_start,
|
link_start,
|
||||||
link_start_output_index: link_start_index,
|
link_start_output_index,
|
||||||
link_end,
|
link_end,
|
||||||
link_end_input_index: link_end_input_index as u64,
|
link_end_input_index,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -318,8 +312,6 @@ impl NodeGraphMessageHandler {
|
|||||||
});
|
});
|
||||||
let primary_output = if node.has_primary_output { outputs.next() } else { None };
|
let primary_output = if node.has_primary_output { outputs.next() } else { None };
|
||||||
|
|
||||||
let _graph_identifier = GraphIdentifier::new(layer_id);
|
|
||||||
|
|
||||||
nodes.push(FrontendNode {
|
nodes.push(FrontendNode {
|
||||||
is_layer: node.is_layer(),
|
is_layer: node.is_layer(),
|
||||||
id: *id,
|
id: *id,
|
||||||
@@ -446,7 +438,7 @@ impl NodeGraphMessageHandler {
|
|||||||
pub struct NodeGraphHandlerData<'a> {
|
pub struct NodeGraphHandlerData<'a> {
|
||||||
pub document_network: &'a mut NodeNetwork,
|
pub document_network: &'a mut NodeNetwork,
|
||||||
pub document_metadata: &'a mut DocumentMetadata,
|
pub document_metadata: &'a mut DocumentMetadata,
|
||||||
pub document_id: u64,
|
pub document_id: DocumentId,
|
||||||
pub document_name: &'a str,
|
pub document_name: &'a str,
|
||||||
pub collapsed: &'a mut Vec<LayerNodeIdentifier>,
|
pub collapsed: &'a mut Vec<LayerNodeIdentifier>,
|
||||||
pub input: &'a InputPreprocessorMessageHandler,
|
pub input: &'a InputPreprocessorMessageHandler,
|
||||||
@@ -495,7 +487,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
error!("No network");
|
error!("No network");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(input_node) = network.nodes.get(&input_node) else {
|
let Some(input_node) = network.nodes.get(&node_id) else {
|
||||||
error!("No to");
|
error!("No to");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -569,11 +561,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
// Only generate node graph if one of the selected nodes is connected to the output
|
// Only generate node graph if one of the selected nodes is connected to the output
|
||||||
if metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
|
if metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
|
||||||
if let Some(layer_path) = self.layer_path.clone() {
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
|
||||||
} else {
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -612,7 +600,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
}
|
}
|
||||||
self.update_selected(document_network, metadata, responses);
|
self.update_selected(document_network, metadata, responses);
|
||||||
}
|
}
|
||||||
@@ -640,7 +628,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
responses.add(NodeGraphMessage::InsertNode { node_id, document_node });
|
responses.add(NodeGraphMessage::InsertNode { node_id, document_node });
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
self.update_selected(document_network, metadata, responses);
|
self.update_selected(document_network, metadata, responses);
|
||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
||||||
}
|
}
|
||||||
@@ -653,7 +641,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
self.network.pop();
|
self.network.pop();
|
||||||
}
|
}
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
}
|
}
|
||||||
self.update_selected(document_network, metadata, responses);
|
self.update_selected(document_network, metadata, responses);
|
||||||
}
|
}
|
||||||
@@ -703,7 +691,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
node.metadata.position += IVec2::new(displacement_x, displacement_y)
|
node.metadata.position += IVec2::new(displacement_x, displacement_y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::PasteNodes { serialized_nodes } => {
|
NodeGraphMessage::PasteNodes { serialized_nodes } => {
|
||||||
let Some(network) = document_network.nested_network(&self.network) else {
|
let Some(network) = document_network.nested_network(&self.network) else {
|
||||||
@@ -752,7 +740,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
|
|
||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path: Vec::new() }),
|
NodeGraphMessage::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id }),
|
||||||
NodeGraphMessage::SelectedNodesAdd { nodes } => {
|
NodeGraphMessage::SelectedNodesAdd { nodes } => {
|
||||||
metadata.add_selected_nodes(nodes);
|
metadata.add_selected_nodes(nodes);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
@@ -768,13 +756,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
}
|
}
|
||||||
NodeGraphMessage::SendGraph { should_rerender } => {
|
NodeGraphMessage::SendGraph { should_rerender } => {
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
if should_rerender {
|
if should_rerender {
|
||||||
if let Some(layer_path) = self.layer_path.clone() {
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
|
||||||
} else {
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -787,11 +771,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
responses.add(NodeGraphMessage::SetNodeInput { node_id, input_index, input });
|
responses.add(NodeGraphMessage::SetNodeInput { node_id, input_index, input });
|
||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
if (node.name != "Imaginate" || input_index == 0) && network.connected_to_output(node_id) {
|
if (node.name != "Imaginate" || input_index == 0) && network.connected_to_output(node_id) {
|
||||||
if let Some(layer_path) = self.layer_path.clone() {
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
|
||||||
} else {
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -811,12 +791,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SetQualifiedInputValue {
|
NodeGraphMessage::SetQualifiedInputValue { node_path, input_index, value } => {
|
||||||
layer_path,
|
|
||||||
node_path,
|
|
||||||
input_index,
|
|
||||||
value,
|
|
||||||
} => {
|
|
||||||
let Some((node_id, node_path)) = node_path.split_last() else {
|
let Some((node_id, node_path)) = node_path.split_last() else {
|
||||||
error!("Node path is empty");
|
error!("Node path is empty");
|
||||||
return;
|
return;
|
||||||
@@ -832,7 +807,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
}
|
}
|
||||||
node.inputs[input_index] = NodeInput::Value { tagged_value: value, exposed: false };
|
node.inputs[input_index] = NodeInput::Value { tagged_value: value, exposed: false };
|
||||||
if network.connected_to_output(*node_id) {
|
if network.connected_to_output(*node_id) {
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -908,7 +883,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
} else if !network.inputs.contains(&node_id) && !network.original_outputs().iter().any(|output| output.node_id == node_id) {
|
} else if !network.inputs.contains(&node_id) && !network.original_outputs().iter().any(|output| output.node_id == node_id) {
|
||||||
network.disabled.push(node_id);
|
network.disabled.push(node_id);
|
||||||
}
|
}
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
|
|
||||||
// Only generate node graph if one of the selected nodes is connected to the output
|
// Only generate node graph if one of the selected nodes is connected to the output
|
||||||
if network.connected_to_output(node_id) {
|
if network.connected_to_output(node_id) {
|
||||||
@@ -944,21 +919,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
}
|
}
|
||||||
self.update_selection_action_buttons(document_network, metadata, responses);
|
self.update_selection_action_buttons(document_network, metadata, responses);
|
||||||
if let Some(layer_path) = self.layer_path.clone() {
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
|
||||||
} else {
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
NodeGraphMessage::UpdateNewNodeGraph => {
|
NodeGraphMessage::UpdateNewNodeGraph => {
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
metadata.clear_selected_nodes();
|
metadata.clear_selected_nodes();
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
|
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
Self::send_graph(network, graph_view_overlay_open, responses);
|
||||||
|
|
||||||
let node_types = document_node_types::collect_node_types();
|
let node_types = document_node_types::collect_node_types();
|
||||||
responses.add(FrontendMessage::UpdateNodeTypes { node_types });
|
responses.add(FrontendMessage::UpdateNodeTypes { node_types });
|
||||||
|
|||||||
+6
-10
@@ -2,7 +2,6 @@ use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
|
|||||||
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
|
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
|
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::portfolio::utility_types::PersistentData;
|
use crate::messages::portfolio::utility_types::PersistentData;
|
||||||
use crate::messages::prelude::Message;
|
use crate::messages::prelude::Message;
|
||||||
use crate::node_graph_executor::NodeGraphExecutor;
|
use crate::node_graph_executor::NodeGraphExecutor;
|
||||||
@@ -74,7 +73,6 @@ impl DocumentOutputType {
|
|||||||
pub struct NodePropertiesContext<'a> {
|
pub struct NodePropertiesContext<'a> {
|
||||||
pub persistent_data: &'a PersistentData,
|
pub persistent_data: &'a PersistentData,
|
||||||
pub responses: &'a mut VecDeque<Message>,
|
pub responses: &'a mut VecDeque<Message>,
|
||||||
pub layer_path: &'a [LayerId],
|
|
||||||
pub nested_path: &'a [NodeId],
|
pub nested_path: &'a [NodeId],
|
||||||
pub executor: &'a mut NodeGraphExecutor,
|
pub executor: &'a mut NodeGraphExecutor,
|
||||||
pub network: &'a NodeNetwork,
|
pub network: &'a NodeNetwork,
|
||||||
@@ -279,7 +277,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||||||
name: "Image Frame",
|
name: "Image Frame",
|
||||||
data_type: FrontendGraphDataType::Raster,
|
data_type: FrontendGraphDataType::Raster,
|
||||||
}],
|
}],
|
||||||
properties: node_properties::input_properties,
|
properties: node_properties::node_no_properties,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
@@ -1069,7 +1067,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||||||
name: "OutputBuffer",
|
name: "OutputBuffer",
|
||||||
data_type: FrontendGraphDataType::General,
|
data_type: FrontendGraphDataType::General,
|
||||||
}],
|
}],
|
||||||
properties: node_properties::input_properties,
|
properties: node_properties::node_no_properties,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
@@ -1137,7 +1135,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||||||
name: "CommandBuffer",
|
name: "CommandBuffer",
|
||||||
data_type: FrontendGraphDataType::General,
|
data_type: FrontendGraphDataType::General,
|
||||||
}],
|
}],
|
||||||
properties: node_properties::input_properties,
|
properties: node_properties::node_no_properties,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
@@ -1171,7 +1169,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||||||
name: "PipelineLayout",
|
name: "PipelineLayout",
|
||||||
data_type: FrontendGraphDataType::General,
|
data_type: FrontendGraphDataType::General,
|
||||||
}],
|
}],
|
||||||
properties: node_properties::input_properties,
|
properties: node_properties::node_no_properties,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
@@ -2377,7 +2375,7 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
|
|||||||
name: "Imaginate",
|
name: "Imaginate",
|
||||||
category: "Image Synthesis",
|
category: "Image Synthesis",
|
||||||
implementation: NodeImplementation::DocumentNode(NodeNetwork {
|
implementation: NodeImplementation::DocumentNode(NodeNetwork {
|
||||||
inputs: vec![0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
inputs: vec![0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||||
outputs: vec![NodeOutput::new(1, 0)],
|
outputs: vec![NodeOutput::new(1, 0)],
|
||||||
nodes: [
|
nodes: [
|
||||||
(
|
(
|
||||||
@@ -2404,14 +2402,13 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
|
|||||||
NodeInput::Network(concrete!(String)),
|
NodeInput::Network(concrete!(String)),
|
||||||
NodeInput::Network(concrete!(bool)),
|
NodeInput::Network(concrete!(bool)),
|
||||||
NodeInput::Network(concrete!(f32)),
|
NodeInput::Network(concrete!(f32)),
|
||||||
NodeInput::Network(concrete!(Option<Vec<u64>>)),
|
|
||||||
NodeInput::Network(concrete!(bool)),
|
NodeInput::Network(concrete!(bool)),
|
||||||
NodeInput::Network(concrete!(f32)),
|
NodeInput::Network(concrete!(f32)),
|
||||||
NodeInput::Network(concrete!(ImaginateMaskStartingFill)),
|
NodeInput::Network(concrete!(ImaginateMaskStartingFill)),
|
||||||
NodeInput::Network(concrete!(bool)),
|
NodeInput::Network(concrete!(bool)),
|
||||||
NodeInput::Network(concrete!(bool)),
|
NodeInput::Network(concrete!(bool)),
|
||||||
],
|
],
|
||||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
implementation: DocumentNodeImplementation::proto("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -2436,7 +2433,6 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
|
|||||||
DocumentInputType::value("Negative Prompt", TaggedValue::String(String::new()), false),
|
DocumentInputType::value("Negative Prompt", TaggedValue::String(String::new()), false),
|
||||||
DocumentInputType::value("Adapt Input Image", TaggedValue::Bool(false), false),
|
DocumentInputType::value("Adapt Input Image", TaggedValue::Bool(false), false),
|
||||||
DocumentInputType::value("Image Creativity", TaggedValue::F32(66.), false),
|
DocumentInputType::value("Image Creativity", TaggedValue::F32(66.), false),
|
||||||
DocumentInputType::value("Masking Layer", TaggedValue::LayerPath(None), false),
|
|
||||||
DocumentInputType::value("Inpaint", TaggedValue::Bool(true), false),
|
DocumentInputType::value("Inpaint", TaggedValue::Bool(true), false),
|
||||||
DocumentInputType::value("Mask Blur", TaggedValue::F32(4.), false),
|
DocumentInputType::value("Mask Blur", TaggedValue::F32(4.), false),
|
||||||
DocumentInputType::value("Mask Starting Fill", TaggedValue::ImaginateMaskStartingFill(ImaginateMaskStartingFill::Fill), false),
|
DocumentInputType::value("Mask Starting Fill", TaggedValue::ImaginateMaskStartingFill(ImaginateMaskStartingFill::Fill), false),
|
||||||
|
|||||||
+29
-46
@@ -144,16 +144,16 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||||||
NumberInput::new(Some(dvec2.x))
|
NumberInput::new(Some(dvec2.x))
|
||||||
.label(x)
|
.label(x)
|
||||||
.unit(unit)
|
.unit(unit)
|
||||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
.min(min.unwrap_or(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(input.value.unwrap(), dvec2.y)), node_id, index))
|
.on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(input.value.unwrap(), dvec2.y)), node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
NumberInput::new(Some(dvec2.y))
|
NumberInput::new(Some(dvec2.y))
|
||||||
.label(y)
|
.label(y)
|
||||||
.unit(unit)
|
.unit(unit)
|
||||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
.min(min.unwrap_or(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(dvec2.x, input.value.unwrap())), node_id, index))
|
.on_update(update_value(move |input: &NumberInput| TaggedValue::DVec2(DVec2::new(dvec2.x, input.value.unwrap())), node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
]);
|
]);
|
||||||
@@ -170,8 +170,8 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||||||
.int()
|
.int()
|
||||||
.label(x)
|
.label(x)
|
||||||
.unit(unit)
|
.unit(unit)
|
||||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
.min(min.unwrap_or(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(update_value(update_x, node_id, index))
|
.on_update(update_value(update_x, node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
@@ -179,8 +179,8 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||||||
.int()
|
.int()
|
||||||
.label(y)
|
.label(y)
|
||||||
.unit(unit)
|
.unit(unit)
|
||||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
.min(min.unwrap_or(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(update_value(update_y, node_id, index))
|
.on_update(update_value(update_y, node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
]);
|
]);
|
||||||
@@ -198,7 +198,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||||||
.label(x)
|
.label(x)
|
||||||
.unit(unit)
|
.unit(unit)
|
||||||
.min(min.unwrap_or(0.))
|
.min(min.unwrap_or(0.))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(update_value(update_x, node_id, index))
|
.on_update(update_value(update_x, node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
Separator::new(SeparatorType::Related).widget_holder(),
|
Separator::new(SeparatorType::Related).widget_holder(),
|
||||||
@@ -207,7 +207,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||||||
.label(y)
|
.label(y)
|
||||||
.unit(unit)
|
.unit(unit)
|
||||||
.min(min.unwrap_or(0.))
|
.min(min.unwrap_or(0.))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(update_value(update_y, node_id, index))
|
.on_update(update_value(update_y, node_id, index))
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
]);
|
]);
|
||||||
@@ -359,7 +359,7 @@ fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO Generalize this instead of using a separate function per dropdown menu enum
|
//TODO Generalize this instead of using a separate function per dropdown menu enum
|
||||||
fn color_channel(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
fn color_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::RedGreenBlue(mode),
|
tagged_value: TaggedValue::RedGreenBlue(mode),
|
||||||
@@ -382,7 +382,7 @@ fn color_channel(document_node: &DocumentNode, node_id: u64, index: usize, name:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
||||||
fn noise_type(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
fn noise_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::NoiseType(noise_type),
|
tagged_value: TaggedValue::NoiseType(noise_type),
|
||||||
@@ -403,7 +403,7 @@ fn noise_type(document_node: &DocumentNode, node_id: u64, index: usize, name: &s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
||||||
fn fractal_type(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
fn fractal_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::FractalType(fractal_type),
|
tagged_value: TaggedValue::FractalType(fractal_type),
|
||||||
@@ -424,7 +424,7 @@ fn fractal_type(document_node: &DocumentNode, node_id: u64, index: usize, name:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
||||||
fn cellular_distance_function(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
fn cellular_distance_function(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::CellularDistanceFunction(cellular_distance_function),
|
tagged_value: TaggedValue::CellularDistanceFunction(cellular_distance_function),
|
||||||
@@ -450,7 +450,7 @@ fn cellular_distance_function(document_node: &DocumentNode, node_id: u64, index:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
||||||
fn cellular_return_type(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
fn cellular_return_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::CellularReturnType(cellular_return_type),
|
tagged_value: TaggedValue::CellularReturnType(cellular_return_type),
|
||||||
@@ -471,7 +471,7 @@ fn cellular_return_type(document_node: &DocumentNode, node_id: u64, index: usize
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
// TODO Generalize this instead of using a separate function per dropdown menu enum
|
||||||
fn domain_warp_type(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
fn domain_warp_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::DomainWarpType(domain_warp_type),
|
tagged_value: TaggedValue::DomainWarpType(domain_warp_type),
|
||||||
@@ -492,7 +492,7 @@ fn domain_warp_type(document_node: &DocumentNode, node_id: u64, index: usize, na
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Generalize this instead of using a separate function per dropdown menu enum
|
// TODO: Generalize this instead of using a separate function per dropdown menu enum
|
||||||
fn blend_mode(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
fn blend_mode(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::BlendMode(blend_mode),
|
tagged_value: TaggedValue::BlendMode(blend_mode),
|
||||||
@@ -520,7 +520,7 @@ fn blend_mode(document_node: &DocumentNode, node_id: u64, index: usize, name: &s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Generalize this for all dropdowns (also see blend_mode and channel_extration)
|
// TODO: Generalize this for all dropdowns (also see blend_mode and channel_extration)
|
||||||
fn luminance_calculation(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
fn luminance_calculation(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::LuminanceCalculation(calculation),
|
tagged_value: TaggedValue::LuminanceCalculation(calculation),
|
||||||
@@ -542,7 +542,7 @@ fn luminance_calculation(document_node: &DocumentNode, node_id: u64, index: usiz
|
|||||||
LayoutGroup::Row { widgets }.with_tooltip("Formula used to calculate the luminance of a pixel")
|
LayoutGroup::Row { widgets }.with_tooltip("Formula used to calculate the luminance of a pixel")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn line_cap_widget(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
fn line_cap_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::LineCap(line_cap),
|
tagged_value: TaggedValue::LineCap(line_cap),
|
||||||
@@ -562,7 +562,7 @@ fn line_cap_widget(document_node: &DocumentNode, node_id: u64, index: usize, nam
|
|||||||
LayoutGroup::Row { widgets }
|
LayoutGroup::Row { widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn line_join_widget(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
fn line_join_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::LineJoin(line_join),
|
tagged_value: TaggedValue::LineJoin(line_join),
|
||||||
@@ -582,7 +582,7 @@ fn line_join_widget(document_node: &DocumentNode, node_id: u64, index: usize, na
|
|||||||
LayoutGroup::Row { widgets }
|
LayoutGroup::Row { widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_type_widget(document_node: &DocumentNode, node_id: u64, index: usize) -> LayoutGroup {
|
fn fill_type_widget(document_node: &DocumentNode, node_id: NodeId, index: usize) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, "Fill Type", FrontendGraphDataType::General, true);
|
let mut widgets = start_widgets(document_node, node_id, index, "Fill Type", FrontendGraphDataType::General, true);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::FillType(fill_type),
|
tagged_value: TaggedValue::FillType(fill_type),
|
||||||
@@ -607,7 +607,7 @@ fn fill_type_widget(document_node: &DocumentNode, node_id: u64, index: usize) ->
|
|||||||
LayoutGroup::Row { widgets }
|
LayoutGroup::Row { widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gradient_type_widget(document_node: &DocumentNode, node_id: u64, index: usize) -> LayoutGroup {
|
fn gradient_type_widget(document_node: &DocumentNode, node_id: NodeId, index: usize) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, "Gradient Type", FrontendGraphDataType::General, true);
|
let mut widgets = start_widgets(document_node, node_id, index, "Gradient Type", FrontendGraphDataType::General, true);
|
||||||
if let &NodeInput::Value {
|
if let &NodeInput::Value {
|
||||||
tagged_value: TaggedValue::GradientType(gradient_type),
|
tagged_value: TaggedValue::GradientType(gradient_type),
|
||||||
@@ -699,7 +699,7 @@ fn gradient_row(row: &mut Vec<WidgetHolder>, positions: &Vec<(f64, Option<Color>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gradient_positions(rows: &mut Vec<LayoutGroup>, document_node: &DocumentNode, name: &str, node_id: u64, input_index: usize) {
|
fn gradient_positions(rows: &mut Vec<LayoutGroup>, document_node: &DocumentNode, name: &str, node_id: NodeId, input_index: usize) {
|
||||||
let mut widgets = vec![expose_widget(node_id, input_index, FrontendGraphDataType::General, document_node.inputs[input_index].is_exposed())];
|
let mut widgets = vec![expose_widget(node_id, input_index, FrontendGraphDataType::General, document_node.inputs[input_index].is_exposed())];
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
if let NodeInput::Value {
|
if let NodeInput::Value {
|
||||||
@@ -742,7 +742,7 @@ fn gradient_positions(rows: &mut Vec<LayoutGroup>, document_node: &DocumentNode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn color_widget(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, color_props: ColorButton, blank_assist: bool) -> LayoutGroup {
|
fn color_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, color_props: ColorButton, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Number, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Number, blank_assist);
|
||||||
|
|
||||||
if let NodeInput::Value { tagged_value, exposed: false } = &document_node.inputs[index] {
|
if let NodeInput::Value { tagged_value, exposed: false } = &document_node.inputs[index] {
|
||||||
@@ -767,7 +767,7 @@ fn color_widget(document_node: &DocumentNode, node_id: u64, index: usize, name:
|
|||||||
LayoutGroup::Row { widgets }
|
LayoutGroup::Row { widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn curves_widget(document_node: &DocumentNode, node_id: u64, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
fn curves_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup {
|
||||||
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
|
||||||
|
|
||||||
if let NodeInput::Value {
|
if let NodeInput::Value {
|
||||||
@@ -785,17 +785,6 @@ fn curves_widget(document_node: &DocumentNode, node_id: u64, index: usize, name:
|
|||||||
LayoutGroup::Row { widgets }
|
LayoutGroup::Row { widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Properties for the input node, with information describing how frames work and a refresh button
|
|
||||||
pub fn input_properties(_document_node: &DocumentNode, _node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
|
||||||
let information = TextLabel::new("The graph's input frame is the rasterized artwork under the layer").widget_holder();
|
|
||||||
let layer_path = context.layer_path.to_vec();
|
|
||||||
let refresh_button = TextButton::new("Refresh Input")
|
|
||||||
.tooltip("Refresh the artwork under the layer")
|
|
||||||
.on_update(move |_| DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.clone() }.into())
|
|
||||||
.widget_holder();
|
|
||||||
vec![LayoutGroup::Row { widgets: vec![information] }, LayoutGroup::Row { widgets: vec![refresh_button] }]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn levels_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
pub fn levels_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||||
let input_shadows = number_widget(document_node, node_id, 1, "Shadows", NumberInput::default().min(0.).max(100.).unit("%"), true);
|
let input_shadows = number_widget(document_node, node_id, 1, "Shadows", NumberInput::default().min(0.).max(100.).unit("%"), true);
|
||||||
let input_midtones = number_widget(document_node, node_id, 2, "Midtones", NumberInput::default().min(0.).max(100.).unit("%"), true);
|
let input_midtones = number_widget(document_node, node_id, 2, "Midtones", NumberInput::default().min(0.).max(100.).unit("%"), true);
|
||||||
@@ -1629,12 +1618,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||||||
.tooltip("Generate with a new random seed")
|
.tooltip("Generate with a new random seed")
|
||||||
.on_update({
|
.on_update({
|
||||||
let imaginate_node = imaginate_node.clone();
|
let imaginate_node = imaginate_node.clone();
|
||||||
let layer_path = context.layer_path.to_vec();
|
|
||||||
let controller = controller.clone();
|
let controller = controller.clone();
|
||||||
move |_| {
|
move |_| {
|
||||||
controller.trigger_regenerate();
|
controller.trigger_regenerate();
|
||||||
DocumentMessage::ImaginateRandom {
|
DocumentMessage::ImaginateRandom {
|
||||||
layer_path: layer_path.clone(),
|
|
||||||
imaginate_node: imaginate_node.clone(),
|
imaginate_node: imaginate_node.clone(),
|
||||||
then_generate: true,
|
then_generate: true,
|
||||||
}
|
}
|
||||||
@@ -1646,11 +1633,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||||||
TextButton::new("Generate")
|
TextButton::new("Generate")
|
||||||
.tooltip("Fill layer frame by generating a new image")
|
.tooltip("Fill layer frame by generating a new image")
|
||||||
.on_update({
|
.on_update({
|
||||||
let layer_path = context.layer_path.to_vec();
|
|
||||||
let controller = controller.clone();
|
let controller = controller.clone();
|
||||||
move |_| {
|
move |_| {
|
||||||
controller.trigger_regenerate();
|
controller.trigger_regenerate();
|
||||||
DocumentMessage::ImaginateGenerate { layer_path: layer_path.clone() }.into()
|
DocumentMessage::ImaginateGenerate.into()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
@@ -1659,11 +1645,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||||||
.tooltip("Remove generated image from the layer frame")
|
.tooltip("Remove generated image from the layer frame")
|
||||||
.disabled(!matches!(imaginate_status, ImaginateStatus::ReadyDone))
|
.disabled(!matches!(imaginate_status, ImaginateStatus::ReadyDone))
|
||||||
.on_update({
|
.on_update({
|
||||||
let layer_path = context.layer_path.to_vec();
|
|
||||||
let controller = controller.clone();
|
let controller = controller.clone();
|
||||||
move |_| {
|
move |_| {
|
||||||
controller.set_status(ImaginateStatus::Ready);
|
controller.set_status(ImaginateStatus::Ready);
|
||||||
DocumentMessage::ImaginateClear { layer_path: layer_path.clone() }.into()
|
DocumentMessage::ImaginateGenerate.into()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
@@ -1687,10 +1672,8 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||||||
.tooltip("Set a new random seed")
|
.tooltip("Set a new random seed")
|
||||||
.on_update({
|
.on_update({
|
||||||
let imaginate_node = imaginate_node.clone();
|
let imaginate_node = imaginate_node.clone();
|
||||||
let layer_path = context.layer_path.to_vec();
|
|
||||||
move |_| {
|
move |_| {
|
||||||
DocumentMessage::ImaginateRandom {
|
DocumentMessage::ImaginateRandom {
|
||||||
layer_path: layer_path.clone(),
|
|
||||||
imaginate_node: imaginate_node.clone(),
|
imaginate_node: imaginate_node.clone(),
|
||||||
then_generate: false,
|
then_generate: false,
|
||||||
}
|
}
|
||||||
@@ -1701,8 +1684,8 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||||
NumberInput::new(Some(seed))
|
NumberInput::new(Some(seed))
|
||||||
.int()
|
.int()
|
||||||
.min(-((1u64 << f64::MANTISSA_DIGITS) as f64))
|
.min(-((1_u64 << f64::MANTISSA_DIGITS) as f64))
|
||||||
.max((1u64 << f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(update_value(move |input: &NumberInput| TaggedValue::F64(input.value.unwrap()), node_id, seed_index))
|
.on_update(update_value(move |input: &NumberInput| TaggedValue::F64(input.value.unwrap()), node_id, seed_index))
|
||||||
.mode(NumberInputMode::Increment)
|
.mode(NumberInputMode::Increment)
|
||||||
.widget_holder(),
|
.widget_holder(),
|
||||||
|
|||||||
-1
@@ -37,7 +37,6 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
|||||||
persistent_data,
|
persistent_data,
|
||||||
responses,
|
responses,
|
||||||
nested_path: &node_graph_message_handler.network,
|
nested_path: &node_graph_message_handler.network,
|
||||||
layer_path: &[],
|
|
||||||
executor,
|
executor,
|
||||||
network: document_network,
|
network: document_network,
|
||||||
metadata: document_metadata,
|
metadata: document_metadata,
|
||||||
|
|||||||
@@ -107,8 +107,9 @@ impl DocumentMetadata {
|
|||||||
layer_path
|
layer_path
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
sorted_layers.sort();
|
|
||||||
// Sorting here creates groups of similar UUID paths
|
// Sorting here creates groups of similar UUID paths
|
||||||
|
sorted_layers.sort();
|
||||||
sorted_layers.dedup_by(|a, b| a.starts_with(b));
|
sorted_layers.dedup_by(|a, b| a.starts_with(b));
|
||||||
sorted_layers
|
sorted_layers
|
||||||
}
|
}
|
||||||
@@ -386,32 +387,27 @@ impl LayerNodeIdentifier {
|
|||||||
u64::from(self.0) - 1
|
u64::from(self.0) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert layer to layer path
|
|
||||||
pub fn to_path(self) -> Vec<NodeId> {
|
|
||||||
vec![self.to_node()]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Access the parent layer if possible
|
/// Access the parent layer if possible
|
||||||
pub fn parent(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
pub fn parent(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
||||||
document_metadata.get_relations(self).and_then(|relations| relations.parent)
|
document_metadata.get_relations(self).and_then(|relations| relations.parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the previous sibling of this layer (up the layer tree)
|
/// Access the previous sibling of this layer (up the Layers panel)
|
||||||
pub fn previous_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
pub fn previous_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
||||||
document_metadata.get_relations(self).and_then(|relations| relations.previous_sibling)
|
document_metadata.get_relations(self).and_then(|relations| relations.previous_sibling)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the next sibling of this layer (down the layer tree)
|
/// Access the next sibling of this layer (down the Layers panel)
|
||||||
pub fn next_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
pub fn next_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
||||||
document_metadata.get_relations(self).and_then(|relations| relations.next_sibling)
|
document_metadata.get_relations(self).and_then(|relations| relations.next_sibling)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the first child of this layer (top most in layer tree)
|
/// Access the first child of this layer (top most in Layers panel)
|
||||||
pub fn first_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
pub fn first_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
||||||
document_metadata.get_relations(self).and_then(|relations| relations.first_child)
|
document_metadata.get_relations(self).and_then(|relations| relations.first_child)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the last child of this layer (bottom most in layer tree)
|
/// Access the last child of this layer (bottom most in Layers panel)
|
||||||
pub fn last_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
pub fn last_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
||||||
document_metadata.get_relations(self).and_then(|relations| relations.last_child)
|
document_metadata.get_relations(self).and_then(|relations| relations.last_child)
|
||||||
}
|
}
|
||||||
@@ -457,7 +453,7 @@ impl LayerNodeIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a child towards the top of the layer tree
|
/// Add a child towards the top of the Layers panel
|
||||||
pub fn push_front_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
pub fn push_front_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
||||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||||
let parent = document_metadata.get_structure_mut(self);
|
let parent = document_metadata.get_structure_mut(self);
|
||||||
@@ -470,7 +466,7 @@ impl LayerNodeIdentifier {
|
|||||||
document_metadata.get_structure_mut(new).parent = Some(self);
|
document_metadata.get_structure_mut(new).parent = Some(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a child towards the bottom of the layer tree
|
/// Add a child towards the bottom of the Layers panel
|
||||||
pub fn push_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
pub fn push_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
||||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||||
let parent = document_metadata.get_structure_mut(self);
|
let parent = document_metadata.get_structure_mut(self);
|
||||||
@@ -483,7 +479,7 @@ impl LayerNodeIdentifier {
|
|||||||
document_metadata.get_structure_mut(new).parent = Some(self);
|
document_metadata.get_structure_mut(new).parent = Some(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add sibling above in the layer tree
|
/// Add sibling above in the Layers panel
|
||||||
pub fn add_before(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
pub fn add_before(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
||||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||||
document_metadata.get_structure_mut(new).next_sibling = Some(self);
|
document_metadata.get_structure_mut(new).next_sibling = Some(self);
|
||||||
@@ -501,7 +497,7 @@ impl LayerNodeIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add sibling below in the layer tree
|
/// Add sibling below in the Layers panel
|
||||||
pub fn add_after(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
pub fn add_after(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
|
||||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||||
document_metadata.get_structure_mut(new).previous_sibling = Some(self);
|
document_metadata.get_structure_mut(new).previous_sibling = Some(self);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
use graph_craft::document::NodeId;
|
||||||
|
|
||||||
use serde::ser::SerializeStruct;
|
use serde::ser::SerializeStruct;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -45,6 +45,9 @@ pub struct LayerPanelEntry {
|
|||||||
pub layer_classification: LayerClassification,
|
pub layer_classification: LayerClassification,
|
||||||
pub selected: bool,
|
pub selected: bool,
|
||||||
pub expanded: bool,
|
pub expanded: bool,
|
||||||
pub path: Vec<LayerId>,
|
#[serde(rename = "parentId")]
|
||||||
|
pub parent_id: Option<NodeId>,
|
||||||
|
pub id: NodeId,
|
||||||
|
pub depth: usize,
|
||||||
pub thumbnail: String,
|
pub thumbnail: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
pub use super::layer_panel::LayerPanelEntry;
|
pub use super::layer_panel::LayerPanelEntry;
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
|
|
||||||
use graphene_core::raster::color::Color;
|
|
||||||
|
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -54,12 +51,6 @@ impl DocumentMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DocumentRenderMode<'a> {
|
|
||||||
Root,
|
|
||||||
OnlyBelowLayerInFolder(&'a [LayerId]),
|
|
||||||
LayerCutout(&'a [LayerId], Color),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// SnappingState determines the current individual snapping states
|
/// SnappingState determines the current individual snapping states
|
||||||
pub struct SnappingState {
|
pub struct SnappingState {
|
||||||
|
|||||||
@@ -4,8 +4,3 @@ pub mod error;
|
|||||||
pub mod layer_panel;
|
pub mod layer_panel;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod transformation;
|
pub mod transformation;
|
||||||
|
|
||||||
// TODO: Remove this entirely
|
|
||||||
/// A number that identifies a layer.
|
|
||||||
/// This does not technically need to be unique globally, only within a folder.
|
|
||||||
pub type LayerId = u64;
|
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ impl<'a> Selected<'a> {
|
|||||||
let to = document_metadata.downstream_transform_to_viewport(layer);
|
let to = document_metadata.downstream_transform_to_viewport(layer);
|
||||||
let new = to.inverse() * transformation * to * original_transform;
|
let new = to.inverse() * transformation * to * original_transform;
|
||||||
responses.add(GraphOperationMessage::TransformSet {
|
responses.add(GraphOperationMessage::TransformSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: new,
|
transform: new,
|
||||||
transform_in: TransformIn::Local,
|
transform_in: TransformIn::Local,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
@@ -404,7 +404,7 @@ impl<'a> Selected<'a> {
|
|||||||
let position = new_pos_viewport;
|
let position = new_pos_viewport;
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -438,17 +438,17 @@ impl<'a> Selected<'a> {
|
|||||||
OriginalTransforms::Layer(hash) => {
|
OriginalTransforms::Layer(hash) => {
|
||||||
let Some(matrix) = hash.get(&layer) else { continue };
|
let Some(matrix) = hash.get(&layer) else { continue };
|
||||||
self.responses.add(GraphOperationMessage::TransformSet {
|
self.responses.add(GraphOperationMessage::TransformSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: *matrix,
|
transform: *matrix,
|
||||||
transform_in: TransformIn::Local,
|
transform_in: TransformIn::Local,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
OriginalTransforms::Path(path) => {
|
OriginalTransforms::Path(path) => {
|
||||||
for (layer, points) in path {
|
for (&layer, points) in path {
|
||||||
for &(point, position) in points {
|
for &(point, position) in points {
|
||||||
self.responses.add(GraphOperationMessage::Vector {
|
self.responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use graphene_core::text::Font;
|
use graphene_core::text::Font;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -22,21 +22,21 @@ pub enum PortfolioMessage {
|
|||||||
// Messages
|
// Messages
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
DocumentPassMessage {
|
DocumentPassMessage {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
message: DocumentMessage,
|
message: DocumentMessage,
|
||||||
},
|
},
|
||||||
AutoSaveActiveDocument,
|
AutoSaveActiveDocument,
|
||||||
AutoSaveDocument {
|
AutoSaveDocument {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
CloseActiveDocumentWithConfirmation,
|
CloseActiveDocumentWithConfirmation,
|
||||||
CloseAllDocuments,
|
CloseAllDocuments,
|
||||||
CloseAllDocumentsWithConfirmation,
|
CloseAllDocumentsWithConfirmation,
|
||||||
CloseDocument {
|
CloseDocument {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
CloseDocumentWithConfirmation {
|
CloseDocumentWithConfirmation {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
Copy {
|
Copy {
|
||||||
clipboard: Clipboard,
|
clipboard: Clipboard,
|
||||||
@@ -45,7 +45,7 @@ pub enum PortfolioMessage {
|
|||||||
clipboard: Clipboard,
|
clipboard: Clipboard,
|
||||||
},
|
},
|
||||||
DeleteDocument {
|
DeleteDocument {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
DestroyAllDocuments,
|
DestroyAllDocuments,
|
||||||
FontLoaded {
|
FontLoaded {
|
||||||
@@ -65,7 +65,7 @@ pub enum PortfolioMessage {
|
|||||||
ImaginateServerHostname,
|
ImaginateServerHostname,
|
||||||
Import,
|
Import,
|
||||||
LoadDocumentResources {
|
LoadDocumentResources {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
LoadFont {
|
LoadFont {
|
||||||
font: Font,
|
font: Font,
|
||||||
@@ -81,7 +81,7 @@ pub enum PortfolioMessage {
|
|||||||
document_serialized_content: String,
|
document_serialized_content: String,
|
||||||
},
|
},
|
||||||
OpenDocumentFileWithId {
|
OpenDocumentFileWithId {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
document_name: String,
|
document_name: String,
|
||||||
document_is_auto_saved: bool,
|
document_is_auto_saved: bool,
|
||||||
document_is_saved: bool,
|
document_is_saved: bool,
|
||||||
@@ -97,10 +97,10 @@ pub enum PortfolioMessage {
|
|||||||
},
|
},
|
||||||
PrevDocument,
|
PrevDocument,
|
||||||
SelectDocument {
|
SelectDocument {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
SetActiveDocument {
|
SetActiveDocument {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
},
|
},
|
||||||
SubmitDocumentExport {
|
SubmitDocumentExport {
|
||||||
file_name: String,
|
file_name: String,
|
||||||
@@ -110,8 +110,7 @@ pub enum PortfolioMessage {
|
|||||||
transparent_background: bool,
|
transparent_background: bool,
|
||||||
},
|
},
|
||||||
SubmitGraphRender {
|
SubmitGraphRender {
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
layer_path: Vec<LayerId>,
|
|
||||||
},
|
},
|
||||||
ToggleRulers,
|
ToggleRulers,
|
||||||
UpdateDocumentWidgets,
|
UpdateDocumentWidgets,
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ use std::sync::Arc;
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct PortfolioMessageHandler {
|
pub struct PortfolioMessageHandler {
|
||||||
menu_bar_message_handler: MenuBarMessageHandler,
|
menu_bar_message_handler: MenuBarMessageHandler,
|
||||||
documents: HashMap<u64, DocumentMessageHandler>,
|
documents: HashMap<DocumentId, DocumentMessageHandler>,
|
||||||
document_ids: Vec<u64>,
|
document_ids: Vec<DocumentId>,
|
||||||
active_document_id: Option<u64>,
|
active_document_id: Option<DocumentId>,
|
||||||
graph_view_overlay_open: bool,
|
graph_view_overlay_open: bool,
|
||||||
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
|
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
|
||||||
pub persistent_data: PersistentData,
|
pub persistent_data: PersistentData,
|
||||||
@@ -109,7 +109,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
|||||||
|
|
||||||
// Clear relevant UI layouts if there are no documents
|
// Clear relevant UI layouts if there are no documents
|
||||||
responses.add(PropertiesPanelMessage::Clear);
|
responses.add(PropertiesPanelMessage::Clear);
|
||||||
responses.add(DocumentMessage::ClearLayerTree);
|
responses.add(DocumentMessage::ClearLayersPanel);
|
||||||
let hint_data = HintData(vec![HintGroup(vec![])]);
|
let hint_data = HintData(vec![HintGroup(vec![])]);
|
||||||
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
|||||||
if self.documents.len() == 1 && self.document_ids[0] == document_id {
|
if self.documents.len() == 1 && self.document_ids[0] == document_id {
|
||||||
// Clear UI layouts that assume the existence of a document
|
// Clear UI layouts that assume the existence of a document
|
||||||
responses.add(PropertiesPanelMessage::Clear);
|
responses.add(PropertiesPanelMessage::Clear);
|
||||||
responses.add(DocumentMessage::ClearLayerTree);
|
responses.add(DocumentMessage::ClearLayersPanel);
|
||||||
let hint_data = HintData(vec![HintGroup(vec![])]);
|
let hint_data = HintData(vec![HintGroup(vec![])]);
|
||||||
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||||
}
|
}
|
||||||
@@ -506,10 +506,9 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PortfolioMessage::SubmitGraphRender { document_id, layer_path } => {
|
PortfolioMessage::SubmitGraphRender { document_id } => {
|
||||||
let result = self.executor.submit_node_graph_evaluation(
|
let result = self.executor.submit_node_graph_evaluation(
|
||||||
self.documents.get_mut(&document_id).expect("Tried to render no existent Document"),
|
self.documents.get_mut(&document_id).expect("Tried to render no existent Document"),
|
||||||
layer_path,
|
|
||||||
ipp.viewport_bounds.size().as_uvec2(),
|
ipp.viewport_bounds.size().as_uvec2(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -591,11 +590,11 @@ impl PortfolioMessageHandler {
|
|||||||
self.executor.introspect_node(node_path)
|
self.executor.introspect_node(node_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn document(&self, document_id: u64) -> Option<&DocumentMessageHandler> {
|
pub fn document(&self, document_id: DocumentId) -> Option<&DocumentMessageHandler> {
|
||||||
self.documents.get(&document_id)
|
self.documents.get(&document_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn document_mut(&mut self, document_id: u64) -> Option<&mut DocumentMessageHandler> {
|
pub fn document_mut(&mut self, document_id: DocumentId) -> Option<&mut DocumentMessageHandler> {
|
||||||
self.documents.get_mut(&document_id)
|
self.documents.get_mut(&document_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,7 +606,7 @@ impl PortfolioMessageHandler {
|
|||||||
self.active_document_id.and_then(|id| self.documents.get_mut(&id))
|
self.active_document_id.and_then(|id| self.documents.get_mut(&id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_document_id(&self) -> Option<u64> {
|
pub fn active_document_id(&self) -> Option<DocumentId> {
|
||||||
self.active_document_id
|
self.active_document_id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,7 +636,7 @@ impl PortfolioMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix how this doesn't preserve tab order upon loading new document from *File > Load*
|
// TODO: Fix how this doesn't preserve tab order upon loading new document from *File > Load*
|
||||||
fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: u64, responses: &mut VecDeque<Message>) {
|
fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: DocumentId, responses: &mut VecDeque<Message>) {
|
||||||
self.document_ids.push(document_id);
|
self.document_ids.push(document_id);
|
||||||
|
|
||||||
new_document.update_layers_panel_options_bar_widgets(responses);
|
new_document.update_layers_panel_options_bar_widgets(responses);
|
||||||
@@ -667,7 +666,7 @@ impl PortfolioMessageHandler {
|
|||||||
self.document_ids.iter().map(|id| self.documents.get(id).expect("document id was not found in the document hashmap"))
|
self.document_ids.iter().map(|id| self.documents.get(id).expect("document id was not found in the document hashmap"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_index(&self, document_id: u64) -> usize {
|
fn document_index(&self, document_id: DocumentId) -> usize {
|
||||||
self.document_ids.iter().position(|id| id == &document_id).expect("Active document is missing from document ids")
|
self.document_ids.iter().position(|id| id == &document_id).expect("Active document is missing from document ids")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ pub use graphite_proc_macros::*;
|
|||||||
|
|
||||||
pub use std::collections::{HashMap, HashSet, VecDeque};
|
pub use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
|
// TODO: Convert from a type alias to a newtype
|
||||||
|
pub type DocumentId = u64;
|
||||||
|
|
||||||
pub trait Responses {
|
pub trait Responses {
|
||||||
fn add(&mut self, message: impl Into<Message>);
|
fn add(&mut self, message: impl Into<Message>);
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ pub fn new_image_layer(image_frame: ImageFrame<Color>, id: NodeId, parent: Layer
|
|||||||
pub fn set_manipulator_mirror_angle(manipulator_groups: &[ManipulatorGroup<ManipulatorGroupId>], layer: LayerNodeIdentifier, mirror_angle: bool, responses: &mut VecDeque<Message>) {
|
pub fn set_manipulator_mirror_angle(manipulator_groups: &[ManipulatorGroup<ManipulatorGroupId>], layer: LayerNodeIdentifier, mirror_angle: bool, responses: &mut VecDeque<Message>) {
|
||||||
for manipulator_group in manipulator_groups {
|
for manipulator_group in manipulator_groups {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||||
id: manipulator_group.id,
|
id: manipulator_group.id,
|
||||||
mirror_angle,
|
mirror_angle,
|
||||||
@@ -216,7 +216,7 @@ impl<'a> NodeGraphLayer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator up the primary flow of the layer
|
/// Return an iterator up the primary flow of the layer
|
||||||
pub fn primary_layer_flow(&self) -> impl Iterator<Item = (&'a DocumentNode, u64)> {
|
pub fn primary_layer_flow(&self) -> impl Iterator<Item = (&'a DocumentNode, NodeId)> {
|
||||||
self.node_graph.upstream_flow_back_from_nodes(vec![self.layer_node], true)
|
self.node_graph.upstream_flow_back_from_nodes(vec![self.layer_node], true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ impl Pivot {
|
|||||||
let pivot = transform.inverse().transform_point2(position);
|
let pivot = transform.inverse().transform_point2(position);
|
||||||
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
||||||
if pivot.is_finite() {
|
if pivot.is_finite() {
|
||||||
let layer = layer.to_path();
|
|
||||||
responses.add(GraphOperationMessage::TransformSetPivot { layer, pivot });
|
responses.add(GraphOperationMessage::TransformSetPivot { layer, pivot });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ impl Resize {
|
|||||||
/// Starts a resize, assigning the snap targets and snapping the starting position.
|
/// Starts a resize, assigning the snap targets and snapping the starting position.
|
||||||
pub fn start(&mut self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
|
pub fn start(&mut self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
|
||||||
self.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
self.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
self.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
let root_transform = document.metadata().document_to_viewport;
|
let root_transform = document.metadata().document_to_viewport;
|
||||||
self.drag_start = root_transform.inverse().transform_point2(self.snap_manager.snap_position(responses, document, input.mouse.position));
|
self.drag_start = root_transform.inverse().transform_point2(self.snap_manager.snap_position(responses, document, input.mouse.position));
|
||||||
}
|
}
|
||||||
@@ -25,7 +24,6 @@ impl Resize {
|
|||||||
/// Recalculates snap targets without snapping the starting position.
|
/// Recalculates snap targets without snapping the starting position.
|
||||||
pub fn recalculate_snaps(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
|
pub fn recalculate_snaps(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
|
||||||
self.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
self.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
self.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the drag start position in viewport space.
|
/// Calculate the drag start position in viewport space.
|
||||||
@@ -65,7 +63,7 @@ impl Resize {
|
|||||||
|
|
||||||
Some(
|
Some(
|
||||||
GraphOperationMessage::TransformSet {
|
GraphOperationMessage::TransformSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: DAffine2::from_scale_angle_translation(size, 0., start),
|
transform: DAffine2::from_scale_angle_translation(size, 0., start),
|
||||||
transform_in: TransformIn::Viewport,
|
transform_in: TransformIn::Viewport,
|
||||||
skip_rerender,
|
skip_rerender,
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ impl ShapeState {
|
|||||||
|
|
||||||
if point.manipulator_type.is_handle() {
|
if point.manipulator_type.is_handle() {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id: group.id, mirror_angle: false },
|
modification: VectorDataModification::SetManipulatorHandleMirroring { id: group.id, mirror_angle: false },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ impl ShapeState {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: (position + delta) },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: (position + delta) },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -270,7 +270,7 @@ impl ShapeState {
|
|||||||
|
|
||||||
// Mirror the angle but not the distance
|
// Mirror the angle but not the distance
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||||
id: manipulator.id,
|
id: manipulator.id,
|
||||||
mirror_angle: true,
|
mirror_angle: true,
|
||||||
@@ -291,7 +291,7 @@ impl ShapeState {
|
|||||||
if let Some(in_handle) = length_previous.map(|length| anchor_position + handle_vector * length) {
|
if let Some(in_handle) = length_previous.map(|length| anchor_position + handle_vector * length) {
|
||||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::InHandle);
|
let point = ManipulatorPointId::new(manipulator.id, SelectedType::InHandle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: in_handle },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: in_handle },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -299,7 +299,7 @@ impl ShapeState {
|
|||||||
if let Some(out_handle) = length_next.map(|length| anchor_position - handle_vector * length) {
|
if let Some(out_handle) = length_next.map(|length| anchor_position - handle_vector * length) {
|
||||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::OutHandle);
|
let point = ManipulatorPointId::new(manipulator.id, SelectedType::OutHandle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: out_handle },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: out_handle },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -338,7 +338,7 @@ impl ShapeState {
|
|||||||
let out_handle = ManipulatorPointId::new(point.group, SelectedType::OutHandle);
|
let out_handle = ManipulatorPointId::new(point.group, SelectedType::OutHandle);
|
||||||
if let Some(position) = group.out_handle {
|
if let Some(position) = group.out_handle {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point: out_handle, position },
|
modification: VectorDataModification::SetManipulatorPosition { point: out_handle, position },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -347,7 +347,7 @@ impl ShapeState {
|
|||||||
let in_handle = ManipulatorPointId::new(point.group, SelectedType::InHandle);
|
let in_handle = ManipulatorPointId::new(point.group, SelectedType::InHandle);
|
||||||
if let Some(position) = group.in_handle {
|
if let Some(position) = group.in_handle {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point: in_handle, position },
|
modification: VectorDataModification::SetManipulatorPosition { point: in_handle, position },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -391,7 +391,7 @@ impl ShapeState {
|
|||||||
let Some(previous_position) = point.manipulator_type.get_position(group) else { return };
|
let Some(previous_position) = point.manipulator_type.get_position(group) else { return };
|
||||||
let position = previous_position + delta;
|
let position = previous_position + delta;
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -410,7 +410,7 @@ impl ShapeState {
|
|||||||
// and set angle mirroring to true.
|
// and set angle mirroring to true.
|
||||||
if !mirror && point.manipulator_type.opposite().get_position(group).is_none() {
|
if !mirror && point.manipulator_type.opposite().get_position(group).is_none() {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id: group.id, mirror_angle: true },
|
modification: VectorDataModification::SetManipulatorHandleMirroring { id: group.id, mirror_angle: true },
|
||||||
});
|
});
|
||||||
mirror = true;
|
mirror = true;
|
||||||
@@ -428,7 +428,7 @@ impl ShapeState {
|
|||||||
}
|
}
|
||||||
let position = group.anchor - (original_handle_position - group.anchor);
|
let position = group.anchor - (original_handle_position - group.anchor);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -471,7 +471,7 @@ impl ShapeState {
|
|||||||
|
|
||||||
if (anchor_position - point_position).length() < DRAG_THRESHOLD {
|
if (anchor_position - point_position).length() < DRAG_THRESHOLD {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::RemoveManipulatorPoint { point },
|
modification: VectorDataModification::RemoveManipulatorPoint { point },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -481,7 +481,7 @@ impl ShapeState {
|
|||||||
if let Some(lengths) = opposing_handle_lengths {
|
if let Some(lengths) = opposing_handle_lengths {
|
||||||
if lengths.contains_key(&point.group) {
|
if lengths.contains_key(&point.group) {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::RemoveManipulatorPoint { point: opposite_point },
|
modification: VectorDataModification::RemoveManipulatorPoint { point: opposite_point },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -567,7 +567,7 @@ impl ShapeState {
|
|||||||
|
|
||||||
let Some(opposing_handle_length) = opposing_handle_length else {
|
let Some(opposing_handle_length) = opposing_handle_length else {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::RemoveManipulatorPoint {
|
modification: VectorDataModification::RemoveManipulatorPoint {
|
||||||
point: ManipulatorPointId::new(manipulator_group.id, single_selected_handle.opposite()),
|
point: ManipulatorPointId::new(manipulator_group.id, single_selected_handle.opposite()),
|
||||||
},
|
},
|
||||||
@@ -586,7 +586,7 @@ impl ShapeState {
|
|||||||
assert!(position.is_finite(), "Opposing handle not finite!");
|
assert!(position.is_finite(), "Opposing handle not finite!");
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -596,10 +596,10 @@ impl ShapeState {
|
|||||||
|
|
||||||
/// Dissolve the selected points.
|
/// Dissolve the selected points.
|
||||||
pub fn delete_selected_points(&self, responses: &mut VecDeque<Message>) {
|
pub fn delete_selected_points(&self, responses: &mut VecDeque<Message>) {
|
||||||
for (layer, state) in &self.selected_shape_state {
|
for (&layer, state) in &self.selected_shape_state {
|
||||||
for &point in &state.selected_points {
|
for &point in &state.selected_points {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::RemoveManipulatorPoint { point },
|
modification: VectorDataModification::RemoveManipulatorPoint { point },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -608,10 +608,10 @@ impl ShapeState {
|
|||||||
|
|
||||||
/// Toggle if the handles should mirror angle across the anchor position.
|
/// Toggle if the handles should mirror angle across the anchor position.
|
||||||
pub fn toggle_handle_mirroring_on_selected(&self, responses: &mut VecDeque<Message>) {
|
pub fn toggle_handle_mirroring_on_selected(&self, responses: &mut VecDeque<Message>) {
|
||||||
for (layer, state) in &self.selected_shape_state {
|
for (&layer, state) in &self.selected_shape_state {
|
||||||
for point in &state.selected_points {
|
for point in &state.selected_points {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::ToggleManipulatorHandleMirroring { id: point.group },
|
modification: VectorDataModification::ToggleManipulatorHandleMirroring { id: point.group },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -620,10 +620,10 @@ impl ShapeState {
|
|||||||
|
|
||||||
/// Toggle if the handles should mirror angle across the anchor position.
|
/// Toggle if the handles should mirror angle across the anchor position.
|
||||||
pub fn set_handle_mirroring_on_selected(&self, mirror_angle: bool, responses: &mut VecDeque<Message>) {
|
pub fn set_handle_mirroring_on_selected(&self, mirror_angle: bool, responses: &mut VecDeque<Message>) {
|
||||||
for (layer, state) in &self.selected_shape_state {
|
for (&layer, state) in &self.selected_shape_state {
|
||||||
for point in &state.selected_points {
|
for point in &state.selected_points {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id: point.group, mirror_angle },
|
modification: VectorDataModification::SetManipulatorHandleMirroring { id: point.group, mirror_angle },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -732,7 +732,7 @@ impl ShapeState {
|
|||||||
let point = ManipulatorPointId::new(start, SelectedType::OutHandle);
|
let point = ManipulatorPointId::new(start, SelectedType::OutHandle);
|
||||||
let position = first.handle_start().unwrap_or(first.start());
|
let position = first.handle_start().unwrap_or(first.start());
|
||||||
let out_handle = GraphOperationMessage::Vector {
|
let out_handle = GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
};
|
};
|
||||||
responses.add(out_handle);
|
responses.add(out_handle);
|
||||||
@@ -740,7 +740,7 @@ impl ShapeState {
|
|||||||
// Insert a new manipulator group between the existing ones
|
// Insert a new manipulator group between the existing ones
|
||||||
let manipulator_group = ManipulatorGroup::new(first.end(), first.handle_end(), second.handle_start());
|
let manipulator_group = ManipulatorGroup::new(first.end(), first.handle_end(), second.handle_start());
|
||||||
let insert = GraphOperationMessage::Vector {
|
let insert = GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::AddManipulatorGroup { manipulator_group, after_id: start },
|
modification: VectorDataModification::AddManipulatorGroup { manipulator_group, after_id: start },
|
||||||
};
|
};
|
||||||
responses.add(insert);
|
responses.add(insert);
|
||||||
@@ -749,7 +749,7 @@ impl ShapeState {
|
|||||||
let point = ManipulatorPointId::new(end, SelectedType::InHandle);
|
let point = ManipulatorPointId::new(end, SelectedType::InHandle);
|
||||||
let position = second.handle_end().unwrap_or(second.end());
|
let position = second.handle_end().unwrap_or(second.end());
|
||||||
let in_handle = GraphOperationMessage::Vector {
|
let in_handle = GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
};
|
};
|
||||||
responses.add(in_handle);
|
responses.add(in_handle);
|
||||||
@@ -797,16 +797,16 @@ impl ShapeState {
|
|||||||
} else {
|
} else {
|
||||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::InHandle);
|
let point = ManipulatorPointId::new(manipulator.id, SelectedType::InHandle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: anchor_position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: anchor_position },
|
||||||
});
|
});
|
||||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::OutHandle);
|
let point = ManipulatorPointId::new(manipulator.id, SelectedType::OutHandle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: anchor_position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: anchor_position },
|
||||||
});
|
});
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||||
id: manipulator.id,
|
id: manipulator.id,
|
||||||
mirror_angle: false,
|
mirror_angle: false,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use super::shape_editor::ManipulatorPointInfo;
|
|
||||||
use crate::consts::{SNAP_AXIS_TOLERANCE, SNAP_POINT_TOLERANCE};
|
use crate::consts::{SNAP_AXIS_TOLERANCE, SNAP_POINT_TOLERANCE};
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
@@ -100,23 +98,6 @@ impl SnapManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds all of the shape handles in the document, including bézier handles of the points specified
|
|
||||||
pub fn add_all_document_handles(
|
|
||||||
&mut self,
|
|
||||||
_document_message_handler: &DocumentMessageHandler,
|
|
||||||
_input: &InputPreprocessorMessageHandler,
|
|
||||||
_include_handles: &[&[LayerId]],
|
|
||||||
_exclude: &[&[LayerId]],
|
|
||||||
_ignore_points: &[ManipulatorPointInfo],
|
|
||||||
) {
|
|
||||||
// for path in document_message_handler.all_layers() {
|
|
||||||
// if !exclude.contains(&path) {
|
|
||||||
// let layer = document_message_handler.document_legacy.layer(path).expect("Could not get layer for snapping");
|
|
||||||
// self.add_snap_path(document_message_handler, input, layer, path, include_handles.contains(&path), ignore_points);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds the closest snap from an array of layers to the specified snap targets in viewport coords.
|
/// Finds the closest snap from an array of layers to the specified snap targets in viewport coords.
|
||||||
/// Returns 0 for each axis that there is no snap less than the snap tolerance.
|
/// Returns 0 for each axis that there is no snap less than the snap tolerance.
|
||||||
pub fn snap_layers(&mut self, responses: &mut VecDeque<Message>, document_message_handler: &DocumentMessageHandler, snap_anchors: Vec<DVec2>, mouse_delta: DVec2) -> DVec2 {
|
pub fn snap_layers(&mut self, responses: &mut VecDeque<Message>, document_message_handler: &DocumentMessageHandler, snap_anchors: Vec<DVec2>, mouse_delta: DVec2) -> DVec2 {
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ pub struct ToolMessageHandler {
|
|||||||
pub shape_editor: ShapeState,
|
pub shape_editor: ShapeState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageHandler<ToolMessage, (&DocumentMessageHandler, u64, &InputPreprocessorMessageHandler, &PersistentData, &NodeGraphExecutor)> for ToolMessageHandler {
|
impl MessageHandler<ToolMessage, (&DocumentMessageHandler, DocumentId, &InputPreprocessorMessageHandler, &PersistentData, &NodeGraphExecutor)> for ToolMessageHandler {
|
||||||
#[remain::check]
|
#[remain::check]
|
||||||
fn process_message(
|
fn process_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
message: ToolMessage,
|
message: ToolMessage,
|
||||||
responses: &mut VecDeque<Message>,
|
responses: &mut VecDeque<Message>,
|
||||||
(document, document_id, input, persistent_data, node_graph): (&DocumentMessageHandler, u64, &InputPreprocessorMessageHandler, &PersistentData, &NodeGraphExecutor),
|
(document, document_id, input, persistent_data, node_graph): (&DocumentMessageHandler, DocumentId, &InputPreprocessorMessageHandler, &PersistentData, &NodeGraphExecutor),
|
||||||
) {
|
) {
|
||||||
let font_cache = &persistent_data.font_cache;
|
let font_cache = &persistent_data.font_cache;
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ impl ArtboardToolData {
|
|||||||
let snap_y = selected_edges.0 || selected_edges.1;
|
let snap_y = selected_edges.0 || selected_edges.1;
|
||||||
|
|
||||||
self.snap_manager.start_snap(document, input, document.bounding_boxes(), snap_x, snap_y);
|
self.snap_manager.start_snap(document, input, document.bounding_boxes(), snap_x, snap_y);
|
||||||
self.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
|
|
||||||
if let Some(bounds) = &mut self.bounding_box_manager {
|
if let Some(bounds) = &mut self.bounding_box_manager {
|
||||||
bounds.center_of_transformation = (bounds.bounds[0] + bounds.bounds[1]) / 2.;
|
bounds.center_of_transformation = (bounds.bounds[0] + bounds.bounds[1]) / 2.;
|
||||||
@@ -139,7 +138,6 @@ impl ArtboardToolData {
|
|||||||
self.selected_artboard = Some(intersection);
|
self.selected_artboard = Some(intersection);
|
||||||
|
|
||||||
self.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
self.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
self.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@@ -279,7 +277,6 @@ impl Fsm for ArtboardToolFsmState {
|
|||||||
tool_data.selected_artboard = Some(LayerNodeIdentifier::new_unchecked(id));
|
tool_data.selected_artboard = Some(LayerNodeIdentifier::new_unchecked(id));
|
||||||
|
|
||||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::NewArtboard {
|
responses.add(GraphOperationMessage::NewArtboard {
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ impl BrushToolData {
|
|||||||
fn update_strokes(&self, responses: &mut VecDeque<Message>) {
|
fn update_strokes(&self, responses: &mut VecDeque<Message>) {
|
||||||
let Some(layer) = self.layer else { return };
|
let Some(layer) = self.layer else { return };
|
||||||
let strokes = self.strokes.clone();
|
let strokes = self.strokes.clone();
|
||||||
responses.add(GraphOperationMessage::Brush { layer: layer.to_path(), strokes });
|
responses.add(GraphOperationMessage::Brush { layer, strokes });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||||||
.unit(" px")
|
.unit(" px")
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| EllipseToolMessage::UpdateOptions(EllipseOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| EllipseToolMessage::UpdateOptions(EllipseOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
@@ -211,12 +211,12 @@ impl Fsm for EllipseToolFsmState {
|
|||||||
|
|
||||||
let fill_color = tool_options.fill.active_color();
|
let fill_color = tool_options.fill.active_color();
|
||||||
responses.add(GraphOperationMessage::FillSet {
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::StrokeSet {
|
responses.add(GraphOperationMessage::StrokeSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ impl Fsm for FillToolFsmState {
|
|||||||
let Some(layer_identifier) = document.click(input.mouse.position, &document.network) else {
|
let Some(layer_identifier) = document.click(input.mouse.position, &document.network) else {
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
let layer = layer_identifier.to_path();
|
|
||||||
|
|
||||||
let color = match event {
|
let color = match event {
|
||||||
FillToolMessage::LeftPointerDown => global_tool_data.primary_color,
|
FillToolMessage::LeftPointerDown => global_tool_data.primary_color,
|
||||||
FillToolMessage::RightPointerDown => global_tool_data.secondary_color,
|
FillToolMessage::RightPointerDown => global_tool_data.secondary_color,
|
||||||
@@ -81,7 +79,7 @@ impl Fsm for FillToolFsmState {
|
|||||||
let fill = Fill::Solid(color);
|
let fill = Fill::Solid(color);
|
||||||
|
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
responses.add(GraphOperationMessage::FillSet { layer: layer_identifier, fill });
|
||||||
responses.add(DocumentMessage::CommitTransaction);
|
responses.add(DocumentMessage::CommitTransaction);
|
||||||
|
|
||||||
FillToolFsmState::Ready
|
FillToolFsmState::Ready
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||||||
.unit(" px")
|
.unit(" px")
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(1.)
|
.min(1.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| FreehandToolMessage::UpdateOptions(FreehandOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
@@ -215,12 +215,12 @@ impl Fsm for FreehandToolFsmState {
|
|||||||
tool_data.layer = Some(layer);
|
tool_data.layer = Some(layer);
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::FillSet {
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
fill: if let Some(color) = tool_options.fill.active_color() { Fill::Solid(color) } else { Fill::None },
|
fill: if let Some(color) = tool_options.fill.active_color() { Fill::Solid(color) } else { Fill::None },
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::StrokeSet {
|
responses.add(GraphOperationMessage::StrokeSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_data.weight),
|
stroke: Stroke::new(tool_options.stroke.active_color(), tool_data.weight),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ impl Fsm for FreehandToolFsmState {
|
|||||||
if tool_data.last_point != pos {
|
if tool_data.last_point != pos {
|
||||||
let manipulator_group = ManipulatorGroup::new_anchor(pos);
|
let manipulator_group = ManipulatorGroup::new_anchor(pos);
|
||||||
let modification = VectorDataModification::AddEndManipulatorGroup { subpath_index: 0, manipulator_group };
|
let modification = VectorDataModification::AddEndManipulatorGroup { subpath_index: 0, manipulator_group };
|
||||||
responses.add(GraphOperationMessage::Vector { layer: layer.to_path(), modification });
|
responses.add(GraphOperationMessage::Vector { layer, modification });
|
||||||
tool_data.dragged = true;
|
tool_data.dragged = true;
|
||||||
tool_data.last_point = pos;
|
tool_data.last_point = pos;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::application::generate_uuid;
|
|
||||||
use crate::consts::{LINE_ROTATE_SNAP_ANGLE, MANIPULATOR_GROUP_MARKER_SIZE, SELECTION_THRESHOLD};
|
use crate::consts::{LINE_ROTATE_SNAP_ANGLE, MANIPULATOR_GROUP_MARKER_SIZE, SELECTION_THRESHOLD};
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
@@ -235,9 +234,10 @@ impl SelectedGradient {
|
|||||||
/// Update the layer fill to the current gradient
|
/// Update the layer fill to the current gradient
|
||||||
pub fn render_gradient(&mut self, responses: &mut VecDeque<Message>) {
|
pub fn render_gradient(&mut self, responses: &mut VecDeque<Message>) {
|
||||||
self.gradient.transform = self.transform;
|
self.gradient.transform = self.transform;
|
||||||
let fill = Fill::Gradient(self.gradient.clone());
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
let layer = self.layer.to_path();
|
layer: self.layer,
|
||||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
fill: Fill::Gradient(self.gradient.clone()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +269,6 @@ struct GradientToolData {
|
|||||||
|
|
||||||
pub fn start_snap(snap_manager: &mut SnapManager, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
|
pub fn start_snap(snap_manager: &mut SnapManager, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler) {
|
||||||
snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fsm for GradientToolFsmState {
|
impl Fsm for GradientToolFsmState {
|
||||||
@@ -338,9 +337,10 @@ impl Fsm for GradientToolFsmState {
|
|||||||
|
|
||||||
// The gradient has only one point and so should become a fill
|
// The gradient has only one point and so should become a fill
|
||||||
if selected_gradient.gradient.positions.len() == 1 {
|
if selected_gradient.gradient.positions.len() == 1 {
|
||||||
let fill = Fill::Solid(selected_gradient.gradient.positions[0].1.unwrap_or(Color::BLACK));
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
let layer = selected_gradient.layer.to_path();
|
layer: selected_gradient.layer,
|
||||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
fill: Fill::Solid(selected_gradient.gradient.positions[0].1.unwrap_or(Color::BLACK)),
|
||||||
|
});
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,7 +467,6 @@ impl Fsm for GradientToolFsmState {
|
|||||||
DVec2::ONE,
|
DVec2::ONE,
|
||||||
global_tool_data.primary_color,
|
global_tool_data.primary_color,
|
||||||
DAffine2::IDENTITY,
|
DAffine2::IDENTITY,
|
||||||
generate_uuid(),
|
|
||||||
tool_options.gradient_type,
|
tool_options.gradient_type,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -172,10 +172,6 @@ impl Fsm for ImaginateToolFsmState {
|
|||||||
state
|
state
|
||||||
}
|
}
|
||||||
(ImaginateToolFsmState::Drawing, ImaginateToolMessage::DragStop) => {
|
(ImaginateToolFsmState::Drawing, ImaginateToolMessage::DragStop) => {
|
||||||
if let Some(layer) = &shape_data.layer {
|
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer.to_path() });
|
|
||||||
}
|
|
||||||
|
|
||||||
input.mouse.finish_transaction(shape_data.viewport_drag_start(document), responses);
|
input.mouse.finish_transaction(shape_data.viewport_drag_start(document), responses);
|
||||||
shape_data.cleanup(responses);
|
shape_data.cleanup(responses);
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||||||
.unit(" px")
|
.unit(" px")
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| LineToolMessage::UpdateOptions(LineOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| LineToolMessage::UpdateOptions(LineOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,6 @@ impl Fsm for LineToolFsmState {
|
|||||||
match (self, event) {
|
match (self, event) {
|
||||||
(LineToolFsmState::Ready, LineToolMessage::DragStart) => {
|
(LineToolFsmState::Ready, LineToolMessage::DragStart) => {
|
||||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
|
|
||||||
let viewport_start = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
|
let viewport_start = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
|
||||||
tool_data.drag_start = document.metadata().document_to_viewport.inverse().transform_point2(viewport_start);
|
tool_data.drag_start = document.metadata().document_to_viewport.inverse().transform_point2(viewport_start);
|
||||||
@@ -186,7 +185,7 @@ impl Fsm for LineToolFsmState {
|
|||||||
|
|
||||||
let layer = graph_modification_utils::new_vector_layer(vec![subpath], generate_uuid(), document.new_layer_parent(), responses);
|
let layer = graph_modification_utils::new_vector_layer(vec![subpath], generate_uuid(), document.new_layer_parent(), responses);
|
||||||
responses.add(GraphOperationMessage::StrokeSet {
|
responses.add(GraphOperationMessage::StrokeSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
||||||
});
|
});
|
||||||
tool_data.layer = Some(layer);
|
tool_data.layer = Some(layer);
|
||||||
@@ -280,7 +279,7 @@ fn generate_transform(tool_data: &mut LineToolData, document_to_viewport: DAffin
|
|||||||
}
|
}
|
||||||
|
|
||||||
GraphOperationMessage::TransformSet {
|
GraphOperationMessage::TransformSet {
|
||||||
layer: tool_data.layer.unwrap().to_path(),
|
layer: tool_data.layer.unwrap(),
|
||||||
transform: glam::DAffine2::from_scale_angle_translation(DVec2::new(line_length, 1.), angle, start),
|
transform: glam::DAffine2::from_scale_angle_translation(DVec2::new(line_length, 1.), angle, start),
|
||||||
transform_in: TransformIn::Viewport,
|
transform_in: TransformIn::Viewport,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ impl LayoutHolder for PathTool {
|
|||||||
.label("X")
|
.label("X")
|
||||||
.min_width(120)
|
.min_width(120)
|
||||||
.disabled(x.is_none())
|
.disabled(x.is_none())
|
||||||
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
|
.min(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(move |number_input: &NumberInput| {
|
.on_update(move |number_input: &NumberInput| {
|
||||||
let new_x = number_input.value.unwrap_or(x.unwrap());
|
let new_x = number_input.value.unwrap_or(x.unwrap());
|
||||||
PathToolMessage::SelectedPointXChanged { new_x }.into()
|
PathToolMessage::SelectedPointXChanged { new_x }.into()
|
||||||
@@ -104,8 +104,8 @@ impl LayoutHolder for PathTool {
|
|||||||
.label("Y")
|
.label("Y")
|
||||||
.min_width(120)
|
.min_width(120)
|
||||||
.disabled(y.is_none())
|
.disabled(y.is_none())
|
||||||
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
|
.min(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64))
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(move |number_input: &NumberInput| {
|
.on_update(move |number_input: &NumberInput| {
|
||||||
let new_y = number_input.value.unwrap_or(y.unwrap());
|
let new_y = number_input.value.unwrap_or(y.unwrap());
|
||||||
PathToolMessage::SelectedPointYChanged { new_y }.into()
|
PathToolMessage::SelectedPointYChanged { new_y }.into()
|
||||||
@@ -275,9 +275,6 @@ impl PathToolData {
|
|||||||
}
|
}
|
||||||
selected_points.points.extend(additional_selected_points);
|
selected_points.points.extend(additional_selected_points);
|
||||||
|
|
||||||
//let include_handles: Vec<_> = selected_layers.iter().map(|x| x.as_slice()).collect();
|
|
||||||
//self.snap_manager.add_all_document_handles(document, input, &include_handles, &[], &selected_points.points);
|
|
||||||
|
|
||||||
self.drag_start_pos = input.mouse.position;
|
self.drag_start_pos = input.mouse.position;
|
||||||
self.previous_mouse_position = input.mouse.position - selected_points.offset;
|
self.previous_mouse_position = input.mouse.position - selected_points.offset;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||||||
.unit(" px")
|
.unit(" px")
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| PenToolMessage::UpdateOptions(PenOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ impl PenToolData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||||
id: last_handle.id,
|
id: last_handle.id,
|
||||||
mirror_angle: false,
|
mirror_angle: false,
|
||||||
@@ -259,12 +259,12 @@ impl PenToolData {
|
|||||||
self.layer = Some(layer);
|
self.layer = Some(layer);
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::FillSet {
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::StrokeSet {
|
responses.add(GraphOperationMessage::StrokeSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
stroke: Stroke::new(stroke_color, line_weight),
|
stroke: Stroke::new(stroke_color, line_weight),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -298,21 +298,21 @@ impl PenToolData {
|
|||||||
}
|
}
|
||||||
// Remove the point that has just been placed
|
// Remove the point that has just been placed
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Move the in handle of the previous anchor to on top of the previous position
|
// Move the in handle of the previous anchor to on top of the previous position
|
||||||
let point = ManipulatorPointId::new(previous_manipulator_group.id, outwards_handle);
|
let point = ManipulatorPointId::new(previous_manipulator_group.id, outwards_handle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: previous_anchor },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: previous_anchor },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stop the handles on the last point from mirroring
|
// Stop the handles on the last point from mirroring
|
||||||
let id = previous_manipulator_group.id;
|
let id = previous_manipulator_group.id;
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: false },
|
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -353,26 +353,26 @@ impl PenToolData {
|
|||||||
// Move the in handle of the first point to where the user has placed it
|
// Move the in handle of the first point to where the user has placed it
|
||||||
let point = ManipulatorPointId::new(first_manipulator_group.id, inwards_handle);
|
let point = ManipulatorPointId::new(first_manipulator_group.id, inwards_handle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: last_in },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: last_in },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stop the handles on the first point from mirroring
|
// Stop the handles on the first point from mirroring
|
||||||
let id = first_manipulator_group.id;
|
let id = first_manipulator_group.id;
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: false },
|
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove the point that has just been placed
|
// Remove the point that has just been placed
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Push a close path node
|
// Push a close path node
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetClosed { index: 0, closed: true },
|
modification: VectorDataModification::SetClosed { index: 0, closed: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ impl PenToolData {
|
|||||||
}
|
}
|
||||||
// Add a new manipulator for the next anchor that we will place
|
// Add a new manipulator for the next anchor that we will place
|
||||||
if let Some(out_handle) = outwards_handle.get_position(last_manipulator_group) {
|
if let Some(out_handle) = outwards_handle.get_position(last_manipulator_group) {
|
||||||
responses.add(add_manipulator_group(&self.layer, self.from_start, bezier_rs::ManipulatorGroup::new_anchor(out_handle)));
|
responses.add(add_manipulator_group(self.layer, self.from_start, bezier_rs::ManipulatorGroup::new_anchor(out_handle)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(PenToolFsmState::PlacingAnchor)
|
Some(PenToolFsmState::PlacingAnchor)
|
||||||
@@ -419,7 +419,7 @@ impl PenToolData {
|
|||||||
// Update points on current segment (to show preview of new handle)
|
// Update points on current segment (to show preview of new handle)
|
||||||
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: self.layer?.to_path(),
|
layer: self.layer?,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -430,7 +430,7 @@ impl PenToolData {
|
|||||||
let pos = last_anchor - (pos - last_anchor);
|
let pos = last_anchor - (pos - last_anchor);
|
||||||
let point = ManipulatorPointId::new(last_manipulator_group.id, inwards_handle);
|
let point = ManipulatorPointId::new(last_manipulator_group.id, inwards_handle);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: self.layer?.to_path(),
|
layer: self.layer?,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -438,7 +438,7 @@ impl PenToolData {
|
|||||||
// Update the mirror status of the currently modifying point
|
// Update the mirror status of the currently modifying point
|
||||||
let id = last_manipulator_group.id;
|
let id = last_manipulator_group.id;
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: self.layer?.to_path(),
|
layer: self.layer?,
|
||||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: should_mirror },
|
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: should_mirror },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -483,7 +483,7 @@ impl PenToolData {
|
|||||||
for manipulator_type in [SelectedType::Anchor, SelectedType::InHandle, SelectedType::OutHandle] {
|
for manipulator_type in [SelectedType::Anchor, SelectedType::InHandle, SelectedType::OutHandle] {
|
||||||
let point = ManipulatorPointId::new(last_manipulator_group.id, manipulator_type);
|
let point = ManipulatorPointId::new(last_manipulator_group.id, manipulator_type);
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -516,7 +516,7 @@ impl PenToolData {
|
|||||||
// Remove the unplaced anchor if in anchor placing mode
|
// Remove the unplaced anchor if in anchor placing mode
|
||||||
if fsm == PenToolFsmState::PlacingAnchor {
|
if fsm == PenToolFsmState::PlacingAnchor {
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: self.layer?.to_path(),
|
layer: self.layer?,
|
||||||
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
||||||
});
|
});
|
||||||
last_manipulator_group = previous_manipulator_group;
|
last_manipulator_group = previous_manipulator_group;
|
||||||
@@ -526,7 +526,7 @@ impl PenToolData {
|
|||||||
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
||||||
let position = last_manipulator_group.anchor;
|
let position = last_manipulator_group.anchor;
|
||||||
responses.add(GraphOperationMessage::Vector {
|
responses.add(GraphOperationMessage::Vector {
|
||||||
layer: self.layer?.to_path(),
|
layer: self.layer?,
|
||||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -591,7 +591,6 @@ impl Fsm for PenToolFsmState {
|
|||||||
|
|
||||||
// Initialize snapping
|
// Initialize snapping
|
||||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
|
|
||||||
// Disable this tool's mirroring
|
// Disable this tool's mirroring
|
||||||
tool_data.should_mirror = false;
|
tool_data.should_mirror = false;
|
||||||
@@ -703,11 +702,10 @@ fn compute_snapped_angle(cached_angle: &mut f64, lock_angle: bool, snap_angle: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes a [ManipulatorGroup] to the current layer via a [GraphOperationMessage].
|
/// Pushes a [ManipulatorGroup] to the current layer via a [GraphOperationMessage].
|
||||||
fn add_manipulator_group(layer: &Option<LayerNodeIdentifier>, from_start: bool, manipulator_group: bezier_rs::ManipulatorGroup<ManipulatorGroupId>) -> Message {
|
fn add_manipulator_group(layer: Option<LayerNodeIdentifier>, from_start: bool, manipulator_group: bezier_rs::ManipulatorGroup<ManipulatorGroupId>) -> Message {
|
||||||
let Some(layer) = layer else {
|
let Some(layer) = layer else {
|
||||||
return Message::NoOp;
|
return Message::NoOp;
|
||||||
};
|
};
|
||||||
let layer = layer.to_path();
|
|
||||||
let modification = if from_start {
|
let modification = if from_start {
|
||||||
VectorDataModification::AddStartManipulatorGroup { subpath_index: 0, manipulator_group }
|
VectorDataModification::AddStartManipulatorGroup { subpath_index: 0, manipulator_group }
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||||||
.unit(" px")
|
.unit(" px")
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| PolygonToolMessage::UpdateOptions(PolygonOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| PolygonToolMessage::UpdateOptions(PolygonOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
@@ -251,12 +251,12 @@ impl Fsm for PolygonToolFsmState {
|
|||||||
|
|
||||||
let fill_color = tool_options.fill.active_color();
|
let fill_color = tool_options.fill.active_color();
|
||||||
responses.add(GraphOperationMessage::FillSet {
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::StrokeSet {
|
responses.add(GraphOperationMessage::StrokeSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||||||
.unit(" px")
|
.unit(" px")
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| RectangleToolMessage::UpdateOptions(RectangleOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| RectangleToolMessage::UpdateOptions(RectangleOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
@@ -220,12 +220,12 @@ impl Fsm for RectangleToolFsmState {
|
|||||||
|
|
||||||
let fill_color = tool_options.fill.active_color();
|
let fill_color = tool_options.fill.active_color();
|
||||||
responses.add(GraphOperationMessage::FillSet {
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::StrokeSet {
|
responses.add(GraphOperationMessage::StrokeSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -302,10 +302,10 @@ impl SelectToolData {
|
|||||||
|
|
||||||
// Duplicate each previously selected layer and select the new ones.
|
// Duplicate each previously selected layer and select the new ones.
|
||||||
for layer_ancestors in document.metadata().shallowest_unique_layers(self.layers_dragging.iter().copied()) {
|
for layer_ancestors in document.metadata().shallowest_unique_layers(self.layers_dragging.iter().copied()) {
|
||||||
let layer = layer_ancestors.last().unwrap();
|
let layer = *layer_ancestors.last().unwrap();
|
||||||
// Moves the original back to its starting position.
|
// Moves the original back to its starting position.
|
||||||
responses.add_front(GraphOperationMessage::TransformChange {
|
responses.add_front(GraphOperationMessage::TransformChange {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
transform: DAffine2::from_translation(self.drag_start - self.drag_current),
|
transform: DAffine2::from_translation(self.drag_start - self.drag_current),
|
||||||
transform_in: TransformIn::Viewport,
|
transform_in: TransformIn::Viewport,
|
||||||
skip_rerender: true,
|
skip_rerender: true,
|
||||||
@@ -336,11 +336,6 @@ impl SelectToolData {
|
|||||||
// layer_metadata,
|
// layer_metadata,
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Since the selected layers have now moved back to their original transforms before the drag began, we rerender them to be displayed as if they weren't touched.
|
|
||||||
// for layer_path in self.not_duplicated_layers.iter().flatten() {
|
|
||||||
// responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.clone() });
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the duplicated layers. Called when Alt is released and the layers have previously been duplicated.
|
/// Removes the duplicated layers. Called when Alt is released and the layers have previously been duplicated.
|
||||||
@@ -361,7 +356,7 @@ impl SelectToolData {
|
|||||||
// Move the original to under the mouse
|
// Move the original to under the mouse
|
||||||
for layer_ancestors in document.metadata().shallowest_unique_layers(originals.iter().copied()) {
|
for layer_ancestors in document.metadata().shallowest_unique_layers(originals.iter().copied()) {
|
||||||
responses.add_front(GraphOperationMessage::TransformChange {
|
responses.add_front(GraphOperationMessage::TransformChange {
|
||||||
layer: layer_ancestors.last().unwrap().to_path(),
|
layer: *layer_ancestors.last().unwrap(),
|
||||||
transform: DAffine2::from_translation(self.drag_current - self.drag_start),
|
transform: DAffine2::from_translation(self.drag_current - self.drag_start),
|
||||||
transform_in: TransformIn::Viewport,
|
transform_in: TransformIn::Viewport,
|
||||||
skip_rerender: true,
|
skip_rerender: true,
|
||||||
@@ -482,22 +477,11 @@ impl Fsm for SelectToolFsmState {
|
|||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
|
|
||||||
SelectToolFsmState::DraggingPivot
|
SelectToolFsmState::DraggingPivot
|
||||||
} else if let Some(_selected_edges) = dragging_bounds {
|
} else if let Some(_selected_edges) = dragging_bounds {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
// let snap_x = selected_edges.2 || selected_edges.3;
|
|
||||||
// let snap_y = selected_edges.0 || selected_edges.1;
|
|
||||||
//
|
|
||||||
// tool_data
|
|
||||||
// .snap_manager
|
|
||||||
// .start_snap(document, input, document.bounding_boxes(Some(&selected), None, font_cache), snap_x, snap_y);
|
|
||||||
// tool_data
|
|
||||||
// .snap_manager
|
|
||||||
// .add_all_document_handles(document, input, &[], &selected.iter().map(|x| x.as_slice()).collect::<Vec<_>>(), &[]);
|
|
||||||
|
|
||||||
tool_data.layers_dragging = selected;
|
tool_data.layers_dragging = selected;
|
||||||
|
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
@@ -606,7 +590,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
|
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
|
||||||
for layer_ancestors in document.metadata().shallowest_unique_layers(tool_data.layers_dragging.iter().copied()) {
|
for layer_ancestors in document.metadata().shallowest_unique_layers(tool_data.layers_dragging.iter().copied()) {
|
||||||
responses.add_front(GraphOperationMessage::TransformChange {
|
responses.add_front(GraphOperationMessage::TransformChange {
|
||||||
layer: layer_ancestors.last().unwrap().to_path(),
|
layer: *layer_ancestors.last().unwrap(),
|
||||||
transform: DAffine2::from_translation(mouse_delta + closest_move),
|
transform: DAffine2::from_translation(mouse_delta + closest_move),
|
||||||
transform_in: TransformIn::Viewport,
|
transform_in: TransformIn::Viewport,
|
||||||
skip_rerender: false,
|
skip_rerender: false,
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||||||
.unit(" px")
|
.unit(" px")
|
||||||
.label("Weight")
|
.label("Weight")
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
.on_update(|number_input: &NumberInput| SplineToolMessage::UpdateOptions(SplineOptionsUpdate::LineWeight(number_input.value.unwrap())).into())
|
||||||
.widget_holder()
|
.widget_holder()
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,6 @@ impl Fsm for SplineToolFsmState {
|
|||||||
let transform = document.metadata().transform_to_viewport(parent);
|
let transform = document.metadata().transform_to_viewport(parent);
|
||||||
|
|
||||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
|
||||||
let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
|
let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
|
||||||
|
|
||||||
let pos = transform.inverse().transform_point2(snapped_position);
|
let pos = transform.inverse().transform_point2(snapped_position);
|
||||||
@@ -228,12 +227,12 @@ impl Fsm for SplineToolFsmState {
|
|||||||
let layer = graph_modification_utils::new_vector_layer(vec![], generate_uuid(), parent, responses);
|
let layer = graph_modification_utils::new_vector_layer(vec![], generate_uuid(), parent, responses);
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::FillSet {
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
fill: if let Some(color) = tool_options.fill.active_color() { Fill::Solid(color) } else { Fill::None },
|
fill: if let Some(color) = tool_options.fill.active_color() { Fill::Solid(color) } else { Fill::None },
|
||||||
});
|
});
|
||||||
|
|
||||||
responses.add(GraphOperationMessage::StrokeSet {
|
responses.add(GraphOperationMessage::StrokeSet {
|
||||||
layer: layer.to_path(),
|
layer,
|
||||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_data.weight),
|
stroke: Stroke::new(tool_options.stroke.active_color(), tool_data.weight),
|
||||||
});
|
});
|
||||||
tool_data.layer = Some(layer);
|
tool_data.layer = Some(layer);
|
||||||
@@ -329,5 +328,5 @@ fn update_spline(tool_data: &SplineToolData, show_preview: bool, responses: &mut
|
|||||||
graph_modification_utils::set_manipulator_mirror_angle(subpath.manipulator_groups(), layer, true, responses);
|
graph_modification_utils::set_manipulator_mirror_angle(subpath.manipulator_groups(), layer, true, responses);
|
||||||
let subpaths = vec![subpath];
|
let subpaths = vec![subpath];
|
||||||
let modification = VectorDataModification::UpdateSubpaths { subpaths };
|
let modification = VectorDataModification::UpdateSubpaths { subpaths };
|
||||||
responses.add_front(GraphOperationMessage::Vector { layer: layer.to_path(), modification });
|
responses.add_front(GraphOperationMessage::Vector { layer, modification });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ fn create_text_widgets(tool: &TextTool) -> Vec<WidgetHolder> {
|
|||||||
.label("Size")
|
.label("Size")
|
||||||
.int()
|
.int()
|
||||||
.min(1.)
|
.min(1.)
|
||||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||||
.on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FontSize(number_input.value.unwrap() as u32)).into())
|
.on_update(|number_input: &NumberInput| TextToolMessage::UpdateOptions(TextOptionsUpdate::FontSize(number_input.value.unwrap() as u32)).into())
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
vec![
|
vec![
|
||||||
@@ -298,11 +298,11 @@ impl TextToolData {
|
|||||||
insert_index: -1,
|
insert_index: -1,
|
||||||
});
|
});
|
||||||
responses.add(GraphOperationMessage::FillSet {
|
responses.add(GraphOperationMessage::FillSet {
|
||||||
layer: self.layer.to_path(),
|
layer: self.layer,
|
||||||
fill: if editing_text.color.is_some() { Fill::Solid(editing_text.color.unwrap()) } else { Fill::None },
|
fill: if editing_text.color.is_some() { Fill::Solid(editing_text.color.unwrap()) } else { Fill::None },
|
||||||
});
|
});
|
||||||
responses.add(GraphOperationMessage::TransformSet {
|
responses.add(GraphOperationMessage::TransformSet {
|
||||||
layer: self.layer.to_path(),
|
layer: self.layer,
|
||||||
transform: editing_text.transform,
|
transform: editing_text.transform,
|
||||||
transform_in: TransformIn::Viewport,
|
transform_in: TransformIn::Viewport,
|
||||||
skip_rerender: true,
|
skip_rerender: true,
|
||||||
@@ -310,7 +310,7 @@ impl TextToolData {
|
|||||||
|
|
||||||
self.set_editing(true, font_cache, document, responses);
|
self.set_editing(true, font_cache, document, responses);
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: self.layer.to_path() });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![self.layer.to_node()] });
|
||||||
|
|
||||||
TextToolFsmState::Editing
|
TextToolFsmState::Editing
|
||||||
} else {
|
} else {
|
||||||
@@ -331,10 +331,11 @@ impl TextToolData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fix_text_bounds(&self, new_text: &str, _document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) -> Option<()> {
|
fn fix_text_bounds(&self, new_text: &str, _document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) -> Option<()> {
|
||||||
let layer = self.layer.to_path();
|
responses.add(GraphOperationMessage::UpdateBounds {
|
||||||
let old_bounds = self.get_bounds(&self.editing_text.as_ref()?.text, font_cache)?;
|
layer: self.layer,
|
||||||
let new_bounds = self.get_bounds(new_text, font_cache)?;
|
old_bounds: self.get_bounds(&self.editing_text.as_ref()?.text, font_cache)?,
|
||||||
responses.add(GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds });
|
new_bounds: self.get_bounds(new_text, font_cache)?,
|
||||||
|
});
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
@@ -437,7 +438,6 @@ impl Fsm for TextToolFsmState {
|
|||||||
(TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => {
|
(TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => {
|
||||||
tool_data.fix_text_bounds(&new_text, document, font_cache, responses);
|
tool_data.fix_text_bounds(&new_text, document, font_cache, responses);
|
||||||
responses.add(NodeGraphMessage::SetQualifiedInputValue {
|
responses.add(NodeGraphMessage::SetQualifiedInputValue {
|
||||||
layer_path: Vec::new(),
|
|
||||||
node_path: vec![graph_modification_utils::get_text_id(tool_data.layer, &document.network).unwrap()],
|
node_path: vec![graph_modification_utils::get_text_id(tool_data.layer, &document.network).unwrap()],
|
||||||
input_index: 1,
|
input_index: 1,
|
||||||
value: TaggedValue::String(new_text),
|
value: TaggedValue::String(new_text),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use std::fmt::{self, Debug};
|
|||||||
|
|
||||||
pub struct ToolActionHandlerData<'a> {
|
pub struct ToolActionHandlerData<'a> {
|
||||||
pub document: &'a DocumentMessageHandler,
|
pub document: &'a DocumentMessageHandler,
|
||||||
pub document_id: u64,
|
pub document_id: DocumentId,
|
||||||
pub global_tool_data: &'a DocumentToolData,
|
pub global_tool_data: &'a DocumentToolData,
|
||||||
pub input: &'a InputPreprocessorMessageHandler,
|
pub input: &'a InputPreprocessorMessageHandler,
|
||||||
pub font_cache: &'a FontCache,
|
pub font_cache: &'a FontCache,
|
||||||
@@ -30,7 +30,7 @@ pub struct ToolActionHandlerData<'a> {
|
|||||||
impl<'a> ToolActionHandlerData<'a> {
|
impl<'a> ToolActionHandlerData<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
document: &'a DocumentMessageHandler,
|
document: &'a DocumentMessageHandler,
|
||||||
document_id: u64,
|
document_id: DocumentId,
|
||||||
global_tool_data: &'a DocumentToolData,
|
global_tool_data: &'a DocumentToolData,
|
||||||
input: &'a InputPreprocessorMessageHandler,
|
input: &'a InputPreprocessorMessageHandler,
|
||||||
font_cache: &'a FontCache,
|
font_cache: &'a FontCache,
|
||||||
|
|||||||
@@ -5,23 +5,22 @@ use crate::messages::portfolio::document::node_graph::wrap_network_in_scope;
|
|||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::portfolio::document::utility_types::layer_panel::LayerClassification;
|
use crate::messages::portfolio::document::utility_types::layer_panel::LayerClassification;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::LayerPanelEntry;
|
use crate::messages::portfolio::document::utility_types::misc::LayerPanelEntry;
|
||||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
|
use graph_craft::concrete;
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
||||||
use graph_craft::graphene_compiler::Compiler;
|
use graph_craft::graphene_compiler::Compiler;
|
||||||
use graph_craft::imaginate_input::ImaginatePreferences;
|
use graph_craft::imaginate_input::ImaginatePreferences;
|
||||||
use graph_craft::{concrete, Type};
|
use graphene_core::application_io::{NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||||
use graphene_core::application_io::{ApplicationIo, NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
|
||||||
use graphene_core::memo::IORecord;
|
use graphene_core::memo::IORecord;
|
||||||
use graphene_core::raster::{Image, ImageFrame};
|
use graphene_core::raster::{Image, ImageFrame};
|
||||||
use graphene_core::renderer::{ClickTarget, GraphicElementRendered, SvgSegment, SvgSegmentList};
|
use graphene_core::renderer::{ClickTarget, GraphicElementRendered, SvgSegmentList};
|
||||||
use graphene_core::text::FontCache;
|
use graphene_core::text::FontCache;
|
||||||
use graphene_core::transform::{Footprint, Transform};
|
use graphene_core::transform::{Footprint, Transform};
|
||||||
use graphene_core::vector::style::ViewMode;
|
use graphene_core::vector::style::ViewMode;
|
||||||
use graphene_core::vector::VectorData;
|
use graphene_core::vector::VectorData;
|
||||||
use graphene_core::{Color, GraphicElement, SurfaceFrame, SurfaceId};
|
use graphene_core::{Color, GraphicElement, SurfaceFrame};
|
||||||
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
||||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||||
|
|
||||||
@@ -31,22 +30,6 @@ use std::rc::Rc;
|
|||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Identifies a node graph, either the document graph or a node graph associated with a legacy layer.
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
|
|
||||||
pub enum GraphIdentifier {
|
|
||||||
DocumentGraph,
|
|
||||||
LayerGraph(LayerId),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GraphIdentifier {
|
|
||||||
pub const fn new(layer_id: Option<LayerId>) -> Self {
|
|
||||||
match layer_id {
|
|
||||||
Some(layer_id) => Self::LayerGraph(layer_id),
|
|
||||||
None => Self::DocumentGraph,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeRuntime {
|
pub struct NodeRuntime {
|
||||||
pub(crate) executor: DynamicExecutor,
|
pub(crate) executor: DynamicExecutor,
|
||||||
font_cache: FontCache,
|
font_cache: FontCache,
|
||||||
@@ -58,7 +41,6 @@ pub struct NodeRuntime {
|
|||||||
pub(crate) click_targets: HashMap<NodeId, Vec<ClickTarget>>,
|
pub(crate) click_targets: HashMap<NodeId, Vec<ClickTarget>>,
|
||||||
pub(crate) upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
|
pub(crate) upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
|
||||||
graph_hash: Option<u64>,
|
graph_hash: Option<u64>,
|
||||||
canvas_cache: HashMap<Vec<LayerId>, SurfaceId>,
|
|
||||||
monitor_nodes: Vec<Vec<NodeId>>,
|
monitor_nodes: Vec<Vec<NodeId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +63,6 @@ pub struct ExportConfig {
|
|||||||
pub(crate) struct GenerationRequest {
|
pub(crate) struct GenerationRequest {
|
||||||
generation_id: u64,
|
generation_id: u64,
|
||||||
graph: NodeNetwork,
|
graph: NodeNetwork,
|
||||||
path: Vec<LayerId>,
|
|
||||||
render_config: RenderConfig,
|
render_config: RenderConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +110,6 @@ impl NodeRuntime {
|
|||||||
imaginate_preferences: Default::default(),
|
imaginate_preferences: Default::default(),
|
||||||
thumbnails: Default::default(),
|
thumbnails: Default::default(),
|
||||||
wasm_io: None,
|
wasm_io: None,
|
||||||
canvas_cache: HashMap::new(),
|
|
||||||
click_targets: HashMap::new(),
|
click_targets: HashMap::new(),
|
||||||
graph_hash: None,
|
graph_hash: None,
|
||||||
upstream_transforms: HashMap::new(),
|
upstream_transforms: HashMap::new(),
|
||||||
@@ -142,7 +122,7 @@ impl NodeRuntime {
|
|||||||
// This should be avoided in the future.
|
// This should be avoided in the future.
|
||||||
requests.reverse();
|
requests.reverse();
|
||||||
requests.dedup_by_key(|x| match x {
|
requests.dedup_by_key(|x| match x {
|
||||||
NodeRuntimeMessage::GenerationRequest(x) => Some(x.path.clone()),
|
NodeRuntimeMessage::GenerationRequest(x) => Some(x.graph.current_hash()),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
requests.reverse();
|
requests.reverse();
|
||||||
@@ -151,17 +131,13 @@ impl NodeRuntime {
|
|||||||
NodeRuntimeMessage::FontCacheUpdate(font_cache) => self.font_cache = font_cache,
|
NodeRuntimeMessage::FontCacheUpdate(font_cache) => self.font_cache = font_cache,
|
||||||
NodeRuntimeMessage::ImaginatePreferencesUpdate(preferences) => self.imaginate_preferences = preferences,
|
NodeRuntimeMessage::ImaginatePreferencesUpdate(preferences) => self.imaginate_preferences = preferences,
|
||||||
NodeRuntimeMessage::GenerationRequest(GenerationRequest {
|
NodeRuntimeMessage::GenerationRequest(GenerationRequest {
|
||||||
generation_id,
|
generation_id, graph, render_config, ..
|
||||||
graph,
|
|
||||||
render_config,
|
|
||||||
path,
|
|
||||||
..
|
|
||||||
}) => {
|
}) => {
|
||||||
let transform = render_config.viewport.transform;
|
let transform = render_config.viewport.transform;
|
||||||
let result = self.execute_network(&path, graph, render_config).await;
|
let result = self.execute_network(graph, render_config).await;
|
||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
self.update_thumbnails(&path, &mut responses);
|
self.update_thumbnails(&mut responses);
|
||||||
self.update_upstream_transforms();
|
self.update_upstream_transforms();
|
||||||
|
|
||||||
let response = GenerationResponse {
|
let response = GenerationResponse {
|
||||||
@@ -179,7 +155,7 @@ impl NodeRuntime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute_network<'a>(&'a mut self, path: &[LayerId], graph: NodeNetwork, render_config: RenderConfig) -> Result<TaggedValue, String> {
|
async fn execute_network<'a>(&'a mut self, graph: NodeNetwork, render_config: RenderConfig) -> Result<TaggedValue, String> {
|
||||||
if self.wasm_io.is_none() {
|
if self.wasm_io.is_none() {
|
||||||
self.wasm_io = Some(WasmApplicationIo::new().await);
|
self.wasm_io = Some(WasmApplicationIo::new().await);
|
||||||
}
|
}
|
||||||
@@ -245,21 +221,21 @@ impl NodeRuntime {
|
|||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let TaggedValue::SurfaceFrame(SurfaceFrame { surface_id, transform: _ }) = result {
|
// if let TaggedValue::SurfaceFrame(SurfaceFrame { surface_id, transform: _ }) = result {
|
||||||
let old_id = self.canvas_cache.insert(path.to_vec(), surface_id);
|
// let old_id = self.canvas_cache.insert(path.to_vec(), surface_id);
|
||||||
if let Some(old_id) = old_id {
|
// if let Some(old_id) = old_id {
|
||||||
if old_id != surface_id {
|
// if old_id != surface_id {
|
||||||
if let Some(io) = self.wasm_io.as_ref() {
|
// if let Some(io) = self.wasm_io.as_ref() {
|
||||||
io.destroy_surface(old_id)
|
// io.destroy_surface(old_id)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recomputes the thumbnails for the layers in the graph, modifying the state and updating the UI.
|
/// Recomputes the thumbnails for the layers in the graph, modifying the state and updating the UI.
|
||||||
pub fn update_thumbnails(&mut self, layer_path: &[LayerId], responses: &mut VecDeque<Message>) {
|
pub fn update_thumbnails(&mut self, responses: &mut VecDeque<Message>) {
|
||||||
let mut image_data: Vec<_> = Vec::new();
|
let mut image_data: Vec<_> = Vec::new();
|
||||||
self.thumbnails.retain(|id, _| self.monitor_nodes.iter().any(|node_path| node_path.contains(id)));
|
self.thumbnails.retain(|id, _| self.monitor_nodes.iter().any(|node_path| node_path.contains(id)));
|
||||||
for node_path in &self.monitor_nodes {
|
for node_path in &self.monitor_nodes {
|
||||||
@@ -299,8 +275,7 @@ impl NodeRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let resize = Some(DVec2::splat(100.));
|
let resize = Some(DVec2::splat(100.));
|
||||||
let create_image_data = |(node_id, image)| NodeGraphExecutor::to_frontend_image_data(image, None, layer_path, Some(node_id), resize).ok();
|
image_data.extend(render.image_data.into_iter().filter_map(|(_, image)| NodeGraphExecutor::to_frontend_image_data(image, resize).ok()))
|
||||||
image_data.extend(render.image_data.into_iter().filter_map(create_image_data))
|
|
||||||
}
|
}
|
||||||
if !image_data.is_empty() {
|
if !image_data.is_empty() {
|
||||||
responses.add(FrontendMessage::UpdateImageData { document_id: 0, image_data });
|
responses.add(FrontendMessage::UpdateImageData { document_id: 0, image_data });
|
||||||
@@ -370,15 +345,11 @@ pub async fn run_node_graph() {
|
|||||||
pub struct NodeGraphExecutor {
|
pub struct NodeGraphExecutor {
|
||||||
sender: Sender<NodeRuntimeMessage>,
|
sender: Sender<NodeRuntimeMessage>,
|
||||||
receiver: Receiver<NodeGraphUpdate>,
|
receiver: Receiver<NodeGraphUpdate>,
|
||||||
// TODO: This is a memory leak since layers are never removed
|
|
||||||
pub(crate) last_output_type: HashMap<Vec<LayerId>, Option<Type>>,
|
|
||||||
pub(crate) thumbnails: HashMap<NodeId, SvgSegmentList>,
|
|
||||||
futures: HashMap<u64, ExecutionContext>,
|
futures: HashMap<u64, ExecutionContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct ExecutionContext {
|
struct ExecutionContext {
|
||||||
layer_path: Vec<LayerId>,
|
|
||||||
export_config: Option<ExportConfig>,
|
export_config: Option<ExportConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,18 +365,15 @@ impl Default for NodeGraphExecutor {
|
|||||||
futures: Default::default(),
|
futures: Default::default(),
|
||||||
sender: request_sender,
|
sender: request_sender,
|
||||||
receiver: response_receiver,
|
receiver: response_receiver,
|
||||||
last_output_type: Default::default(),
|
|
||||||
thumbnails: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeGraphExecutor {
|
impl NodeGraphExecutor {
|
||||||
/// Execute the network by flattening it and creating a borrow stack.
|
/// Execute the network by flattening it and creating a borrow stack.
|
||||||
fn queue_execution(&self, network: NodeNetwork, layer_path: Vec<LayerId>, render_config: RenderConfig) -> u64 {
|
fn queue_execution(&self, network: NodeNetwork, render_config: RenderConfig) -> u64 {
|
||||||
let generation_id = generate_uuid();
|
let generation_id = generate_uuid();
|
||||||
let request = GenerationRequest {
|
let request = GenerationRequest {
|
||||||
path: layer_path,
|
|
||||||
graph: network,
|
graph: network,
|
||||||
generation_id,
|
generation_id,
|
||||||
render_config,
|
render_config,
|
||||||
@@ -470,23 +438,17 @@ impl NodeGraphExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a new [`FrontendImageData`] from the [`Image`].
|
/// Generate a new [`FrontendImageData`] from the [`Image`].
|
||||||
fn to_frontend_image_data(image: Image<Color>, transform: Option<[f64; 6]>, layer_path: &[LayerId], node_id: Option<u64>, resize: Option<DVec2>) -> Result<FrontendImageData, String> {
|
fn to_frontend_image_data(image: Image<Color>, resize: Option<DVec2>) -> Result<FrontendImageData, String> {
|
||||||
let (image_data, _size) = Self::encode_img(image, resize, image::ImageOutputFormat::Bmp)?;
|
let (image_data, _size) = Self::encode_img(image, resize, image::ImageOutputFormat::Bmp)?;
|
||||||
|
|
||||||
let mime = "image/bmp".to_string();
|
let mime = "image/bmp".to_string();
|
||||||
let image_data = std::sync::Arc::new(image_data);
|
let image_data = std::sync::Arc::new(image_data);
|
||||||
|
|
||||||
Ok(FrontendImageData {
|
Ok(FrontendImageData { image_data, mime })
|
||||||
path: layer_path.to_vec(),
|
|
||||||
node_id,
|
|
||||||
image_data,
|
|
||||||
mime,
|
|
||||||
transform,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates a node graph, computing the entire graph
|
/// Evaluates a node graph, computing the entire graph
|
||||||
pub fn submit_node_graph_evaluation(&mut self, document: &mut DocumentMessageHandler, layer_path: Vec<LayerId>, viewport_resolution: UVec2) -> Result<(), String> {
|
pub fn submit_node_graph_evaluation(&mut self, document: &mut DocumentMessageHandler, viewport_resolution: UVec2) -> Result<(), String> {
|
||||||
// Get the node graph layer
|
// Get the node graph layer
|
||||||
let network = document.network().clone();
|
let network = document.network().clone();
|
||||||
|
|
||||||
@@ -506,9 +468,9 @@ impl NodeGraphExecutor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Execute the node graph
|
// Execute the node graph
|
||||||
let generation_id = self.queue_execution(network, layer_path.clone(), render_config);
|
let generation_id = self.queue_execution(network, render_config);
|
||||||
|
|
||||||
self.futures.insert(generation_id, ExecutionContext { layer_path, export_config: None });
|
self.futures.insert(generation_id, ExecutionContext { export_config: None });
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -541,11 +503,8 @@ impl NodeGraphExecutor {
|
|||||||
export_config.size = size;
|
export_config.size = size;
|
||||||
|
|
||||||
// Execute the node graph
|
// Execute the node graph
|
||||||
let generation_id = self.queue_execution(network, Vec::new(), render_config);
|
let generation_id = self.queue_execution(network, render_config);
|
||||||
let execution_context = ExecutionContext {
|
let execution_context = ExecutionContext { export_config: Some(export_config) };
|
||||||
layer_path: Vec::new(),
|
|
||||||
export_config: Some(export_config),
|
|
||||||
};
|
|
||||||
self.futures.insert(generation_id, execution_context);
|
self.futures.insert(generation_id, execution_context);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -626,16 +585,17 @@ impl NodeGraphExecutor {
|
|||||||
},
|
},
|
||||||
expanded: layer.has_children(document_metadata) && !collapsed.contains(&layer),
|
expanded: layer.has_children(document_metadata) && !collapsed.contains(&layer),
|
||||||
selected: document_metadata.selected_layers_contains(layer),
|
selected: document_metadata.selected_layers_contains(layer),
|
||||||
path: vec![node_id],
|
parent_id: layer.parent(document_metadata).map(|parent| parent.to_node()),
|
||||||
|
id: node_id,
|
||||||
|
depth: layer.ancestors(document_metadata).count() - 1,
|
||||||
thumbnail: svg.to_string(),
|
thumbnail: svg.to_string(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.thumbnails = new_thumbnails;
|
|
||||||
document_metadata.update_transforms(new_upstream_transforms);
|
document_metadata.update_transforms(new_upstream_transforms);
|
||||||
document_metadata.update_click_targets(new_click_targets);
|
document_metadata.update_click_targets(new_click_targets);
|
||||||
responses.extend(updates);
|
responses.extend(updates);
|
||||||
self.process_node_graph_output(node_graph_output, execution_context.layer_path.clone(), transform, responses)?;
|
self.process_node_graph_output(node_graph_output, transform, responses)?;
|
||||||
responses.add(DocumentMessage::RenderDocument);
|
responses.add(DocumentMessage::RenderDocument);
|
||||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
@@ -665,8 +625,7 @@ impl NodeGraphExecutor {
|
|||||||
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
|
responses.add(FrontendMessage::UpdateDocumentArtwork { svg });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_node_graph_output(&mut self, node_graph_output: TaggedValue, layer_path: Vec<LayerId>, transform: DAffine2, responses: &mut VecDeque<Message>) -> Result<(), String> {
|
fn process_node_graph_output(&mut self, node_graph_output: TaggedValue, transform: DAffine2, responses: &mut VecDeque<Message>) -> Result<(), String> {
|
||||||
self.last_output_type.insert(layer_path.clone(), Some(node_graph_output.ty()));
|
|
||||||
match node_graph_output {
|
match node_graph_output {
|
||||||
TaggedValue::SurfaceFrame(SurfaceFrame { surface_id: _, transform: _ }) => {
|
TaggedValue::SurfaceFrame(SurfaceFrame { surface_id: _, transform: _ }) => {
|
||||||
// TODO: Reimplement this now that document-legacy is gone
|
// TODO: Reimplement this now that document-legacy is gone
|
||||||
@@ -709,19 +668,4 @@ impl NodeGraphExecutor {
|
|||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When a blob url for a thumbnail is loaded, update the state and the UI.
|
|
||||||
pub fn insert_thumbnail_blob_url(&mut self, blob_url: String, node_id: NodeId, responses: &mut VecDeque<Message>) {
|
|
||||||
for segment_list in self.thumbnails.values_mut() {
|
|
||||||
if let Some(segment) = segment_list.iter_mut().find(|segment| **segment == SvgSegment::BlobUrl(node_id)) {
|
|
||||||
*segment = SvgSegment::String(blob_url);
|
|
||||||
responses.add(FrontendMessage::UpdateNodeThumbnail {
|
|
||||||
id: node_id,
|
|
||||||
value: segment_list.to_string(),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
warn!("Received blob url for invalid segment")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,36 +4,35 @@ use graphite_editor::application::Editor;
|
|||||||
use graphite_editor::messages::frontend::utility_types::FrontendImageData;
|
use graphite_editor::messages::frontend::utility_types::FrontendImageData;
|
||||||
use graphite_editor::messages::prelude::*;
|
use graphite_editor::messages::prelude::*;
|
||||||
|
|
||||||
use axum::body::StreamBody;
|
// use axum::body::StreamBody;
|
||||||
use axum::extract::Path;
|
// use axum::extract::Path;
|
||||||
use axum::http;
|
// use axum::http;
|
||||||
use axum::response::IntoResponse;
|
// use axum::response::IntoResponse;
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use fern::colors::{Color, ColoredLevelConfig};
|
use fern::colors::{Color, ColoredLevelConfig};
|
||||||
use http::{Response, StatusCode};
|
// use http::{Response, StatusCode};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
// use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::Mutex;
|
// use std::sync::Mutex;
|
||||||
|
|
||||||
static IMAGES: Mutex<Option<HashMap<String, FrontendImageData>>> = Mutex::new(None);
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static EDITOR: RefCell<Option<Editor>> = RefCell::new(None);
|
static EDITOR: RefCell<Option<Editor>> = RefCell::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn respond_to(id: Path<String>) -> impl IntoResponse {
|
// async fn respond_to(id: Path<String>) -> impl IntoResponse {
|
||||||
let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
|
// let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
|
||||||
|
|
||||||
let guard = IMAGES.lock().unwrap();
|
// let guard = IMAGES.lock().unwrap();
|
||||||
let images = guard;
|
// let images = guard;
|
||||||
let image = images.as_ref().unwrap().get(&id.0).unwrap();
|
// let image = images.as_ref().unwrap().get(&id.0).unwrap();
|
||||||
|
|
||||||
println!("image: {:#?}", image.path);
|
// println!("image: {:#?}", image.path);
|
||||||
let result: Result<Vec<u8>, &str> = Ok((*image.image_data).clone());
|
// let result: Result<Vec<u8>, &str> = Ok((*image.image_data).clone());
|
||||||
let stream = futures::stream::once(async move { result });
|
// let stream = futures::stream::once(async move { result });
|
||||||
builder.body(StreamBody::new(stream)).unwrap()
|
// builder.body(StreamBody::new(stream)).unwrap()
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@@ -56,10 +55,10 @@ async fn main() {
|
|||||||
.apply()
|
.apply()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
*(IMAGES.lock().unwrap()) = Some(HashMap::new());
|
// *(IMAGES.lock().unwrap()) = Some(HashMap::new());
|
||||||
graphite_editor::application::set_uuid_seed(0);
|
graphite_editor::application::set_uuid_seed(0);
|
||||||
EDITOR.with(|editor| editor.borrow_mut().replace(Editor::new()));
|
EDITOR.with(|editor| editor.borrow_mut().replace(Editor::new()));
|
||||||
let app = Router::new().route("/", get(|| async { "Hello, World!" })).route("/image/:id", get(respond_to));
|
let app = Router::new().route("/", get(|| async { "Hello, World!" }))/*.route("/image/:id", get(respond_to))*/;
|
||||||
|
|
||||||
// run it with hyper on localhost:3000
|
// run it with hyper on localhost:3000
|
||||||
tauri::async_runtime::spawn(async {
|
tauri::async_runtime::spawn(async {
|
||||||
@@ -78,8 +77,7 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn set_random_seed(seed: f64) {
|
fn set_random_seed(seed: f64) {
|
||||||
let seed = seed as u64;
|
graphite_editor::application::set_uuid_seed(seed as u64);
|
||||||
graphite_editor::application::set_uuid_seed(seed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -96,20 +94,11 @@ fn handle_message(message: String) -> String {
|
|||||||
fn send_frontend_message_to_js(message: FrontendMessage) -> FrontendMessage {
|
fn send_frontend_message_to_js(message: FrontendMessage) -> FrontendMessage {
|
||||||
// Special case for update image data to avoid serialization times.
|
// Special case for update image data to avoid serialization times.
|
||||||
if let FrontendMessage::UpdateImageData { document_id, image_data } = message {
|
if let FrontendMessage::UpdateImageData { document_id, image_data } = message {
|
||||||
let mut guard = IMAGES.lock().unwrap();
|
|
||||||
let images = (*guard).as_mut().unwrap();
|
|
||||||
let mut stub_data = Vec::with_capacity(image_data.len());
|
let mut stub_data = Vec::with_capacity(image_data.len());
|
||||||
for image in image_data {
|
for image in image_data {
|
||||||
let path = image.path.clone();
|
|
||||||
let mime = image.mime.clone();
|
|
||||||
let transform = image.transform;
|
|
||||||
images.insert(format!("{:?}_{}", image.path, document_id), image);
|
|
||||||
stub_data.push(FrontendImageData {
|
stub_data.push(FrontendImageData {
|
||||||
path,
|
mime: image.mime.clone(),
|
||||||
node_id: None,
|
|
||||||
mime,
|
|
||||||
image_data: Arc::new(Vec::new()),
|
image_data: Arc::new(Vec::new()),
|
||||||
transform,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
FrontendMessage::UpdateImageData { document_id, image_data: stub_data }
|
FrontendMessage::UpdateImageData { document_id, image_data: stub_data }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import { beginDraggingElement } from "@graphite/io-managers/drag";
|
import { beginDraggingElement } from "@graphite/io-managers/drag";
|
||||||
import { platformIsMac } from "@graphite/utility-functions/platform";
|
import { platformIsMac } from "@graphite/utility-functions/platform";
|
||||||
import type { Editor } from "@graphite/wasm-communication/editor";
|
import type { Editor } from "@graphite/wasm-communication/editor";
|
||||||
import { defaultWidgetLayout, patchWidgetLayout, UpdateDocumentLayerDetails, UpdateDocumentLayerTreeStructureJs, UpdateLayersPanelOptionsLayout } from "@graphite/wasm-communication/messages";
|
import { defaultWidgetLayout, patchWidgetLayout, UpdateDocumentLayerDetails, UpdateDocumentLayerStructureJs, UpdateLayersPanelOptionsLayout } from "@graphite/wasm-communication/messages";
|
||||||
import type { LayerClassification, LayerPanelEntry } from "@graphite/wasm-communication/messages";
|
import type { LayerClassification, LayerPanelEntry } from "@graphite/wasm-communication/messages";
|
||||||
|
|
||||||
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||||
@@ -27,8 +27,9 @@
|
|||||||
|
|
||||||
type DraggingData = {
|
type DraggingData = {
|
||||||
select?: () => void;
|
select?: () => void;
|
||||||
insertFolder: BigUint64Array;
|
insertParentId: bigint | undefined;
|
||||||
insertIndex: number;
|
insertDepth: number;
|
||||||
|
insertIndex: number | undefined;
|
||||||
highlightFolder: boolean;
|
highlightFolder: boolean;
|
||||||
markerHeight: number;
|
markerHeight: number;
|
||||||
};
|
};
|
||||||
@@ -42,7 +43,7 @@
|
|||||||
// Interactive dragging
|
// Interactive dragging
|
||||||
let draggable = true;
|
let draggable = true;
|
||||||
let draggingData: undefined | DraggingData = undefined;
|
let draggingData: undefined | DraggingData = undefined;
|
||||||
let fakeHighlight: undefined | BigUint64Array[] = undefined;
|
let fakeHighlight: undefined | bigint = undefined;
|
||||||
let dragInPanel = false;
|
let dragInPanel = false;
|
||||||
|
|
||||||
// Layouts
|
// Layouts
|
||||||
@@ -54,24 +55,24 @@
|
|||||||
layersPanelOptionsLayout = layersPanelOptionsLayout;
|
layersPanelOptionsLayout = layersPanelOptionsLayout;
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerTreeStructureJs, (updateDocumentLayerTreeStructure) => {
|
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerStructureJs, (updateDocumentLayerStructure) => {
|
||||||
rebuildLayerTree(updateDocumentLayerTreeStructure);
|
rebuildLayerHierarchy(updateDocumentLayerStructure);
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
|
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
|
||||||
const targetLayer = updateDocumentLayerDetails.data;
|
const targetLayer = updateDocumentLayerDetails.data;
|
||||||
const targetPath = targetLayer.path;
|
const targetId = targetLayer.id;
|
||||||
|
|
||||||
updateLayerInTree(targetPath, targetLayer);
|
updateLayerInTree(targetId, targetLayer);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleLayerVisibility(path: BigUint64Array) {
|
function toggleLayerVisibility(id: bigint) {
|
||||||
editor.instance.toggleLayerVisibility(path);
|
editor.instance.toggleLayerVisibility(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleExpandArrowClick(path: BigUint64Array) {
|
function handleExpandArrowClick(id: bigint) {
|
||||||
editor.instance.toggleLayerExpansion(path);
|
editor.instance.toggleLayerExpansion(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onEditLayerName(listing: LayerListingInfo) {
|
async function onEditLayerName(listing: LayerListingInfo) {
|
||||||
@@ -97,7 +98,7 @@
|
|||||||
layers = layers;
|
layers = layers;
|
||||||
|
|
||||||
const name = (e.target instanceof HTMLInputElement && e.target.value) || "";
|
const name = (e.target instanceof HTMLInputElement && e.target.value) || "";
|
||||||
editor.instance.setLayerName(listing.entry.path, name);
|
editor.instance.setLayerName(listing.entry.id, name);
|
||||||
listing.entry.name = name;
|
listing.entry.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,16 +121,16 @@
|
|||||||
const [accel, oppositeAccel] = platformIsMac() ? [meta, ctrl] : [ctrl, meta];
|
const [accel, oppositeAccel] = platformIsMac() ? [meta, ctrl] : [ctrl, meta];
|
||||||
|
|
||||||
// Select the layer only if the accel and/or shift keys are pressed
|
// Select the layer only if the accel and/or shift keys are pressed
|
||||||
if (!oppositeAccel && !alt) selectLayer(accel, shift, listing);
|
if (!oppositeAccel && !alt) selectLayer(listing, accel, shift);
|
||||||
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLayer(accel: boolean, shift: boolean, listing: LayerListingInfo) {
|
function selectLayer(listing: LayerListingInfo, accel: boolean, shift: boolean) {
|
||||||
// Don't select while we are entering text to rename the layer
|
// Don't select while we are entering text to rename the layer
|
||||||
if (listing.editingName) return;
|
if (listing.editingName) return;
|
||||||
|
|
||||||
editor.instance.selectLayer(listing.entry.path, accel, shift);
|
editor.instance.selectLayer(listing.entry.id, accel, shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deselectAllLayers() {
|
async function deselectAllLayers() {
|
||||||
@@ -148,10 +149,11 @@
|
|||||||
let closest = Infinity;
|
let closest = Infinity;
|
||||||
|
|
||||||
// Folder to insert into
|
// Folder to insert into
|
||||||
let insertFolder = new BigUint64Array();
|
let insertParentId: bigint | undefined = undefined;
|
||||||
|
let insertDepth = 0;
|
||||||
|
|
||||||
// Insert index
|
// Insert index (starts at the end, essentially infinity)
|
||||||
let insertIndex = -1;
|
let insertIndex = undefined;
|
||||||
|
|
||||||
// Whether you are inserting into a folder and should show the folder outline
|
// Whether you are inserting into a folder and should show the folder outline
|
||||||
let highlightFolder = false;
|
let highlightFolder = false;
|
||||||
@@ -171,7 +173,8 @@
|
|||||||
|
|
||||||
// Inserting above current row
|
// Inserting above current row
|
||||||
if (distance > 0 && distance < closest) {
|
if (distance > 0 && distance < closest) {
|
||||||
insertFolder = layer.path.slice(0, layer.path.length - 1);
|
insertParentId = layer.parentId;
|
||||||
|
insertDepth = layer.depth - 1;
|
||||||
insertIndex = folderIndex;
|
insertIndex = folderIndex;
|
||||||
highlightFolder = false;
|
highlightFolder = false;
|
||||||
closest = distance;
|
closest = distance;
|
||||||
@@ -179,15 +182,24 @@
|
|||||||
}
|
}
|
||||||
// Inserting below current row
|
// Inserting below current row
|
||||||
else if (distance > -closest && distance > -RANGE_TO_INSERT_WITHIN_BOTTOM_FOLDER_NOT_ROOT && distance < 0) {
|
else if (distance > -closest && distance > -RANGE_TO_INSERT_WITHIN_BOTTOM_FOLDER_NOT_ROOT && distance < 0) {
|
||||||
insertFolder = isNestingLayer(layer.layerClassification) ? layer.path : layer.path.slice(0, layer.path.length - 1);
|
if (isNestingLayer(layer.layerClassification)) {
|
||||||
insertIndex = isNestingLayer(layer.layerClassification) ? 0 : folderIndex + 1;
|
insertParentId = layer.id;
|
||||||
highlightFolder = isNestingLayer(layer.layerClassification);
|
insertDepth = layer.depth;
|
||||||
|
insertIndex = 0;
|
||||||
|
highlightFolder = true;
|
||||||
|
} else {
|
||||||
|
insertParentId = layer.parentId;
|
||||||
|
insertDepth = layer.depth - 1;
|
||||||
|
insertIndex = folderIndex + 1;
|
||||||
|
highlightFolder = false;
|
||||||
|
}
|
||||||
|
|
||||||
closest = -distance;
|
closest = -distance;
|
||||||
markerHeight = index === treeChildren.length - 1 ? rect.bottom - INSERT_MARK_OFFSET : rect.bottom;
|
markerHeight = index === treeChildren.length - 1 ? rect.bottom - INSERT_MARK_OFFSET : rect.bottom;
|
||||||
}
|
}
|
||||||
// Inserting with no nesting at the end of the panel
|
// Inserting with no nesting at the end of the panel
|
||||||
else if (closest === Infinity) {
|
else if (closest === Infinity) {
|
||||||
if (layer.path.length === 1) insertIndex = folderIndex + 1;
|
if (layer.parentId === undefined) insertIndex = folderIndex + 1;
|
||||||
|
|
||||||
markerHeight = rect.bottom - INSERT_MARK_OFFSET;
|
markerHeight = rect.bottom - INSERT_MARK_OFFSET;
|
||||||
}
|
}
|
||||||
@@ -199,7 +211,8 @@
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
select,
|
select,
|
||||||
insertFolder,
|
insertParentId,
|
||||||
|
insertDepth,
|
||||||
insertIndex,
|
insertIndex,
|
||||||
highlightFolder,
|
highlightFolder,
|
||||||
markerHeight,
|
markerHeight,
|
||||||
@@ -210,10 +223,10 @@
|
|||||||
const layer = listing.entry;
|
const layer = listing.entry;
|
||||||
dragInPanel = true;
|
dragInPanel = true;
|
||||||
if (!layer.selected) {
|
if (!layer.selected) {
|
||||||
fakeHighlight = [layer.path];
|
fakeHighlight = layer.id;
|
||||||
}
|
}
|
||||||
const select = () => {
|
const select = () => {
|
||||||
if (!layer.selected) selectLayer(false, false, listing);
|
if (!layer.selected) selectLayer(listing, false, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const target = (event.target instanceof HTMLElement && event.target) || undefined;
|
const target = (event.target instanceof HTMLElement && event.target) || undefined;
|
||||||
@@ -240,58 +253,49 @@
|
|||||||
|
|
||||||
async function drop() {
|
async function drop() {
|
||||||
if (draggingData && dragInPanel) {
|
if (draggingData && dragInPanel) {
|
||||||
const { select, insertFolder, insertIndex } = draggingData;
|
const { select, insertParentId, insertIndex } = draggingData;
|
||||||
|
|
||||||
select?.();
|
select?.();
|
||||||
editor.instance.moveLayerInTree(insertFolder, insertIndex);
|
editor.instance.moveLayerInTree(insertParentId, insertIndex);
|
||||||
}
|
}
|
||||||
draggingData = undefined;
|
draggingData = undefined;
|
||||||
fakeHighlight = undefined;
|
fakeHighlight = undefined;
|
||||||
dragInPanel = false;
|
dragInPanel = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rebuildLayerTree(updateDocumentLayerTreeStructure: UpdateDocumentLayerTreeStructureJs) {
|
function rebuildLayerHierarchy(updateDocumentLayerStructure: UpdateDocumentLayerStructureJs) {
|
||||||
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
|
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
|
||||||
const layerPathWithNameBeingEdited = layerWithNameBeingEdited?.entry.path;
|
const layerIdWithNameBeingEdited = layerWithNameBeingEdited?.entry.id;
|
||||||
const layerIdWithNameBeingEdited = layerPathWithNameBeingEdited?.slice(-1)[0];
|
|
||||||
const path: bigint[] = [];
|
|
||||||
|
|
||||||
// Clear the layer tree before rebuilding it
|
// Clear the layer hierarchy before rebuilding it
|
||||||
layers = [];
|
layers = [];
|
||||||
|
|
||||||
// Build the new layer tree
|
// Build the new layer hierarchy
|
||||||
const recurse = (folder: UpdateDocumentLayerTreeStructureJs) => {
|
const recurse = (folder: UpdateDocumentLayerStructureJs) => {
|
||||||
folder.children.forEach((item, index) => {
|
folder.children.forEach((item, index) => {
|
||||||
// TODO: fix toString
|
const mapping = layerCache.get(String(item.layerId));
|
||||||
const layerId = BigInt(item.layerId.toString());
|
|
||||||
path.push(layerId);
|
|
||||||
|
|
||||||
const mapping = layerCache.get([path[path.length - 1]].toString());
|
|
||||||
if (mapping) {
|
if (mapping) {
|
||||||
mapping.path = new BigUint64Array(path);
|
mapping.id = item.layerId;
|
||||||
layers.push({
|
layers.push({
|
||||||
folderIndex: index,
|
folderIndex: index,
|
||||||
bottomLayer: index === folder.children.length - 1,
|
bottomLayer: index === folder.children.length - 1,
|
||||||
entry: mapping,
|
entry: mapping,
|
||||||
editingName: layerIdWithNameBeingEdited === layerId,
|
editingName: layerIdWithNameBeingEdited === item.layerId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call self recursively if there are any children
|
// Call self recursively if there are any children
|
||||||
if (item.children.length >= 1) recurse(item);
|
if (item.children.length >= 1) recurse(item);
|
||||||
|
|
||||||
path.pop();
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
recurse(updateDocumentLayerTreeStructure);
|
recurse(updateDocumentLayerStructure);
|
||||||
layers = layers;
|
layers = layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLayerInTree(targetPath: BigUint64Array, targetLayer: LayerPanelEntry) {
|
function updateLayerInTree(targetId: bigint, targetLayer: LayerPanelEntry) {
|
||||||
const path = targetPath.toString();
|
layerCache.set(String(targetId), targetLayer);
|
||||||
layerCache.set(path, targetLayer);
|
|
||||||
|
|
||||||
const layer = layers.find((layer: LayerListingInfo) => layer.entry.path.toString() === path);
|
const layer = layers.find((layer: LayerListingInfo) => layer.entry.id === targetId);
|
||||||
if (layer) {
|
if (layer) {
|
||||||
layer.entry = targetLayer;
|
layer.entry = targetLayer;
|
||||||
layers = layers;
|
layers = layers;
|
||||||
@@ -305,15 +309,15 @@
|
|||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
<LayoutRow class="list-area" scrollableY={true}>
|
<LayoutRow class="list-area" scrollableY={true}>
|
||||||
<LayoutCol class="list" bind:this={list} on:click={() => deselectAllLayers()} on:dragover={(e) => draggable && updateInsertLine(e)} on:dragend={() => draggable && drop()}>
|
<LayoutCol class="list" bind:this={list} on:click={() => deselectAllLayers()} on:dragover={(e) => draggable && updateInsertLine(e)} on:dragend={() => draggable && drop()}>
|
||||||
{#each layers as listing, index (String(listing.entry.path.slice(-1)))}
|
{#each layers as listing, index (String(listing.entry.id))}
|
||||||
<LayoutRow
|
<LayoutRow
|
||||||
class="layer"
|
class="layer"
|
||||||
classes={{
|
classes={{
|
||||||
selected: fakeHighlight ? fakeHighlight.includes(listing.entry.path) : listing.entry.selected,
|
selected: fakeHighlight !== undefined ? fakeHighlight === listing.entry.id : listing.entry.selected,
|
||||||
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertFolder === listing.entry.path,
|
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertParentId === listing.entry.id,
|
||||||
}}
|
}}
|
||||||
styles={{ "--layer-indent-levels": `${listing.entry.path.length - 1}` }}
|
styles={{ "--layer-indent-levels": `${listing.entry.depth - 1}` }}
|
||||||
data-layer={String(listing.entry.path)}
|
data-layer
|
||||||
data-index={index}
|
data-index={index}
|
||||||
tooltip={listing.entry.tooltip}
|
tooltip={listing.entry.tooltip}
|
||||||
{draggable}
|
{draggable}
|
||||||
@@ -321,7 +325,7 @@
|
|||||||
on:click={(e) => selectLayerWithModifiers(e, listing)}
|
on:click={(e) => selectLayerWithModifiers(e, listing)}
|
||||||
>
|
>
|
||||||
{#if isNestingLayer(listing.entry.layerClassification)}
|
{#if isNestingLayer(listing.entry.layerClassification)}
|
||||||
<button class="expand-arrow" class:expanded={listing.entry.expanded} on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.path)} tabindex="0" />
|
<button class="expand-arrow" class:expanded={listing.entry.expanded} on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.id)} tabindex="0" />
|
||||||
{#if listing.entry.layerClassification === "Artboard"}
|
{#if listing.entry.layerClassification === "Artboard"}
|
||||||
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
||||||
{:else if listing.entry.layerClassification === "Folder"}
|
{:else if listing.entry.layerClassification === "Folder"}
|
||||||
@@ -347,7 +351,7 @@
|
|||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
<IconButton
|
<IconButton
|
||||||
class={"visibility"}
|
class={"visibility"}
|
||||||
action={(e) => (toggleLayerVisibility(listing.entry.path), e?.stopPropagation())}
|
action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())}
|
||||||
size={24}
|
size={24}
|
||||||
icon={(() => true)() ? "EyeVisible" : "EyeHidden"}
|
icon={(() => true)() ? "EyeVisible" : "EyeHidden"}
|
||||||
tooltip={(() => true)() ? "Visible" : "Hidden"}
|
tooltip={(() => true)() ? "Visible" : "Hidden"}
|
||||||
@@ -356,7 +360,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
{#if draggingData && !draggingData.highlightFolder && dragInPanel}
|
{#if draggingData && !draggingData.highlightFolder && dragInPanel}
|
||||||
<div class="insert-mark" style:left={`${4 + draggingData.insertFolder.length * 16}px`} style:top={`${draggingData.markerHeight}px`} />
|
<div class="insert-mark" style:left={`${4 + draggingData.insertDepth * 16}px`} style:top={`${draggingData.markerHeight}px`} />
|
||||||
{/if}
|
{/if}
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
@@ -387,7 +391,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layer tree
|
// Layer hierarchy
|
||||||
.list-area {
|
.list-area {
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -116,8 +116,8 @@
|
|||||||
const from = connectorToNodeIndex(linkInProgressFromConnector);
|
const from = connectorToNodeIndex(linkInProgressFromConnector);
|
||||||
const to = linkInProgressToConnector instanceof SVGSVGElement ? connectorToNodeIndex(linkInProgressToConnector) : undefined;
|
const to = linkInProgressToConnector instanceof SVGSVGElement ? connectorToNodeIndex(linkInProgressToConnector) : undefined;
|
||||||
|
|
||||||
const linkStart = $nodeGraph.nodes.find((node) => node.id === from?.nodeId)?.isLayer;
|
const linkStart = $nodeGraph.nodes.find((node) => node.id === from?.nodeId)?.isLayer || false;
|
||||||
const linkEnd = $nodeGraph.nodes.find((node) => node.id === to?.nodeId)?.isLayer && to?.index !== 0;
|
const linkEnd = ($nodeGraph.nodes.find((node) => node.id === to?.nodeId)?.isLayer && to?.index !== 0) || false;
|
||||||
return createWirePath(linkInProgressFromConnector, linkInProgressToConnector, linkStart, linkEnd);
|
return createWirePath(linkInProgressFromConnector, linkInProgressToConnector, linkStart, linkEnd);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -158,8 +158,8 @@
|
|||||||
const { nodeInput, nodeOutput } = resolveLink(link);
|
const { nodeInput, nodeOutput } = resolveLink(link);
|
||||||
if (!nodeInput || !nodeOutput) return [];
|
if (!nodeInput || !nodeOutput) return [];
|
||||||
if (disconnecting?.linkIndex === index) return [];
|
if (disconnecting?.linkIndex === index) return [];
|
||||||
const linkStart = $nodeGraph.nodes.find((node) => node.id === link.linkStart)?.isLayer;
|
const linkStart = $nodeGraph.nodes.find((node) => node.id === link.linkStart)?.isLayer || false;
|
||||||
const linkEnd = $nodeGraph.nodes.find((node) => node.id === link.linkEnd)?.isLayer && link.linkEndInputIndex !== 0n;
|
const linkEnd = ($nodeGraph.nodes.find((node) => node.id === link.linkEnd)?.isLayer && link.linkEndInputIndex !== 0n) || false;
|
||||||
|
|
||||||
return [createWirePath(nodeOutput, nodeInput.getBoundingClientRect(), linkStart, linkEnd)];
|
return [createWirePath(nodeOutput, nodeInput.getBoundingClientRect(), linkStart, linkEnd)];
|
||||||
});
|
});
|
||||||
@@ -673,7 +673,7 @@
|
|||||||
<div class="layers-and-nodes" style:transform={`scale(${transform.scale}) translate(${transform.x}px, ${transform.y}px)`} style:transform-origin={`0 0`} bind:this={nodesContainer}>
|
<div class="layers-and-nodes" style:transform={`scale(${transform.scale}) translate(${transform.x}px, ${transform.y}px)`} style:transform-origin={`0 0`} bind:this={nodesContainer}>
|
||||||
<!-- Layers -->
|
<!-- Layers -->
|
||||||
{#each $nodeGraph.nodes.flatMap((node, nodeIndex) => (node.isLayer ? [{ node, nodeIndex }] : [])) as { node, nodeIndex } (nodeIndex)}
|
{#each $nodeGraph.nodes.flatMap((node, nodeIndex) => (node.isLayer ? [{ node, nodeIndex }] : [])) as { node, nodeIndex } (nodeIndex)}
|
||||||
{@const clipPathId = `${Math.random()}`.substring(2)}
|
{@const clipPathId = String(Math.random()).substring(2)}
|
||||||
{@const stackDatainput = node.exposedInputs[0]}
|
{@const stackDatainput = node.exposedInputs[0]}
|
||||||
<div
|
<div
|
||||||
class="layer"
|
class="layer"
|
||||||
@@ -756,7 +756,7 @@
|
|||||||
<!-- Nodes -->
|
<!-- Nodes -->
|
||||||
{#each $nodeGraph.nodes.flatMap((node, nodeIndex) => (node.isLayer ? [] : [{ node, nodeIndex }])) as { node, nodeIndex } (nodeIndex)}
|
{#each $nodeGraph.nodes.flatMap((node, nodeIndex) => (node.isLayer ? [] : [{ node, nodeIndex }])) as { node, nodeIndex } (nodeIndex)}
|
||||||
{@const exposedInputsOutputs = [...node.exposedInputs, ...node.exposedOutputs]}
|
{@const exposedInputsOutputs = [...node.exposedInputs, ...node.exposedOutputs]}
|
||||||
{@const clipPathId = `${Math.random()}`.substring(2)}
|
{@const clipPathId = String(Math.random()).substring(2)}
|
||||||
<div
|
<div
|
||||||
class="node"
|
class="node"
|
||||||
class:selected={selected.includes(node.id)}
|
class:selected={selected.includes(node.id)}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
let inputElement: HTMLInputElement | undefined;
|
let inputElement: HTMLInputElement | undefined;
|
||||||
|
|
||||||
let id = `${Math.random()}`.substring(2);
|
let id = String(Math.random()).substring(2);
|
||||||
|
|
||||||
$: displayIcon = (!checked && icon === "Checkmark" ? "Empty12px" : icon) as IconName;
|
$: displayIcon = (!checked && icon === "Checkmark" ? "Empty12px" : icon) as IconName;
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
export let hideContextMenu = false;
|
export let hideContextMenu = false;
|
||||||
|
|
||||||
let inputOrTextarea: HTMLInputElement | HTMLTextAreaElement | undefined;
|
let inputOrTextarea: HTMLInputElement | HTMLTextAreaElement | undefined;
|
||||||
let id = `${Math.random()}`.substring(2);
|
let id = String(Math.random()).substring(2);
|
||||||
let macKeyboardLayout = platformIsMac();
|
let macKeyboardLayout = platformIsMac();
|
||||||
|
|
||||||
$: inputValue = value;
|
$: inputValue = value;
|
||||||
|
|||||||
@@ -176,7 +176,7 @@
|
|||||||
|
|
||||||
function onTextFocused() {
|
function onTextFocused() {
|
||||||
if (value === undefined) text = "";
|
if (value === undefined) text = "";
|
||||||
else if (unitIsHiddenWhenEditing) text = `${value}`;
|
else if (unitIsHiddenWhenEditing) text = String(value);
|
||||||
else text = `${value}${unPluralize(unit, value)}`;
|
else text = `${value}${unPluralize(unit, value)}`;
|
||||||
|
|
||||||
editing = true;
|
editing = true;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function createLocalizationManager(editor: Editor) {
|
|||||||
const dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
const dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
||||||
const timeString = `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
const timeString = `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
||||||
const timezoneNameString = timezoneName?.value;
|
const timezoneNameString = timezoneName?.value;
|
||||||
return { timestamp: `${dateString} ${timeString} ${timezoneNameString}`, year: `${date.getFullYear()}` };
|
return { timestamp: `${dateString} ${timeString} ${timezoneNameString}`, year: String(date.getFullYear()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to process backend event
|
// Subscribe to process backend event
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export function panicProxy<T extends object>(module: T): T {
|
|||||||
result = targetValue.apply(this, args);
|
result = targetValue.apply(this, args);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Suppress `unreachable` WebAssembly.RuntimeError exceptions
|
// Suppress `unreachable` WebAssembly.RuntimeError exceptions
|
||||||
if (!`${err}`.startsWith("RuntimeError: unreachable")) throw err;
|
if (!String(err).startsWith("RuntimeError: unreachable")) throw err;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,35 +10,6 @@ export type Editor = Readonly<ReturnType<typeof createEditor>>;
|
|||||||
// `wasmImport` starts uninitialized because its initialization needs to occur asynchronously, and thus needs to occur by manually calling and awaiting `initWasm()`
|
// `wasmImport` starts uninitialized because its initialization needs to occur asynchronously, and thus needs to occur by manually calling and awaiting `initWasm()`
|
||||||
let wasmImport: WebAssembly.Memory | undefined;
|
let wasmImport: WebAssembly.Memory | undefined;
|
||||||
|
|
||||||
export async function updateImage(path: BigUint64Array, nodeId: bigint, mime: string, imageData: Uint8Array, _transform: Float64Array, _documentId: bigint) {
|
|
||||||
const blob = new Blob([imageData], { type: mime });
|
|
||||||
|
|
||||||
const blobURL = URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
// Pre-decode the image so it is ready to be drawn instantly once it's placed into the viewport SVG
|
|
||||||
const image = new Image();
|
|
||||||
image.src = blobURL;
|
|
||||||
await image.decode();
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
// (window as any).editorInstance?.setImageBlobURL(documentId, path, nodeId, blobURL, image.naturalWidth, image.naturalHeight, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchImage(_path: BigUint64Array, _nodeId: bigint, _mime: string, _documentId: bigint, url: string) {
|
|
||||||
const data = await fetch(url);
|
|
||||||
const blob = await data.blob();
|
|
||||||
|
|
||||||
const blobURL = URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
// Pre-decode the image so it is ready to be drawn instantly once it's placed into the viewport SVG
|
|
||||||
const image = new Image();
|
|
||||||
image.src = blobURL;
|
|
||||||
await image.decode();
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
// (window as any).editorInstance?.setImageBlobURL(documentId, path, nodeId, blobURL, image.naturalWidth, image.naturalHeight, undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
const tauri = "__TAURI_METADATA__" in window && import("@tauri-apps/api");
|
const tauri = "__TAURI_METADATA__" in window && import("@tauri-apps/api");
|
||||||
export async function dispatchTauri(message: unknown) {
|
export async function dispatchTauri(message: unknown) {
|
||||||
if (!tauri) return;
|
if (!tauri) return;
|
||||||
|
|||||||
@@ -560,10 +560,10 @@ export class TriggerSavePreferences extends JsMessage {
|
|||||||
|
|
||||||
export class DocumentChanged extends JsMessage {}
|
export class DocumentChanged extends JsMessage {}
|
||||||
|
|
||||||
export class UpdateDocumentLayerTreeStructureJs extends JsMessage {
|
export class UpdateDocumentLayerStructureJs extends JsMessage {
|
||||||
constructor(
|
constructor(
|
||||||
readonly layerId: bigint,
|
readonly layerId: bigint,
|
||||||
readonly children: UpdateDocumentLayerTreeStructureJs[],
|
readonly children: UpdateDocumentLayerStructureJs[],
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
@@ -574,7 +574,7 @@ type DataBuffer = {
|
|||||||
length: bigint;
|
length: bigint;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function newUpdateDocumentLayerTreeStructure(input: { dataBuffer: DataBuffer }, wasm: WasmRawInstance): UpdateDocumentLayerTreeStructureJs {
|
export function newUpdateDocumentLayerStructure(input: { dataBuffer: DataBuffer }, wasm: WasmRawInstance): UpdateDocumentLayerStructureJs {
|
||||||
const pointerNum = Number(input.dataBuffer.pointer);
|
const pointerNum = Number(input.dataBuffer.pointer);
|
||||||
const lengthNum = Number(input.dataBuffer.length);
|
const lengthNum = Number(input.dataBuffer.length);
|
||||||
|
|
||||||
@@ -591,7 +591,7 @@ export function newUpdateDocumentLayerTreeStructure(input: { dataBuffer: DataBuf
|
|||||||
const layerIdsSection = new DataView(wasmMemoryBuffer, pointerNum + 8 + structureSectionLength * 8);
|
const layerIdsSection = new DataView(wasmMemoryBuffer, pointerNum + 8 + structureSectionLength * 8);
|
||||||
|
|
||||||
let layersEncountered = 0;
|
let layersEncountered = 0;
|
||||||
let currentFolder = new UpdateDocumentLayerTreeStructureJs(BigInt(-1), []);
|
let currentFolder = new UpdateDocumentLayerStructureJs(BigInt(-1), []);
|
||||||
const currentFolderStack = [currentFolder];
|
const currentFolderStack = [currentFolder];
|
||||||
|
|
||||||
for (let i = 0; i < structureSectionLength; i += 1) {
|
for (let i = 0; i < structureSectionLength; i += 1) {
|
||||||
@@ -606,7 +606,7 @@ export function newUpdateDocumentLayerTreeStructure(input: { dataBuffer: DataBuf
|
|||||||
const layerId = layerIdsSection.getBigUint64(layersEncountered * 8, true);
|
const layerId = layerIdsSection.getBigUint64(layersEncountered * 8, true);
|
||||||
layersEncountered += 1;
|
layersEncountered += 1;
|
||||||
|
|
||||||
const childLayer = new UpdateDocumentLayerTreeStructureJs(layerId, []);
|
const childLayer = new UpdateDocumentLayerStructureJs(layerId, []);
|
||||||
currentFolder.children.push(childLayer);
|
currentFolder.children.push(childLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,8 +650,8 @@ export class DisplayEditableTextboxTransform extends JsMessage {
|
|||||||
export class UpdateImageData extends JsMessage {
|
export class UpdateImageData extends JsMessage {
|
||||||
readonly documentId!: bigint;
|
readonly documentId!: bigint;
|
||||||
|
|
||||||
@Type(() => RenderedImageData)
|
@Type(() => FrontendImageData)
|
||||||
readonly imageData!: RenderedImageData[];
|
readonly imageData!: FrontendImageData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DisplayRemoveEditableTextbox extends JsMessage {}
|
export class DisplayRemoveEditableTextbox extends JsMessage {}
|
||||||
@@ -669,8 +669,12 @@ export class LayerPanelEntry {
|
|||||||
|
|
||||||
layerClassification!: LayerClassification;
|
layerClassification!: LayerClassification;
|
||||||
|
|
||||||
@Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value))
|
parentId!: bigint | undefined;
|
||||||
path!: BigUint64Array;
|
|
||||||
|
id!: bigint;
|
||||||
|
|
||||||
|
@Transform(({ value }: { value: bigint }) => Number(value))
|
||||||
|
depth!: number;
|
||||||
|
|
||||||
expanded!: boolean;
|
expanded!: boolean;
|
||||||
|
|
||||||
@@ -681,16 +685,10 @@ export class LayerPanelEntry {
|
|||||||
|
|
||||||
export type LayerClassification = "Folder" | "Artboard" | "Layer";
|
export type LayerClassification = "Folder" | "Artboard" | "Layer";
|
||||||
|
|
||||||
export class RenderedImageData {
|
export class FrontendImageData {
|
||||||
readonly path!: BigUint64Array;
|
|
||||||
|
|
||||||
readonly nodeId!: bigint;
|
|
||||||
|
|
||||||
readonly mime!: string;
|
readonly mime!: string;
|
||||||
|
|
||||||
readonly imageData!: Uint8Array;
|
readonly imageData!: Uint8Array;
|
||||||
|
|
||||||
readonly transform!: Float64Array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DisplayDialogDismiss extends JsMessage {}
|
export class DisplayDialogDismiss extends JsMessage {}
|
||||||
@@ -1381,7 +1379,7 @@ export const messageMakers: Record<string, MessageMaker> = {
|
|||||||
UpdateDocumentArtwork,
|
UpdateDocumentArtwork,
|
||||||
UpdateDocumentBarLayout,
|
UpdateDocumentBarLayout,
|
||||||
UpdateDocumentLayerDetails,
|
UpdateDocumentLayerDetails,
|
||||||
UpdateDocumentLayerTreeStructureJs: newUpdateDocumentLayerTreeStructure,
|
UpdateDocumentLayerStructureJs: newUpdateDocumentLayerStructure,
|
||||||
UpdateDocumentModeLayout,
|
UpdateDocumentModeLayout,
|
||||||
UpdateDocumentRulers,
|
UpdateDocumentRulers,
|
||||||
UpdateDocumentScrollbars,
|
UpdateDocumentScrollbars,
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use editor::consts::{FILE_SAVE_SUFFIX, GRAPHITE_DOCUMENT_VERSION};
|
|||||||
use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
||||||
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta, ViewportBounds};
|
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta, ViewportBounds};
|
||||||
use editor::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use editor::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use editor::messages::portfolio::document::utility_types::LayerId;
|
|
||||||
use editor::messages::portfolio::utility_types::Platform;
|
use editor::messages::portfolio::utility_types::Platform;
|
||||||
use editor::messages::prelude::*;
|
use editor::messages::prelude::*;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
@@ -35,8 +34,6 @@ pub fn set_random_seed(seed: u64) {
|
|||||||
/// This avoids creating a json with a list millions of numbers long.
|
/// This avoids creating a json with a list millions of numbers long.
|
||||||
#[wasm_bindgen(module = "/../src/wasm-communication/editor.ts")]
|
#[wasm_bindgen(module = "/../src/wasm-communication/editor.ts")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn updateImage(path: Vec<u64>, nodeId: Option<u64>, mime: String, imageData: &[u8], transform: js_sys::Float64Array, document_id: u64);
|
|
||||||
fn fetchImage(path: Vec<u64>, nodeId: Option<u64>, mime: String, document_id: u64, identifier: String);
|
|
||||||
//fn dispatchTauri(message: String) -> String;
|
//fn dispatchTauri(message: String) -> String;
|
||||||
fn dispatchTauri(message: String);
|
fn dispatchTauri(message: String);
|
||||||
}
|
}
|
||||||
@@ -160,29 +157,28 @@ impl JsEditorHandle {
|
|||||||
// Sends a FrontendMessage to JavaScript
|
// Sends a FrontendMessage to JavaScript
|
||||||
fn send_frontend_message_to_js(&self, mut message: FrontendMessage) {
|
fn send_frontend_message_to_js(&self, mut message: FrontendMessage) {
|
||||||
// Special case for update image data to avoid serialization times.
|
// Special case for update image data to avoid serialization times.
|
||||||
if let FrontendMessage::UpdateImageData { document_id, image_data } = message {
|
if let FrontendMessage::UpdateImageData { document_id: _, image_data: _ } = message {
|
||||||
for image in image_data {
|
// for image in image_data {
|
||||||
#[cfg(not(feature = "tauri"))]
|
// #[cfg(not(feature = "tauri"))]
|
||||||
{
|
// {
|
||||||
let transform = if let Some(transform_val) = image.transform {
|
// let transform = if let Some(transform_val) = image.transform {
|
||||||
let transform = js_sys::Float64Array::new_with_length(6);
|
// let transform = js_sys::Float64Array::new_with_length(6);
|
||||||
transform.copy_from(&transform_val);
|
// transform.copy_from(&transform_val);
|
||||||
transform
|
// transform
|
||||||
} else {
|
// } else {
|
||||||
js_sys::Float64Array::default()
|
// js_sys::Float64Array::default()
|
||||||
};
|
// };
|
||||||
updateImage(image.path, image.node_id, image.mime, &image.image_data, transform, document_id);
|
// }
|
||||||
}
|
// #[cfg(feature = "tauri")]
|
||||||
#[cfg(feature = "tauri")]
|
// {
|
||||||
{
|
// let identifier = format!("http://localhost:3001/image/{:?}_{}", image.path, document_id);
|
||||||
let identifier = format!("http://localhost:3001/image/{:?}_{}", image.path, document_id);
|
// fetchImage(image.path.clone(), image.node_id, image.mime, document_id, identifier);
|
||||||
fetchImage(image.path.clone(), image.node_id, image.mime, document_id, identifier);
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer } = message {
|
if let FrontendMessage::UpdateDocumentLayerStructure { data_buffer } = message {
|
||||||
message = FrontendMessage::UpdateDocumentLayerTreeStructureJs { data_buffer: data_buffer.into() };
|
message = FrontendMessage::UpdateDocumentLayerStructureJs { data_buffer: data_buffer.into() };
|
||||||
}
|
}
|
||||||
|
|
||||||
let message_type = message.to_discriminant().local_name();
|
let message_type = message.to_discriminant().local_name();
|
||||||
@@ -298,7 +294,7 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = selectDocument)]
|
#[wasm_bindgen(js_name = selectDocument)]
|
||||||
pub fn select_document(&self, document_id: u64) {
|
pub fn select_document(&self, document_id: DocumentId) {
|
||||||
let message = PortfolioMessage::SelectDocument { document_id };
|
let message = PortfolioMessage::SelectDocument { document_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
@@ -331,7 +327,7 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = openAutoSavedDocument)]
|
#[wasm_bindgen(js_name = openAutoSavedDocument)]
|
||||||
pub fn open_auto_saved_document(&self, document_id: u64, document_name: String, document_is_saved: bool, document_serialized_content: String) {
|
pub fn open_auto_saved_document(&self, document_id: DocumentId, document_name: String, document_is_saved: bool, document_serialized_content: String) {
|
||||||
let message = PortfolioMessage::OpenDocumentFileWithId {
|
let message = PortfolioMessage::OpenDocumentFileWithId {
|
||||||
document_id,
|
document_id,
|
||||||
document_name,
|
document_name,
|
||||||
@@ -343,13 +339,13 @@ impl JsEditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = triggerAutoSave)]
|
#[wasm_bindgen(js_name = triggerAutoSave)]
|
||||||
pub fn trigger_auto_save(&self, document_id: u64) {
|
pub fn trigger_auto_save(&self, document_id: DocumentId) {
|
||||||
let message = PortfolioMessage::AutoSaveDocument { document_id };
|
let message = PortfolioMessage::AutoSaveDocument { document_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = closeDocumentWithConfirmation)]
|
#[wasm_bindgen(js_name = closeDocumentWithConfirmation)]
|
||||||
pub fn close_document_with_confirmation(&self, document_id: u64) {
|
pub fn close_document_with_confirmation(&self, document_id: DocumentId) {
|
||||||
let message = PortfolioMessage::CloseDocumentWithConfirmation { document_id };
|
let message = PortfolioMessage::CloseDocumentWithConfirmation { document_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
@@ -532,8 +528,8 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
/// Modify the layer selection based on the layer which is clicked while holding down the <kbd>Ctrl</kbd> and/or <kbd>Shift</kbd> modifier keys used for range selection behavior
|
/// Modify the layer selection based on the layer which is clicked while holding down the <kbd>Ctrl</kbd> and/or <kbd>Shift</kbd> modifier keys used for range selection behavior
|
||||||
#[wasm_bindgen(js_name = selectLayer)]
|
#[wasm_bindgen(js_name = selectLayer)]
|
||||||
pub fn select_layer(&self, layer_path: Vec<LayerId>, ctrl: bool, shift: bool) {
|
pub fn select_layer(&self, id: NodeId, ctrl: bool, shift: bool) {
|
||||||
let message = DocumentMessage::SelectLayer { layer_path, ctrl, shift };
|
let message = DocumentMessage::SelectLayer { id, ctrl, shift };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,20 +540,23 @@ impl JsEditorHandle {
|
|||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move a layer to be next to the specified neighbor
|
/// Move a layer to within a folder and placed down at the given index.
|
||||||
|
/// If the folder is `None`, it is inserted into the document root.
|
||||||
|
/// If the insert index is `None`, it is inserted at the end of the folder (equivalent to index infinity).
|
||||||
#[wasm_bindgen(js_name = moveLayerInTree)]
|
#[wasm_bindgen(js_name = moveLayerInTree)]
|
||||||
pub fn move_layer_in_tree(&self, folder_path: Vec<LayerId>, insert_index: isize) {
|
pub fn move_layer_in_tree(&self, insert_parent_id: Option<NodeId>, insert_index: Option<usize>) {
|
||||||
let parent = folder_path.last().copied().map(LayerNodeIdentifier::new_unchecked).unwrap_or(LayerNodeIdentifier::ROOT);
|
let parent = insert_parent_id.map(|id| LayerNodeIdentifier::new_unchecked(id)).unwrap_or(LayerNodeIdentifier::default());
|
||||||
|
let message = DocumentMessage::MoveSelectedLayersTo {
|
||||||
let message = DocumentMessage::MoveSelectedLayersTo { parent, insert_index };
|
parent,
|
||||||
|
insert_index: insert_index.map(|x| x as isize).unwrap_or(-1),
|
||||||
|
};
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the name for the layer
|
/// Set the name for the layer
|
||||||
#[wasm_bindgen(js_name = setLayerName)]
|
#[wasm_bindgen(js_name = setLayerName)]
|
||||||
pub fn set_layer_name(&self, layer_path: Vec<LayerId>, name: String) {
|
pub fn set_layer_name(&self, id: NodeId, name: String) {
|
||||||
let node_id = *layer_path.last().unwrap();
|
let message = NodeGraphMessage::SetName { node_id: id, name };
|
||||||
let message = NodeGraphMessage::SetName { node_id, name };
|
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,23 +574,9 @@ impl JsEditorHandle {
|
|||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// Sends the blob URL generated by JS to the Image layer
|
|
||||||
// #[wasm_bindgen(js_name = setImageBlobURL)]
|
|
||||||
// pub fn set_image_blob_url(&self, document_id: u64, layer_path: Vec<LayerId>, node_id: Option<NodeId>, blob_url: String, width: f64, height: f64, _transform: Option<js_sys::Float64Array>) {
|
|
||||||
// let resolution = (width, height);
|
|
||||||
// let message = PortfolioMessage::SetImageBlobUrl {
|
|
||||||
// document_id,
|
|
||||||
// layer_path: layer_path.clone(),
|
|
||||||
// node_id,
|
|
||||||
// blob_url,
|
|
||||||
// resolution,
|
|
||||||
// };
|
|
||||||
// self.dispatch(message);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// Notifies the backend that the user connected a node's primary output to one of another node's inputs
|
/// Notifies the backend that the user connected a node's primary output to one of another node's inputs
|
||||||
#[wasm_bindgen(js_name = connectNodesByLink)]
|
#[wasm_bindgen(js_name = connectNodesByLink)]
|
||||||
pub fn connect_nodes_by_link(&self, output_node: u64, output_node_connector_index: usize, input_node: u64, input_node_connector_index: usize) {
|
pub fn connect_nodes_by_link(&self, output_node: NodeId, output_node_connector_index: usize, input_node: NodeId, input_node_connector_index: usize) {
|
||||||
let message = NodeGraphMessage::ConnectNodesByLink {
|
let message = NodeGraphMessage::ConnectNodesByLink {
|
||||||
output_node,
|
output_node,
|
||||||
output_node_connector_index,
|
output_node_connector_index,
|
||||||
@@ -603,14 +588,14 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
/// Shifts the node and its children to stop nodes going on top of each other
|
/// Shifts the node and its children to stop nodes going on top of each other
|
||||||
#[wasm_bindgen(js_name = shiftNode)]
|
#[wasm_bindgen(js_name = shiftNode)]
|
||||||
pub fn shift_node(&self, node_id: u64) {
|
pub fn shift_node(&self, node_id: NodeId) {
|
||||||
let message = NodeGraphMessage::ShiftNode { node_id };
|
let message = NodeGraphMessage::ShiftNode { node_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notifies the backend that the user disconnected a node
|
/// Notifies the backend that the user disconnected a node
|
||||||
#[wasm_bindgen(js_name = disconnectNodes)]
|
#[wasm_bindgen(js_name = disconnectNodes)]
|
||||||
pub fn disconnect_nodes(&self, node_id: u64, input_index: usize) {
|
pub fn disconnect_nodes(&self, node_id: NodeId, input_index: usize) {
|
||||||
let message = NodeGraphMessage::DisconnectNodes { node_id, input_index };
|
let message = NodeGraphMessage::DisconnectNodes { node_id, input_index };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
@@ -629,7 +614,7 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
/// Creates a new document node in the node graph
|
/// Creates a new document node in the node graph
|
||||||
#[wasm_bindgen(js_name = createNode)]
|
#[wasm_bindgen(js_name = createNode)]
|
||||||
pub fn create_node(&self, node_type: String, x: i32, y: i32) -> u64 {
|
pub fn create_node(&self, node_type: String, x: i32, y: i32) -> NodeId {
|
||||||
let id = generate_uuid();
|
let id = generate_uuid();
|
||||||
let message = NodeGraphMessage::CreateNode { node_id: Some(id), node_type, x, y };
|
let message = NodeGraphMessage::CreateNode { node_id: Some(id), node_type, x, y };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
@@ -638,7 +623,7 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
/// Notifies the backend that the user selected a node in the node graph
|
/// Notifies the backend that the user selected a node in the node graph
|
||||||
#[wasm_bindgen(js_name = selectNodes)]
|
#[wasm_bindgen(js_name = selectNodes)]
|
||||||
pub fn select_nodes(&self, nodes: Option<Vec<u64>>) {
|
pub fn select_nodes(&self, nodes: Option<Vec<NodeId>>) {
|
||||||
let nodes = nodes.unwrap_or_default();
|
let nodes = nodes.unwrap_or_default();
|
||||||
let message = NodeGraphMessage::SelectedNodesSet { nodes };
|
let message = NodeGraphMessage::SelectedNodesSet { nodes };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
@@ -653,7 +638,7 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
/// Notifies the backend that the user double clicked a node
|
/// Notifies the backend that the user double clicked a node
|
||||||
#[wasm_bindgen(js_name = doubleClickNode)]
|
#[wasm_bindgen(js_name = doubleClickNode)]
|
||||||
pub fn double_click_node(&self, node: u64) {
|
pub fn double_click_node(&self, node: NodeId) {
|
||||||
let message = NodeGraphMessage::DoubleClickNode { node };
|
let message = NodeGraphMessage::DoubleClickNode { node };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
@@ -686,15 +671,15 @@ impl JsEditorHandle {
|
|||||||
|
|
||||||
/// Toggle visibility of a layer from the layer list
|
/// Toggle visibility of a layer from the layer list
|
||||||
#[wasm_bindgen(js_name = toggleLayerVisibility)]
|
#[wasm_bindgen(js_name = toggleLayerVisibility)]
|
||||||
pub fn toggle_layer_visibility(&self, layer_path: Vec<LayerId>) {
|
pub fn toggle_layer_visibility(&self, id: NodeId) {
|
||||||
let message = NodeGraphMessage::ToggleHidden { node_id: *layer_path.last().unwrap() };
|
let message = NodeGraphMessage::ToggleHidden { node_id: id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle expansions state of a layer from the layer list
|
/// Toggle expansions state of a layer from the layer list
|
||||||
#[wasm_bindgen(js_name = toggleLayerExpansion)]
|
#[wasm_bindgen(js_name = toggleLayerExpansion)]
|
||||||
pub fn toggle_layer_expansion(&self, layer_path: Vec<LayerId>) {
|
pub fn toggle_layer_expansion(&self, id: NodeId) {
|
||||||
let message = DocumentMessage::ToggleLayerExpansion { layer: *layer_path.last().unwrap() };
|
let message = DocumentMessage::ToggleLayerExpansion { id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use wasm_bindgen::prelude::*;
|
|||||||
pub static EDITOR_HAS_CRASHED: AtomicBool = AtomicBool::new(false);
|
pub static EDITOR_HAS_CRASHED: AtomicBool = AtomicBool::new(false);
|
||||||
pub static LOGGER: WasmLog = WasmLog;
|
pub static LOGGER: WasmLog = WasmLog;
|
||||||
thread_local! {
|
thread_local! {
|
||||||
|
// TODO: Remove the concept of multiple editor instances to simplify all of this
|
||||||
pub static EDITOR_INSTANCES: RefCell<HashMap<u64, editor::application::Editor>> = RefCell::new(HashMap::new());
|
pub static EDITOR_INSTANCES: RefCell<HashMap<u64, editor::application::Editor>> = RefCell::new(HashMap::new());
|
||||||
pub static JS_EDITOR_HANDLES: RefCell<HashMap<u64, editor_api::JsEditorHandle>> = RefCell::new(HashMap::new());
|
pub static JS_EDITOR_HANDLES: RefCell<HashMap<u64, editor_api::JsEditorHandle>> = RefCell::new(HashMap::new());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ fn add_network() -> NodeNetwork {
|
|||||||
}]
|
}]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, n)| (i as u64, n))
|
.map(|(id, node)| (id as NodeId, node))
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ use alloc::vec::Vec;
|
|||||||
/// This data structure is somewhat similar to a linked list in terms of invariants.
|
/// This data structure is somewhat similar to a linked list in terms of invariants.
|
||||||
/// The downside is that currently it requires a lot of iteration.
|
/// The downside is that currently it requires a lot of iteration.
|
||||||
|
|
||||||
type ElementId = u64;
|
// TODO: Convert from a type alias to a newtype
|
||||||
|
pub type ElementId = u64;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, specta::Type, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, specta::Type, Hash)]
|
||||||
pub struct IdBackedVec<T> {
|
pub struct IdBackedVec<T> {
|
||||||
/// Contained elements
|
/// Contained elements
|
||||||
@@ -124,7 +125,7 @@ impl<T> IdBackedVec<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Enumerate the ids and elements in this container `(&ElementId, &T)`
|
/// Enumerate the ids and elements in this container `(&ElementId, &T)`
|
||||||
pub fn enumerate(&self) -> core::iter::Zip<core::slice::Iter<u64>, core::slice::Iter<T>> {
|
pub fn enumerate(&self) -> core::iter::Zip<core::slice::Iter<ElementId>, core::slice::Iter<T>> {
|
||||||
self.element_ids.iter().zip(self.elements.iter())
|
self.element_ids.iter().zip(self.elements.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ impl core::hash::Hash for Gradient {
|
|||||||
}
|
}
|
||||||
impl Gradient {
|
impl Gradient {
|
||||||
/// Constructs a new gradient with the colors at 0 and 1 specified.
|
/// Constructs a new gradient with the colors at 0 and 1 specified.
|
||||||
pub fn new(start: DVec2, start_color: Color, end: DVec2, end_color: Color, transform: DAffine2, _uuid: u64, gradient_type: GradientType) -> Self {
|
pub fn new(start: DVec2, start_color: Color, end: DVec2, end_color: Color, transform: DAffine2, gradient_type: GradientType) -> Self {
|
||||||
Gradient {
|
Gradient {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::consts::ManipulatorType;
|
|
||||||
use super::id_vec::IdBackedVec;
|
use super::id_vec::IdBackedVec;
|
||||||
use super::manipulator_group::ManipulatorGroup;
|
use super::manipulator_group::ManipulatorGroup;
|
||||||
use super::manipulator_point::ManipulatorPoint;
|
use super::manipulator_point::ManipulatorPoint;
|
||||||
|
use super::{consts::ManipulatorType, id_vec::ElementId};
|
||||||
use crate::uuid::ManipulatorGroupId;
|
use crate::uuid::ManipulatorGroupId;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
@@ -204,7 +204,7 @@ impl Subpath {
|
|||||||
|
|
||||||
/// Delete the selected points from the [Subpath]
|
/// Delete the selected points from the [Subpath]
|
||||||
pub fn delete_selected(&mut self) {
|
pub fn delete_selected(&mut self) {
|
||||||
let mut ids_to_delete: Vec<u64> = vec![];
|
let mut ids_to_delete: Vec<ElementId> = vec![];
|
||||||
for (id, manipulator_group) in self.manipulator_groups_mut().enumerate_mut() {
|
for (id, manipulator_group) in self.manipulator_groups_mut().enumerate_mut() {
|
||||||
if manipulator_group.is_anchor_selected() {
|
if manipulator_group.is_anchor_selected() {
|
||||||
ids_to_delete.push(*id);
|
ids_to_delete.push(*id);
|
||||||
@@ -228,7 +228,7 @@ impl Subpath {
|
|||||||
// ** SELECTION OF POINTS **
|
// ** SELECTION OF POINTS **
|
||||||
|
|
||||||
/// Set a single point to a chosen selection state by providing `(manipulator group ID, manipulator type)`.
|
/// Set a single point to a chosen selection state by providing `(manipulator group ID, manipulator type)`.
|
||||||
pub fn select_point(&mut self, point: (u64, ManipulatorType), selected: bool) -> Option<&mut ManipulatorGroup> {
|
pub fn select_point(&mut self, point: (ElementId, ManipulatorType), selected: bool) -> Option<&mut ManipulatorGroup> {
|
||||||
let (manipulator_group_id, point_id) = point;
|
let (manipulator_group_id, point_id) = point;
|
||||||
if let Some(manipulator_group) = self.manipulator_groups_mut().by_id_mut(manipulator_group_id) {
|
if let Some(manipulator_group) = self.manipulator_groups_mut().by_id_mut(manipulator_group_id) {
|
||||||
manipulator_group.select_point(point_id as usize, selected);
|
manipulator_group.select_point(point_id as usize, selected);
|
||||||
@@ -240,7 +240,7 @@ impl Subpath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set points in the [Subpath] to a chosen selection state, given by `(manipulator group ID, manipulator type)`.
|
/// Set points in the [Subpath] to a chosen selection state, given by `(manipulator group ID, manipulator type)`.
|
||||||
pub fn select_points(&mut self, points: &[(u64, ManipulatorType)], selected: bool) {
|
pub fn select_points(&mut self, points: &[(ElementId, ManipulatorType)], selected: bool) {
|
||||||
points.iter().for_each(|point| {
|
points.iter().for_each(|point| {
|
||||||
self.select_point(*point, selected);
|
self.select_point(*point, selected);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ use std::hash::{Hash, Hasher};
|
|||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
|
// TODO: Convert from a type alias to a newtype
|
||||||
pub type NodeId = u64;
|
pub type NodeId = u64;
|
||||||
|
|
||||||
/// Hash two IDs together, returning a new ID that is always consistant for two input IDs in a specific order.
|
/// Hash two IDs together, returning a new ID that is always consistant for two input IDs in a specific order.
|
||||||
/// This is used during [`NodeNetwork::flatten`] in order to ensure consistant yet non-conflicting IDs for inner networks.
|
/// This is used during [`NodeNetwork::flatten`] in order to ensure consistant yet non-conflicting IDs for inner networks.
|
||||||
fn merge_ids(a: u64, b: u64) -> u64 {
|
fn merge_ids(a: NodeId, b: NodeId) -> NodeId {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
a.hash(&mut hasher);
|
a.hash(&mut hasher);
|
||||||
b.hash(&mut hasher);
|
b.hash(&mut hasher);
|
||||||
@@ -639,7 +640,7 @@ impl NodeNetwork {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gives an iterator to all nodes connected to the given nodes by all inputs (primary or primary + secondary depending on `only_follow_primary` choice), traversing backwards upstream starting from the given node's inputs.
|
/// Gives an iterator to all nodes connected to the given nodes by all inputs (primary or primary + secondary depending on `only_follow_primary` choice), traversing backwards upstream starting from the given node's inputs.
|
||||||
pub fn upstream_flow_back_from_nodes(&self, node_ids: Vec<NodeId>, only_follow_primary: bool) -> impl Iterator<Item = (&DocumentNode, u64)> {
|
pub fn upstream_flow_back_from_nodes(&self, node_ids: Vec<NodeId>, only_follow_primary: bool) -> impl Iterator<Item = (&DocumentNode, NodeId)> {
|
||||||
FlowIter {
|
FlowIter {
|
||||||
stack: node_ids,
|
stack: node_ids,
|
||||||
network: self,
|
network: self,
|
||||||
@@ -654,13 +655,13 @@ impl NodeNetwork {
|
|||||||
|
|
||||||
/// Check there are no cycles in the graph (this should never happen).
|
/// Check there are no cycles in the graph (this should never happen).
|
||||||
pub fn is_acyclic(&self) -> bool {
|
pub fn is_acyclic(&self) -> bool {
|
||||||
let mut dependencies: HashMap<u64, Vec<u64>> = HashMap::new();
|
let mut dependencies: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
||||||
for (node_id, node) in &self.nodes {
|
for (node_id, node) in &self.nodes {
|
||||||
dependencies.insert(
|
dependencies.insert(
|
||||||
*node_id,
|
*node_id,
|
||||||
node.inputs
|
node.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|input| if let NodeInput::Node { node_id: ref_id, .. } = input { Some(*ref_id) } else { None })
|
.filter_map(|input| if let NodeInput::Node { node_id, .. } = input { Some(*node_id) } else { None })
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -734,11 +735,12 @@ impl NodeNetwork {
|
|||||||
|
|
||||||
/// Collect a hashmap of nodes with a list of the nodes that use it as input
|
/// Collect a hashmap of nodes with a list of the nodes that use it as input
|
||||||
pub fn collect_outwards_links(&self) -> HashMap<NodeId, Vec<NodeId>> {
|
pub fn collect_outwards_links(&self) -> HashMap<NodeId, Vec<NodeId>> {
|
||||||
let mut outwards_links: HashMap<u64, Vec<u64>> = HashMap::new();
|
let mut outwards_links: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
||||||
for (node_id, node) in &self.nodes {
|
for (current_node_id, node) in &self.nodes {
|
||||||
for input in &node.inputs {
|
for input in &node.inputs {
|
||||||
if let NodeInput::Node { node_id: ref_id, .. } = input {
|
if let NodeInput::Node { node_id, .. } = input {
|
||||||
outwards_links.entry(*ref_id).or_default().push(*node_id)
|
let outward_links_entry = outwards_links.entry(*node_id).or_default();
|
||||||
|
outward_links_entry.push(*current_node_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ pub enum TaggedValue {
|
|||||||
ImaginateSamplingMethod(ImaginateSamplingMethod),
|
ImaginateSamplingMethod(ImaginateSamplingMethod),
|
||||||
ImaginateMaskStartingFill(ImaginateMaskStartingFill),
|
ImaginateMaskStartingFill(ImaginateMaskStartingFill),
|
||||||
ImaginateController(ImaginateController),
|
ImaginateController(ImaginateController),
|
||||||
LayerPath(Option<Vec<u64>>),
|
|
||||||
VectorData(graphene_core::vector::VectorData),
|
VectorData(graphene_core::vector::VectorData),
|
||||||
Fill(graphene_core::vector::style::Fill),
|
Fill(graphene_core::vector::style::Fill),
|
||||||
Stroke(graphene_core::vector::style::Stroke),
|
Stroke(graphene_core::vector::style::Stroke),
|
||||||
@@ -104,7 +103,6 @@ impl Hash for TaggedValue {
|
|||||||
Self::ImaginateSamplingMethod(x) => x.hash(state),
|
Self::ImaginateSamplingMethod(x) => x.hash(state),
|
||||||
Self::ImaginateMaskStartingFill(x) => x.hash(state),
|
Self::ImaginateMaskStartingFill(x) => x.hash(state),
|
||||||
Self::ImaginateController(x) => x.hash(state),
|
Self::ImaginateController(x) => x.hash(state),
|
||||||
Self::LayerPath(x) => x.hash(state),
|
|
||||||
Self::ImageFrame(x) => x.hash(state),
|
Self::ImageFrame(x) => x.hash(state),
|
||||||
Self::VectorData(x) => x.hash(state),
|
Self::VectorData(x) => x.hash(state),
|
||||||
Self::Fill(x) => x.hash(state),
|
Self::Fill(x) => x.hash(state),
|
||||||
@@ -179,7 +177,6 @@ impl<'a> TaggedValue {
|
|||||||
TaggedValue::ImaginateSamplingMethod(x) => Box::new(x),
|
TaggedValue::ImaginateSamplingMethod(x) => Box::new(x),
|
||||||
TaggedValue::ImaginateMaskStartingFill(x) => Box::new(x),
|
TaggedValue::ImaginateMaskStartingFill(x) => Box::new(x),
|
||||||
TaggedValue::ImaginateController(x) => Box::new(x),
|
TaggedValue::ImaginateController(x) => Box::new(x),
|
||||||
TaggedValue::LayerPath(x) => Box::new(x),
|
|
||||||
TaggedValue::VectorData(x) => Box::new(x),
|
TaggedValue::VectorData(x) => Box::new(x),
|
||||||
TaggedValue::Fill(x) => Box::new(x),
|
TaggedValue::Fill(x) => Box::new(x),
|
||||||
TaggedValue::Stroke(x) => Box::new(x),
|
TaggedValue::Stroke(x) => Box::new(x),
|
||||||
@@ -252,7 +249,6 @@ impl<'a> TaggedValue {
|
|||||||
TaggedValue::ImaginateSamplingMethod(_) => concrete!(ImaginateSamplingMethod),
|
TaggedValue::ImaginateSamplingMethod(_) => concrete!(ImaginateSamplingMethod),
|
||||||
TaggedValue::ImaginateMaskStartingFill(_) => concrete!(ImaginateMaskStartingFill),
|
TaggedValue::ImaginateMaskStartingFill(_) => concrete!(ImaginateMaskStartingFill),
|
||||||
TaggedValue::ImaginateController(_) => concrete!(ImaginateController),
|
TaggedValue::ImaginateController(_) => concrete!(ImaginateController),
|
||||||
TaggedValue::LayerPath(_) => concrete!(Option<Vec<u64>>),
|
|
||||||
TaggedValue::DAffine2(_) => concrete!(DAffine2),
|
TaggedValue::DAffine2(_) => concrete!(DAffine2),
|
||||||
TaggedValue::LuminanceCalculation(_) => concrete!(LuminanceCalculation),
|
TaggedValue::LuminanceCalculation(_) => concrete!(LuminanceCalculation),
|
||||||
TaggedValue::VectorData(_) => concrete!(graphene_core::vector::VectorData),
|
TaggedValue::VectorData(_) => concrete!(graphene_core::vector::VectorData),
|
||||||
@@ -316,7 +312,6 @@ impl<'a> TaggedValue {
|
|||||||
x if x == TypeId::of::<ImaginateSamplingMethod>() => Ok(TaggedValue::ImaginateSamplingMethod(*downcast(input).unwrap())),
|
x if x == TypeId::of::<ImaginateSamplingMethod>() => Ok(TaggedValue::ImaginateSamplingMethod(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<ImaginateMaskStartingFill>() => Ok(TaggedValue::ImaginateMaskStartingFill(*downcast(input).unwrap())),
|
x if x == TypeId::of::<ImaginateMaskStartingFill>() => Ok(TaggedValue::ImaginateMaskStartingFill(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<ImaginateController>() => Ok(TaggedValue::ImaginateController(*downcast(input).unwrap())),
|
x if x == TypeId::of::<ImaginateController>() => Ok(TaggedValue::ImaginateController(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<Option<Vec<u64>>>() => Ok(TaggedValue::LayerPath(*downcast(input).unwrap())),
|
|
||||||
x if x == TypeId::of::<DAffine2>() => Ok(TaggedValue::DAffine2(*downcast(input).unwrap())),
|
x if x == TypeId::of::<DAffine2>() => Ok(TaggedValue::DAffine2(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<LuminanceCalculation>() => Ok(TaggedValue::LuminanceCalculation(*downcast(input).unwrap())),
|
x if x == TypeId::of::<LuminanceCalculation>() => Ok(TaggedValue::LuminanceCalculation(*downcast(input).unwrap())),
|
||||||
x if x == TypeId::of::<graphene_core::vector::VectorData>() => Ok(TaggedValue::VectorData(*downcast(input).unwrap())),
|
x if x == TypeId::of::<graphene_core::vector::VectorData>() => Ok(TaggedValue::VectorData(*downcast(input).unwrap())),
|
||||||
|
|||||||
@@ -207,7 +207,8 @@ pub struct ProtoNode {
|
|||||||
pub identifier: ProtoNodeIdentifier,
|
pub identifier: ProtoNodeIdentifier,
|
||||||
pub document_node_path: Vec<NodeId>,
|
pub document_node_path: Vec<NodeId>,
|
||||||
pub skip_deduplication: bool,
|
pub skip_deduplication: bool,
|
||||||
/// Represents a global state on which the node depends. This is a hack, TODO: figure out a proper solution
|
// TODO: This is a hack, figure out a proper solution
|
||||||
|
/// Represents a global state on which the node depends.
|
||||||
pub world_state_hash: u64,
|
pub world_state_hash: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +413,7 @@ impl ProtoNetwork {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update all of the references to a node ID in the graph with a new ID named `compose_node_id`.
|
/// Update all of the references to a node ID in the graph with a new ID named `compose_node_id`.
|
||||||
fn replace_node_id(&mut self, outwards_edges: &HashMap<u64, Vec<u64>>, node_id: u64, compose_node_id: u64, skip_lambdas: bool) {
|
fn replace_node_id(&mut self, outwards_edges: &HashMap<NodeId, Vec<NodeId>>, node_id: NodeId, compose_node_id: NodeId, skip_lambdas: bool) {
|
||||||
// Update references in other nodes to use the new compose node
|
// Update references in other nodes to use the new compose node
|
||||||
if let Some(referring_nodes) = outwards_edges.get(&node_id) {
|
if let Some(referring_nodes) = outwards_edges.get(&node_id) {
|
||||||
for &referring_node_id in referring_nodes {
|
for &referring_node_id in referring_nodes {
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ async fn create_compute_pass_descriptor<T: Clone + Pixel + StaticTypeSized>(
|
|||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, n)| (i as u64, n))
|
.map(|(id, node)| (id as NodeId, node))
|
||||||
.collect(),
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@@ -464,7 +464,7 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
|
|||||||
}]
|
}]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, n)| (i as u64, n))
|
.map(|(id, node)| (id as NodeId, node))
|
||||||
.collect(),
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -274,7 +274,6 @@ pub async fn imaginate<'a, P: Pixel>(
|
|||||||
negative_prompt: impl Future<Output = String>,
|
negative_prompt: impl Future<Output = String>,
|
||||||
adapt_input_image: impl Future<Output = bool>,
|
adapt_input_image: impl Future<Output = bool>,
|
||||||
image_creativity: impl Future<Output = f32>,
|
image_creativity: impl Future<Output = f32>,
|
||||||
masking_layer: impl Future<Output = Option<Vec<u64>>>,
|
|
||||||
inpaint: impl Future<Output = bool>,
|
inpaint: impl Future<Output = bool>,
|
||||||
mask_blur: impl Future<Output = f32>,
|
mask_blur: impl Future<Output = f32>,
|
||||||
mask_starting_fill: impl Future<Output = ImaginateMaskStartingFill>,
|
mask_starting_fill: impl Future<Output = ImaginateMaskStartingFill>,
|
||||||
@@ -305,7 +304,6 @@ pub async fn imaginate<'a, P: Pixel>(
|
|||||||
negative_prompt,
|
negative_prompt,
|
||||||
adapt_input_image,
|
adapt_input_image,
|
||||||
image_creativity,
|
image_creativity,
|
||||||
masking_layer,
|
|
||||||
inpaint,
|
inpaint,
|
||||||
mask_blur,
|
mask_blur,
|
||||||
mask_starting_fill,
|
mask_starting_fill,
|
||||||
@@ -343,7 +341,6 @@ async fn imaginate_maybe_fail<'a, P: Pixel, F: Fn(ImaginateStatus)>(
|
|||||||
negative_prompt: impl Future<Output = String>,
|
negative_prompt: impl Future<Output = String>,
|
||||||
adapt_input_image: impl Future<Output = bool>,
|
adapt_input_image: impl Future<Output = bool>,
|
||||||
image_creativity: impl Future<Output = f32>,
|
image_creativity: impl Future<Output = f32>,
|
||||||
_masking_layer: impl Future<Output = Option<Vec<u64>>>,
|
|
||||||
_inpaint: impl Future<Output = bool>,
|
_inpaint: impl Future<Output = bool>,
|
||||||
_mask_blur: impl Future<Output = f32>,
|
_mask_blur: impl Future<Output = f32>,
|
||||||
_mask_starting_fill: impl Future<Output = ImaginateMaskStartingFill>,
|
_mask_starting_fill: impl Future<Output = ImaginateMaskStartingFill>,
|
||||||
|
|||||||
@@ -533,7 +533,6 @@ generate_imaginate_node! {
|
|||||||
negative_prompt: NegativePrompt: String,
|
negative_prompt: NegativePrompt: String,
|
||||||
adapt_input_image: AdaptInputImage: bool,
|
adapt_input_image: AdaptInputImage: bool,
|
||||||
image_creativity: ImageCreativity: f32,
|
image_creativity: ImageCreativity: f32,
|
||||||
masking_layer: MaskingLayer: Option<Vec<u64>>,
|
|
||||||
inpaint: Inpaint: bool,
|
inpaint: Inpaint: bool,
|
||||||
mask_blur: MaskBlur: f32,
|
mask_blur: MaskBlur: f32,
|
||||||
mask_starting_fill: MaskStartingFill: ImaginateMaskStartingFill,
|
mask_starting_fill: MaskStartingFill: ImaginateMaskStartingFill,
|
||||||
|
|||||||
@@ -605,14 +605,14 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
NodeIOTypes::new(concrete!(()), concrete!(WasmEditorApi), vec![fn_type!(Option<WasmEditorApi>, WasmEditorApi)]),
|
NodeIOTypes::new(concrete!(()), concrete!(WasmEditorApi), vec![fn_type!(Option<WasmEditorApi>, WasmEditorApi)]),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
ProtoNodeIdentifier::new("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
ProtoNodeIdentifier::new("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||||
|args: Vec<graph_craft::proto::SharedNodeContainer>| {
|
|args: Vec<graph_craft::proto::SharedNodeContainer>| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
use graphene_std::raster::ImaginateNode;
|
use graphene_std::raster::ImaginateNode;
|
||||||
macro_rules! instantiate_imaginate_node {
|
macro_rules! instantiate_imaginate_node {
|
||||||
($($i:expr,)*) => { ImaginateNode::new($(graphene_std::any::input_node(args[$i].clone()),)* ) };
|
($($i:expr,)*) => { ImaginateNode::new($(graphene_std::any::input_node(args[$i].clone()),)* ) };
|
||||||
}
|
}
|
||||||
let node: ImaginateNode<Color, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _> = instantiate_imaginate_node!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,);
|
let node: ImaginateNode<Color, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _> = instantiate_imaginate_node!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,);
|
||||||
let any = graphene_std::any::DynAnyNode::new(node);
|
let any = graphene_std::any::DynAnyNode::new(node);
|
||||||
any.into_type_erased()
|
any.into_type_erased()
|
||||||
})
|
})
|
||||||
@@ -632,7 +632,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
fn_type!(String),
|
fn_type!(String),
|
||||||
fn_type!(bool),
|
fn_type!(bool),
|
||||||
fn_type!(f32),
|
fn_type!(f32),
|
||||||
fn_type!(Option<Vec<u64>>),
|
|
||||||
fn_type!(bool),
|
fn_type!(bool),
|
||||||
fn_type!(f32),
|
fn_type!(f32),
|
||||||
fn_type!(ImaginateMaskStartingFill),
|
fn_type!(ImaginateMaskStartingFill),
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ A message is an enum variant of a certain message sub-type like `FrontendMessage
|
|||||||
DocumentMessage::DeleteSelectedLayers
|
DocumentMessage::DeleteSelectedLayers
|
||||||
|
|
||||||
// Carries a layer path and a string as data
|
// Carries a layer path and a string as data
|
||||||
DocumentMessage::RenameLayer(Vec<LayerId>, String)
|
DocumentMessage::DeleteLayer {
|
||||||
|
id: NodeId,
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Message sub-types hierarchically wrap other message sub-types; for example, `DocumentMessage` is wrapped by `PortfolioMessage` via:
|
Message sub-types hierarchically wrap other message sub-types; for example, `DocumentMessage` is wrapped by `PortfolioMessage` via:
|
||||||
@@ -66,3 +68,8 @@ instead of:
|
|||||||
```rs
|
```rs
|
||||||
Message(PortfolioMessage::Document(DocumentMessage::DeleteSelectedLayers))
|
Message(PortfolioMessage::Document(DocumentMessage::DeleteSelectedLayers))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
And when pushing a message to the queue, we have the `add` and `add_front` functions which call `.into()` for you. Therefore it's as simple as writing:
|
||||||
|
```rs
|
||||||
|
responses.add(DocumentMessage::DeleteSelectedLayers.into());
|
||||||
|
```
|
||||||
|
|||||||
@@ -25,6 +25,6 @@ To show `trace!()` logs, activate *Help* > *Debug: Print Trace Logs*.
|
|||||||
|
|
||||||
To also view logs of the messages dispatched by the message bus system, activate *Help* > *Debug: Print Messages* > *Only Names*. Or use *Full Contents* for more verbose insight with the actual data being passed. This is an invaluable window into the activity of the message flow and works well together with `debug!()` printouts for tracking down message-related issues.
|
To also view logs of the messages dispatched by the message bus system, activate *Help* > *Debug: Print Messages* > *Only Names*. Or use *Full Contents* for more verbose insight with the actual data being passed. This is an invaluable window into the activity of the message flow and works well together with `debug!()` printouts for tracking down message-related issues.
|
||||||
|
|
||||||
## Layer paths and document IDs
|
## Node/layer and document IDs
|
||||||
|
|
||||||
In debug mode, hover over a layer's name in the Layer Tree panel to view a tooltip with its `u64` path. Likewise, document IDs may be read by hovering over their tabs.
|
In debug mode, hover over a layer's name in the Layers panel, or a layer/node in the node graph, to view a tooltip with its ID. Likewise, document IDs may be read by hovering over their tabs.
|
||||||
|
|||||||
Reference in New Issue
Block a user