Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 28 additions & 15 deletions docs/editor-packages.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
# Svg.Editor package layout

`samples/AvalonDraw` is now the demo host for the extracted editor stack.
The canonical end-user documentation for the extracted editor stack now lives in the Lunet site:

Reference `Svg.Editor.Skia.Avalonia` when you want the ready-made editor workspace and interactive canvas.
It now exposes `SvgEditorWorkspace` for the full composed editor and `SvgEditorSurface` for the canvas only.
- `site/articles/editor/` for architecture and integration guides
- `site/articles/packages/svg-editor-*.md` for package-by-package coverage
- `site/articles/reference/api-coverage-index.md` for generated API inputs

Reference `Svg.Editor.Avalonia` when you only need the editor dialogs and other Avalonia-specific UI pieces without the Skia editing surface.
It now contains the reusable side-panel controls: `DocumentOutlineView`, `ResourceBrowserView`, `PropertyInspectorView`, `ToolPaletteView`, and `StatusBarView`.
It also exposes the standalone editor views used by the default dialog host, including `InsertElementPickerView`, `PatternEditorView`, `GradientStopsEditorView`, `GradientMeshEditorView`, `StrokeProfileEditorView`, `TextEditorView`, `PathSegmentsEditorView`, `SwatchEditorView`, `SymbolPickerView`, `SymbolNameEditorView`, and `SettingsEditorView`.
Use `ISvgEditorDialogService` and `ISvgEditorFileDialogService` to replace the default window/file-picker flow when embedding the editor into a host application.
Use this file as a short maintainer note only.

Reference `Svg.Editor.Skia` when you need rendering/editing helpers and overlay logic but are composing your own UI.
It exposes the public editor-side helpers `SvgEditorOverlayRenderer`, `SvgEditorInteractionController`, `BoundsInfo`, and `PathPoint`.
## Package summary

Reference `Svg.Editor.Svg` for SVG document mutation services, resource management, and property editing support.
- `Svg.Editor.Core`: shared session, settings, outline, artboard, clipboard, and history state
- `Svg.Editor.Svg`: document mutation services and editor-side SVG/resource models
- `Svg.Editor.Skia`: selection math, path editing, align/distribute, and overlay rendering
- `Svg.Editor.Avalonia`: reusable Avalonia panels, editor views, and dialog abstractions
- `Svg.Editor.Skia.Avalonia`: `SvgEditorSurface` and `SvgEditorWorkspace`

Reference `Svg.Editor.Core` for shared editor state types such as `SvgEditorSession`, `SvgEditorSettings`, `SvgNode`, and `ArtboardInfo`.
## Host-owned seams on `SvgEditorWorkspace`

`SvgEditorWorkspace` now keeps host-owned seams public:
- assign `DialogService` to customize modal presentation and inline editor hosting
- assign `FileDialogService` to customize open/save/export/image picking
- call `OpenDocumentAsync`, `SaveDocumentAsync`, `ExportSelectedElementAsync`, `ExportPdfAsync`, `ExportXpsAsync`, `PlaceImageAsync`, and `ShowSettingsAsync` from host menus or commands instead of relying on the built-in menu bar
- `DialogService`
- `FileDialogService`
- `PreviewRequested`
- `ResourceAssembly`
- `WorkspaceTitlePrefix`

Public host command entry points remain:

- `LoadDocument`
- `OpenDocumentAsync`
- `SaveDocumentAsync`
- `ExportSelectedElementAsync`
- `ExportPdfAsync`
- `ExportXpsAsync`
- `PlaceImageAsync`
- `ShowSettingsAsync`
13 changes: 13 additions & 0 deletions site/articles/concepts/package-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ Svg.Skia is composed of several layers that can be used independently or togethe
- `Svg.Controls.Avalonia` exposes a similar API surface but renders through the Avalonia drawing model.
- `Skia.Controls.Avalonia` provides reusable general-purpose Skia controls such as `SKCanvasControl`, `SKPictureControl`, and `SKPictureImage`.

## Editor composition path

- `Svg.Editor.Core` carries shared editor session state and history.
- `Svg.Editor.Svg` carries document mutation, properties, layers, patterns, symbols, styles, and tool-creation services.
- `Svg.Editor.Skia` carries the editing math and overlay rendering.
- `Svg.Editor.Avalonia` carries reusable side panels, editor views, and dialog abstractions.
- `Svg.Editor.Skia.Avalonia` composes the full interactive editor workspace on top of the lower layers.

## Generated-code path

