mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00: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:
parent
5c7e04a725
commit
7bfe0ce55b
73 changed files with 532 additions and 798 deletions
|
@ -38,10 +38,9 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
|
|||
PropertiesPanelMessageDiscriminant::Refresh,
|
||||
))),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)),
|
||||
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure),
|
||||
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerStructure),
|
||||
MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad),
|
||||
MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::DocumentIsDirty)),
|
||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::InputFrameRasterizeRegionBelowLayer)),
|
||||
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::test_utils::EditorTestUtils;
|
||||
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_core::raster::color::Color;
|
||||
|
||||
fn init_logger() {
|
||||
|
@ -359,7 +359,7 @@ mod test {
|
|||
fn copy_paste_folder() {
|
||||
let mut editor = create_editor_with_three_layers();
|
||||
|
||||
const FOLDER_ID: u64 = 3;
|
||||
const FOLDER_ID: NodeId = 3;
|
||||
|
||||
editor.handle_message(GraphOperationMessage::NewCustomLayer {
|
||||
id: FOLDER_ID,
|
||||
|
|
|
@ -78,7 +78,7 @@ impl LayoutHolder for ExportDialogMessageHandler {
|
|||
NumberInput::new(Some(self.scale_factor))
|
||||
.unit("")
|
||||
.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)
|
||||
.on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor(number_input.value.unwrap()).into())
|
||||
.min_width(200)
|
||||
|
|
|
@ -95,7 +95,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
|||
.label("W")
|
||||
.unit(" px")
|
||||
.min(0.)
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.is_integer(true)
|
||||
.disabled(self.infinite)
|
||||
.min_width(100)
|
||||
|
@ -106,7 +106,7 @@ impl LayoutHolder for NewDocumentDialogMessageHandler {
|
|||
.label("H")
|
||||
.unit(" px")
|
||||
.min(0.)
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.is_integer(true)
|
||||
.disabled(self.infinite)
|
||||
.min_width(100)
|
||||
|
|
|
@ -57,7 +57,7 @@ impl PreferencesDialogMessageHandler {
|
|||
NumberInput::new(Some(preferences.imaginate_refresh_frequency))
|
||||
.unit(" seconds")
|
||||
.min(0.)
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.min_width(200)
|
||||
.on_update(|number_input: &NumberInput| PreferencesMessage::ImaginateRefreshFrequency { seconds: number_input.value.unwrap() }.into())
|
||||
.widget_holder(),
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::messages::prelude::*;
|
|||
/// A dialog for confirming the closing a document with unsaved changes.
|
||||
pub struct CloseDocumentDialog {
|
||||
pub document_name: String,
|
||||
pub document_id: u64,
|
||||
pub document_id: DocumentId,
|
||||
}
|
||||
|
||||
impl DialogLayoutHolder for CloseDocumentDialog {
|
||||
|
|
|
@ -80,7 +80,7 @@ pub enum FrontendMessage {
|
|||
TriggerImport,
|
||||
TriggerIndexedDbRemoveDocument {
|
||||
#[serde(rename = "documentId")]
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
TriggerIndexedDbWriteDocument {
|
||||
document: String,
|
||||
|
@ -111,7 +111,7 @@ pub enum FrontendMessage {
|
|||
// Update prefix: give the frontend a new value or state for it to use
|
||||
UpdateActiveDocument {
|
||||
#[serde(rename = "documentId")]
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
UpdateDialogButtons {
|
||||
#[serde(rename = "layoutTarget")]
|
||||
|
@ -139,11 +139,11 @@ pub enum FrontendMessage {
|
|||
UpdateDocumentLayerDetails {
|
||||
data: LayerPanelEntry,
|
||||
},
|
||||
UpdateDocumentLayerTreeStructure {
|
||||
UpdateDocumentLayerStructure {
|
||||
#[serde(rename = "dataBuffer")]
|
||||
data_buffer: RawBuffer,
|
||||
},
|
||||
UpdateDocumentLayerTreeStructureJs {
|
||||
UpdateDocumentLayerStructureJs {
|
||||
#[serde(rename = "dataBuffer")]
|
||||
data_buffer: JsRawBuffer,
|
||||
},
|
||||
|
@ -180,7 +180,7 @@ pub enum FrontendMessage {
|
|||
},
|
||||
UpdateImageData {
|
||||
#[serde(rename = "documentId")]
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
#[serde(rename = "imageData")]
|
||||
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::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -10,18 +10,14 @@ pub struct FrontendDocumentDetails {
|
|||
#[serde(rename = "isSaved")]
|
||||
pub is_saved: bool,
|
||||
pub name: String,
|
||||
pub id: u64,
|
||||
pub id: DocumentId,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)]
|
||||
pub struct FrontendImageData {
|
||||
pub path: Vec<LayerId>,
|
||||
pub mime: String,
|
||||
#[serde(skip)]
|
||||
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)]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
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::misc::{AlignAggregate, AlignAxis, FlipAxis};
|
||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use graph_craft::document::{NodeId, NodeNetwork};
|
||||
|
@ -42,14 +41,14 @@ pub enum DocumentMessage {
|
|||
BackupDocument {
|
||||
network: NodeNetwork,
|
||||
},
|
||||
ClearLayerTree,
|
||||
ClearLayersPanel,
|
||||
CommitTransaction,
|
||||
CreateEmptyFolder {
|
||||
parent: LayerNodeIdentifier,
|
||||
},
|
||||
DebugPrintDocument,
|
||||
DeleteLayer {
|
||||
layer_path: Vec<LayerId>,
|
||||
id: NodeId,
|
||||
},
|
||||
DeleteSelectedLayers,
|
||||
DeselectAllLayers,
|
||||
|
@ -61,20 +60,11 @@ pub enum DocumentMessage {
|
|||
flip_axis: FlipAxis,
|
||||
},
|
||||
GroupSelectedLayers,
|
||||
ImaginateClear {
|
||||
layer_path: Vec<LayerId>,
|
||||
},
|
||||
ImaginateGenerate {
|
||||
layer_path: Vec<LayerId>,
|
||||
},
|
||||
ImaginateGenerate,
|
||||
ImaginateRandom {
|
||||
layer_path: Vec<LayerId>,
|
||||
imaginate_node: Vec<NodeId>,
|
||||
then_generate: bool,
|
||||
},
|
||||
InputFrameRasterizeRegionBelowLayer {
|
||||
layer_path: Vec<LayerId>,
|
||||
},
|
||||
MoveSelectedLayersTo {
|
||||
parent: LayerNodeIdentifier,
|
||||
insert_index: isize,
|
||||
|
@ -106,7 +96,7 @@ pub enum DocumentMessage {
|
|||
relative_index_offset: isize,
|
||||
},
|
||||
SelectLayer {
|
||||
layer_path: Vec<LayerId>,
|
||||
id: NodeId,
|
||||
ctrl: bool,
|
||||
shift: bool,
|
||||
},
|
||||
|
@ -132,7 +122,7 @@ pub enum DocumentMessage {
|
|||
},
|
||||
StartTransaction,
|
||||
ToggleLayerExpansion {
|
||||
layer: NodeId,
|
||||
id: NodeId,
|
||||
},
|
||||
Undo,
|
||||
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::layer_panel::RawBuffer;
|
||||
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::prelude::*;
|
||||
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 document_id: u64,
|
||||
pub document_id: DocumentId,
|
||||
pub ipp: &'a InputPreprocessorMessageHandler,
|
||||
pub persistent_data: &'a PersistentData,
|
||||
pub executor: &'a mut NodeGraphExecutor,
|
||||
|
@ -324,7 +323,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
};
|
||||
let translation = (aggregated - center) * axis;
|
||||
responses.add(GraphOperationMessage::TransformChange {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: DAffine2::from_translation(translation),
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
|
@ -333,10 +332,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||
}
|
||||
BackupDocument { network } => self.backup_with_document(network, responses),
|
||||
ClearLayerTree => {
|
||||
// Send an empty layer tree
|
||||
let data_buffer: RawBuffer = Self::default().serialize_root().as_slice().into();
|
||||
responses.add(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer });
|
||||
ClearLayersPanel => {
|
||||
// Send an empty layer list
|
||||
let data_buffer: RawBuffer = Self::default().serialize_root();
|
||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
||||
|
||||
// Clear the options bar
|
||||
responses.add(LayoutMessage::SendLayout {
|
||||
|
@ -359,8 +358,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
DebugPrintDocument => {
|
||||
info!("{:#?}", self.network);
|
||||
}
|
||||
DeleteLayer { layer_path } => {
|
||||
responses.add(GraphOperationMessage::DeleteLayer { id: layer_path[0] });
|
||||
DeleteLayer { id } => {
|
||||
responses.add(GraphOperationMessage::DeleteLayer { id });
|
||||
responses.add_front(BroadcastEvent::ToolAbort);
|
||||
}
|
||||
DeleteSelectedLayers => {
|
||||
|
@ -368,9 +367,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
|
||||
responses.add_front(BroadcastEvent::SelectionChanged);
|
||||
for path in self.metadata().shallowest_unique_layers(self.metadata().selected_layers()) {
|
||||
responses.add_front(DocumentMessage::DeleteLayer {
|
||||
layer_path: path.last().unwrap().to_path(),
|
||||
});
|
||||
responses.add_front(DocumentMessage::DeleteLayer { id: path.last().unwrap().to_node() });
|
||||
}
|
||||
|
||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||
|
@ -384,8 +381,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
DocumentStructureChanged => {
|
||||
self.update_layers_panel_options_bar_widgets(responses);
|
||||
|
||||
let data_buffer: RawBuffer = self.serialize_root().as_slice().into();
|
||||
responses.add(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer })
|
||||
let data_buffer: RawBuffer = self.serialize_root();
|
||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer })
|
||||
}
|
||||
DuplicateSelectedLayers => {
|
||||
// TODO: Reimplement selected layer duplication
|
||||
|
@ -406,7 +403,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
let bbox_trans = DAffine2::from_translation(-center);
|
||||
for layer in self.metadata().selected_layers() {
|
||||
responses.add(GraphOperationMessage::TransformChange {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: DAffine2::from_scale(scale),
|
||||
transform_in: TransformIn::Scope { scope: bbox_trans },
|
||||
skip_rerender: false,
|
||||
|
@ -438,13 +435,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
|
||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder_id] });
|
||||
}
|
||||
ImaginateClear { layer_path } => responses.add(InputFrameRasterizeRegionBelowLayer { layer_path }),
|
||||
ImaginateGenerate { layer_path } => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path }),
|
||||
ImaginateRandom {
|
||||
layer_path,
|
||||
imaginate_node,
|
||||
then_generate,
|
||||
} => {
|
||||
ImaginateGenerate => responses.add(PortfolioMessage::SubmitGraphRender { document_id }),
|
||||
ImaginateRandom { imaginate_node, then_generate } => {
|
||||
// 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
|
||||
let random_bits = generate_uuid();
|
||||
|
@ -459,10 +451,9 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
|
||||
// Generate the image
|
||||
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 } => {
|
||||
let selected_layers = self.metadata().selected_layers().collect::<Vec<_>>();
|
||||
|
||||
|
@ -496,7 +487,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
// Nudge translation
|
||||
if !ipp.keyboard.key(resize) {
|
||||
responses.add(GraphOperationMessage::TransformChange {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: DAffine2::from_translation(delta),
|
||||
transform_in: TransformIn::Local,
|
||||
skip_rerender: false,
|
||||
|
@ -525,7 +516,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
let original_transform = self.metadata().upstream_transform(layer.to_node());
|
||||
let new = to.inverse() * transformation * to * original_transform;
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: new,
|
||||
transform_in: TransformIn::Local,
|
||||
skip_rerender: false,
|
||||
|
@ -561,7 +552,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
|
||||
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform,
|
||||
transform_in: TransformIn::Local,
|
||||
skip_rerender: false,
|
||||
|
@ -655,16 +646,15 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
SelectedLayersReorder { relative_index_offset } => {
|
||||
self.selected_layers_reorder(relative_index_offset, responses);
|
||||
}
|
||||
SelectLayer { layer_path, ctrl, shift } => {
|
||||
let clicked_node = *layer_path.last().expect("Cannot select root");
|
||||
let layer = LayerNodeIdentifier::new(clicked_node, self.network());
|
||||
SelectLayer { id, ctrl, shift } => {
|
||||
let layer = LayerNodeIdentifier::new(id, self.network());
|
||||
|
||||
let mut nodes = vec![];
|
||||
|
||||
// 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) {
|
||||
nodes.push(last_selected.to_node());
|
||||
nodes.push(clicked_node);
|
||||
nodes.push(id);
|
||||
|
||||
// Fill the selection range
|
||||
self.metadata()
|
||||
|
@ -677,13 +667,13 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
if ctrl {
|
||||
// Toggle selection when holding ctrl
|
||||
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 {
|
||||
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![clicked_node] });
|
||||
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
||||
}
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
} else {
|
||||
nodes.push(clicked_node);
|
||||
nodes.push(id);
|
||||
}
|
||||
|
||||
// Set our last selection reference
|
||||
|
@ -703,7 +693,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
SetBlendModeForSelectedLayers { blend_mode } => {
|
||||
self.backup(responses);
|
||||
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 } => {
|
||||
|
@ -711,7 +701,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
let opacity = opacity.clamp(0., 1.) as f32;
|
||||
|
||||
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 } => {
|
||||
|
@ -742,8 +732,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||
responses.add_front(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
StartTransaction => self.backup(responses),
|
||||
ToggleLayerExpansion { layer } => {
|
||||
let layer = LayerNodeIdentifier::new(layer, self.network());
|
||||
ToggleLayerExpansion { id } => {
|
||||
let layer = LayerNodeIdentifier::new(id, self.network());
|
||||
if self.collapsed.contains(&layer) {
|
||||
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer);
|
||||
} else {
|
||||
|
@ -908,23 +898,23 @@ impl DocumentMessageHandler {
|
|||
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;
|
||||
for layer_node in folder.children(self.metadata()) {
|
||||
data.push(layer_node.to_node());
|
||||
data.push(layer_node);
|
||||
space += 1;
|
||||
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.
|
||||
structure.push(space);
|
||||
structure.push(LayerNodeIdentifier::new_unchecked(space));
|
||||
self.serialize_structure(layer_node, structure, data, path);
|
||||
space = 0;
|
||||
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
structure.push(space | 1 << 63);
|
||||
structure.push(LayerNodeIdentifier::new_unchecked(space | 1 << 63));
|
||||
}
|
||||
|
||||
/// Serializes the layer structure into a condensed 1D structure.
|
||||
|
@ -959,13 +949,15 @@ impl DocumentMessageHandler {
|
|||
/// [3427872634365736244,18115028555707261608,15878401910454357952]
|
||||
/// [3427872634365736244,18115028555707261608,449479075714955186]
|
||||
/// ```
|
||||
pub fn serialize_root(&self) -> Vec<u64> {
|
||||
let (mut structure, mut data) = (vec![0], Vec::new());
|
||||
pub fn serialize_root(&self) -> RawBuffer {
|
||||
let mut structure = vec![LayerNodeIdentifier::ROOT];
|
||||
let mut data = Vec::new();
|
||||
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
|
||||
structure.iter().map(|id| id.to_node()).collect::<Vec<_>>().as_slice().into()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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 new_insert_index = layer_ids_above.filter(|layer_id| !layers.contains(layer_id)).count() as isize;
|
||||
|
||||
new_insert_index
|
||||
let take_amount = if insert_index < 0 { usize::MAX } else { insert_index as usize };
|
||||
let layer_ids_above = parent.children(self.metadata()).take(take_amount);
|
||||
layer_ids_above.filter(|layer_id| !layers.contains(layer_id)).count() as isize
|
||||
}
|
||||
|
||||
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::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use bezier_rs::Subpath;
|
||||
|
@ -16,56 +15,54 @@ use graphene_core::{Artboard, Color};
|
|||
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
|
||||
pub type LayerIdentifier = Vec<LayerId>;
|
||||
|
||||
#[impl_message(Message, DocumentMessage, GraphOperation)]
|
||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum GraphOperationMessage {
|
||||
FillSet {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
fill: Fill,
|
||||
},
|
||||
OpacitySet {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
opacity: f32,
|
||||
},
|
||||
BlendModeSet {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
blend_mode: BlendMode,
|
||||
},
|
||||
UpdateBounds {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
old_bounds: [DVec2; 2],
|
||||
new_bounds: [DVec2; 2],
|
||||
},
|
||||
StrokeSet {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
stroke: Stroke,
|
||||
},
|
||||
|
||||
TransformChange {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
transform: DAffine2,
|
||||
transform_in: TransformIn,
|
||||
skip_rerender: bool,
|
||||
},
|
||||
TransformSet {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
transform: DAffine2,
|
||||
transform_in: TransformIn,
|
||||
skip_rerender: bool,
|
||||
},
|
||||
TransformSetPivot {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
pivot: DVec2,
|
||||
},
|
||||
|
||||
Vector {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
modification: VectorDataModification,
|
||||
},
|
||||
Brush {
|
||||
layer: LayerIdentifier,
|
||||
layer: LayerNodeIdentifier,
|
||||
strokes: Vec<BrushStroke>,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
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::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use bezier_rs::Subpath;
|
||||
|
@ -26,7 +25,6 @@ struct ModifyInputsContext<'a> {
|
|||
document_network: &'a mut NodeNetwork,
|
||||
node_graph: &'a mut NodeGraphMessageHandler,
|
||||
responses: &'a mut VecDeque<Message>,
|
||||
layer: &'a [LayerId],
|
||||
outwards_links: HashMap<NodeId, Vec<NodeId>>,
|
||||
layer_node: Option<NodeId>,
|
||||
}
|
||||
|
@ -38,27 +36,25 @@ impl<'a> ModifyInputsContext<'a> {
|
|||
document_network,
|
||||
node_graph,
|
||||
responses,
|
||||
layer: &[],
|
||||
layer_node: None,
|
||||
document_metadata,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_with_layer(
|
||||
layer: &'a [LayerId],
|
||||
id: NodeId,
|
||||
document_network: &'a mut NodeNetwork,
|
||||
document_metadata: &'a mut DocumentMetadata,
|
||||
node_graph: &'a mut NodeGraphMessageHandler,
|
||||
responses: &'a mut VecDeque<Message>,
|
||||
) -> Option<Self> {
|
||||
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");
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut id = id;
|
||||
while !document.document_network.nodes.get(&id)?.is_layer() {
|
||||
id = document.outwards_links.get(&id)?.first().copied()?;
|
||||
}
|
||||
|
||||
document.layer_node = Some(id);
|
||||
Some(document)
|
||||
}
|
||||
|
@ -325,10 +321,9 @@ impl<'a> ModifyInputsContext<'a> {
|
|||
|
||||
self.node_graph.network.clear();
|
||||
self.responses.add(PropertiesPanelMessage::Refresh);
|
||||
let layer_path = self.layer.to_vec();
|
||||
|
||||
if !skip_rerender {
|
||||
self.responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||
self.responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
} else {
|
||||
// Code was removed from here which cleared the frame
|
||||
}
|
||||
|
@ -354,10 +349,9 @@ impl<'a> ModifyInputsContext<'a> {
|
|||
}
|
||||
|
||||
self.responses.add(PropertiesPanelMessage::Refresh);
|
||||
let layer_path = self.layer.to_vec();
|
||||
|
||||
if !skip_rerender {
|
||||
self.responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||
self.responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
} else {
|
||||
// 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]);
|
||||
if empty {
|
||||
if let Some(layer) = self.layer_node {
|
||||
self.responses.add(DocumentMessage::DeleteLayer { layer_path: vec![layer] })
|
||||
if let Some(id) = self.layer_node {
|
||||
self.responses.add(DocumentMessage::DeleteLayer { id })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -594,27 +588,27 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
|
|||
) {
|
||||
match message {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -624,10 +618,9 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
|
|||
transform_in,
|
||||
skip_rerender,
|
||||
} => {
|
||||
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
||||
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
|
||||
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
||||
let parent_transform = document_metadata.downstream_transform_to_viewport(layer);
|
||||
let bounds = LayerBounds::new(document_metadata, layer);
|
||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
|
||||
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,
|
||||
skip_rerender,
|
||||
} => {
|
||||
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
||||
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
|
||||
let parent_transform = document_metadata.downstream_transform_to_viewport(layer);
|
||||
|
||||
let current_transform = Some(document_metadata.transform_to_viewport(layer_identifier));
|
||||
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
||||
let current_transform = Some(document_metadata.transform_to_viewport(layer));
|
||||
let bounds = LayerBounds::new(document_metadata, layer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
GraphOperationMessage::TransformSetPivot { layer, pivot } => {
|
||||
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
||||
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
|
||||
let bounds = LayerBounds::new(document_metadata, layer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -744,7 +736,7 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
|
|||
load_network_structure(document_network, document_metadata, collapsed);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
|||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
|
||||
use bezier_rs::{ManipulatorGroup, Subpath};
|
||||
use graph_craft::document::NodeNetwork;
|
||||
use graph_craft::document::{value::TaggedValue, NodeInput};
|
||||
use graphene_core::uuid::ManipulatorGroupId;
|
||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||
|
@ -53,8 +52,7 @@ pub struct LayerBounds {
|
|||
|
||||
impl LayerBounds {
|
||||
/// Extract the layer bounds and their transform for a layer.
|
||||
pub fn new(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: &[u64]) -> Self {
|
||||
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
||||
pub fn new(document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier) -> Self {
|
||||
Self {
|
||||
bounds: document_metadata.nonzero_bounding_box(layer),
|
||||
bounds_transform: DAffine2::IDENTITY,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
|
@ -11,14 +10,13 @@ pub enum NodeGraphMessage {
|
|||
Init,
|
||||
SelectedNodesUpdated,
|
||||
ConnectNodesByLink {
|
||||
output_node: u64,
|
||||
output_node: NodeId,
|
||||
output_node_connector_index: usize,
|
||||
input_node: u64,
|
||||
input_node: NodeId,
|
||||
input_node_connector_index: usize,
|
||||
},
|
||||
Copy,
|
||||
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_type: String,
|
||||
x: i32,
|
||||
|
@ -83,7 +81,6 @@ pub enum NodeGraphMessage {
|
|||
input: NodeInput,
|
||||
},
|
||||
SetQualifiedInputValue {
|
||||
layer_path: Vec<LayerId>,
|
||||
node_path: Vec<NodeId>,
|
||||
input_index: usize,
|
||||
value: TaggedValue,
|
||||
|
|
|
@ -3,9 +3,7 @@ use super::load_network_structure;
|
|||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||
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::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::node_graph_executor::GraphIdentifier;
|
||||
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
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)]
|
||||
pub struct FrontendNodeLink {
|
||||
#[serde(rename = "linkStart")]
|
||||
pub link_start: u64,
|
||||
pub link_start: NodeId,
|
||||
#[serde(rename = "linkStartOutputIndex")]
|
||||
pub link_start_output_index: usize,
|
||||
#[serde(rename = "linkEnd")]
|
||||
pub link_end: u64,
|
||||
pub link_end: NodeId,
|
||||
#[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)]
|
||||
|
@ -124,10 +122,9 @@ impl FrontendNodeType {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct NodeGraphMessageHandler {
|
||||
pub layer_path: Option<Vec<LayerId>>,
|
||||
pub network: Vec<NodeId>,
|
||||
has_selection: bool,
|
||||
pub widgets: [LayoutGroup; 2],
|
||||
widgets: [LayoutGroup; 2],
|
||||
}
|
||||
|
||||
impl Default for NodeGraphMessageHandler {
|
||||
|
@ -137,7 +134,6 @@ impl Default for NodeGraphMessageHandler {
|
|||
let add_nodes_label_row = LayoutGroup::Row { widgets: vec![add_nodes_label] };
|
||||
|
||||
Self {
|
||||
layer_path: None,
|
||||
network: Vec::new(),
|
||||
has_selection: false,
|
||||
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);
|
||||
|
||||
if !graph_view_overlay_open {
|
||||
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)
|
||||
let links = network
|
||||
.nodes
|
||||
|
@ -278,16 +272,16 @@ impl NodeGraphMessageHandler {
|
|||
.filter_map(|(input, &link_end, link_end_input_index)| {
|
||||
if let NodeInput::Node {
|
||||
node_id: link_start,
|
||||
output_index: link_start_index,
|
||||
output_index: link_start_output_index,
|
||||
// TODO: add ui for lambdas
|
||||
lambda: _,
|
||||
} = *input
|
||||
{
|
||||
Some(FrontendNodeLink {
|
||||
link_start,
|
||||
link_start_output_index: link_start_index,
|
||||
link_start_output_index,
|
||||
link_end,
|
||||
link_end_input_index: link_end_input_index as u64,
|
||||
link_end_input_index,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -318,8 +312,6 @@ impl NodeGraphMessageHandler {
|
|||
});
|
||||
let primary_output = if node.has_primary_output { outputs.next() } else { None };
|
||||
|
||||
let _graph_identifier = GraphIdentifier::new(layer_id);
|
||||
|
||||
nodes.push(FrontendNode {
|
||||
is_layer: node.is_layer(),
|
||||
id: *id,
|
||||
|
@ -446,7 +438,7 @@ impl NodeGraphMessageHandler {
|
|||
pub struct NodeGraphHandlerData<'a> {
|
||||
pub document_network: &'a mut NodeNetwork,
|
||||
pub document_metadata: &'a mut DocumentMetadata,
|
||||
pub document_id: u64,
|
||||
pub document_id: DocumentId,
|
||||
pub document_name: &'a str,
|
||||
pub collapsed: &'a mut Vec<LayerNodeIdentifier>,
|
||||
pub input: &'a InputPreprocessorMessageHandler,
|
||||
|
@ -495,7 +487,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
error!("No network");
|
||||
return;
|
||||
};
|
||||
let Some(input_node) = network.nodes.get(&input_node) else {
|
||||
let Some(input_node) = network.nodes.get(&node_id) else {
|
||||
error!("No to");
|
||||
return;
|
||||
};
|
||||
|
@ -569,11 +561,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
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
|
||||
if metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
|
||||
if let Some(layer_path) = self.layer_path.clone() {
|
||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||
} else {
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
@ -640,7 +628,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
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);
|
||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
||||
}
|
||||
|
@ -653,7 +641,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
self.network.pop();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -703,7 +691,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
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 } => {
|
||||
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 });
|
||||
}
|
||||
NodeGraphMessage::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path: Vec::new() }),
|
||||
NodeGraphMessage::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id }),
|
||||
NodeGraphMessage::SelectedNodesAdd { nodes } => {
|
||||
metadata.add_selected_nodes(nodes);
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
|
@ -768,13 +756,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
}
|
||||
NodeGraphMessage::SendGraph { should_rerender } => {
|
||||
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 let Some(layer_path) = self.layer_path.clone() {
|
||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||
} else {
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
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(PropertiesPanelMessage::Refresh);
|
||||
if (node.name != "Imaginate" || input_index == 0) && network.connected_to_output(node_id) {
|
||||
if let Some(layer_path) = self.layer_path.clone() {
|
||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||
} else {
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -811,12 +791,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
}
|
||||
}
|
||||
}
|
||||
NodeGraphMessage::SetQualifiedInputValue {
|
||||
layer_path,
|
||||
node_path,
|
||||
input_index,
|
||||
value,
|
||||
} => {
|
||||
NodeGraphMessage::SetQualifiedInputValue { node_path, input_index, value } => {
|
||||
let Some((node_id, node_path)) = node_path.split_last() else {
|
||||
error!("Node path is empty");
|
||||
return;
|
||||
|
@ -832,7 +807,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
}
|
||||
node.inputs[input_index] = NodeInput::Value { tagged_value: value, exposed: false };
|
||||
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) {
|
||||
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
|
||||
if network.connected_to_output(node_id) {
|
||||
|
@ -944,21 +919,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
} else {
|
||||
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);
|
||||
if let Some(layer_path) = self.layer_path.clone() {
|
||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||
} else {
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
NodeGraphMessage::UpdateNewNodeGraph => {
|
||||
if let Some(network) = document_network.nested_network(&self.network) {
|
||||
metadata.clear_selected_nodes();
|
||||
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();
|
||||
responses.add(FrontendMessage::UpdateNodeTypes { node_types });
|
||||
|
|
|
@ -2,7 +2,6 @@ use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
|
|||
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
|
||||
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::LayerId;
|
||||
use crate::messages::portfolio::utility_types::PersistentData;
|
||||
use crate::messages::prelude::Message;
|
||||
use crate::node_graph_executor::NodeGraphExecutor;
|
||||
|
@ -74,7 +73,6 @@ impl DocumentOutputType {
|
|||
pub struct NodePropertiesContext<'a> {
|
||||
pub persistent_data: &'a PersistentData,
|
||||
pub responses: &'a mut VecDeque<Message>,
|
||||
pub layer_path: &'a [LayerId],
|
||||
pub nested_path: &'a [NodeId],
|
||||
pub executor: &'a mut NodeGraphExecutor,
|
||||
pub network: &'a NodeNetwork,
|
||||
|
@ -279,7 +277,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
name: "Image Frame",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
}],
|
||||
properties: node_properties::input_properties,
|
||||
properties: node_properties::node_no_properties,
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
|
@ -1069,7 +1067,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
name: "OutputBuffer",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
}],
|
||||
properties: node_properties::input_properties,
|
||||
properties: node_properties::node_no_properties,
|
||||
..Default::default()
|
||||
},
|
||||
#[cfg(feature = "gpu")]
|
||||
|
@ -1137,7 +1135,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
name: "CommandBuffer",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
}],
|
||||
properties: node_properties::input_properties,
|
||||
properties: node_properties::node_no_properties,
|
||||
..Default::default()
|
||||
},
|
||||
#[cfg(feature = "gpu")]
|
||||
|
@ -1171,7 +1169,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
name: "PipelineLayout",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
}],
|
||||
properties: node_properties::input_properties,
|
||||
properties: node_properties::node_no_properties,
|
||||
..Default::default()
|
||||
},
|
||||
#[cfg(feature = "gpu")]
|
||||
|
@ -2377,7 +2375,7 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
|
|||
name: "Imaginate",
|
||||
category: "Image Synthesis",
|
||||
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)],
|
||||
nodes: [
|
||||
(
|
||||
|
@ -2404,14 +2402,13 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
|
|||
NodeInput::Network(concrete!(String)),
|
||||
NodeInput::Network(concrete!(bool)),
|
||||
NodeInput::Network(concrete!(f32)),
|
||||
NodeInput::Network(concrete!(Option<Vec<u64>>)),
|
||||
NodeInput::Network(concrete!(bool)),
|
||||
NodeInput::Network(concrete!(f32)),
|
||||
NodeInput::Network(concrete!(ImaginateMaskStartingFill)),
|
||||
NodeInput::Network(concrete!(bool)),
|
||||
NodeInput::Network(concrete!(bool)),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||
..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("Adapt Input Image", TaggedValue::Bool(false), 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("Mask Blur", TaggedValue::F32(4.), false),
|
||||
DocumentInputType::value("Mask Starting Fill", TaggedValue::ImaginateMaskStartingFill(ImaginateMaskStartingFill::Fill), false),
|
||||
|
|
|
@ -144,16 +144,16 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||
NumberInput::new(Some(dvec2.x))
|
||||
.label(x)
|
||||
.unit(unit)
|
||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.min(min.unwrap_or(-((1_u64 << 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))
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
NumberInput::new(Some(dvec2.y))
|
||||
.label(y)
|
||||
.unit(unit)
|
||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.min(min.unwrap_or(-((1_u64 << 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))
|
||||
.widget_holder(),
|
||||
]);
|
||||
|
@ -170,8 +170,8 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||
.int()
|
||||
.label(x)
|
||||
.unit(unit)
|
||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.min(min.unwrap_or(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.on_update(update_value(update_x, node_id, index))
|
||||
.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()
|
||||
.label(y)
|
||||
.unit(unit)
|
||||
.min(min.unwrap_or(-((1u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.min(min.unwrap_or(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64)))
|
||||
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.on_update(update_value(update_y, node_id, index))
|
||||
.widget_holder(),
|
||||
]);
|
||||
|
@ -198,7 +198,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
|
|||
.label(x)
|
||||
.unit(unit)
|
||||
.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))
|
||||
.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)
|
||||
.unit(unit)
|
||||
.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))
|
||||
.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
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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)
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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")
|
||||
}
|
||||
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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 }
|
||||
}
|
||||
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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 }
|
||||
}
|
||||
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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 }
|
||||
}
|
||||
|
||||
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);
|
||||
if let &NodeInput::Value {
|
||||
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())];
|
||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
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);
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if let NodeInput::Value {
|
||||
|
@ -785,17 +785,6 @@ fn curves_widget(document_node: &DocumentNode, node_id: u64, index: usize, name:
|
|||
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> {
|
||||
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);
|
||||
|
@ -1629,12 +1618,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||
.tooltip("Generate with a new random seed")
|
||||
.on_update({
|
||||
let imaginate_node = imaginate_node.clone();
|
||||
let layer_path = context.layer_path.to_vec();
|
||||
let controller = controller.clone();
|
||||
move |_| {
|
||||
controller.trigger_regenerate();
|
||||
DocumentMessage::ImaginateRandom {
|
||||
layer_path: layer_path.clone(),
|
||||
imaginate_node: imaginate_node.clone(),
|
||||
then_generate: true,
|
||||
}
|
||||
|
@ -1646,11 +1633,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||
TextButton::new("Generate")
|
||||
.tooltip("Fill layer frame by generating a new image")
|
||||
.on_update({
|
||||
let layer_path = context.layer_path.to_vec();
|
||||
let controller = controller.clone();
|
||||
move |_| {
|
||||
controller.trigger_regenerate();
|
||||
DocumentMessage::ImaginateGenerate { layer_path: layer_path.clone() }.into()
|
||||
DocumentMessage::ImaginateGenerate.into()
|
||||
}
|
||||
})
|
||||
.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")
|
||||
.disabled(!matches!(imaginate_status, ImaginateStatus::ReadyDone))
|
||||
.on_update({
|
||||
let layer_path = context.layer_path.to_vec();
|
||||
let controller = controller.clone();
|
||||
move |_| {
|
||||
controller.set_status(ImaginateStatus::Ready);
|
||||
DocumentMessage::ImaginateClear { layer_path: layer_path.clone() }.into()
|
||||
DocumentMessage::ImaginateGenerate.into()
|
||||
}
|
||||
})
|
||||
.widget_holder(),
|
||||
|
@ -1687,10 +1672,8 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||
.tooltip("Set a new random seed")
|
||||
.on_update({
|
||||
let imaginate_node = imaginate_node.clone();
|
||||
let layer_path = context.layer_path.to_vec();
|
||||
move |_| {
|
||||
DocumentMessage::ImaginateRandom {
|
||||
layer_path: layer_path.clone(),
|
||||
imaginate_node: imaginate_node.clone(),
|
||||
then_generate: false,
|
||||
}
|
||||
|
@ -1701,8 +1684,8 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
|
|||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
NumberInput::new(Some(seed))
|
||||
.int()
|
||||
.min(-((1u64 << f64::MANTISSA_DIGITS) as f64))
|
||||
.max((1u64 << f64::MANTISSA_DIGITS) as f64)
|
||||
.min(-((1_u64 << 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))
|
||||
.mode(NumberInputMode::Increment)
|
||||
.widget_holder(),
|
||||
|
|
|
@ -37,7 +37,6 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
|||
persistent_data,
|
||||
responses,
|
||||
nested_path: &node_graph_message_handler.network,
|
||||
layer_path: &[],
|
||||
executor,
|
||||
network: document_network,
|
||||
metadata: document_metadata,
|
||||
|
|
|
@ -107,8 +107,9 @@ impl DocumentMetadata {
|
|||
layer_path
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
sorted_layers.sort();
|
||||
|
||||
// Sorting here creates groups of similar UUID paths
|
||||
sorted_layers.sort();
|
||||
sorted_layers.dedup_by(|a, b| a.starts_with(b));
|
||||
sorted_layers
|
||||
}
|
||||
|
@ -386,32 +387,27 @@ impl LayerNodeIdentifier {
|
|||
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
|
||||
pub fn parent(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
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) {
|
||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||
let parent = document_metadata.get_structure_mut(self);
|
||||
|
@ -470,7 +466,7 @@ impl LayerNodeIdentifier {
|
|||
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) {
|
||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||
let parent = document_metadata.get_structure_mut(self);
|
||||
|
@ -483,7 +479,7 @@ impl LayerNodeIdentifier {
|
|||
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) {
|
||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||
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) {
|
||||
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
|
||||
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::{Deserialize, Serialize};
|
||||
|
@ -45,6 +45,9 @@ pub struct LayerPanelEntry {
|
|||
pub layer_classification: LayerClassification,
|
||||
pub selected: 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,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
pub use super::layer_panel::LayerPanelEntry;
|
||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||
|
||||
use graphene_core::raster::color::Color;
|
||||
|
||||
use glam::DVec2;
|
||||
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)]
|
||||
/// SnappingState determines the current individual snapping states
|
||||
pub struct SnappingState {
|
||||
|
|
|
@ -4,8 +4,3 @@ pub mod error;
|
|||
pub mod layer_panel;
|
||||
pub mod misc;
|
||||
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 new = to.inverse() * transformation * to * original_transform;
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: new,
|
||||
transform_in: TransformIn::Local,
|
||||
skip_rerender: false,
|
||||
|
@ -404,7 +404,7 @@ impl<'a> Selected<'a> {
|
|||
let position = new_pos_viewport;
|
||||
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
});
|
||||
}
|
||||
|
@ -438,17 +438,17 @@ impl<'a> Selected<'a> {
|
|||
OriginalTransforms::Layer(hash) => {
|
||||
let Some(matrix) = hash.get(&layer) else { continue };
|
||||
self.responses.add(GraphOperationMessage::TransformSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: *matrix,
|
||||
transform_in: TransformIn::Local,
|
||||
skip_rerender: false,
|
||||
});
|
||||
}
|
||||
OriginalTransforms::Path(path) => {
|
||||
for (layer, points) in path {
|
||||
for (&layer, points) in path {
|
||||
for &(point, position) in points {
|
||||
self.responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use graphene_core::text::Font;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -22,21 +22,21 @@ pub enum PortfolioMessage {
|
|||
// Messages
|
||||
#[remain::unsorted]
|
||||
DocumentPassMessage {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
message: DocumentMessage,
|
||||
},
|
||||
AutoSaveActiveDocument,
|
||||
AutoSaveDocument {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
CloseActiveDocumentWithConfirmation,
|
||||
CloseAllDocuments,
|
||||
CloseAllDocumentsWithConfirmation,
|
||||
CloseDocument {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
CloseDocumentWithConfirmation {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
Copy {
|
||||
clipboard: Clipboard,
|
||||
|
@ -45,7 +45,7 @@ pub enum PortfolioMessage {
|
|||
clipboard: Clipboard,
|
||||
},
|
||||
DeleteDocument {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
DestroyAllDocuments,
|
||||
FontLoaded {
|
||||
|
@ -65,7 +65,7 @@ pub enum PortfolioMessage {
|
|||
ImaginateServerHostname,
|
||||
Import,
|
||||
LoadDocumentResources {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
LoadFont {
|
||||
font: Font,
|
||||
|
@ -81,7 +81,7 @@ pub enum PortfolioMessage {
|
|||
document_serialized_content: String,
|
||||
},
|
||||
OpenDocumentFileWithId {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
document_name: String,
|
||||
document_is_auto_saved: bool,
|
||||
document_is_saved: bool,
|
||||
|
@ -97,10 +97,10 @@ pub enum PortfolioMessage {
|
|||
},
|
||||
PrevDocument,
|
||||
SelectDocument {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
SetActiveDocument {
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
SubmitDocumentExport {
|
||||
file_name: String,
|
||||
|
@ -110,8 +110,7 @@ pub enum PortfolioMessage {
|
|||
transparent_background: bool,
|
||||
},
|
||||
SubmitGraphRender {
|
||||
document_id: u64,
|
||||
layer_path: Vec<LayerId>,
|
||||
document_id: DocumentId,
|
||||
},
|
||||
ToggleRulers,
|
||||
UpdateDocumentWidgets,
|
||||
|
|
|
@ -19,9 +19,9 @@ use std::sync::Arc;
|
|||
#[derive(Debug, Default)]
|
||||
pub struct PortfolioMessageHandler {
|
||||
menu_bar_message_handler: MenuBarMessageHandler,
|
||||
documents: HashMap<u64, DocumentMessageHandler>,
|
||||
document_ids: Vec<u64>,
|
||||
active_document_id: Option<u64>,
|
||||
documents: HashMap<DocumentId, DocumentMessageHandler>,
|
||||
document_ids: Vec<DocumentId>,
|
||||
active_document_id: Option<DocumentId>,
|
||||
graph_view_overlay_open: bool,
|
||||
copy_buffer: [Vec<CopyBufferEntry>; INTERNAL_CLIPBOARD_COUNT as usize],
|
||||
pub persistent_data: PersistentData,
|
||||
|
@ -109,7 +109,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
|||
|
||||
// Clear relevant UI layouts if there are no documents
|
||||
responses.add(PropertiesPanelMessage::Clear);
|
||||
responses.add(DocumentMessage::ClearLayerTree);
|
||||
responses.add(DocumentMessage::ClearLayersPanel);
|
||||
let hint_data = HintData(vec![HintGroup(vec![])]);
|
||||
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 {
|
||||
// Clear UI layouts that assume the existence of a document
|
||||
responses.add(PropertiesPanelMessage::Clear);
|
||||
responses.add(DocumentMessage::ClearLayerTree);
|
||||
responses.add(DocumentMessage::ClearLayersPanel);
|
||||
let hint_data = HintData(vec![HintGroup(vec![])]);
|
||||
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(
|
||||
self.documents.get_mut(&document_id).expect("Tried to render no existent Document"),
|
||||
layer_path,
|
||||
ipp.viewport_bounds.size().as_uvec2(),
|
||||
);
|
||||
|
||||
|
@ -591,11 +590,11 @@ impl PortfolioMessageHandler {
|
|||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -607,7 +606,7 @@ impl PortfolioMessageHandler {
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -637,7 +636,7 @@ impl PortfolioMessageHandler {
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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"))
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ pub use graphite_proc_macros::*;
|
|||
|
||||
pub use std::collections::{HashMap, HashSet, VecDeque};
|
||||
|
||||
// TODO: Convert from a type alias to a newtype
|
||||
pub type DocumentId = u64;
|
||||
|
||||
pub trait Responses {
|
||||
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>) {
|
||||
for manipulator_group in manipulator_groups {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||
id: manipulator_group.id,
|
||||
mirror_angle,
|
||||
|
@ -216,7 +216,7 @@ impl<'a> NodeGraphLayer<'a> {
|
|||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,6 @@ impl Pivot {
|
|||
let pivot = transform.inverse().transform_point2(position);
|
||||
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
||||
if pivot.is_finite() {
|
||||
let layer = layer.to_path();
|
||||
responses.add(GraphOperationMessage::TransformSetPivot { layer, pivot });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ impl Resize {
|
|||
/// 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) {
|
||||
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;
|
||||
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.
|
||||
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.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
}
|
||||
|
||||
/// Calculate the drag start position in viewport space.
|
||||
|
@ -65,7 +63,7 @@ impl Resize {
|
|||
|
||||
Some(
|
||||
GraphOperationMessage::TransformSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: DAffine2::from_scale_angle_translation(size, 0., start),
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender,
|
||||
|
|
|
@ -192,7 +192,7 @@ impl ShapeState {
|
|||
|
||||
if point.manipulator_type.is_handle() {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id: group.id, mirror_angle: false },
|
||||
});
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ impl ShapeState {
|
|||
return;
|
||||
};
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: (position + delta) },
|
||||
});
|
||||
};
|
||||
|
@ -270,7 +270,7 @@ impl ShapeState {
|
|||
|
||||
// Mirror the angle but not the distance
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||
id: manipulator.id,
|
||||
mirror_angle: true,
|
||||
|
@ -291,7 +291,7 @@ impl ShapeState {
|
|||
if let Some(in_handle) = length_previous.map(|length| anchor_position + handle_vector * length) {
|
||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::InHandle);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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) {
|
||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::OutHandle);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: out_handle },
|
||||
});
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ impl ShapeState {
|
|||
let out_handle = ManipulatorPointId::new(point.group, SelectedType::OutHandle);
|
||||
if let Some(position) = group.out_handle {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point: out_handle, position },
|
||||
});
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ impl ShapeState {
|
|||
let in_handle = ManipulatorPointId::new(point.group, SelectedType::InHandle);
|
||||
if let Some(position) = group.in_handle {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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 position = previous_position + delta;
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
});
|
||||
};
|
||||
|
@ -410,7 +410,7 @@ impl ShapeState {
|
|||
// and set angle mirroring to true.
|
||||
if !mirror && point.manipulator_type.opposite().get_position(group).is_none() {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id: group.id, mirror_angle: true },
|
||||
});
|
||||
mirror = true;
|
||||
|
@ -428,7 +428,7 @@ impl ShapeState {
|
|||
}
|
||||
let position = group.anchor - (original_handle_position - group.anchor);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
});
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ impl ShapeState {
|
|||
|
||||
if (anchor_position - point_position).length() < DRAG_THRESHOLD {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::RemoveManipulatorPoint { point },
|
||||
});
|
||||
|
||||
|
@ -481,7 +481,7 @@ impl ShapeState {
|
|||
if let Some(lengths) = opposing_handle_lengths {
|
||||
if lengths.contains_key(&point.group) {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::RemoveManipulatorPoint { point: opposite_point },
|
||||
});
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ impl ShapeState {
|
|||
|
||||
let Some(opposing_handle_length) = opposing_handle_length else {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::RemoveManipulatorPoint {
|
||||
point: ManipulatorPointId::new(manipulator_group.id, single_selected_handle.opposite()),
|
||||
},
|
||||
|
@ -586,7 +586,7 @@ impl ShapeState {
|
|||
assert!(position.is_finite(), "Opposing handle not finite!");
|
||||
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
});
|
||||
}
|
||||
|
@ -596,10 +596,10 @@ impl ShapeState {
|
|||
|
||||
/// Dissolve the selected points.
|
||||
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 {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::RemoveManipulatorPoint { point },
|
||||
})
|
||||
}
|
||||
|
@ -608,10 +608,10 @@ impl ShapeState {
|
|||
|
||||
/// Toggle if the handles should mirror angle across the anchor position.
|
||||
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 {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::ToggleManipulatorHandleMirroring { id: point.group },
|
||||
})
|
||||
}
|
||||
|
@ -620,10 +620,10 @@ impl ShapeState {
|
|||
|
||||
/// 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>) {
|
||||
for (layer, state) in &self.selected_shape_state {
|
||||
for (&layer, state) in &self.selected_shape_state {
|
||||
for point in &state.selected_points {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id: point.group, mirror_angle },
|
||||
});
|
||||
}
|
||||
|
@ -732,7 +732,7 @@ impl ShapeState {
|
|||
let point = ManipulatorPointId::new(start, SelectedType::OutHandle);
|
||||
let position = first.handle_start().unwrap_or(first.start());
|
||||
let out_handle = GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
};
|
||||
responses.add(out_handle);
|
||||
|
@ -740,7 +740,7 @@ impl ShapeState {
|
|||
// Insert a new manipulator group between the existing ones
|
||||
let manipulator_group = ManipulatorGroup::new(first.end(), first.handle_end(), second.handle_start());
|
||||
let insert = GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::AddManipulatorGroup { manipulator_group, after_id: start },
|
||||
};
|
||||
responses.add(insert);
|
||||
|
@ -749,7 +749,7 @@ impl ShapeState {
|
|||
let point = ManipulatorPointId::new(end, SelectedType::InHandle);
|
||||
let position = second.handle_end().unwrap_or(second.end());
|
||||
let in_handle = GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
};
|
||||
responses.add(in_handle);
|
||||
|
@ -797,16 +797,16 @@ impl ShapeState {
|
|||
} else {
|
||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::InHandle);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: anchor_position },
|
||||
});
|
||||
let point = ManipulatorPointId::new(manipulator.id, SelectedType::OutHandle);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: anchor_position },
|
||||
});
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||
id: manipulator.id,
|
||||
mirror_angle: false,
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use super::shape_editor::ManipulatorPointInfo;
|
||||
use crate::consts::{SNAP_AXIS_TOLERANCE, SNAP_POINT_TOLERANCE};
|
||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
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.
|
||||
/// 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 {
|
||||
|
|
|
@ -16,13 +16,13 @@ pub struct ToolMessageHandler {
|
|||
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]
|
||||
fn process_message(
|
||||
&mut self,
|
||||
message: ToolMessage,
|
||||
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;
|
||||
|
||||
|
|
|
@ -120,7 +120,6 @@ impl ArtboardToolData {
|
|||
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.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
if let Some(bounds) = &mut self.bounding_box_manager {
|
||||
bounds.center_of_transformation = (bounds.bounds[0] + bounds.bounds[1]) / 2.;
|
||||
|
@ -139,7 +138,6 @@ impl ArtboardToolData {
|
|||
self.selected_artboard = Some(intersection);
|
||||
|
||||
self.snap_manager.start_snap(document, input, document.bounding_boxes(), true, true);
|
||||
self.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
true
|
||||
} else {
|
||||
|
@ -279,7 +277,6 @@ impl Fsm for ArtboardToolFsmState {
|
|||
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.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
responses.add(GraphOperationMessage::NewArtboard {
|
||||
id,
|
||||
|
|
|
@ -301,7 +301,7 @@ impl BrushToolData {
|
|||
fn update_strokes(&self, responses: &mut VecDeque<Message>) {
|
||||
let Some(layer) = self.layer else { return };
|
||||
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")
|
||||
.label("Weight")
|
||||
.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())
|
||||
.widget_holder()
|
||||
}
|
||||
|
@ -211,12 +211,12 @@ impl Fsm for EllipseToolFsmState {
|
|||
|
||||
let fill_color = tool_options.fill.active_color();
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||
});
|
||||
|
||||
responses.add(GraphOperationMessage::StrokeSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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 {
|
||||
return self;
|
||||
};
|
||||
let layer = layer_identifier.to_path();
|
||||
|
||||
let color = match event {
|
||||
FillToolMessage::LeftPointerDown => global_tool_data.primary_color,
|
||||
FillToolMessage::RightPointerDown => global_tool_data.secondary_color,
|
||||
|
@ -81,7 +79,7 @@ impl Fsm for FillToolFsmState {
|
|||
let fill = Fill::Solid(color);
|
||||
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
||||
responses.add(GraphOperationMessage::FillSet { layer: layer_identifier, fill });
|
||||
responses.add(DocumentMessage::CommitTransaction);
|
||||
|
||||
FillToolFsmState::Ready
|
||||
|
|
|
@ -87,7 +87,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||
.unit(" px")
|
||||
.label("Weight")
|
||||
.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())
|
||||
.widget_holder()
|
||||
}
|
||||
|
@ -215,12 +215,12 @@ impl Fsm for FreehandToolFsmState {
|
|||
tool_data.layer = Some(layer);
|
||||
|
||||
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 },
|
||||
});
|
||||
|
||||
responses.add(GraphOperationMessage::StrokeSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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 {
|
||||
let manipulator_group = ManipulatorGroup::new_anchor(pos);
|
||||
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.last_point = pos;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use super::tool_prelude::*;
|
||||
use crate::application::generate_uuid;
|
||||
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::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
|
@ -235,9 +234,10 @@ impl SelectedGradient {
|
|||
/// Update the layer fill to the current gradient
|
||||
pub fn render_gradient(&mut self, responses: &mut VecDeque<Message>) {
|
||||
self.gradient.transform = self.transform;
|
||||
let fill = Fill::Gradient(self.gradient.clone());
|
||||
let layer = self.layer.to_path();
|
||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: self.layer,
|
||||
fill: Fill::Gradient(self.gradient.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,6 @@ struct GradientToolData {
|
|||
|
||||
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.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
}
|
||||
|
||||
impl Fsm for GradientToolFsmState {
|
||||
|
@ -338,9 +337,10 @@ impl Fsm for GradientToolFsmState {
|
|||
|
||||
// The gradient has only one point and so should become a fill
|
||||
if selected_gradient.gradient.positions.len() == 1 {
|
||||
let fill = Fill::Solid(selected_gradient.gradient.positions[0].1.unwrap_or(Color::BLACK));
|
||||
let layer = selected_gradient.layer.to_path();
|
||||
responses.add(GraphOperationMessage::FillSet { layer, fill });
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: selected_gradient.layer,
|
||||
fill: Fill::Solid(selected_gradient.gradient.positions[0].1.unwrap_or(Color::BLACK)),
|
||||
});
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -467,7 +467,6 @@ impl Fsm for GradientToolFsmState {
|
|||
DVec2::ONE,
|
||||
global_tool_data.primary_color,
|
||||
DAffine2::IDENTITY,
|
||||
generate_uuid(),
|
||||
tool_options.gradient_type,
|
||||
)
|
||||
};
|
||||
|
|
|
@ -172,10 +172,6 @@ impl Fsm for ImaginateToolFsmState {
|
|||
state
|
||||
}
|
||||
(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);
|
||||
shape_data.cleanup(responses);
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||
.unit(" px")
|
||||
.label("Weight")
|
||||
.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())
|
||||
.widget_holder()
|
||||
}
|
||||
|
@ -175,7 +175,6 @@ impl Fsm for LineToolFsmState {
|
|||
match (self, event) {
|
||||
(LineToolFsmState::Ready, LineToolMessage::DragStart) => {
|
||||
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);
|
||||
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);
|
||||
responses.add(GraphOperationMessage::StrokeSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_options.line_weight),
|
||||
});
|
||||
tool_data.layer = Some(layer);
|
||||
|
@ -280,7 +279,7 @@ fn generate_transform(tool_data: &mut LineToolData, document_to_viewport: DAffin
|
|||
}
|
||||
|
||||
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_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
|
|
|
@ -91,8 +91,8 @@ impl LayoutHolder for PathTool {
|
|||
.label("X")
|
||||
.min_width(120)
|
||||
.disabled(x.is_none())
|
||||
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.min(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64))
|
||||
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.on_update(move |number_input: &NumberInput| {
|
||||
let new_x = number_input.value.unwrap_or(x.unwrap());
|
||||
PathToolMessage::SelectedPointXChanged { new_x }.into()
|
||||
|
@ -104,8 +104,8 @@ impl LayoutHolder for PathTool {
|
|||
.label("Y")
|
||||
.min_width(120)
|
||||
.disabled(y.is_none())
|
||||
.min(-((1u64 << std::f64::MANTISSA_DIGITS) as f64))
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.min(-((1_u64 << std::f64::MANTISSA_DIGITS) as f64))
|
||||
.max((1_u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.on_update(move |number_input: &NumberInput| {
|
||||
let new_y = number_input.value.unwrap_or(y.unwrap());
|
||||
PathToolMessage::SelectedPointYChanged { new_y }.into()
|
||||
|
@ -275,9 +275,6 @@ impl PathToolData {
|
|||
}
|
||||
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.previous_mouse_position = input.mouse.position - selected_points.offset;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||
.unit(" px")
|
||||
.label("Weight")
|
||||
.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())
|
||||
.widget_holder()
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ impl PenToolData {
|
|||
};
|
||||
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring {
|
||||
id: last_handle.id,
|
||||
mirror_angle: false,
|
||||
|
@ -259,12 +259,12 @@ impl PenToolData {
|
|||
self.layer = Some(layer);
|
||||
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||
});
|
||||
|
||||
responses.add(GraphOperationMessage::StrokeSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
stroke: Stroke::new(stroke_color, line_weight),
|
||||
});
|
||||
|
||||
|
@ -298,21 +298,21 @@ impl PenToolData {
|
|||
}
|
||||
// Remove the point that has just been placed
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
||||
});
|
||||
|
||||
// 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);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: previous_anchor },
|
||||
});
|
||||
|
||||
// Stop the handles on the last point from mirroring
|
||||
let id = previous_manipulator_group.id;
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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
|
||||
let point = ManipulatorPointId::new(first_manipulator_group.id, inwards_handle);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: last_in },
|
||||
});
|
||||
|
||||
// Stop the handles on the first point from mirroring
|
||||
let id = first_manipulator_group.id;
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: false },
|
||||
});
|
||||
|
||||
// Remove the point that has just been placed
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
||||
});
|
||||
|
||||
// Push a close path node
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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
|
||||
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)
|
||||
|
@ -419,7 +419,7 @@ impl PenToolData {
|
|||
// Update points on current segment (to show preview of new handle)
|
||||
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: self.layer?.to_path(),
|
||||
layer: self.layer?,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
||||
});
|
||||
|
||||
|
@ -430,7 +430,7 @@ impl PenToolData {
|
|||
let pos = last_anchor - (pos - last_anchor);
|
||||
let point = ManipulatorPointId::new(last_manipulator_group.id, inwards_handle);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: self.layer?.to_path(),
|
||||
layer: self.layer?,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
||||
});
|
||||
}
|
||||
|
@ -438,7 +438,7 @@ impl PenToolData {
|
|||
// Update the mirror status of the currently modifying point
|
||||
let id = last_manipulator_group.id;
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: self.layer?.to_path(),
|
||||
layer: self.layer?,
|
||||
modification: VectorDataModification::SetManipulatorHandleMirroring { id, mirror_angle: should_mirror },
|
||||
});
|
||||
|
||||
|
@ -483,7 +483,7 @@ impl PenToolData {
|
|||
for manipulator_type in [SelectedType::Anchor, SelectedType::InHandle, SelectedType::OutHandle] {
|
||||
let point = ManipulatorPointId::new(last_manipulator_group.id, manipulator_type);
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position: pos },
|
||||
});
|
||||
}
|
||||
|
@ -516,7 +516,7 @@ impl PenToolData {
|
|||
// Remove the unplaced anchor if in anchor placing mode
|
||||
if fsm == PenToolFsmState::PlacingAnchor {
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: self.layer?.to_path(),
|
||||
layer: self.layer?,
|
||||
modification: VectorDataModification::RemoveManipulatorGroup { id: last_manipulator_group.id },
|
||||
});
|
||||
last_manipulator_group = previous_manipulator_group;
|
||||
|
@ -526,7 +526,7 @@ impl PenToolData {
|
|||
let point = ManipulatorPointId::new(last_manipulator_group.id, outwards_handle);
|
||||
let position = last_manipulator_group.anchor;
|
||||
responses.add(GraphOperationMessage::Vector {
|
||||
layer: self.layer?.to_path(),
|
||||
layer: self.layer?,
|
||||
modification: VectorDataModification::SetManipulatorPosition { point, position },
|
||||
});
|
||||
|
||||
|
@ -591,7 +591,6 @@ impl Fsm for PenToolFsmState {
|
|||
|
||||
// Initialize snapping
|
||||
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
|
||||
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].
|
||||
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 {
|
||||
return Message::NoOp;
|
||||
};
|
||||
let layer = layer.to_path();
|
||||
let modification = if from_start {
|
||||
VectorDataModification::AddStartManipulatorGroup { subpath_index: 0, manipulator_group }
|
||||
} else {
|
||||
|
|
|
@ -111,7 +111,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||
.unit(" px")
|
||||
.label("Weight")
|
||||
.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())
|
||||
.widget_holder()
|
||||
}
|
||||
|
@ -251,12 +251,12 @@ impl Fsm for PolygonToolFsmState {
|
|||
|
||||
let fill_color = tool_options.fill.active_color();
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||
});
|
||||
|
||||
responses.add(GraphOperationMessage::StrokeSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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")
|
||||
.label("Weight")
|
||||
.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())
|
||||
.widget_holder()
|
||||
}
|
||||
|
@ -220,12 +220,12 @@ impl Fsm for RectangleToolFsmState {
|
|||
|
||||
let fill_color = tool_options.fill.active_color();
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
fill: if let Some(color) = fill_color { Fill::Solid(color) } else { Fill::None },
|
||||
});
|
||||
|
||||
responses.add(GraphOperationMessage::StrokeSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
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.
|
||||
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.
|
||||
responses.add_front(GraphOperationMessage::TransformChange {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
transform: DAffine2::from_translation(self.drag_start - self.drag_current),
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: true,
|
||||
|
@ -336,11 +336,6 @@ impl SelectToolData {
|
|||
// 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.
|
||||
|
@ -361,7 +356,7 @@ impl SelectToolData {
|
|||
// Move the original to under the mouse
|
||||
for layer_ancestors in document.metadata().shallowest_unique_layers(originals.iter().copied()) {
|
||||
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_in: TransformIn::Viewport,
|
||||
skip_rerender: true,
|
||||
|
@ -482,22 +477,11 @@ impl Fsm for SelectToolFsmState {
|
|||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
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
|
||||
} else if let Some(_selected_edges) = dragging_bounds {
|
||||
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;
|
||||
|
||||
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
|
||||
for layer_ancestors in document.metadata().shallowest_unique_layers(tool_data.layers_dragging.iter().copied()) {
|
||||
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_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
|
|
|
@ -89,7 +89,7 @@ fn create_weight_widget(line_weight: f64) -> WidgetHolder {
|
|||
.unit(" px")
|
||||
.label("Weight")
|
||||
.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())
|
||||
.widget_holder()
|
||||
}
|
||||
|
@ -215,7 +215,6 @@ impl Fsm for SplineToolFsmState {
|
|||
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.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.mouse.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);
|
||||
|
||||
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 },
|
||||
});
|
||||
|
||||
responses.add(GraphOperationMessage::StrokeSet {
|
||||
layer: layer.to_path(),
|
||||
layer,
|
||||
stroke: Stroke::new(tool_options.stroke.active_color(), tool_data.weight),
|
||||
});
|
||||
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);
|
||||
let subpaths = vec![subpath];
|
||||
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")
|
||||
.int()
|
||||
.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())
|
||||
.widget_holder();
|
||||
vec![
|
||||
|
@ -298,11 +298,11 @@ impl TextToolData {
|
|||
insert_index: -1,
|
||||
});
|
||||
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 },
|
||||
});
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer: self.layer.to_path(),
|
||||
layer: self.layer,
|
||||
transform: editing_text.transform,
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: true,
|
||||
|
@ -310,7 +310,7 @@ impl TextToolData {
|
|||
|
||||
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
|
||||
} 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<()> {
|
||||
let layer = self.layer.to_path();
|
||||
let old_bounds = self.get_bounds(&self.editing_text.as_ref()?.text, font_cache)?;
|
||||
let new_bounds = self.get_bounds(new_text, font_cache)?;
|
||||
responses.add(GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds });
|
||||
responses.add(GraphOperationMessage::UpdateBounds {
|
||||
layer: self.layer,
|
||||
old_bounds: self.get_bounds(&self.editing_text.as_ref()?.text, font_cache)?,
|
||||
new_bounds: self.get_bounds(new_text, font_cache)?,
|
||||
});
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
@ -437,7 +438,6 @@ impl Fsm for TextToolFsmState {
|
|||
(TextToolFsmState::Editing, TextToolMessage::TextChange { new_text }) => {
|
||||
tool_data.fix_text_bounds(&new_text, document, font_cache, responses);
|
||||
responses.add(NodeGraphMessage::SetQualifiedInputValue {
|
||||
layer_path: Vec::new(),
|
||||
node_path: vec![graph_modification_utils::get_text_id(tool_data.layer, &document.network).unwrap()],
|
||||
input_index: 1,
|
||||
value: TaggedValue::String(new_text),
|
||||
|
|
|
@ -20,7 +20,7 @@ use std::fmt::{self, Debug};
|
|||
|
||||
pub struct ToolActionHandlerData<'a> {
|
||||
pub document: &'a DocumentMessageHandler,
|
||||
pub document_id: u64,
|
||||
pub document_id: DocumentId,
|
||||
pub global_tool_data: &'a DocumentToolData,
|
||||
pub input: &'a InputPreprocessorMessageHandler,
|
||||
pub font_cache: &'a FontCache,
|
||||
|
@ -30,7 +30,7 @@ pub struct ToolActionHandlerData<'a> {
|
|||
impl<'a> ToolActionHandlerData<'a> {
|
||||
pub fn new(
|
||||
document: &'a DocumentMessageHandler,
|
||||
document_id: u64,
|
||||
document_id: DocumentId,
|
||||
global_tool_data: &'a DocumentToolData,
|
||||
input: &'a InputPreprocessorMessageHandler,
|
||||
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::layer_panel::LayerClassification;
|
||||
use crate::messages::portfolio::document::utility_types::misc::LayerPanelEntry;
|
||||
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use graph_craft::concrete;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
||||
use graph_craft::graphene_compiler::Compiler;
|
||||
use graph_craft::imaginate_input::ImaginatePreferences;
|
||||
use graph_craft::{concrete, Type};
|
||||
use graphene_core::application_io::{ApplicationIo, NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||
use graphene_core::application_io::{NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||
use graphene_core::memo::IORecord;
|
||||
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::transform::{Footprint, Transform};
|
||||
use graphene_core::vector::style::ViewMode;
|
||||
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 interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||
|
||||
|
@ -31,22 +30,6 @@ use std::rc::Rc;
|
|||
use std::sync::mpsc::{Receiver, Sender};
|
||||
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(crate) executor: DynamicExecutor,
|
||||
font_cache: FontCache,
|
||||
|
@ -58,7 +41,6 @@ pub struct NodeRuntime {
|
|||
pub(crate) click_targets: HashMap<NodeId, Vec<ClickTarget>>,
|
||||
pub(crate) upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
|
||||
graph_hash: Option<u64>,
|
||||
canvas_cache: HashMap<Vec<LayerId>, SurfaceId>,
|
||||
monitor_nodes: Vec<Vec<NodeId>>,
|
||||
}
|
||||
|
||||
|
@ -81,7 +63,6 @@ pub struct ExportConfig {
|
|||
pub(crate) struct GenerationRequest {
|
||||
generation_id: u64,
|
||||
graph: NodeNetwork,
|
||||
path: Vec<LayerId>,
|
||||
render_config: RenderConfig,
|
||||
}
|
||||
|
||||
|
@ -129,7 +110,6 @@ impl NodeRuntime {
|
|||
imaginate_preferences: Default::default(),
|
||||
thumbnails: Default::default(),
|
||||
wasm_io: None,
|
||||
canvas_cache: HashMap::new(),
|
||||
click_targets: HashMap::new(),
|
||||
graph_hash: None,
|
||||
upstream_transforms: HashMap::new(),
|
||||
|
@ -142,7 +122,7 @@ impl NodeRuntime {
|
|||
// This should be avoided in the future.
|
||||
requests.reverse();
|
||||
requests.dedup_by_key(|x| match x {
|
||||
NodeRuntimeMessage::GenerationRequest(x) => Some(x.path.clone()),
|
||||
NodeRuntimeMessage::GenerationRequest(x) => Some(x.graph.current_hash()),
|
||||
_ => None,
|
||||
});
|
||||
requests.reverse();
|
||||
|
@ -151,17 +131,13 @@ impl NodeRuntime {
|
|||
NodeRuntimeMessage::FontCacheUpdate(font_cache) => self.font_cache = font_cache,
|
||||
NodeRuntimeMessage::ImaginatePreferencesUpdate(preferences) => self.imaginate_preferences = preferences,
|
||||
NodeRuntimeMessage::GenerationRequest(GenerationRequest {
|
||||
generation_id,
|
||||
graph,
|
||||
render_config,
|
||||
path,
|
||||
..
|
||||
generation_id, graph, render_config, ..
|
||||
}) => {
|
||||
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();
|
||||
|
||||
self.update_thumbnails(&path, &mut responses);
|
||||
self.update_thumbnails(&mut responses);
|
||||
self.update_upstream_transforms();
|
||||
|
||||
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() {
|
||||
self.wasm_io = Some(WasmApplicationIo::new().await);
|
||||
}
|
||||
|
@ -245,21 +221,21 @@ impl NodeRuntime {
|
|||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
if let TaggedValue::SurfaceFrame(SurfaceFrame { surface_id, transform: _ }) = result {
|
||||
let old_id = self.canvas_cache.insert(path.to_vec(), surface_id);
|
||||
if let Some(old_id) = old_id {
|
||||
if old_id != surface_id {
|
||||
if let Some(io) = self.wasm_io.as_ref() {
|
||||
io.destroy_surface(old_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if let TaggedValue::SurfaceFrame(SurfaceFrame { surface_id, transform: _ }) = result {
|
||||
// let old_id = self.canvas_cache.insert(path.to_vec(), surface_id);
|
||||
// if let Some(old_id) = old_id {
|
||||
// if old_id != surface_id {
|
||||
// if let Some(io) = self.wasm_io.as_ref() {
|
||||
// io.destroy_surface(old_id)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// 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();
|
||||
self.thumbnails.retain(|id, _| self.monitor_nodes.iter().any(|node_path| node_path.contains(id)));
|
||||
for node_path in &self.monitor_nodes {
|
||||
|
@ -299,8 +275,7 @@ impl NodeRuntime {
|
|||
}
|
||||
|
||||
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(create_image_data))
|
||||
image_data.extend(render.image_data.into_iter().filter_map(|(_, image)| NodeGraphExecutor::to_frontend_image_data(image, resize).ok()))
|
||||
}
|
||||
if !image_data.is_empty() {
|
||||
responses.add(FrontendMessage::UpdateImageData { document_id: 0, image_data });
|
||||
|
@ -370,15 +345,11 @@ pub async fn run_node_graph() {
|
|||
pub struct NodeGraphExecutor {
|
||||
sender: Sender<NodeRuntimeMessage>,
|
||||
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>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ExecutionContext {
|
||||
layer_path: Vec<LayerId>,
|
||||
export_config: Option<ExportConfig>,
|
||||
}
|
||||
|
||||
|
@ -394,18 +365,15 @@ impl Default for NodeGraphExecutor {
|
|||
futures: Default::default(),
|
||||
sender: request_sender,
|
||||
receiver: response_receiver,
|
||||
last_output_type: Default::default(),
|
||||
thumbnails: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeGraphExecutor {
|
||||
/// 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 request = GenerationRequest {
|
||||
path: layer_path,
|
||||
graph: network,
|
||||
generation_id,
|
||||
render_config,
|
||||
|
@ -470,23 +438,17 @@ impl NodeGraphExecutor {
|
|||
}
|
||||
|
||||
/// 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 mime = "image/bmp".to_string();
|
||||
let image_data = std::sync::Arc::new(image_data);
|
||||
|
||||
Ok(FrontendImageData {
|
||||
path: layer_path.to_vec(),
|
||||
node_id,
|
||||
image_data,
|
||||
mime,
|
||||
transform,
|
||||
})
|
||||
Ok(FrontendImageData { image_data, mime })
|
||||
}
|
||||
|
||||
/// 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
|
||||
let network = document.network().clone();
|
||||
|
||||
|
@ -506,9 +468,9 @@ impl NodeGraphExecutor {
|
|||
};
|
||||
|
||||
// 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(())
|
||||
}
|
||||
|
@ -541,11 +503,8 @@ impl NodeGraphExecutor {
|
|||
export_config.size = size;
|
||||
|
||||
// Execute the node graph
|
||||
let generation_id = self.queue_execution(network, Vec::new(), render_config);
|
||||
let execution_context = ExecutionContext {
|
||||
layer_path: Vec::new(),
|
||||
export_config: Some(export_config),
|
||||
};
|
||||
let generation_id = self.queue_execution(network, render_config);
|
||||
let execution_context = ExecutionContext { export_config: Some(export_config) };
|
||||
self.futures.insert(generation_id, execution_context);
|
||||
|
||||
Ok(())
|
||||
|
@ -626,16 +585,17 @@ impl NodeGraphExecutor {
|
|||
},
|
||||
expanded: layer.has_children(document_metadata) && !collapsed.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(),
|
||||
},
|
||||
});
|
||||
}
|
||||
self.thumbnails = new_thumbnails;
|
||||
document_metadata.update_transforms(new_upstream_transforms);
|
||||
document_metadata.update_click_targets(new_click_targets);
|
||||
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::DocumentStructureChanged);
|
||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||
|
@ -665,8 +625,7 @@ impl NodeGraphExecutor {
|
|||
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> {
|
||||
self.last_output_type.insert(layer_path.clone(), Some(node_graph_output.ty()));
|
||||
fn process_node_graph_output(&mut self, node_graph_output: TaggedValue, transform: DAffine2, responses: &mut VecDeque<Message>) -> Result<(), String> {
|
||||
match node_graph_output {
|
||||
TaggedValue::SurfaceFrame(SurfaceFrame { surface_id: _, transform: _ }) => {
|
||||
// TODO: Reimplement this now that document-legacy is gone
|
||||
|
@ -709,19 +668,4 @@ impl NodeGraphExecutor {
|
|||
};
|
||||
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::prelude::*;
|
||||
|
||||
use axum::body::StreamBody;
|
||||
use axum::extract::Path;
|
||||
use axum::http;
|
||||
use axum::response::IntoResponse;
|
||||
// use axum::body::StreamBody;
|
||||
// use axum::extract::Path;
|
||||
// use axum::http;
|
||||
// use axum::response::IntoResponse;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
use http::{Response, StatusCode};
|
||||
// use http::{Response, StatusCode};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
// use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
// use std::sync::Mutex;
|
||||
|
||||
static IMAGES: Mutex<Option<HashMap<String, FrontendImageData>>> = Mutex::new(None);
|
||||
thread_local! {
|
||||
static EDITOR: RefCell<Option<Editor>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
async fn respond_to(id: Path<String>) -> impl IntoResponse {
|
||||
let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
|
||||
// async fn respond_to(id: Path<String>) -> impl IntoResponse {
|
||||
// let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
|
||||
|
||||
let guard = IMAGES.lock().unwrap();
|
||||
let images = guard;
|
||||
let image = images.as_ref().unwrap().get(&id.0).unwrap();
|
||||
// let guard = IMAGES.lock().unwrap();
|
||||
// let images = guard;
|
||||
// let image = images.as_ref().unwrap().get(&id.0).unwrap();
|
||||
|
||||
println!("image: {:#?}", image.path);
|
||||
let result: Result<Vec<u8>, &str> = Ok((*image.image_data).clone());
|
||||
let stream = futures::stream::once(async move { result });
|
||||
builder.body(StreamBody::new(stream)).unwrap()
|
||||
}
|
||||
// println!("image: {:#?}", image.path);
|
||||
// let result: Result<Vec<u8>, &str> = Ok((*image.image_data).clone());
|
||||
// let stream = futures::stream::once(async move { result });
|
||||
// builder.body(StreamBody::new(stream)).unwrap()
|
||||
// }
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -56,10 +55,10 @@ async fn main() {
|
|||
.apply()
|
||||
.unwrap();
|
||||
|
||||
*(IMAGES.lock().unwrap()) = Some(HashMap::new());
|
||||
// *(IMAGES.lock().unwrap()) = Some(HashMap::new());
|
||||
graphite_editor::application::set_uuid_seed(0);
|
||||
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
|
||||
tauri::async_runtime::spawn(async {
|
||||
|
@ -78,8 +77,7 @@ async fn main() {
|
|||
}
|
||||
#[tauri::command]
|
||||
fn set_random_seed(seed: f64) {
|
||||
let seed = seed as u64;
|
||||
graphite_editor::application::set_uuid_seed(seed);
|
||||
graphite_editor::application::set_uuid_seed(seed as u64);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
@ -96,20 +94,11 @@ fn handle_message(message: String) -> String {
|
|||
fn send_frontend_message_to_js(message: FrontendMessage) -> FrontendMessage {
|
||||
// Special case for update image data to avoid serialization times.
|
||||
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());
|
||||
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 {
|
||||
path,
|
||||
node_id: None,
|
||||
mime,
|
||||
mime: image.mime.clone(),
|
||||
image_data: Arc::new(Vec::new()),
|
||||
transform,
|
||||
});
|
||||
}
|
||||
FrontendMessage::UpdateImageData { document_id, image_data: stub_data }
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import { beginDraggingElement } from "@graphite/io-managers/drag";
|
||||
import { platformIsMac } from "@graphite/utility-functions/platform";
|
||||
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 LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
|
||||
|
@ -27,8 +27,9 @@
|
|||
|
||||
type DraggingData = {
|
||||
select?: () => void;
|
||||
insertFolder: BigUint64Array;
|
||||
insertIndex: number;
|
||||
insertParentId: bigint | undefined;
|
||||
insertDepth: number;
|
||||
insertIndex: number | undefined;
|
||||
highlightFolder: boolean;
|
||||
markerHeight: number;
|
||||
};
|
||||
|
@ -42,7 +43,7 @@
|
|||
// Interactive dragging
|
||||
let draggable = true;
|
||||
let draggingData: undefined | DraggingData = undefined;
|
||||
let fakeHighlight: undefined | BigUint64Array[] = undefined;
|
||||
let fakeHighlight: undefined | bigint = undefined;
|
||||
let dragInPanel = false;
|
||||
|
||||
// Layouts
|
||||
|
@ -54,24 +55,24 @@
|
|||
layersPanelOptionsLayout = layersPanelOptionsLayout;
|
||||
});
|
||||
|
||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerTreeStructureJs, (updateDocumentLayerTreeStructure) => {
|
||||
rebuildLayerTree(updateDocumentLayerTreeStructure);
|
||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerStructureJs, (updateDocumentLayerStructure) => {
|
||||
rebuildLayerHierarchy(updateDocumentLayerStructure);
|
||||
});
|
||||
|
||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
|
||||
const targetLayer = updateDocumentLayerDetails.data;
|
||||
const targetPath = targetLayer.path;
|
||||
const targetId = targetLayer.id;
|
||||
|
||||
updateLayerInTree(targetPath, targetLayer);
|
||||
updateLayerInTree(targetId, targetLayer);
|
||||
});
|
||||
});
|
||||
|
||||
function toggleLayerVisibility(path: BigUint64Array) {
|
||||
editor.instance.toggleLayerVisibility(path);
|
||||
function toggleLayerVisibility(id: bigint) {
|
||||
editor.instance.toggleLayerVisibility(id);
|
||||
}
|
||||
|
||||
function handleExpandArrowClick(path: BigUint64Array) {
|
||||
editor.instance.toggleLayerExpansion(path);
|
||||
function handleExpandArrowClick(id: bigint) {
|
||||
editor.instance.toggleLayerExpansion(id);
|
||||
}
|
||||
|
||||
async function onEditLayerName(listing: LayerListingInfo) {
|
||||
|
@ -97,7 +98,7 @@
|
|||
layers = layers;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -120,16 +121,16 @@
|
|||
const [accel, oppositeAccel] = platformIsMac() ? [meta, ctrl] : [ctrl, meta];
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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
|
||||
if (listing.editingName) return;
|
||||
|
||||
editor.instance.selectLayer(listing.entry.path, accel, shift);
|
||||
editor.instance.selectLayer(listing.entry.id, accel, shift);
|
||||
}
|
||||
|
||||
async function deselectAllLayers() {
|
||||
|
@ -148,10 +149,11 @@
|
|||
let closest = Infinity;
|
||||
|
||||
// Folder to insert into
|
||||
let insertFolder = new BigUint64Array();
|
||||
let insertParentId: bigint | undefined = undefined;
|
||||
let insertDepth = 0;
|
||||
|
||||
// Insert index
|
||||
let insertIndex = -1;
|
||||
// Insert index (starts at the end, essentially infinity)
|
||||
let insertIndex = undefined;
|
||||
|
||||
// Whether you are inserting into a folder and should show the folder outline
|
||||
let highlightFolder = false;
|
||||
|
@ -171,7 +173,8 @@
|
|||
|
||||
// Inserting above current row
|
||||
if (distance > 0 && distance < closest) {
|
||||
insertFolder = layer.path.slice(0, layer.path.length - 1);
|
||||
insertParentId = layer.parentId;
|
||||
insertDepth = layer.depth - 1;
|
||||
insertIndex = folderIndex;
|
||||
highlightFolder = false;
|
||||
closest = distance;
|
||||
|
@ -179,15 +182,24 @@
|
|||
}
|
||||
// Inserting below current row
|
||||
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);
|
||||
insertIndex = isNestingLayer(layer.layerClassification) ? 0 : folderIndex + 1;
|
||||
highlightFolder = isNestingLayer(layer.layerClassification);
|
||||
if (isNestingLayer(layer.layerClassification)) {
|
||||
insertParentId = layer.id;
|
||||
insertDepth = layer.depth;
|
||||
insertIndex = 0;
|
||||
highlightFolder = true;
|
||||
} else {
|
||||
insertParentId = layer.parentId;
|
||||
insertDepth = layer.depth - 1;
|
||||
insertIndex = folderIndex + 1;
|
||||
highlightFolder = false;
|
||||
}
|
||||
|
||||
closest = -distance;
|
||||
markerHeight = index === treeChildren.length - 1 ? rect.bottom - INSERT_MARK_OFFSET : rect.bottom;
|
||||
}
|
||||
// Inserting with no nesting at the end of the panel
|
||||
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;
|
||||
}
|
||||
|
@ -199,7 +211,8 @@
|
|||
|
||||
return {
|
||||
select,
|
||||
insertFolder,
|
||||
insertParentId,
|
||||
insertDepth,
|
||||
insertIndex,
|
||||
highlightFolder,
|
||||
markerHeight,
|
||||
|
@ -210,10 +223,10 @@
|
|||
const layer = listing.entry;
|
||||
dragInPanel = true;
|
||||
if (!layer.selected) {
|
||||
fakeHighlight = [layer.path];
|
||||
fakeHighlight = layer.id;
|
||||
}
|
||||
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;
|
||||
|
@ -240,58 +253,49 @@
|
|||
|
||||
async function drop() {
|
||||
if (draggingData && dragInPanel) {
|
||||
const { select, insertFolder, insertIndex } = draggingData;
|
||||
const { select, insertParentId, insertIndex } = draggingData;
|
||||
|
||||
select?.();
|
||||
editor.instance.moveLayerInTree(insertFolder, insertIndex);
|
||||
editor.instance.moveLayerInTree(insertParentId, insertIndex);
|
||||
}
|
||||
draggingData = undefined;
|
||||
fakeHighlight = undefined;
|
||||
dragInPanel = false;
|
||||
}
|
||||
|
||||
function rebuildLayerTree(updateDocumentLayerTreeStructure: UpdateDocumentLayerTreeStructureJs) {
|
||||
function rebuildLayerHierarchy(updateDocumentLayerStructure: UpdateDocumentLayerStructureJs) {
|
||||
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
|
||||
const layerPathWithNameBeingEdited = layerWithNameBeingEdited?.entry.path;
|
||||
const layerIdWithNameBeingEdited = layerPathWithNameBeingEdited?.slice(-1)[0];
|
||||
const path: bigint[] = [];
|
||||
const layerIdWithNameBeingEdited = layerWithNameBeingEdited?.entry.id;
|
||||
|
||||
// Clear the layer tree before rebuilding it
|
||||
// Clear the layer hierarchy before rebuilding it
|
||||
layers = [];
|
||||
|
||||
// Build the new layer tree
|
||||
const recurse = (folder: UpdateDocumentLayerTreeStructureJs) => {
|
||||
// Build the new layer hierarchy
|
||||
const recurse = (folder: UpdateDocumentLayerStructureJs) => {
|
||||
folder.children.forEach((item, index) => {
|
||||
// TODO: fix toString
|
||||
const layerId = BigInt(item.layerId.toString());
|
||||
path.push(layerId);
|
||||
|
||||
const mapping = layerCache.get([path[path.length - 1]].toString());
|
||||
const mapping = layerCache.get(String(item.layerId));
|
||||
if (mapping) {
|
||||
mapping.path = new BigUint64Array(path);
|
||||
mapping.id = item.layerId;
|
||||
layers.push({
|
||||
folderIndex: index,
|
||||
bottomLayer: index === folder.children.length - 1,
|
||||
entry: mapping,
|
||||
editingName: layerIdWithNameBeingEdited === layerId,
|
||||
editingName: layerIdWithNameBeingEdited === item.layerId,
|
||||
});
|
||||
}
|
||||
|
||||
// Call self recursively if there are any children
|
||||
if (item.children.length >= 1) recurse(item);
|
||||
|
||||
path.pop();
|
||||
});
|
||||
};
|
||||
recurse(updateDocumentLayerTreeStructure);
|
||||
recurse(updateDocumentLayerStructure);
|
||||
layers = layers;
|
||||
}
|
||||
|
||||
function updateLayerInTree(targetPath: BigUint64Array, targetLayer: LayerPanelEntry) {
|
||||
const path = targetPath.toString();
|
||||
layerCache.set(path, targetLayer);
|
||||
function updateLayerInTree(targetId: bigint, targetLayer: LayerPanelEntry) {
|
||||
layerCache.set(String(targetId), targetLayer);
|
||||
|
||||
const layer = layers.find((layer: LayerListingInfo) => layer.entry.path.toString() === path);
|
||||
const layer = layers.find((layer: LayerListingInfo) => layer.entry.id === targetId);
|
||||
if (layer) {
|
||||
layer.entry = targetLayer;
|
||||
layers = layers;
|
||||
|
@ -305,15 +309,15 @@
|
|||
</LayoutRow>
|
||||
<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()}>
|
||||
{#each layers as listing, index (String(listing.entry.path.slice(-1)))}
|
||||
{#each layers as listing, index (String(listing.entry.id))}
|
||||
<LayoutRow
|
||||
class="layer"
|
||||
classes={{
|
||||
selected: fakeHighlight ? fakeHighlight.includes(listing.entry.path) : listing.entry.selected,
|
||||
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertFolder === listing.entry.path,
|
||||
selected: fakeHighlight !== undefined ? fakeHighlight === listing.entry.id : listing.entry.selected,
|
||||
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertParentId === listing.entry.id,
|
||||
}}
|
||||
styles={{ "--layer-indent-levels": `${listing.entry.path.length - 1}` }}
|
||||
data-layer={String(listing.entry.path)}
|
||||
styles={{ "--layer-indent-levels": `${listing.entry.depth - 1}` }}
|
||||
data-layer
|
||||
data-index={index}
|
||||
tooltip={listing.entry.tooltip}
|
||||
{draggable}
|
||||
|
@ -321,7 +325,7 @@
|
|||
on:click={(e) => selectLayerWithModifiers(e, listing)}
|
||||
>
|
||||
{#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"}
|
||||
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
||||
{:else if listing.entry.layerClassification === "Folder"}
|
||||
|
@ -347,7 +351,7 @@
|
|||
</LayoutRow>
|
||||
<IconButton
|
||||
class={"visibility"}
|
||||
action={(e) => (toggleLayerVisibility(listing.entry.path), e?.stopPropagation())}
|
||||
action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())}
|
||||
size={24}
|
||||
icon={(() => true)() ? "EyeVisible" : "EyeHidden"}
|
||||
tooltip={(() => true)() ? "Visible" : "Hidden"}
|
||||
|
@ -356,7 +360,7 @@
|
|||
{/each}
|
||||
</LayoutCol>
|
||||
{#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}
|
||||
</LayoutRow>
|
||||
</LayoutCol>
|
||||
|
@ -387,7 +391,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Layer tree
|
||||
// Layer hierarchy
|
||||
.list-area {
|
||||
margin: 4px 0;
|
||||
position: relative;
|
||||
|
|
|
@ -116,8 +116,8 @@
|
|||
const from = connectorToNodeIndex(linkInProgressFromConnector);
|
||||
const to = linkInProgressToConnector instanceof SVGSVGElement ? connectorToNodeIndex(linkInProgressToConnector) : undefined;
|
||||
|
||||
const linkStart = $nodeGraph.nodes.find((node) => node.id === from?.nodeId)?.isLayer;
|
||||
const linkEnd = $nodeGraph.nodes.find((node) => node.id === to?.nodeId)?.isLayer && to?.index !== 0;
|
||||
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) || false;
|
||||
return createWirePath(linkInProgressFromConnector, linkInProgressToConnector, linkStart, linkEnd);
|
||||
}
|
||||
return undefined;
|
||||
|
@ -158,8 +158,8 @@
|
|||
const { nodeInput, nodeOutput } = resolveLink(link);
|
||||
if (!nodeInput || !nodeOutput) return [];
|
||||
if (disconnecting?.linkIndex === index) return [];
|
||||
const linkStart = $nodeGraph.nodes.find((node) => node.id === link.linkStart)?.isLayer;
|
||||
const linkEnd = $nodeGraph.nodes.find((node) => node.id === link.linkEnd)?.isLayer && link.linkEndInputIndex !== 0n;
|
||||
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) || false;
|
||||
|
||||
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}>
|
||||
<!-- Layers -->
|
||||
{#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]}
|
||||
<div
|
||||
class="layer"
|
||||
|
@ -756,7 +756,7 @@
|
|||
<!-- Nodes -->
|
||||
{#each $nodeGraph.nodes.flatMap((node, nodeIndex) => (node.isLayer ? [] : [{ node, nodeIndex }])) as { node, nodeIndex } (nodeIndex)}
|
||||
{@const exposedInputsOutputs = [...node.exposedInputs, ...node.exposedOutputs]}
|
||||
{@const clipPathId = `${Math.random()}`.substring(2)}
|
||||
{@const clipPathId = String(Math.random()).substring(2)}
|
||||
<div
|
||||
class="node"
|
||||
class:selected={selected.includes(node.id)}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
export let hideContextMenu = false;
|
||||
|
||||
let inputOrTextarea: HTMLInputElement | HTMLTextAreaElement | undefined;
|
||||
let id = `${Math.random()}`.substring(2);
|
||||
let id = String(Math.random()).substring(2);
|
||||
let macKeyboardLayout = platformIsMac();
|
||||
|
||||
$: inputValue = value;
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
|
||||
function onTextFocused() {
|
||||
if (value === undefined) text = "";
|
||||
else if (unitIsHiddenWhenEditing) text = `${value}`;
|
||||
else if (unitIsHiddenWhenEditing) text = String(value);
|
||||
else text = `${value}${unPluralize(unit, value)}`;
|
||||
|
||||
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 timeString = `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
||||
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
|
||||
|
|
|
@ -33,7 +33,7 @@ export function panicProxy<T extends object>(module: T): T {
|
|||
result = targetValue.apply(this, args);
|
||||
} catch (err) {
|
||||
// Suppress `unreachable` WebAssembly.RuntimeError exceptions
|
||||
if (!`${err}`.startsWith("RuntimeError: unreachable")) throw err;
|
||||
if (!String(err).startsWith("RuntimeError: unreachable")) throw err;
|
||||
}
|
||||
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()`
|
||||
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");
|
||||
export async function dispatchTauri(message: unknown) {
|
||||
if (!tauri) return;
|
||||
|
|
|
@ -560,10 +560,10 @@ export class TriggerSavePreferences extends JsMessage {
|
|||
|
||||
export class DocumentChanged extends JsMessage {}
|
||||
|
||||
export class UpdateDocumentLayerTreeStructureJs extends JsMessage {
|
||||
export class UpdateDocumentLayerStructureJs extends JsMessage {
|
||||
constructor(
|
||||
readonly layerId: bigint,
|
||||
readonly children: UpdateDocumentLayerTreeStructureJs[],
|
||||
readonly children: UpdateDocumentLayerStructureJs[],
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ type DataBuffer = {
|
|||
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 lengthNum = Number(input.dataBuffer.length);
|
||||
|
||||
|
@ -591,7 +591,7 @@ export function newUpdateDocumentLayerTreeStructure(input: { dataBuffer: DataBuf
|
|||
const layerIdsSection = new DataView(wasmMemoryBuffer, pointerNum + 8 + structureSectionLength * 8);
|
||||
|
||||
let layersEncountered = 0;
|
||||
let currentFolder = new UpdateDocumentLayerTreeStructureJs(BigInt(-1), []);
|
||||
let currentFolder = new UpdateDocumentLayerStructureJs(BigInt(-1), []);
|
||||
const currentFolderStack = [currentFolder];
|
||||
|
||||
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);
|
||||
layersEncountered += 1;
|
||||
|
||||
const childLayer = new UpdateDocumentLayerTreeStructureJs(layerId, []);
|
||||
const childLayer = new UpdateDocumentLayerStructureJs(layerId, []);
|
||||
currentFolder.children.push(childLayer);
|
||||
}
|
||||
|
||||
|
@ -650,8 +650,8 @@ export class DisplayEditableTextboxTransform extends JsMessage {
|
|||
export class UpdateImageData extends JsMessage {
|
||||
readonly documentId!: bigint;
|
||||
|
||||
@Type(() => RenderedImageData)
|
||||
readonly imageData!: RenderedImageData[];
|
||||
@Type(() => FrontendImageData)
|
||||
readonly imageData!: FrontendImageData[];
|
||||
}
|
||||
|
||||
export class DisplayRemoveEditableTextbox extends JsMessage {}
|
||||
|
@ -669,8 +669,12 @@ export class LayerPanelEntry {
|
|||
|
||||
layerClassification!: LayerClassification;
|
||||
|
||||
@Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value))
|
||||
path!: BigUint64Array;
|
||||
parentId!: bigint | undefined;
|
||||
|
||||
id!: bigint;
|
||||
|
||||
@Transform(({ value }: { value: bigint }) => Number(value))
|
||||
depth!: number;
|
||||
|
||||
expanded!: boolean;
|
||||
|
||||
|
@ -681,16 +685,10 @@ export class LayerPanelEntry {
|
|||
|
||||
export type LayerClassification = "Folder" | "Artboard" | "Layer";
|
||||
|
||||
export class RenderedImageData {
|
||||
readonly path!: BigUint64Array;
|
||||
|
||||
readonly nodeId!: bigint;
|
||||
|
||||
export class FrontendImageData {
|
||||
readonly mime!: string;
|
||||
|
||||
readonly imageData!: Uint8Array;
|
||||
|
||||
readonly transform!: Float64Array;
|
||||
}
|
||||
|
||||
export class DisplayDialogDismiss extends JsMessage {}
|
||||
|
@ -1381,7 +1379,7 @@ export const messageMakers: Record<string, MessageMaker> = {
|
|||
UpdateDocumentArtwork,
|
||||
UpdateDocumentBarLayout,
|
||||
UpdateDocumentLayerDetails,
|
||||
UpdateDocumentLayerTreeStructureJs: newUpdateDocumentLayerTreeStructure,
|
||||
UpdateDocumentLayerStructureJs: newUpdateDocumentLayerStructure,
|
||||
UpdateDocumentModeLayout,
|
||||
UpdateDocumentRulers,
|
||||
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_mouse::{EditorMouseState, ScrollDelta, ViewportBounds};
|
||||
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::prelude::*;
|
||||
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.
|
||||
#[wasm_bindgen(module = "/../src/wasm-communication/editor.ts")]
|
||||
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);
|
||||
}
|
||||
|
@ -160,29 +157,28 @@ impl JsEditorHandle {
|
|||
// Sends a FrontendMessage to JavaScript
|
||||
fn send_frontend_message_to_js(&self, mut message: FrontendMessage) {
|
||||
// Special case for update image data to avoid serialization times.
|
||||
if let FrontendMessage::UpdateImageData { document_id, image_data } = message {
|
||||
for image in image_data {
|
||||
#[cfg(not(feature = "tauri"))]
|
||||
{
|
||||
let transform = if let Some(transform_val) = image.transform {
|
||||
let transform = js_sys::Float64Array::new_with_length(6);
|
||||
transform.copy_from(&transform_val);
|
||||
transform
|
||||
} else {
|
||||
js_sys::Float64Array::default()
|
||||
};
|
||||
updateImage(image.path, image.node_id, image.mime, &image.image_data, transform, document_id);
|
||||
}
|
||||
#[cfg(feature = "tauri")]
|
||||
{
|
||||
let identifier = format!("http://localhost:3001/image/{:?}_{}", image.path, document_id);
|
||||
fetchImage(image.path.clone(), image.node_id, image.mime, document_id, identifier);
|
||||
}
|
||||
}
|
||||
if let FrontendMessage::UpdateImageData { document_id: _, image_data: _ } = message {
|
||||
// for image in image_data {
|
||||
// #[cfg(not(feature = "tauri"))]
|
||||
// {
|
||||
// let transform = if let Some(transform_val) = image.transform {
|
||||
// let transform = js_sys::Float64Array::new_with_length(6);
|
||||
// transform.copy_from(&transform_val);
|
||||
// transform
|
||||
// } else {
|
||||
// js_sys::Float64Array::default()
|
||||
// };
|
||||
// }
|
||||
// #[cfg(feature = "tauri")]
|
||||
// {
|
||||
// let identifier = format!("http://localhost:3001/image/{:?}_{}", image.path, document_id);
|
||||
// fetchImage(image.path.clone(), image.node_id, image.mime, document_id, identifier);
|
||||
// }
|
||||
// }
|
||||
return;
|
||||
}
|
||||
if let FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer } = message {
|
||||
message = FrontendMessage::UpdateDocumentLayerTreeStructureJs { data_buffer: data_buffer.into() };
|
||||
if let FrontendMessage::UpdateDocumentLayerStructure { data_buffer } = message {
|
||||
message = FrontendMessage::UpdateDocumentLayerStructureJs { data_buffer: data_buffer.into() };
|
||||
}
|
||||
|
||||
let message_type = message.to_discriminant().local_name();
|
||||
|
@ -298,7 +294,7 @@ impl JsEditorHandle {
|
|||
}
|
||||
|
||||
#[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 };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
@ -331,7 +327,7 @@ impl JsEditorHandle {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
document_id,
|
||||
document_name,
|
||||
|
@ -343,13 +339,13 @@ impl JsEditorHandle {
|
|||
}
|
||||
|
||||
#[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 };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
#[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 };
|
||||
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
|
||||
#[wasm_bindgen(js_name = selectLayer)]
|
||||
pub fn select_layer(&self, layer_path: Vec<LayerId>, ctrl: bool, shift: bool) {
|
||||
let message = DocumentMessage::SelectLayer { layer_path, ctrl, shift };
|
||||
pub fn select_layer(&self, id: NodeId, ctrl: bool, shift: bool) {
|
||||
let message = DocumentMessage::SelectLayer { id, ctrl, shift };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
|
@ -544,20 +540,23 @@ impl JsEditorHandle {
|
|||
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)]
|
||||
pub fn move_layer_in_tree(&self, folder_path: Vec<LayerId>, insert_index: isize) {
|
||||
let parent = folder_path.last().copied().map(LayerNodeIdentifier::new_unchecked).unwrap_or(LayerNodeIdentifier::ROOT);
|
||||
|
||||
let message = DocumentMessage::MoveSelectedLayersTo { parent, insert_index };
|
||||
pub fn move_layer_in_tree(&self, insert_parent_id: Option<NodeId>, insert_index: Option<usize>) {
|
||||
let parent = insert_parent_id.map(|id| LayerNodeIdentifier::new_unchecked(id)).unwrap_or(LayerNodeIdentifier::default());
|
||||
let message = DocumentMessage::MoveSelectedLayersTo {
|
||||
parent,
|
||||
insert_index: insert_index.map(|x| x as isize).unwrap_or(-1),
|
||||
};
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Set the name for the layer
|
||||
#[wasm_bindgen(js_name = setLayerName)]
|
||||
pub fn set_layer_name(&self, layer_path: Vec<LayerId>, name: String) {
|
||||
let node_id = *layer_path.last().unwrap();
|
||||
let message = NodeGraphMessage::SetName { node_id, name };
|
||||
pub fn set_layer_name(&self, id: NodeId, name: String) {
|
||||
let message = NodeGraphMessage::SetName { node_id: id, name };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
|
@ -575,23 +574,9 @@ impl JsEditorHandle {
|
|||
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
|
||||
#[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 {
|
||||
output_node,
|
||||
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
|
||||
#[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 };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Notifies the backend that the user disconnected a node
|
||||
#[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 };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
@ -629,7 +614,7 @@ impl JsEditorHandle {
|
|||
|
||||
/// Creates a new document node in the node graph
|
||||
#[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 message = NodeGraphMessage::CreateNode { node_id: Some(id), node_type, x, y };
|
||||
self.dispatch(message);
|
||||
|
@ -638,7 +623,7 @@ impl JsEditorHandle {
|
|||
|
||||
/// Notifies the backend that the user selected a node in the node graph
|
||||
#[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 message = NodeGraphMessage::SelectedNodesSet { nodes };
|
||||
self.dispatch(message);
|
||||
|
@ -653,7 +638,7 @@ impl JsEditorHandle {
|
|||
|
||||
/// Notifies the backend that the user double clicked a node
|
||||
#[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 };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
@ -686,15 +671,15 @@ impl JsEditorHandle {
|
|||
|
||||
/// Toggle visibility of a layer from the layer list
|
||||
#[wasm_bindgen(js_name = toggleLayerVisibility)]
|
||||
pub fn toggle_layer_visibility(&self, layer_path: Vec<LayerId>) {
|
||||
let message = NodeGraphMessage::ToggleHidden { node_id: *layer_path.last().unwrap() };
|
||||
pub fn toggle_layer_visibility(&self, id: NodeId) {
|
||||
let message = NodeGraphMessage::ToggleHidden { node_id: id };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Toggle expansions state of a layer from the layer list
|
||||
#[wasm_bindgen(js_name = toggleLayerExpansion)]
|
||||
pub fn toggle_layer_expansion(&self, layer_path: Vec<LayerId>) {
|
||||
let message = DocumentMessage::ToggleLayerExpansion { layer: *layer_path.last().unwrap() };
|
||||
pub fn toggle_layer_expansion(&self, id: NodeId) {
|
||||
let message = DocumentMessage::ToggleLayerExpansion { id };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ use wasm_bindgen::prelude::*;
|
|||
pub static EDITOR_HAS_CRASHED: AtomicBool = AtomicBool::new(false);
|
||||
pub static LOGGER: WasmLog = WasmLog;
|
||||
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 JS_EDITOR_HANDLES: RefCell<HashMap<u64, editor_api::JsEditorHandle>> = RefCell::new(HashMap::new());
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ fn add_network() -> NodeNetwork {
|
|||
}]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, n)| (i as u64, n))
|
||||
.map(|(id, node)| (id as NodeId, node))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ use alloc::vec::Vec;
|
|||
/// 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.
|
||||
|
||||
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)]
|
||||
pub struct IdBackedVec<T> {
|
||||
/// Contained elements
|
||||
|
@ -124,7 +125,7 @@ impl<T> IdBackedVec<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())
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ impl core::hash::Hash for Gradient {
|
|||
}
|
||||
impl Gradient {
|
||||
/// 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 {
|
||||
start,
|
||||
end,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::consts::ManipulatorType;
|
||||
use super::id_vec::IdBackedVec;
|
||||
use super::manipulator_group::ManipulatorGroup;
|
||||
use super::manipulator_point::ManipulatorPoint;
|
||||
use super::{consts::ManipulatorType, id_vec::ElementId};
|
||||
use crate::uuid::ManipulatorGroupId;
|
||||
|
||||
use alloc::string::String;
|
||||
|
@ -204,7 +204,7 @@ impl Subpath {
|
|||
|
||||
/// Delete the selected points from the [Subpath]
|
||||
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() {
|
||||
if manipulator_group.is_anchor_selected() {
|
||||
ids_to_delete.push(*id);
|
||||
|
@ -228,7 +228,7 @@ impl Subpath {
|
|||
// ** SELECTION OF POINTS **
|
||||
|
||||
/// 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;
|
||||
if let Some(manipulator_group) = self.manipulator_groups_mut().by_id_mut(manipulator_group_id) {
|
||||
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)`.
|
||||
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| {
|
||||
self.select_point(*point, selected);
|
||||
});
|
||||
|
|
|
@ -12,11 +12,12 @@ use std::hash::{Hash, Hasher};
|
|||
|
||||
pub mod value;
|
||||
|
||||
// TODO: Convert from a type alias to a newtype
|
||||
pub type NodeId = u64;
|
||||
|
||||
/// 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.
|
||||
fn merge_ids(a: u64, b: u64) -> u64 {
|
||||
fn merge_ids(a: NodeId, b: NodeId) -> NodeId {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
a.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.
|
||||
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 {
|
||||
stack: node_ids,
|
||||
network: self,
|
||||
|
@ -654,13 +655,13 @@ impl NodeNetwork {
|
|||
|
||||
/// Check there are no cycles in the graph (this should never happen).
|
||||
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 {
|
||||
dependencies.insert(
|
||||
*node_id,
|
||||
node.inputs
|
||||
.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(),
|
||||
);
|
||||
}
|
||||
|
@ -734,11 +735,12 @@ impl NodeNetwork {
|
|||
|
||||
/// 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>> {
|
||||
let mut outwards_links: HashMap<u64, Vec<u64>> = HashMap::new();
|
||||
for (node_id, node) in &self.nodes {
|
||||
let mut outwards_links: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
||||
for (current_node_id, node) in &self.nodes {
|
||||
for input in &node.inputs {
|
||||
if let NodeInput::Node { node_id: ref_id, .. } = input {
|
||||
outwards_links.entry(*ref_id).or_default().push(*node_id)
|
||||
if let NodeInput::Node { node_id, .. } = input {
|
||||
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),
|
||||
ImaginateMaskStartingFill(ImaginateMaskStartingFill),
|
||||
ImaginateController(ImaginateController),
|
||||
LayerPath(Option<Vec<u64>>),
|
||||
VectorData(graphene_core::vector::VectorData),
|
||||
Fill(graphene_core::vector::style::Fill),
|
||||
Stroke(graphene_core::vector::style::Stroke),
|
||||
|
@ -104,7 +103,6 @@ impl Hash for TaggedValue {
|
|||
Self::ImaginateSamplingMethod(x) => x.hash(state),
|
||||
Self::ImaginateMaskStartingFill(x) => x.hash(state),
|
||||
Self::ImaginateController(x) => x.hash(state),
|
||||
Self::LayerPath(x) => x.hash(state),
|
||||
Self::ImageFrame(x) => x.hash(state),
|
||||
Self::VectorData(x) => x.hash(state),
|
||||
Self::Fill(x) => x.hash(state),
|
||||
|
@ -179,7 +177,6 @@ impl<'a> TaggedValue {
|
|||
TaggedValue::ImaginateSamplingMethod(x) => Box::new(x),
|
||||
TaggedValue::ImaginateMaskStartingFill(x) => Box::new(x),
|
||||
TaggedValue::ImaginateController(x) => Box::new(x),
|
||||
TaggedValue::LayerPath(x) => Box::new(x),
|
||||
TaggedValue::VectorData(x) => Box::new(x),
|
||||
TaggedValue::Fill(x) => Box::new(x),
|
||||
TaggedValue::Stroke(x) => Box::new(x),
|
||||
|
@ -252,7 +249,6 @@ impl<'a> TaggedValue {
|
|||
TaggedValue::ImaginateSamplingMethod(_) => concrete!(ImaginateSamplingMethod),
|
||||
TaggedValue::ImaginateMaskStartingFill(_) => concrete!(ImaginateMaskStartingFill),
|
||||
TaggedValue::ImaginateController(_) => concrete!(ImaginateController),
|
||||
TaggedValue::LayerPath(_) => concrete!(Option<Vec<u64>>),
|
||||
TaggedValue::DAffine2(_) => concrete!(DAffine2),
|
||||
TaggedValue::LuminanceCalculation(_) => concrete!(LuminanceCalculation),
|
||||
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::<ImaginateMaskStartingFill>() => Ok(TaggedValue::ImaginateMaskStartingFill(*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::<LuminanceCalculation>() => Ok(TaggedValue::LuminanceCalculation(*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 document_node_path: Vec<NodeId>,
|
||||
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,
|
||||
}
|
||||
|
||||
|
@ -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`.
|
||||
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
|
||||
if let Some(referring_nodes) = outwards_edges.get(&node_id) {
|
||||
for &referring_node_id in referring_nodes {
|
||||
|
|
|
@ -246,7 +246,7 @@ async fn create_compute_pass_descriptor<T: Clone + Pixel + StaticTypeSized>(
|
|||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, n)| (i as u64, n))
|
||||
.map(|(id, node)| (id as NodeId, node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -464,7 +464,7 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
|
|||
}]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, n)| (i as u64, n))
|
||||
.map(|(id, node)| (id as NodeId, node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
};
|
||||
|
|
|
@ -274,7 +274,6 @@ pub async fn imaginate<'a, P: Pixel>(
|
|||
negative_prompt: impl Future<Output = String>,
|
||||
adapt_input_image: impl Future<Output = bool>,
|
||||
image_creativity: impl Future<Output = f32>,
|
||||
masking_layer: impl Future<Output = Option<Vec<u64>>>,
|
||||
inpaint: impl Future<Output = bool>,
|
||||
mask_blur: impl Future<Output = f32>,
|
||||
mask_starting_fill: impl Future<Output = ImaginateMaskStartingFill>,
|
||||
|
@ -305,7 +304,6 @@ pub async fn imaginate<'a, P: Pixel>(
|
|||
negative_prompt,
|
||||
adapt_input_image,
|
||||
image_creativity,
|
||||
masking_layer,
|
||||
inpaint,
|
||||
mask_blur,
|
||||
mask_starting_fill,
|
||||
|
@ -343,7 +341,6 @@ async fn imaginate_maybe_fail<'a, P: Pixel, F: Fn(ImaginateStatus)>(
|
|||
negative_prompt: impl Future<Output = String>,
|
||||
adapt_input_image: impl Future<Output = bool>,
|
||||
image_creativity: impl Future<Output = f32>,
|
||||
_masking_layer: impl Future<Output = Option<Vec<u64>>>,
|
||||
_inpaint: impl Future<Output = bool>,
|
||||
_mask_blur: impl Future<Output = f32>,
|
||||
_mask_starting_fill: impl Future<Output = ImaginateMaskStartingFill>,
|
||||
|
|
|
@ -533,7 +533,6 @@ generate_imaginate_node! {
|
|||
negative_prompt: NegativePrompt: String,
|
||||
adapt_input_image: AdaptInputImage: bool,
|
||||
image_creativity: ImageCreativity: f32,
|
||||
masking_layer: MaskingLayer: Option<Vec<u64>>,
|
||||
inpaint: Inpaint: bool,
|
||||
mask_blur: MaskBlur: f32,
|
||||
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)]),
|
||||
),
|
||||
(
|
||||
ProtoNodeIdentifier::new("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||
ProtoNodeIdentifier::new("graphene_std::raster::ImaginateNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"),
|
||||
|args: Vec<graph_craft::proto::SharedNodeContainer>| {
|
||||
Box::pin(async move {
|
||||
use graphene_std::raster::ImaginateNode;
|
||||
macro_rules! instantiate_imaginate_node {
|
||||
($($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);
|
||||
any.into_type_erased()
|
||||
})
|
||||
|
@ -632,7 +632,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
fn_type!(String),
|
||||
fn_type!(bool),
|
||||
fn_type!(f32),
|
||||
fn_type!(Option<Vec<u64>>),
|
||||
fn_type!(bool),
|
||||
fn_type!(f32),
|
||||
fn_type!(ImaginateMaskStartingFill),
|
||||
|
|
|
@ -40,7 +40,9 @@ A message is an enum variant of a certain message sub-type like `FrontendMessage
|
|||
DocumentMessage::DeleteSelectedLayers
|
||||
|
||||
// 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:
|
||||
|
@ -66,3 +68,8 @@ instead of:
|
|||
```rs
|
||||
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.
|
||||
|
||||
## 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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue