31 Commits
Author SHA1 Message Date
Mike-Solar 79b3a8fbd4 feat(widgets): CurveEditor::is_dragging for host re-sync suppression 2026-08-21 04:42:30 +08:00
Mike-Solar 8a0b7569a3 fix(widgets): menu hover occlusion and popup placement, clip selection shading
- Menu popups (menu bar, context menus, submenus) now occlude hover
  beneath them via a BlockMouse hitbox, so items under an open popup no
  longer stay highlighted.
- Menu bar dropdowns anchor to the opened title's bottom-left (local
  anchoring) instead of the raw pointer position plus a fixed offset;
  submenus are absolute children of the popup with separator-aware row
  alignment.
- Selected timeline clips render one luma notch darker so the
  selection is visible against the green clip body.
2026-08-20 18:56:01 +08:00
Mike-Solar dea33c713f style: professional dark theme refresh aligned with the design spec
- oak theme palette to a denser professional dark (near-black base,
  container/window surfaces, subtler secondary text).
- Dock tabs: selected tab solid accent with white text, hairline
  separators between panels.
- Timeline: green clip blocks, blue playhead, neutral track headers,
  brighter ruler labels, deep-green waveforms.
- Viewer: green timecode readout, solid-accent play button, chip-style
  fit/safe-margin buttons.
- Effect stack cards and node cards get rounded borders; spinbox
  values in amber per the design.
2026-08-20 17:43:44 +08:00
Mike-Solar f7a00fdd91 feat(dock,timeline): visible tab close buttons, tear-off windows, clip drag ghost, explorer thumbnails
- Tab close buttons are now visible and right-aligned with a hover
  background (they were nearly invisible, causing accidental panel
  closes).
- Tear-off: dragging a tab outside the dock opens the panel in its own
  floating window; closing the window re-docks the panel to its last
  group (or closes it outright from the Window menu).
- Timeline clip dragging shows a translucent ghost at the target track
  and frame, including cross-track moves.
- Project explorer icon view renders real thumbnail images when the
  engine provides them, with debug selectors and a structural test.
2026-08-20 16:20:49 +08:00
Mike-Solar 0b3e30c095 feat(widgets): viewer interact pointer/key events for OFX interacts
ViewerEvent gains InteractPointer/InteractKey variants and the picture
area captures pointer and key input for them (the OFX Interact overlay
integration forwards these to the plugin).
2026-08-20 15:11:29 +08:00
Mike-Solar c4c1d34bd7 fix(widgets): context-menu hover tracking, submenus, and snap-proof placement
The right-click ContextMenu never tracked hover (the listener was a
no-op), so rows did not highlight and parent items never opened their
submenus. Hover now drives the highlight and opens the parent's
submenu, with Left/Right and Enter keyboard parity.

The submenu is an absolutely positioned child of the popup instead of
a second window-anchored popup computed from the raw click point, so
it follows the popup's final snapped/switched bounds and can never
detach from its parent row.
2026-08-19 17:41:40 +08:00
Mike-Solar e521a8af83 fix(widgets): open context-menu submenus on hover
The right-click ContextMenu's hover listener was a no-op: it never
tracked the hovered row and never rendered a submenu popup, so every
menu item with a submenu (Proxy, Cache, Color, Show Thumbnails, Zoom,
Playback Resolution...) was a dead end. Hover now drives the row
highlight and opens the parent's submenu anchored to its right (the
menu bar's model), with keyboard Left/Right to close/open it and Enter
expanding a parent row instead of firing it.
2026-08-19 15:21:54 +08:00
Mike-Solar 050d5ba22d feat(widgets): right-click context-menu events for timeline, node graph, explorer
TimelineView emits ContextMenuRequested with hit target (clip/empty/
track head/ruler marker), NodeGraphView emits it for nodes and the
background, and ProjectExplorer emits it for entries and blank areas,
so the app can open context menus aligned with the C++ version.
2026-08-18 17:14:37 +08:00
Mike-Solar 447353ebbd fix(gpui): node cards scale with zoom; explorer icon grid shows thumbnails
- node_graph: card geometry stays graph-space; paint/hit-test/wire
  endpoints scale by zoom so nodes no longer overlap at zoom != 1
