Donner SVG Editor & Engine
SVG-native editor and embeddable SVG2 + CSS3 engine in C++20, with GPU (WebGPU) and compact CPU renderers, built for correctness, security, and performance.
Loading...
Searching...
No Matches
donner::editor::LayersPanel Class Reference

ImGui Layers panel backed by a LayerTreeModel snapshot. More...

#include "donner/editor/LayersPanel.h"

Classes

struct  ThumbnailTexture
 Maps a per-row rendered thumbnail bitmap to an ImGui texture handle for display. The editor shell supplies an implementation backed by GlTextureCache (the same Donner-bitmap -> GL/WGPU texture path the render pane uses); when null (e.g. in headless unit tests) the panel falls back to the deterministic swatch. Donner renders the thumbnail pixels; ImGui only blits the resulting texture - see CLAUDE.md "No Rendering Vector Graphics With ImGui". More...
struct  IconTexture
 Maps a static layer-affordance icon bitmap to an ImGui texture handle for display. The icon bitmaps are rendered from embedded Bootstrap SVG resources through Donner; ImGui only receives the final raster texture for the image button. More...
struct  ThumbnailRefreshStats
 Diagnostics for the most recent thumbnail refresh. More...
struct  ClickModifiers
 Modifier state for a row click. Mirrors the ImGui click path so tests can drive selection without a live ImGui frame. More...

Public Types

enum class  ThumbnailRefreshMode {
  Render ,
  SwatchesOnly
}
using ThumbnailTextureProvider
using IconTextureProvider

Public Member Functions

