Skip to content

Spec: Tabbed Multi-Document Interface

Overview

Add support for opening and working on multiple circuits simultaneously using a tabbed interface, enabling rapid switching between related circuits and macro definitions.

Motivation

Real projects often involve multiple related circuit files — a top-level design, macro sub-circuits, testbenches, and library components. Currently, users must close one file to open another, losing context. Tabs allow parallel work and quick reference across files.

Requirements

Functional Requirements

  1. Tab Bar: Horizontal tab bar showing all open circuits, each with filename and close button.
  2. Multiple Open Files: Open unlimited circuit files simultaneously (memory-permitting).
  3. Tab Switching: Click tab to switch, Ctrl+Tab to cycle, Ctrl+1-9 for specific tabs.
  4. Close Tab: Close individual tabs with middle-click or X button.
  5. Dirty Indicator: Modified/unsaved tabs show a dot or asterisk indicator.
  6. New Tab: Ctrl+N creates a new empty circuit in a new tab.
  7. Tab Reordering: Drag tabs to reorder.
  8. Tab Overflow: When tabs exceed space, show a dropdown or scroll arrows.
  9. Context Menu: Right-click tab for options (Close, Close Others, Close All, Copy Path).
  10. Independent State: Each tab maintains its own zoom, scroll position, selection, and editor mode.
  11. Shared Simulation: Option to simulate all open circuits or just the active tab.
  12. Open Macro in Tab: Double-click a macro component to open its definition in a new tab.
  13. Tab Persistence: Remember open tabs across application sessions (restore on startup).

Non-Functional Requirements

  • Tab switching is instant (< 50ms) — canvas state is preserved in memory.
  • Memory usage scales linearly with open circuits.
  • No performance impact on inactive tabs.

Design

Architecture

csharp
public class DocumentManager
{
    public ObservableCollection<CircuitDocument> OpenDocuments { get; }
    public CircuitDocument ActiveDocument { get; set; }
    
    public CircuitDocument OpenFile(string path);
    public CircuitDocument CreateNew();
    public void CloseDocument(CircuitDocument doc);
    public bool HasUnsavedChanges { get; }
}

public class CircuitDocument
{
    public string FilePath { get; }
    public string DisplayName { get; }  // filename or "Untitled N"
    public Circuit Circuit { get; }
    public bool IsDirty { get; }
    public EditorState EditorState { get; }  // zoom, scroll, selection, mode
    public UndoStack UndoStack { get; }  // per-document undo
}

UI Layout

┌─────────────────────────────────────────────┐
│ [Tab1] [Tab2*] [Tab3] [+]          [▼ overflow]  │
├─────────────────────────────────────────────┤
│                                             │
│              Canvas Area                    │
│         (active document)                   │
│                                             │
└─────────────────────────────────────────────┘

Tab Rendering

  • Active tab: elevated/highlighted with accent color.
  • Inactive tabs: subtle background.
  • Dirty tab: filename suffixed with ● or bolded.
  • Tab shows file icon + filename (truncated if long).

Session Persistence

json
// Saved to app settings
{
  "openTabs": [
    { "path": "C:\\circuits\\cpu.dwm", "isActive": true },
    { "path": "C:\\circuits\\alu.dwm", "isActive": false }
  ]
}

Implementation Tasks

  1. Create DocumentManager class to manage open documents.
  2. Create CircuitDocument class wrapping Circuit + editor state.
  3. Implement tab bar UI control (WinUI TabView or custom).
  4. Implement tab switching with state preservation.
  5. Move per-document state (undo stack, zoom, selection) into CircuitDocument.
  6. Implement dirty tracking per document.
  7. Add keyboard shortcuts (Ctrl+Tab, Ctrl+W, Ctrl+N, Ctrl+1-9).
  8. Implement tab context menu (Close, Close Others, Close All).
  9. Implement "Open Macro in Tab" navigation.
  10. Add session persistence (remember open tabs across restarts).
  11. Update window title to show active document name.

Risks & Open Questions

  • Memory impact of keeping many large circuits in memory simultaneously?
  • Should inactive tabs keep their canvas rendered or regenerate on switch?
  • How do shared resources (toolbox, properties panel) update when switching tabs?
  • Should there be a limit on open tabs, or leave it to system resources?

Priority

Medium-High — Standard modern application feature, expected by users.