- project_explorer: icon grid aligns items to start (no full-height
  selection stretch), loads thumbnails from filesystem paths and
  observes the data source for late arrivals
2026-08-18 12:41:04 +08:00
Mike-Solar 27c6c393c3 feat(gpui): track-header toggle targets + explorer icon buttons 2026-08-17 01:37:31 +08:00
Mike-Solar c1fc52c654 feat: explorer icons show root-level footage; footage drag source; timeline layout constants public 2026-08-16 19:07:33 +08:00
Mike-Solar df726fd3e3 fix(gpui_widgets): file drops onto the project explorer fire (bare ExternalPaths type) 2026-08-16 15:05:17 +08:00
Mike-Solar fc0420ddd8 feat(gpui): content-width dock tabs, rounded timeline clips 2026-08-13 23:37:57 +08:00
Mike-Solar 888c39bf27 feat(gpui_widgets): menu scrubbing, content-width popups, density pass
- MenuBar: hover another title with a menu open to switch (scrubbing)
- menu popup width computed from the longest label; ROW_HEIGHT 22
- dock tab bar 26px / smaller tab text; viewer transport tightened
2026-08-13 18:16:10 +08:00
Mike-Solar af5482d774 style: cargo fmt with the workspace tab policy (hard_tabs)
Whitespace only; the fork has no own rustfmt.toml so the Oak root
policy applies.
2026-08-11 23:06:13 +08:00
Mike-Solar 507d7e6e8d fix(gpui_widgets): submenu hover opens nested popup; add icons + tooltip helpers
- MenuBar: mouse hover now sets the hovered row and opens submenus next
  to the hovered item (previously hover state was never set from the
  mouse, so '>' rows never opened their submenu)
- Menu popup: debug selectors for test automation
- viewer: transport bar renders 16px icon buttons with localized
  tooltips via a host-registered icon resolver (glyph fallback kept)
- new icons.rs (theme-aware icon resolver) and tooltip.rs helpers
2026-08-11 00:23:59 +08:00
Mike-Solar 49e471ae64 feat(gpui, gpui_widgets): i18n string-table hook + node-graph fit API
- gpui::i18n: minimal string-table override (set_table/tr/clear_table) with
  built-in defaults; effect-stack and viewer strings now go through it so
  hosts can localize widget-baked labels without a full i18n framework.
- gpui_widgets::i18n re-exports the hook (gpui_widgets::i18n::set_table).
- node_graph: GraphViewState::fit_to_rect for fit-window/initial viewports
  (unit tested); NodeGraphView::viewport_size accessor for fit targets.
2026-08-10 16:52:39 +08:00
Mike-Solar 16ae7c42df gpui_widgets defect fixes: menu checkmarks, dock ratios, meter orientation, CPU frames, drop-frame timecode
- menu: add runtime set-checked path (MenuItem::set_checked/clear_checked,
  Menu::set_item_checked recursive, MenuBar::set_item_checked)
- dock: Split now stores per-child ratios (sum 1.0) so 3+ panels on one
  axis keep distinct sizes; resize_split_child adjusts a single boundary,
  resize_split keeps its two-arg whole-share semantics; one handle per
  boundary; DockLayoutState VERSION bumped to 2 for the new ratios field
- audio_meter: MeterOrientation::Vertical for the 26px transport strip,
  segments lit bottom to top
- viewer: ViewerFrameSource::CpuFrame + set_cpu_frame (BGRA8 RenderImage
  via the sprite atlas) for platforms without CVPixelBuffer
- timeline: TimeDisplay::TimecodeDropFrame (SMPTE drop-frame for NTSC
  rates, non-drop fallback otherwise)
- gpui_widgets: regression test pinning the fractional spacing helpers
  (py_0p5/py_1p5/py_2p5/py_3p5 already exist; no _0_5 aliases added)