void refreshSnapshot (const EditorApp &app, svg::RendererInterface *renderer=nullptr, ThumbnailRefreshMode mode=ThumbnailRefreshMode::Render)
 Rebuild the row snapshot, per-row preview swatches, and per-row rendered thumbnail bitmaps from live editor state. Safe to call only when the async renderer is idle (delegates to LayerTreeModel::refresh and renders each row's element subtree through svg::Renderer::renderElementToBitmap, which takes document write access).
void render (EditorApp *liveApp, const ThumbnailTextureProvider &textureProvider={}, const IconTextureProvider &iconTextureProvider={}, float minimumInteractionHeight=0.0f)
 Render the panel into the current ImGui window. Must be called inside an ImGui::Begin(...) / End() pair. When liveApp is null (the worker owns the document) mutating clicks are dropped.
void setLockedRejectionFlash (std::optional< LayersLockedRejectionFlash > flash)
 Set the current locked-rejection flash (or clear it with std::nullopt). When set with a positive intensity and the flashed element matches a visible row, render paints that row's background red with alpha scaled by intensity, in sync with the canvas outline flash. EditorShell calls this each frame with SelectTool::lockedRejectionFlash() mapped into the input struct, before render.
std::optional< std::size_t > flashedRowIndex () const
 The visible row index that the active locked-rejection flash maps to (an exact element match against a visible row), or std::nullopt when no flash is active, its intensity is non-positive, or its element is not a visible row. The non-ImGui seam the row-flash test asserts on.
float lockedRejectionFlashIntensity () const
 The fade intensity of the active locked-rejection flash, or 0 when none is set. Testing/diagnostics accessor paired with flashedRowIndex.
const std::vector< LayerTreeRow > & rows () const
 The current flat row list (testing/diagnostics accessor).
const ThumbnailRefreshStatsthumbnailRefreshStats () const
 Diagnostics for the most recent thumbnail refresh.
std::size_t visibleRowCount () const
 Number of currently-visible rows (rows in the flat list).
void handleRowClick (EditorApp &app, std::size_t rowIndex, ClickModifiers mods)
 Apply the selection logic for a click on the visible row at rowIndex. This is the exact logic the ImGui click path uses, factored out so it is unit-testable without an ImGui context.
void handleEyeClick (EditorApp &app, std::size_t rowIndex)
 Toggle the visibility of the row at rowIndex via the shared EditorApp::setElementVisible path (the same path the context-menu Hide/Show items use). Factored out so the eye-button affordance is unit-testable without an ImGui frame. No-op for an out-of-range index.
void handleLockClick (EditorApp &app, std::size_t rowIndex)
 Toggle the lock state of the row at rowIndex via the shared EditorApp::setElementLocked path (the same path the context-menu Lock/Unlock items use). Factored out so the lock-button affordance is unit-testable without an ImGui frame. No-op for an out-of-range index.
bool handleRowRename (EditorApp &app, std::size_t rowIndex, std::string_view newId)
 Rename the element at rowIndex to newId via the shared EditorApp::renameSelectedElement path - a DOM-level id change that also repoints url(#...) / href references and <style> selectors. The row's element is selected first (renaming the thing you double-clicked), then the engine runs. Factored out so the inline-edit affordance is unit-testable without an ImGui frame.
bool handleRowReorder (EditorApp &app, std::size_t fromIndex, std::size_t toIndex)
 Move the element at fromIndex so it sits at the toIndex row's position, among the same parent's children, via the shared EditorApp::reorderElementBeforeSibling DOM move. Cross-parent drops and locked elements are rejected. Factored out so drag-to-reorder is unit-testable without an ImGui frame.
bool handleRowZOrder (EditorApp &app, std::size_t rowIndex, EditorApp::ZOrder direction)
 Reorder the element at rowIndex in paint order (z-order) via the shared EditorApp::reorderSelectedElement engine - the same path as the canvas Arrange menu and the Cmd+[ / Cmd+] shortcuts. The row's element is selected first, then the move runs. Factored out so the Layers context-menu Arrange items are unit-testable without an ImGui frame.
void beginRename (std::uint64_t stableId)
 Begin an inline rename of the row identified by stableId (the render loop draws an edit field in place of the row label). No-op if the row is not present. Exposed so the context-menu "Rename" item and tests can start an edit; the double-click path calls it internally.
std::optional< std::uint64_t > renamingStableId () const
 The stable id of the row currently being inline-renamed, or std::nullopt.
bool hasThumbnailOrSwatch (std::uint64_t stableId) const
 Whether the row identified by stableId has a non-null thumbnail handle or a deterministic fallback swatch. Always true for every visible row.
std::optional< css::RGBArowFallbackSwatch (std::uint64_t stableId) const
 The fallback preview swatch color for the row identified by stableId, or std::nullopt if the row is not present.
const svg::RendererBitmaprowThumbnail (std::uint64_t stableId) const
 The Donner-rendered preview thumbnail bitmap for the row identified by stableId, or nullptr when the row has no real raster preview (it then uses the fallback swatch). This is the non-ImGui data seam: tests assert on the rendered pixels here without needing a GL context or an ImGui frame.
bool consumeSelectionChanged ()
 Whether the most recent render / handleRowClick changed the editor selection. Consumes the flag. Used by EditorShell to fire the existing canvas/source selection-sync plumbing when a Layers row drives selection.
bool consumeQueuedMutation ()
 Whether the most recent render queued a DOM mutation (show/hide, lock, rename, reorder, z-order) that is not reflected by a selection change. Consumes the flag. EditorShell flushes the queued mutation and re-renders when this is set; without it a show/hide toggle would leave the canvas showing the pre-mutation frame (the "hidden layer ghost" report).
void noteRowHovered (std::optional< std::size_t > rowIndex)
 Record which visible row (if any) is under the mouse cursor. Called from render with the hovered row index, and directly by tests. Drives the canvas hover-highlight chrome the same way the source pane does. Passing std::nullopt (or an out-of-range index) clears the hover.
std::optional< svg::SVGElementhoveredElement () const
 The element under the mouse cursor as of the most recent render / noteRowHovered, or std::nullopt when no row is hovered.
const LayerTreeModelmodel () const
 Access the underlying model (testing/diagnostics).

Detailed Description

ImGui Layers panel backed by a LayerTreeModel snapshot.


Class Documentation

◆ donner::editor::LayersPanel::ThumbnailTexture

struct donner::editor::LayersPanel::ThumbnailTexture

Maps a per-row rendered thumbnail bitmap to an ImGui texture handle for display. The editor shell supplies an implementation backed by GlTextureCache (the same Donner-bitmap -> GL/WGPU texture path the render pane uses); when null (e.g. in headless unit tests) the panel falls back to the deterministic swatch. Donner renders the thumbnail pixels; ImGui only blits the resulting texture - see CLAUDE.md "No Rendering Vector Graphics With ImGui".

Parameters
stableIdStable id of the row whose thumbnail is being uploaded.
bitmapThe Donner-rendered RGBA thumbnail bitmap.
Returns
An ImGui texture handle plus the valid payload UV range, or an empty texture if upload failed.
Class Members
ImTextureID texture = 0 ImGui texture handle.
Vector2d uvBottomRight = Vector2d(1.0, 1.0) Bottom-right valid payload UV.

◆ donner::editor::LayersPanel::IconTexture

struct donner::editor::LayersPanel::IconTexture

Maps a static layer-affordance icon bitmap to an ImGui texture handle for display. The icon bitmaps are rendered from embedded Bootstrap SVG resources through Donner; ImGui only receives the final raster texture for the image button.

Parameters
stableIdStable id of the static icon resource being uploaded.
bitmapThe Donner-rendered RGBA icon bitmap.
Returns
An ImGui texture handle plus the valid payload UV range, or an empty texture if upload failed.
Class Members
ImTextureID texture = 0 ImGui texture handle.
Vector2d uvBottomRight = Vector2d(1.0, 1.0) Bottom-right valid payload UV.

◆ donner::editor::LayersPanel::ThumbnailRefreshStats

struct donner::editor::LayersPanel::ThumbnailRefreshStats

Diagnostics for the most recent thumbnail refresh.

Class Members
uint64_t documentFrameVersion = 0 Document frame version observed during the refresh.
size_t renderedCount = 0 Number of row thumbnails rasterized through Donner during this refresh.
double renderMs = 0.0 Wall time spent in thumbnail rasterization work.
size_t reusedCount = 0 Number of cached row thumbnails reused during this refresh.
size_t rowCount = 0 Visible row count after refreshing the model.
size_t skippedForCanvasInvalidationCount = 0 Number of rows skipped because the canvas render tree had pending invalidation.

◆ donner::editor::LayersPanel::ClickModifiers

struct donner::editor::LayersPanel::ClickModifiers

Modifier state for a row click. Mirrors the ImGui click path so tests can drive selection without a live ImGui frame.

Class Members
bool ctrl = false Ctrl/Cmd toggles the clicked row in the selection.
bool shift = false Shift extends selection in visible row order.

Member Typedef Documentation

◆ IconTextureProvider

using donner::editor::LayersPanel::IconTextureProvider
Initial value:
std::function<IconTexture(std::uint64_t stableId, const svg::RendererBitmap& bitmap)>
Maps a static layer-affordance icon bitmap to an ImGui texture handle for display....
Definition LayersPanel.h:85
CPU-readable bitmap produced by a renderer snapshot.
Definition RendererInterface.h:59

◆ ThumbnailTextureProvider

using donner::editor::LayersPanel::ThumbnailTextureProvider
Initial value:
std::function<ThumbnailTexture(std::uint64_t stableId, const svg::RendererBitmap& bitmap)>
Maps a per-row rendered thumbnail bitmap to an ImGui texture handle for display. The editor shell sup...
Definition LayersPanel.h:69

Member Function Documentation

◆ handleEyeClick()

void donner::editor::LayersPanel::handleEyeClick ( EditorApp & app,
std::size_t rowIndex )

Toggle the visibility of the row at rowIndex via the shared EditorApp::setElementVisible path (the same path the context-menu Hide/Show items use). Factored out so the eye-button affordance is unit-testable without an ImGui frame. No-op for an out-of-range index.

Parameters
appLive editor app the mutation is applied to.
rowIndexIndex into rows().

◆ handleLockClick()

void donner::editor::LayersPanel::handleLockClick ( EditorApp & app,
std::size_t rowIndex )

Toggle the lock state of the row at rowIndex via the shared EditorApp::setElementLocked path (the same path the context-menu Lock/Unlock items use). Factored out so the lock-button affordance is unit-testable without an ImGui frame. No-op for an out-of-range index.

Parameters
appLive editor app the mutation is applied to.
rowIndexIndex into rows().

◆ handleRowClick()

void donner::editor::LayersPanel::handleRowClick ( EditorApp & app,
std::size_t rowIndex,
ClickModifiers mods )

Apply the selection logic for a click on the visible row at rowIndex. This is the exact logic the ImGui click path uses, factored out so it is unit-testable without an ImGui context.

Parameters
appLive editor app the selection request is applied to.
rowIndexIndex into rows().
modsModifier-key state for the click.

◆ handleRowRename()

bool donner::editor::LayersPanel::handleRowRename ( EditorApp & app,
std::size_t rowIndex,
std::string_view newId )

Rename the element at rowIndex to newId via the shared EditorApp::renameSelectedElement path - a DOM-level id change that also repoints url(#...) / href references and <style> selectors. The row's element is selected first (renaming the thing you double-clicked), then the engine runs. Factored out so the inline-edit affordance is unit-testable without an ImGui frame.

Parameters
appLive editor app the mutation is applied to.
rowIndexIndex into rows().
newIdThe requested new element id.
Returns
True if the rename was applied; false on out-of-range index or when the engine rejects it (locked, empty, unchanged, or duplicate id).

◆ handleRowReorder()

bool donner::editor::LayersPanel::handleRowReorder ( EditorApp & app,
std::size_t fromIndex,
std::size_t toIndex )

Move the element at fromIndex so it sits at the toIndex row's position, among the same parent's children, via the shared EditorApp::reorderElementBeforeSibling DOM move. Cross-parent drops and locked elements are rejected. Factored out so drag-to-reorder is unit-testable without an ImGui frame.

Parameters
appLive editor app the mutation is applied to.
fromIndexIndex of the dragged row.
toIndexIndex of the drop-target row.
Returns
True if a move was applied; false on out-of-range/no-op/rejected.

◆ handleRowZOrder()

bool donner::editor::LayersPanel::handleRowZOrder ( EditorApp & app,
std::size_t rowIndex,
EditorApp::ZOrder direction )

Reorder the element at rowIndex in paint order (z-order) via the shared EditorApp::reorderSelectedElement engine - the same path as the canvas Arrange menu and the Cmd+[ / Cmd+] shortcuts. The row's element is selected first, then the move runs. Factored out so the Layers context-menu Arrange items are unit-testable without an ImGui frame.

Parameters
appLive editor app the mutation is applied to.
rowIndexIndex into rows().
directionWhich way to move the element in paint order.
Returns
True if the element moved; false on out-of-range index or when the engine rejects it (root element, locked, or already at the extreme).

◆ refreshSnapshot()

void donner::editor::LayersPanel::refreshSnapshot ( const EditorApp & app,
svg::RendererInterface * renderer = nullptr,
ThumbnailRefreshMode mode = ThumbnailRefreshMode::Render )

Rebuild the row snapshot, per-row preview swatches, and per-row rendered thumbnail bitmaps from live editor state. Safe to call only when the async renderer is idle (delegates to LayerTreeModel::refresh and renders each row's element subtree through svg::Renderer::renderElementToBitmap, which takes document write access).

Parameters
appLive editor app to snapshot.
rendererOptional renderer to use for thumbnail rasterization.
modeWhether to render thumbnails or refresh only the row swatches.

◆ render()

void donner::editor::LayersPanel::render ( EditorApp * liveApp,
const ThumbnailTextureProvider & textureProvider = {},
const IconTextureProvider & iconTextureProvider = {},
float minimumInteractionHeight = 0.0f )

Render the panel into the current ImGui window. Must be called inside an ImGui::Begin(...) / End() pair. When liveApp is null (the worker owns the document) mutating clicks are dropped.

Parameters
liveAppLive editor app for selection/mutation, or null.
textureProviderUploads a row's rendered thumbnail bitmap to an ImGui texture for display, or null to fall back to the swatch.
iconTextureProviderUploads the static Donner-rendered layer icon bitmaps to ImGui textures for display, or null to keep a blank hit area in headless tests.
minimumInteractionHeightMinimum row and icon-button target height. Compact touch sheets pass 44 logical pixels; desktop keeps the dense default by passing zero.

◆ rowThumbnail()

const svg::RendererBitmap * donner::editor::LayersPanel::rowThumbnail ( std::uint64_t stableId) const
nodiscard

The Donner-rendered preview thumbnail bitmap for the row identified by stableId, or nullptr when the row has no real raster preview (it then uses the fallback swatch). This is the non-ImGui data seam: tests assert on the rendered pixels here without needing a GL context or an ImGui frame.

Parameters
stableIdStable id of the row.

The documentation for this class was generated from the following file: