Skip to content

Commit f29562d

Browse files
committed
DRAFT: Add support for saving full document
Most of the code is similar to the export functionality. The exception is that this document will encompass additional non-svg data. The `SerializeData` request accepts an `action` string that it opaquely passes through. The response handler can use the `action` string to decide if the serialization is for saving or auto-saving.
1 parent 09f8f44 commit f29562d

File tree

8 files changed

+48
-2
lines changed

8 files changed

+48
-2
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/web/src/components/panels/Document.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@
240240
<script lang="ts">
241241
import { defineComponent } from "vue";
242242
import { makeModifiersBitfield } from "@/utilities/input";
243-
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, SetActiveTool, ExportDocument, SetCanvasZoom, SetCanvasRotation } from "@/utilities/response-handler";
243+
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, SetActiveTool, ExportDocument, SetCanvasZoom, SetCanvasRotation, SerializeDocument } from "@/utilities/response-handler";
244244
import LayoutRow from "@/components/layout/LayoutRow.vue";
245245
import LayoutCol from "@/components/layout/LayoutCol.vue";
246246
import SwatchPairInput from "@/components/widgets/inputs/SwatchPairInput.vue";
@@ -342,6 +342,12 @@ export default defineComponent({
342342
const updateData = responseData as ExportDocument;
343343
if (updateData) this.download("canvas.svg", updateData.document);
344344
});
345+
registerResponseHandler(ResponseType.SerializeDocument, (responseData: Response) => {
346+
const data = responseData as SerializeDocument;
347+
if (data && data.action === "save") {
348+
this.download("canvas.gsvg", data.document);
349+
}
350+
});
345351
registerResponseHandler(ResponseType.SetActiveTool, (responseData: Response) => {
346352
const toolData = responseData as SetActiveTool;
347353
if (toolData) this.activeTool = toolData.tool_name;

client/web/src/components/widgets/inputs/MenuBarInput.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const menuEntries: MenuListEntries = [
8787
{ label: "Close All", shortcut: ["Ctrl", "Alt", "W"], action: async () => (await wasm).close_all_documents_with_confirmation() },
8888
],
8989
[
90-
{ label: "Save", shortcut: ["Ctrl", "S"] },
90+
{ label: "Save", shortcut: ["Ctrl", "S"], action: async () => (await wasm).serialize_document("save") },
9191
{ label: "Save As…", shortcut: ["Ctrl", "", "S"] },
9292
{ label: "Save All", shortcut: ["Ctrl", "Alt", "S"] },
9393
{ label: "Auto-Save", shortcut: undefined },

client/web/src/utilities/response-handler.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export enum ResponseType {
2424
SetCanvasRotation = "SetCanvasRotation",
2525
DisplayConfirmationToCloseDocument = "DisplayConfirmationToCloseDocument",
2626
DisplayConfirmationToCloseAllDocuments = "DisplayConfirmationToCloseAllDocuments",
27+
SerializeDocument = "SerializeDocument",
2728
}
2829

2930
export function registerResponseHandler(responseType: ResponseType, callback: ResponseCallback) {
@@ -73,6 +74,8 @@ function parseResponse(responseType: string, data: any): Response {
7374
return newDisplayConfirmationToCloseDocument(data.DisplayConfirmationToCloseDocument);
7475
case "DisplayConfirmationToCloseAllDocuments":
7576
return newDisplayConfirmationToCloseAllDocuments(data.DisplayConfirmationToCloseAllDocuments);
77+
case "SerializeDocument":
78+
return newSerializeDocument(data.SerializeDocument);
7679
default:
7780
throw new Error(`Unrecognized origin/responseType pair: ${origin}, '${responseType}'`);
7881
}
@@ -158,6 +161,17 @@ function newExportDocument(input: any): UpdateCanvas {
158161
};
159162
}
160163

164+
export interface SerializeDocument {
165+
document: string;
166+
action: string;
167+
}
168+
function newSerializeDocument(input: any): SerializeDocument {
169+
return {
170+
document: input.document,
171+
action: input.action,
172+
};
173+
}
174+
161175
export type DocumentChanged = {};
162176
function newDocumentChanged(_: any): DocumentChanged {
163177
return {};

client/web/wasm/src/document.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ pub fn export_document() -> Result<(), JsValue> {
177177
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(DocumentMessage::ExportDocument)).map_err(convert_error)
178178
}
179179

180+
/// Serialize document
181+
#[wasm_bindgen]
182+
pub fn serialize_document(action: String) -> Result<(), JsValue> {
183+
EDITOR_STATE
184+
.with(|editor| editor.borrow_mut().handle_message(DocumentMessage::SerializeDocument(action)))
185+
.map_err(convert_error)
186+
}
187+
180188
/// Sets the zoom to the value
181189
#[wasm_bindgen]
182190
pub fn set_zoom(new_zoom: f64) -> Result<(), JsValue> {

core/document/src/document.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ impl Document {
6464
svg
6565
}
6666

67+
// Returns string that represents the full document (not just svg)
68+
pub fn serialize_document(&mut self) -> String {
69+
// Manually constructing JSON. Should switch to serde_json
70+
format!("{{\"version\": 0, \"svg\": \"{}\"}}", self.render_root())
71+
}
72+
6773
/// Checks whether each layer under `path` intersects with the provided `quad` and adds all intersection layers as paths to `intersections`.
6874
pub fn intersects_quad(&self, quad: [DVec2; 4], path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>) {
6975
self.document_folder(path).unwrap().intersects_quad(quad, path, intersections);

core/editor/src/document/document_message_handler.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub enum DocumentMessage {
5454
WheelCanvasZoom,
5555
SetCanvasRotation(f64),
5656
NudgeSelectedLayers(f64, f64),
57+
SerializeDocument(String),
5758
}
5859

5960
impl From<DocumentOperation> for DocumentMessage {
@@ -328,6 +329,13 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
328329
}
329330
.into(),
330331
),
332+
SerializeDocument(action) => responses.push_back(
333+
FrontendMessage::SerializeDocument {
334+
document: self.active_document_mut().document.serialize_document(),
335+
action,
336+
}
337+
.into(),
338+
),
331339
ToggleLayerVisibility(path) => {
332340
responses.push_back(DocumentOperation::ToggleVisibility { path }.into());
333341
}
@@ -581,6 +589,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
581589
SetCanvasRotation,
582590
WheelCanvasZoom,
583591
WheelCanvasTranslate,
592+
SerializeDocument
584593
);
585594

586595
if self.active_document().layer_data.values().any(|data| data.selected) {

core/editor/src/frontend/frontend_message_handler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub enum FrontendMessage {
2222
UpdateWorkingColors { primary: Color, secondary: Color },
2323
SetCanvasZoom { new_zoom: f64 },
2424
SetCanvasRotation { new_radians: f64 },
25+
SerializeDocument { document: String, action: String },
2526
}
2627

2728
pub struct FrontendMessageHandler {

0 commit comments

Comments
 (0)