2026-08-10 05:45:53 +08:00
Mike-Solar a64234936c test(gpui_widgets): add interaction tests for view code, raising coverage to 89.4%
Adds interaction/render tests for the untested view layers: menu bar popup
open/click/keyboard-nav/escape, project explorer expand/open/view-switch,
scope widgets and keyable diamond rendering in windows, progress and file
dialog content rendering, and viewer transport buttons. gpui_widgets line
coverage rises from 75.4% to 89.4% (menu/mod 3.7%->71.9%, project_explorer
21.4%->91.3%, scopes/mod 0%->96.7%, keyable 69%->98.4%); every module is now
>=70%. 115 widget tests pass.
2026-08-09 07:37:57 +08:00
Mike-Solar 098d422628 feat(gpui_widgets): add olive theme system with runtime switching
W7 of the oak task list. OakTheme::olive_dark/olive_light translate oak's
palette.ini files into a structured theme (window/base/alternate/accent/
link/disabled plus a derived border). apply_theme swaps gpui's GlobalColors
so every widget reading cx.default_colors() re-themes immediately, and
stores the full theme in a ThemeGlobal. Palette contrast and mapping are
unit-tested, with a gpui::test verifying the runtime switch;
examples/themes.rs toggles between the two themes live. 101 widget tests
pass.
2026-08-09 06:31:44 +08:00
Mike-Solar bdb1684de7 feat(gpui_widgets): add scope widgets and audio level meter
W6 of the oak task list. scopes::math is a pure, unit-tested core
(histogram binning, waveform min/max envelopes, vectorscope chroma
projection, meter segment math, peak-hold decay) feeding three canvas
widgets - Histogram, Waveform, Vectorscope - generic over LumaDataSource /
ChromaDataSource traits the host implements over its frame buffers, plus an
AudioLevelMeter over AudioMeterDataSource with lit segments and a peak
marker. examples/scopes.rs drives all four from mock signals. 96 widget
tests pass.
2026-08-09 06:29:06 +08:00
Mike-Solar 63dbc64a32 feat(gpui_widgets): add project explorer (material bin) with tree/icon views
W5 companion widget. ProjectExplorer is data-agnostic over a
ProjectDataSource trait: a tree view with expandable folders and
double-click-to-open, an icon grid with thumbnails (img/placeholder
swatch), a view switcher, and file-drop import via on_drop (platform
FileDrop becomes an internal drag), emitting OpenRequested /
FileDropRequested / ViewChanged requests. flatten_tree (pure) is
unit-tested; examples/project_explorer.rs demos a mock project. 89 widget
tests pass.
2026-08-09 06:25:38 +08:00
Mike-Solar d97e3abd20 feat(gpui): support BGRA surfaces on macOS; add W4 viewer widget
Two changes landing W4 of the oak task list:

gpui_macos: the Surface renderer only accepted biplanar YUV 4:2:0 pixel
buffers, so engine BGRA frames could not be displayed. SurfaceBounds gains an
is_bgra flag and draw_surfaces now creates a single BGRA8Unorm texture (and
the fragment shader swizzles it to RGBA) for 32BGRA buffers, keeping the
YUV path unchanged. Verified by running the W3 surface_bridge demo.

