Skip to content

feat(desktop-gpui): pick an area's aspect ratio from chips and a menu, with fill and reset - #3450

Open
richiemcilroy wants to merge 7 commits into
fix/gpui-camera-above-pickerfrom
feat/gpui-area-aspect-picker
Open

richiemcilroy wants to merge 7 commits into
fix/gpui-camera-above-pickerfrom
feat/gpui-area-aspect-picker

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Stacked on #3441.

Problem

The area picker could lock its selection to an aspect ratio, but the only control was a chip that cycled through all nine ratios one click at a time. There was no way to see the choices, jump straight to one, fill the display, or start the selection over.

Change

  • Chips: the toolbar shows the size readout, then one-click chips for Free, 16:9, 4:3, 1:1 and 9:16.
  • More menu: a ratio button opens a menu with the rest (16:10, 21:9, 3:2, 2:1). The button stays highlighted while one of those is active. The menu closes with Escape, the arrow keys move through it, and opening any other overlay menu closes it.
  • Reset and Fill: Reset clears the selection and keeps the ratio. Fill takes the whole display, or the largest centred area of the locked ratio.
  • Animation: choosing a ratio, filling, or resetting animates the selection to its new shape over 240 ms on an ease-out curve. The occluder and the start controls move with it. Starting a drag cuts the animation short, from the shape as drawn, so a handle grabbed mid-animation resizes instead of starting a new selection.
  • Persistence: the chosen ratio is still remembered across pickers (gpui_area_selection.aspectRatio).

The toolbar keeps today's surface styling; the glass restyle lands separately.

Test

  • Unit tests:
    • the quick chips and the More menu cover every ratio exactly once;
    • Fill matches the display or the centred ratio area on a 1512x982 display;
    • the animation starts and ends exactly and grows monotonically.
  • The existing area tests still pass (24 in target_overlay).
  • Picker smoke (real app) now saves a screenshot of every picker mode on macOS, Windows and Linux.

RetriggerView in GreptileConfidence Score: 5/5

The reviewed changes appear safe to merge.

Summary

Adds aspect-ratio chips and a More menu, Fill and Reset controls, animated selection changes, and picker screenshots.

  • Area picking now offers quick ratios, a menu, Reset, and Fill.
  • Picker smoke runs now save screenshots of each target mode.

Reviews (5) · Last reviewed commit: "fix(desktop-gpui): colour the area toolb..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cap-status Ready Ready Preview Oct 27, 2026 9:03am UTC

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

Comment thread apps/desktop-gpui/src/target_overlay.rs Outdated
Comment thread apps/desktop-gpui/src/target_overlay.rs Outdated
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found 2 potential issues (2 medium).

Open in Capy

Comment on lines +2958 to +2963
if let (Some(crop), Some((from, started))) = (self.crop, self.reshape.take()) {
self.crop = Some(area_between(
from,
crop,
started.elapsed().as_secs_f32() / AREA_RESHAPE.as_secs_f32(),
));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving during a reshape leaves the crop outside its locked ratio

Medium Severity

Change a 640×360 selection to 1:1, then grab inside it before the 240 ms animation completes. This freezes an intermediate, non-square rectangle into self.crop. The AreaDrag::Move branch preserves those dimensions, mouse-up only clamps them, and target() sends them directly to capture, so the resulting recording can remain non-square while 1:1 is selected. Preserve hit testing against the displayed rectangle, but reconcile the crop with the locked ratio when interrupting or completing a move.

Open in Capy

Comment on lines +1277 to +1282
if let Some(menu) = &mut this.aspect_menu {
match menu.on_key(&event.keystroke.key) {
crate::ui::MenuKey::Commit(index) => this.choose_aspect(index, cx),
crate::ui::MenuKey::Dismiss => {
this.aspect_menu = None;
cx.notify();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Escape dismisses the whole picker instead of the aspect menu on macOS

Medium Severity

The unchanged global Escape receiver in app_windows.rs unconditionally calls dismiss_target_overlays(). While the picker is open on macOS, platform::escape_hotkey::escape_pressed consumes Escape through Carbon and sends it to that receiver, bypassing this new local menu handler. Opening More and pressing Escape therefore closes the entire picker and loses the selection rather than merely closing the menu. Route the global Escape through open-menu dismissal before falling back to dismissing the overlays.

Open in Capy

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capy found no issues.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

This branch was successfully deployed

2 active deployments
Preview – cap-web — 48184cfb Deployed Oct 27, 2026 by vercel[bot]
Preview – cap-status — 48184cfb Deployed Oct 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant