Appearance
Spec: High-DPI / Scale Support
Overview
Ensure DigitalWorks renders crisply and functions correctly at all display scale factors (100%–400%) and resolutions (1080p through 8K), including multi-monitor setups with different DPI settings per display.
Motivation
Modern displays range from standard 1080p (96 DPI) to 4K/5K monitors (200+ DPI) and even 8K panels. Windows display scaling (125%, 150%, 200%, etc.) is common. Without proper High-DPI support, the application appears blurry, elements are too small or too large, and multi-monitor workflows break.
Requirements
Functional Requirements
- Per-Monitor DPI Awareness: Application responds correctly to different DPI on each monitor.
- Dynamic DPI Change: Handle DPI changes at runtime (dragging window between monitors).
- Crisp Rendering at All Scales: All UI elements, canvas content, and text render at native resolution.
- Canvas Scaling: Circuit canvas renders at display-native resolution (not upscaled bitmap).
- Consistent Element Sizes: Components, wires, and pins maintain consistent physical size across DPI.
- UI Element Scaling: Toolbars, dialogs, panels, and menus scale proportionally.
- Icon Assets: Provide multiple icon resolutions (1x, 1.5x, 2x, 3x) or use vector icons.
- Font Scaling: All text renders at correct size relative to DPI (not pixelated).
- Grid Scaling: Grid lines remain at consistent visual spacing regardless of zoom/DPI.
- Print Fidelity: Export/print at actual DPI (not screen DPI).
- User Scale Override: Allow users to adjust UI scale independently of system setting.
Non-Functional Requirements
- No blurry rendering at any standard Windows scale factor (100–400%).
- No layout breakage when scale changes at runtime.
- Smooth transition when dragging between monitors of different DPI.
- Memory usage scales reasonably with resolution (no 4x bitmap memory at 2x scale).
- Performance maintained at high DPI (60fps canvas rendering at 4K).
Design
DPI Awareness Model
WinUI 3 apps are automatically per-monitor DPI-aware v2. Key considerations:
csharp
// Get effective DPI for the current window
double scaleFactor = XamlRoot.RasterizationScale; // 1.0, 1.25, 1.5, 2.0, etc.
// Canvas rendering must account for scale
public void OnDraw(CanvasDrawEventArgs args)
{
var session = args.DrawingSession;
// Win2D automatically handles DPI - draw in logical pixels
// The CanvasControl.DpiScale handles physical pixel mapping
}Canvas Rendering Strategy
Win2D CanvasControl is already DPI-aware:
- Draw calls use logical (DIP) coordinates.
- Win2D internally renders at the display's physical pixel density.
- No manual scaling math needed for basic rendering.
Additional considerations:
- Custom offscreen render targets must specify correct DPI.
- Bitmap caches (minimap, thumbnails) must be invalidated on DPI change.
- Shape definitions must use resolution-independent units.
Areas Requiring DPI-Aware Code
| Area | Approach |
|---|---|
| Canvas rendering | Win2D handles automatically |
| Hit-testing | Use logical coordinates (already correct) |
| Custom controls | Use WinUI layout system (automatic) |
| Offscreen bitmaps | Specify DPI when creating CanvasBitmap |
| Minimap | Regenerate at new DPI on scale change |
| Exported images | Use export DPI setting, not screen DPI |
| Icons/assets | Use vector (SVG) icons or multi-resolution assets |
| Grid rendering | Calculate grid spacing in logical pixels |
| Mouse position | Ensure raw position is in logical coordinates |
Multi-Monitor Handling
csharp
// Listen for DPI changes
window.DpiChanged += (sender, args) =>
{
// Invalidate bitmap caches
_minimapCache = null;
_componentThumbnails.Clear();
// Re-render canvas at new DPI
_canvas.Invalidate();
// Update any custom pixel calculations
UpdateHitTestThresholds(args.NewDpi);
};Icon Strategy
Replace raster icons with:
- SVG icons (rendered via Win2D or WinUI image elements) — scales perfectly.
- Or provide asset variants:
icon.scale-100.png,icon.scale-150.png,icon.scale-200.png, etc.
Implementation Tasks
- Audit all custom pixel calculations for DPI-dependence.
- Ensure all offscreen render targets specify correct DPI.
- Implement DPI change handler (invalidate caches, re-render).
- Replace raster icon assets with vector (SVG) or multi-scale assets.
- Verify hit-testing uses logical coordinates at all scale factors.
- Update minimap rendering to regenerate on DPI change.
- Verify grid rendering at various scale factors (100%, 150%, 200%, 300%).
- Test multi-monitor scenarios (drag between different DPI displays).
- Add user-configurable UI scale override in preferences.
- Verify export/print uses correct DPI (not screen DPI).
- Performance test canvas rendering at 4K (3840×2160) at 60fps.
Risks & Open Questions
- Are there any Win2D limitations at very high DPI (8K displays)?
- Memory impact of high-DPI offscreen bitmaps for large circuits?
- Should custom controls handle DPI themselves or rely on WinUI layout?
- How to test across many DPI values without physical hardware (virtual displays)?
Priority
Low-Medium — WinUI 3 + Win2D handle most cases automatically; main risk is custom code with pixel assumptions.