## 1. Extract ViewportTile class - [x] 1.1 Create `src/ui/ViewportTile.h` with class declaration — owns `ViewportCamera`, `UsdSceneRenderer`, per-tile settings (grid, AA, bbox mode, bg color, render delegate, camera index), and a pointer to the shared selection + manipulator - [x] 1.2 Create `src/ui/ViewportTile.cpp` — extract per-tile rendering logic from `ViewportPanel::Render()`: camera resolution, scene rendering, overlay rendering (axis, bbox, camera wireframes), DrawSelectionRect, RenderManipulatorOverlay, RenderContextMenu, HandleInput - [x] 1.3 Verify tile renders standalone by temporarily instantiating one ViewportTile in Application ## 2. Refactor ViewportPanel into container - [x] 2.1 Rewrite `ViewportPanel` header to own `std::vector>`, `TransformManipulator`, shared selection state (`m_selectedSdfPaths`, `m_selectedPrimPath`), layout enum (`LayoutMode`), divider normalized positions, and maximize state (`m_maximizedTileIndex`, `m_layoutBeforeMaximize`) - [x] 2.2 Rewrite `ViewportPanel::Render()` to compute tile rectangles from layout state, iterate tiles calling `ViewportTile::Render()` + `ViewportTile::HandleInput()`, and draw dividers. When maximized, render only the maximized tile at full viewport area (no dividers) - [x] 2.3 Add `ViewportPanel::SetLayout(LayoutMode)` — creates/destroys tiles as needed, preserves focused tile's camera/settings when possible. Clear `m_maximizedTileIndex` on explicit layout change - [x] 2.4 Add divider-drag handling in `ViewportPanel::Render()` — hit-test divider regions, update normalized positions on drag. Skip divider hit-test when maximized - [x] 2.5 Add `ViewportPanel::SetLayoutMenu()` — a layout menu in the viewport title bar or right-click context menu - [x] 2.6 Add Space-key maximize/restore: detect Space key press (guarded by `!io.WantTextInput` and `LayoutMode != Single`), save pre-maximize layout, set `m_maximizedTileIndex` to the hovered tile's index. On second Space or Escape, restore `m_maximizedTileIndex` to -1 and reload saved layout. Add visual indicator (border glow or text label) on maximized tile - [x] 2.7 Expose `ViewportPanel::GetFocusedTileIndex()` and wire up `OnPrimPicked` / `OnPrimsPickedRect` from the focused tile to the shared selection callbacks. When maximized, the maximized tile is implicitly the focused tile ## 3. Implement shared selection - [x] 3.1 Store `m_selectedSdfPaths` and `m_selectedPrimPath` on `ViewportPanel` (container) - [x] 3.2 On pick in any tile, update shared selection, then broadcast `m_renderer.SetSelectedPaths()` to all tiles - [x] 3.3 Fire `OnPrimPicked` / `OnPrimsPickedRect` from the container (not tiles) so downstream panels see a single source of truth ## 4. Implement focused-viewport manipulator - [x] 4.1 Track `m_focusedTileIndex` on `ViewportPanel` — updated on LMB click in any tile - [x] 4.2 Only call `m_manipulator.Render()` and `m_manipulator.HandleInput()` for the focused tile - [x] 4.3 Wire keyboard shortcuts (Q/W/E/R) through the container to the global manipulator, and F/A to the focused tile's camera. Ensure Space maximize toggle works correctly when a tile is focused (not consumed by manipulator) ## 5. Add per-tile compact toolbar - [x] 5.1 Implement compact icon-only toolbar in `ViewportTile::RenderToolbar()` — camera selector + render delegate button + grid/AA/bbox icons, all 16×16 with tooltips - [ ] 5.2 Add overflow handling: if toolbar exceeds tile width, collapse into a "..." dropdown menu ## 6. Wire up Application integration - [x] 6.1 Update `Application::Initialize()` — `m_viewportPanel` still works, `SetStage` broadcasts to all tiles, `SetSelectedPrimPath` updates shared selection - [x] 6.2 Update `Application::RenderUI()` — ensure the Viewport window renders correctly with the new container layout - [ ] 6.3 Test all existing interaction flows: stage open/close, camera switching, selection sync, manipulator tools, context menu, frame shortcuts ## 7. Build and test - [x] 7.1 Configure with `cmake --preset default` - [x] 7.2 Build Release with `cmake --build build --config Release` — fix any compilation errors - [x] 7.3 Install with `cmake --install build --config Release` - [ ] 7.4 Run `App.exe` and visually verify: single viewport works, switch to HSplit/VSplit/Quad, camera independence, shared selection, manipulator in focused tile only, divider dragging, Space-key maximize/restore with correct layout preservation, Escape restore, maximize in Quad layout, Space no-op in Single layout - [ ] 7.5 Run CTest: `ctest --test-dir build -C Release` — fix any test failures