From 85df47fd5cf0008ec55639b3975bff4d0f8566f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Sat, 26 Sep 2026 21:12:38 -0400 Subject: [PATCH] Files: a press on a download's button stays with the button gpui runs the click of every pressed element under the pointer, so a press on a finished download's Show button also opened the file through the pressable row. The actions' box stops the press on mouse down, so the row starts no click of its own. --- AGENTS.md | 1 + TASKS.md | 1 + src/files/tests/transfers.rs | 21 +++++++++++++++++++-- src/files/transfer.rs | 6 ++++-- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 91a4510..2cf25af 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -70,6 +70,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark. - A palette goes through `navigation::palette::Palette`: query field, grouped rows, cursor, keys and focus live there. CommandPalette, QuickOpen, QuickSwitcher, SearchPalette and QuickLauncher only build rows. - A menu goes through `menus::menu`: rows, submenus, keys, focus and presses outside live there, for DropdownMenu, OverflowMenu, SplitButton, ContextMenu, SearchableMenu and MenuBar. A press on the host's own box is the host's to handle, so a trigger toggles and a right click moves a context menu without a close and reopen in one event. - gpui focuses the nearest focusable ancestor on mouse down, and apps wrap everything in a `FocusScope`. A press that must leave focus alone calls `prevent_default`, as buttons and context regions do. +- gpui runs the click of every pressed element under the pointer, a row's with its button's. A pressable row that holds buttons stops their press at their box on mouse down (`files::transfer`), as `overlays::media_button` stops its own. - gpui draws a window's first frame inside `open_window`. State the first frame reads, such as `cx.set_menus`, is set before it opens. - gpui clicks a focused element when Enter or Space is released. An overlay that hands focus back picks on release too; a pick on press returns focus first, and the release clicks the opener again. An edit in place that hands focus back keeps its text on Enter's release (`forms::InlineEdit`). The press itself bubbles, so a container that takes Space leaves a focused button its own: `overlays::media_button` stops it. - A focus handle a component hands back lives across all its modes: take it with `tab_stop` before any early return, or keyed state drops it while the other mode draws and the handed-back focus lands nowhere. diff --git a/TASKS.md b/TASKS.md index 5b127d4..9dca411 100644 --- a/TASKS.md +++ b/TASKS.md @@ -327,3 +327,4 @@ Per-component lines live in `tasks/`. Tags there: | T27b | 2 | PASS | | | T27c | 1 | FAIL | recent and found files were keyed by their place, so the cursor left a file an open moved | | T27c | 2 | PASS | | +| T27d | 1 | FAIL | a press on a finished download's Show button also opened the file through its row | diff --git a/src/files/tests/transfers.rs b/src/files/tests/transfers.rs index ff4110c..9c5951c 100644 --- a/src/files/tests/transfers.rs +++ b/src/files/tests/transfers.rs @@ -1,6 +1,6 @@ use gpui::{ - Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled, TestAppContext, - VisualTestContext, Window, div, px, + Context, Entity, IntoElement, Modifiers, ParentElement, Render, SharedString, Styled, + TestAppContext, VisualTestContext, Window, div, px, }; use super::{press, settle, setup}; @@ -255,3 +255,20 @@ fn a_download_comes_down() { up.upload = true; let _ = DownloadManager::new("downloads", [up]); } + +#[gpui::test] +fn a_press_on_show_shows_and_opens_nothing(cx: &mut TestAppContext) { + setup(cx); + let (host, cx) = cx.add_window_view(|_, _| Downloading { asked: Vec::new() }); + cx.update(|window, _| window.activate_window()); + settle(cx); + let actions = cx + .debug_bounds("transfer-actions done") + .expect("the finished row's actions draw"); + cx.simulate_click(actions.center(), Modifiers::none()); + settle(cx); + assert_eq!( + host.read_with(cx, |host, _| host.asked.clone()), + ["show done"] + ); +} diff --git a/src/files/transfer.rs b/src/files/transfer.rs index 2999353..48c882b 100644 --- a/src/files/transfer.rs +++ b/src/files/transfer.rs @@ -1,8 +1,8 @@ use std::rc::Rc; use gpui::{ - AnyElement, App, ElementId, InteractiveElement, IntoElement, ParentElement, SharedString, - StatefulInteractiveElement, Styled, Window, div, prelude::*, + AnyElement, App, ElementId, InteractiveElement, IntoElement, MouseButton, ParentElement, + SharedString, StatefulInteractiveElement, Styled, Window, div, prelude::*, }; use super::FileIcon; @@ -201,8 +201,10 @@ pub(super) fn row(id: ElementId, transfer: &Transfer, asks: &Asks, cx: &App) -> ) .child( div() + .debug_selector(move || format!("transfer-actions {key}")) .flex_none() .flex() + .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation()) .children(actions.into_iter().flatten()), ) .into_any_element()