- `Svg.CodeGen.Skia` generates C# from the picture model.
Expand All @@ -33,6 +41,11 @@ Svg.Skia is composed of several layers that can be used independently or togethe
| `Avalonia.Svg.Skia` | Skia-backed Avalonia controls and resources |
| `Avalonia.Svg` | Avalonia drawing-stack controls and resources |
| `Avalonia.Controls.Skia` | general-purpose Skia controls for Avalonia |
| `Svg.Editor.Core` | editor session, settings, nodes, artboards, clipboard |
| `Svg.Editor.Svg` | editor document mutation services and models |
| `Svg.Editor.Skia` | editor selection, path editing, and overlay rendering |
| `Svg.Editor.Avalonia` | reusable editor controls, dialogs, and views |
| `Svg.Editor.Skia.Avalonia` | interactive editor surface and workspace |
| `ShimSkiaSharp` | picture-recorder model used for command inspection and rebuild |
| `Svg.SourceGenerator.Skia` | incremental generator surface |
| `Svg.CodeGen.Skia` | direct code-generation helpers |
Expand Down
71 changes: 71 additions & 0 deletions site/articles/editor/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: "Architecture"
---

# Architecture

The editor stack is layered so applications can pick the lowest level that still solves the problem.

## Dependency order

| Layer | Depends on | Main responsibility |
| --- | --- | --- |
| `Svg.Editor.Core` | `Svg.Model` | Host-agnostic state such as the active document, outline tree, selected ids, settings, clipboard, and undo/redo history |
| `Svg.Editor.Svg` | `Svg.Editor.Core`, `Svg.Model`, `Svg.Skia` | SVG document loading, save/export helpers, properties, layers, patterns, swatches, symbols, styles, and creation tools |
| `Svg.Editor.Skia` | `Svg.Editor.Core`, `Svg.Editor.Svg`, `Svg.Model`, `Svg.Skia` | Bounds math, hit handles, transforms, path editing, align/distribute, and overlay rendering |
| `Svg.Editor.Avalonia` | `Svg.Editor.Core`, `Svg.Editor.Svg` | Reusable Avalonia panels, property editors, standalone dialog views, and dialog/file-dialog service abstractions |
| `Svg.Editor.Skia.Avalonia` | `Svg.Editor.Avalonia`, `Svg.Editor.Core`, `Svg.Editor.Skia`, `Svg.Editor.Svg`, `Svg.Controls.Skia.Avalonia` | The interactive `SvgEditorSurface` and the default `SvgEditorWorkspace` composition |

## Package responsibilities

### `Svg.Editor.Core`

Use this layer when your host already has its own UI and needs a durable editor session object. `SvgEditorSession` stores the document reference, current file, title, filter text, selected ids, artboards, outline nodes, settings, clipboard contents, and undo/redo snapshots.

### `Svg.Editor.Svg`

This layer owns document mutation and resource-oriented models. It is the package behind the property inspector, layer browser, pattern list, swatches, symbols, and styles. It also carries `SvgDocumentService` for open, save, XML round-tripping, and export helpers.

### `Svg.Editor.Skia`

This layer owns the editing math. `SelectionService` and `PathService` handle transforms and editable path points, `AlignService` handles arrangement commands, and `RenderingService` draws the editor-only overlays. `SvgEditorInteractionController` and `SvgEditorOverlayRenderer` are the public adapter types meant for hosts.

### `Svg.Editor.Avalonia`

This layer exposes reusable controls and standalone views rather than a monolithic window. The main reusable panels are `DocumentOutlineView`, `ResourceBrowserView`, `PropertyInspectorView`, `ToolPaletteView`, and `StatusBarView`. Dialog workflows are abstracted through `ISvgEditorDialogService` and `ISvgEditorFileDialogService`.

### `Svg.Editor.Skia.Avalonia`

This is the highest-level package. `SvgEditorSurface` extends `Avalonia.Svg.Skia.Svg` with public overlay and interaction adapters, and `SvgEditorWorkspace` composes the menu, tool palette, left-side panels, canvas, and property inspector into the same layout used by AvalonDraw.

## Host-owned seams

The reusable workspace is intentionally not the final application shell. Hosts remain responsible for:

- window creation and app branding through `WorkspaceTitlePrefix`,
- default resource lookup via `ResourceAssembly`,
- preview window ownership via `PreviewRequested`,
- modal editors via `DialogService`,
- file picking and save locations via `FileDialogService`.

That design keeps the reusable packages independent from any single desktop app policy.

## Sample-to-package split

`samples/AvalonDraw` is now a thin host that:

- instantiates `SvgEditorWorkspace`,
- assigns the default dialog and file-dialog services,
- sets the title prefix to `AvalonDraw`,
- opens the preview window,
- loads the default `Assets/__tiger.svg` document.

All reusable editor code now lives under `src/Svg.Editor.*`.

## Choosing the smallest useful layer

- Choose `Svg.Editor.Skia.Avalonia` for the complete editor experience inside an Avalonia app.
- Choose `Svg.Editor.Avalonia` when you want the panels and dialogs but not the default canvas/workspace.
- Choose `Svg.Editor.Skia` when you are building your own interactive surface or canvas control.
- Choose `Svg.Editor.Svg` when the task is document/resource mutation without UI.
- Choose `Svg.Editor.Core` when you only need common session state and history primitives.
105 changes: 105 additions & 0 deletions site/articles/editor/composing-panels-and-dialogs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
title: "Composing Panels and Dialogs"
---

# Composing Panels and Dialogs

Use `Svg.Editor.Avalonia` when you want reusable editor UI parts without taking the default `SvgEditorWorkspace`.

## Install

```bash
dotnet add package Svg.Editor.Avalonia
```

If your custom shell also wants the reusable Skia-backed canvas shown below, reference `Svg.Editor.Skia.Avalonia` alongside `Svg.Editor.Avalonia`.

## Reusable panel controls

| Control | Purpose |
| --- | --- |
| `DocumentOutlineView` | Tree and artboard list for document structure |
| `ResourceBrowserView` | Layers, patterns, swatches, brushes, symbols, and styles |
| `PropertyInspectorView` | Filterable property grid with specialized editors for gradients, meshes, stroke profiles, and pattern references |
| `ToolPaletteView` | Tool-selection buttons and stroke-width input |
| `StatusBarView` | Status text plus reset affordance |

These controls expose direct Avalonia properties or public control references so hosts can bind data and attach their own events.

## Example composition

```xml
<Grid xmlns:controls="clr-namespace:Svg.Editor.Avalonia.Controls;assembly=Svg.Editor.Avalonia"
xmlns:editor="clr-namespace:Svg.Editor.Skia.Avalonia;assembly=Svg.Editor.Skia.Avalonia"
ColumnDefinitions="280,*,320">
<controls:DocumentOutlineView Grid.Column="0"
Nodes="{Binding Session.Nodes}"
Artboards="{Binding Session.Artboards}" />

<editor:SvgEditorSurface Grid.Column="1" />

<controls:PropertyInspectorView Grid.Column="2"
FilteredProperties="{Binding FilteredProperties}" />
</Grid>
```

In a custom shell, the host typically provides:

- the `SvgEditorSession` from `Svg.Editor.Core`,
- `ObservableCollection<PropertyEntry>` from `PropertiesService`,
- resource collections from `LayerService`, `PatternService`, `BrushService`, `SymbolService`, and `AppearanceService`,
- command handlers that react to selection or property changes.

## Dialog abstractions

`Svg.Editor.Avalonia` separates the editor workflows from a particular windowing policy:

- `ISvgEditorDialogService` covers insert-element, gradient, gradient mesh, stroke profile, text, swatch, symbol, path, and settings workflows.
- `ISvgEditorFileDialogService` covers open/save/export/image-pick workflows.

The default implementations are `SvgEditorDialogService` and `SvgEditorFileDialogService`, but hosts can replace them with:

- docked panels,
- flyouts,
- embedded tabs,
- custom storage-provider dialogs,
- application-specific naming or validation logic.

## Standalone editor views

The package also exposes the reusable editor views that back the default window wrappers:

- `InsertElementPickerView`
- `PatternEditorView`
- `GradientStopsEditorView`
- `GradientMeshEditorView`
- `StrokeProfileEditorView`
- `TextEditorView`
- `PathSegmentsEditorView`
- `SwatchEditorView`
- `SymbolPickerView`
- `SymbolNameEditorView`
- `SettingsEditorView`

These views return strongly typed result models such as `GradientStopsEditorResult`, `GradientMeshEditorResult`, `StrokeProfileEditorResult`, `TextEditorResult`, and `SettingsEditorResult`.

## Property inspector hooks

`PropertyInspectorView` exposes delegates for the editor-specific sub-editors:

- `PatternReferenceProvider`
- `CreatePatternReferenceAsync`
- `EditGradientStopsAsync`
- `EditGradientMeshAsync`
- `EditStrokeProfileAsync`

That allows a host to keep the grid itself reusable while redirecting advanced edits into its own UI flow.

## Typical composition split

- Put session and model services in the host view model or document controller.
- Bind collections into the reusable controls.
- Route advanced editing through your own `ISvgEditorDialogService`.
- Add `Svg.Editor.Skia.Avalonia` only if you want `SvgEditorSurface` in the same custom shell.

For the non-UI editing primitives behind those controls, continue with [Rendering and Svg Services](rendering-and-svg-services).
106 changes: 106 additions & 0 deletions site/articles/editor/embedding-workspace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---
title: "Embedding SvgEditorWorkspace"
---

# Embedding SvgEditorWorkspace

`SvgEditorWorkspace` is the fastest way to ship the editor in an Avalonia application. It already composes the menu bar, tool palette, document outline, resource browser, canvas, property inspector, and status bar.

## Install

```bash
dotnet add package Svg.Editor.Skia.Avalonia
```

## Minimal host window

```xml
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:editor="clr-namespace:Svg.Editor.Skia.Avalonia;assembly=Svg.Editor.Skia.Avalonia"
x:Class="MyApp.MainWindow"
Width="1200"
Height="800">
<editor:SvgEditorWorkspace x:Name="EditorWorkspace" />
</Window>
```

```csharp
using System.Threading.Tasks;
using Avalonia.Controls;
using Svg;
using Svg.Editor.Avalonia;
using Svg.Editor.Skia.Avalonia;

namespace MyApp;

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

EditorWorkspace.WorkspaceTitlePrefix = "MyApp";
EditorWorkspace.ResourceAssembly = typeof(MainWindow).Assembly;
EditorWorkspace.DialogService = new SvgEditorDialogService();
EditorWorkspace.FileDialogService = new SvgEditorFileDialogService();
EditorWorkspace.PreviewRequested = ShowPreviewAsync;
EditorWorkspace.WorkspaceTitleChanged += (_, title) => Title = title;

EditorWorkspace.LoadDocument("Assets/__tiger.svg");
Title = EditorWorkspace.WorkspaceTitle;
}

private Task ShowPreviewAsync(SvgDocument document)
{
var preview = new Window
{
Title = "Preview"
};

return preview.ShowDialog(this);
}
}
```

`LoadDocument(...)` accepts either a file-system path or an `avares`-resolvable asset path. Set `ResourceAssembly` when the document lives in the host application's resources instead of the editor package assembly.

## Host-controlled commands

The built-in menu uses the same public methods that your own shell can call:

- `LoadDocument(string path)`
- `OpenDocumentAsync()`
- `SaveDocumentAsync()`
- `ExportSelectedElementAsync()`
- `ExportPdfAsync()`
- `ExportXpsAsync()`
- `PlaceImageAsync()`
- `ShowSettingsAsync()`

That means you can keep the workspace layout but move the commands to your own menu, toolbar, or command system.

## Important public properties

| Member | Purpose |
| --- | --- |
| `Session` | Access the shared `SvgEditorSession` for document, title, selection ids, settings, nodes, artboards, and history |
| `Surface` | Access the `SvgEditorSurface` control directly |
| `WorkspaceTitlePrefix` | Replace the default `SVG Editor` branding |
| `ResourceAssembly` | Resolve embedded `avares` document paths against the host assembly |
| `DialogService` | Replace modal editor presentation |
| `FileDialogService` | Replace open/save/export/image pickers |
| `PreviewRequested` | Hook preview behavior without coupling the package to a window type |

## When to drop down a level

Use the full workspace when the default three-column editor layout matches your app.

Drop down to the lower packages when:

- the host already has its own document browser or shell chrome,
- file picking must go through a custom storage abstraction,
- dialogs need to be inline flyouts or docked panes rather than windows,
- you want a custom surface layout around `SvgEditorSurface`.

For that composition path, continue with [Composing Panels and Dialogs](composing-panels-and-dialogs).
6 changes: 6 additions & 0 deletions site/articles/editor/menu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
editor:
- {path: readme.md, title: "Editor"}
- {path: architecture.md, title: "Architecture"}
- {path: embedding-workspace.md, title: "Embedding SvgEditorWorkspace"}
- {path: composing-panels-and-dialogs.md, title: "Composing Panels and Dialogs"}
- {path: rendering-and-svg-services.md, title: "Rendering and Svg Services"}
Loading
Loading