Desktop: Add native file dialogs (#2939)

* Add native open file dialog

* Add native save file dialog

* Fix integer underflow in defer message handler

* Update nix flake

* Cleanup

---------

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
Timon
2025-08-04 15:58:33 +02:00
committed by GitHub
parent c98477d8ed
commit 7cb42b9523
15 changed files with 665 additions and 64 deletions

View File

@@ -25,8 +25,8 @@ impl MessageHandler<DeferMessage, ()> for DeferMessageHandler {
return;
}
// Find the index of the last message we can process
let num_elements_to_remove = self.after_graph_run.binary_search_by_key(&(execution_id + 1), |x| x.0).unwrap_or_else(|pos| pos - 1);
let elements = self.after_graph_run.drain(0..=num_elements_to_remove);
let split = self.after_graph_run.partition_point(|&(id, _)| id <= execution_id);
let elements = self.after_graph_run.drain(..split);
for (_, message) in elements.rev() {
responses.add_front(message);
}

View File

@@ -12,6 +12,7 @@ use graph_craft::document::NodeId;
use graphene_std::raster::Image;
use graphene_std::raster::color::Color;
use graphene_std::text::{Font, TextAlign};
use std::path::PathBuf;
#[cfg(not(target_family = "wasm"))]
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
@@ -63,6 +64,12 @@ pub enum FrontendMessage {
#[serde(rename = "commitDate")]
commit_date: String,
},
TriggerSaveDocument {
document_id: DocumentId,
name: String,
path: Option<PathBuf>,
document: String,
},
TriggerDownloadImage {
svg: String,
name: String,

View File

@@ -1,3 +1,5 @@
use std::path::PathBuf;
use super::utility_types::misc::{GroupFolderType, SnappingState};
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
@@ -105,6 +107,9 @@ pub enum DocumentMessage {
RenderRulers,
RenderScrollbars,
SaveDocument,
SavedDocument {
path: Option<PathBuf>,
},
SelectParentLayer,
SelectAllLayers,
SelectedLayersLower,

View File

@@ -37,6 +37,7 @@ use graphene_std::table::Table;
use graphene_std::vector::PointId;
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
use graphene_std::vector::style::ViewMode;
use std::path::PathBuf;
use std::time::Duration;
#[derive(ExtractField)]
@@ -115,6 +116,9 @@ pub struct DocumentMessageHandler {
/// Stack of document network snapshots for future history states.
#[serde(skip)]
document_redo_history: VecDeque<NodeNetworkInterface>,
/// The path of the to the document file.
#[serde(skip)]
path: Option<PathBuf>,
/// Hash of the document snapshot that was most recently saved to disk by the user.
#[serde(skip)]
saved_hash: Option<u64>,
@@ -162,6 +166,7 @@ impl Default for DocumentMessageHandler {
selection_network_path: Vec::new(),
document_undo_history: VecDeque::new(),
document_redo_history: VecDeque::new(),
path: None,
saved_hash: None,
auto_saved_hash: None,
layer_range_selection_reference: None,
@@ -996,11 +1001,16 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
true => self.name.clone(),
false => self.name.clone() + FILE_SAVE_SUFFIX,
};
responses.add(FrontendMessage::TriggerDownloadTextFile {
document: self.serialize_document(),
responses.add(FrontendMessage::TriggerSaveDocument {
document_id,
name,
path: self.path.clone(),
document: self.serialize_document(),
})
}
DocumentMessage::SavedDocument { path } => {
self.path = path;
}
DocumentMessage::SelectParentLayer => {
let selected_nodes = self.network_interface.selected_nodes();
let selected_layers = selected_nodes.selected_layers(self.metadata());