gpui_widgets::viewer: ViewerWidget with a pure TransportState machine
(advance/loop/step/in-out, unit-tested), a PlaybackClock trait the host
implements over the engine, a ~60Hz polling ticker, a transport bar emitting
ViewerEvent requests, timecode via gpui::timeline::time, and safe-frame/zoom
toggles. examples/viewer.rs shows a mock clock with generated macOS test
frames. 87 widget + 182 gpui tests pass.
2026-08-09 06:05:54 +08:00
Mike-Solar d72d2e8210 feat(gpui_widgets): add menu bar, context menu and modal dialog framework
W2 of the oak task list. A pure menu model (nesting, disabled items,
separators, checked state, wrap-around keyboard navigation arithmetic) feeds
two views: a MenuBar with drop-down popups and a right-click ContextMenu,
both built on anchored+deferred with keyboard navigation (up/down/enter/
escape), hover-opened submenus, check marks, shortcut labels and request
events. The Modal framework provides the mask, title bar, content slot and
button row with escape/enter defaults; message_box (info/warning/error),
progress_dialog (driven by ProgressContent) and file_dialog (native gpui
fallback - the fork has no prompt_for_paths platform API) are built on it.
A menus_dialogs example demonstrates everything. 79 tests pass.
2026-08-09 05:33:29 +08:00
Mike-Solar 4a92ab13d8 feat(gpui_widgets): add controls demo example and mark W1 complete
Adds a parameter-panel example (cargo run -p gpui_widgets --example controls)
that demonstrates every form control: float/rational/angle sliders with
keying diamonds, a spinbox, a combo box, checkboxes, a radio group, a color
picker and a curve editor, printing each edit as a request event. Marks all
W1 checklist items done in docs/zh/oak-app-rewrite.md. 65 tests pass.
2026-08-09 05:24:10 +08:00
Mike-Solar b2ed7a66e4 feat(gpui_widgets): add curve editor with bezier handle dragging
CurveEditor edits a normalized x->y keyframe curve: cubic bezier segments
with per-point in/out control handles. Points are dragged with x clamped to
keep the list sorted; handles drag as offsets; double-click inserts a new
point at the cursor. Every gesture emits CurveEditorEvent requests while the
widget keeps a local working copy for fluid dragging. Pure geometry
(bezier evaluation, sampling via binary search, polyline approximation, hit
tests) is unit-tested; interaction tests cover point dragging and adding.
65 tests pass.
2026-08-09 05:22:30 +08:00
Mike-Solar 25b3167162 feat(gpui_widgets): add color swatch + HSV color picker popup
ColorPicker is a swatch button that opens a popup picker built from
anchored+deferred: an SV square (layered linear gradients over the hue) and
a 48-segment hue strip, both click- and drag-editable, plus RGBA spinboxes
reusing the SpinBox control. Pure HsvColor math (hue wrapping, saturation/
value extremes, u8 conversion) is unit-tested; an interaction test verifies
clicking the SV square emits ColorChanged. The eyedropper is a placeholder.
55 tests pass.
2026-08-09 05:11:32 +08:00
Mike-Solar 23b1f610a2 feat(gpui_widgets): add combo box with anchored+deferred popup menu
ComboBox renders a field showing the selection and a drop-down menu built
entirely with gpui's anchored + deferred elements (no platform primitives).
Menu dismissal is mouse-up-out based so an option click is never swallowed
by a capture-phase close that would redraw the menu away; the field toggles
from the open state recorded at mouse-down. Arrow keys cycle the selection
with wrap-around, escape closes. 48 tests pass.
2026-08-09 05:02:04 +08:00
Mike-Solar b65ccf1417 feat(gpui_widgets): add spinbox, checkbox and radio group controls
Completes the basic form controls of W1: a SpinBox reusing SliderModel for
range/step/clamping with an editable_text field (enter/blur commits,
escape reverts, invalid input rejected) and up/down buttons; a CheckBox with
optional tri-state and request-only Toggled events; a RadioGroup that emits
Selected requests. All three follow the request-only contract: the host
applies changes and updates the widget's display state. 45 tests pass.
2026-08-09 04:54:31 +08:00
Mike-Solar 6e0b541660 feat(gpui_widgets): add slider family with drag/double-click/wheel/reset gestures
Implements W1's slider: a pure SliderModel state machine (float, integer,
rational and angle kinds with clamping, step snapping, fine adjustment and
drag math) plus the Slider view with vertical-drag scrubbing (shift for
fine), double-click direct entry backed by editable_text (enter commits,
escape cancels, click-away commits, invalid text rejected), wheel stepping,
middle-click reset and arrow-key navigation. Every edit is emitted as a
SliderEvent request; keyable controls expose a Keying diamond. 37 unit and
interaction tests pass.
2026-08-09 04:48:57 +08:00
Mike-Solar df7c3d274f feat(gpui_widgets): scaffold form-controls crate with value core and keying diamond
New workspace crate implementing W1 of the oak task list. This first
slice lands the pure numeric core (ValueKind / SliderValue /
RationalValue / ValueFormatter with round-trip tests) and the keying
diamond button (KeyingState / KeyingRequest) that keyable controls
embed. 12 unit tests pass.
2026-08-09 04:20:48 +08:00