diff --git a/crates/op-editor-core/src/agent_settings_button_state.rs b/crates/op-editor-core/src/agent_settings_button_state.rs index b033159ad..374f672d2 100644 --- a/crates/op-editor-core/src/agent_settings_button_state.rs +++ b/crates/op-editor-core/src/agent_settings_button_state.rs @@ -9,8 +9,12 @@ pub enum AgentSettingsButton { AddAcpAgent, BuiltinEdit(usize), BuiltinRemove(usize), + BuiltinSaveDraft, + BuiltinCancelDraft, AcpEdit(usize), AcpRemove(usize), + AcpSaveDraft, + AcpCancelDraft, McpServer, McpClientConfigCopy, ImageSearchTest, diff --git a/crates/op-editor-ui/src/widgets/agent_settings_acp.rs b/crates/op-editor-ui/src/widgets/agent_settings_acp.rs index 960b51ed0..686841247 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_acp.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_acp.rs @@ -200,6 +200,12 @@ pub fn paint_acp_section( card, EXPANDED_CARD_H, ui.acp_agent_draft_ready(), + ui.button_pressed(ButtonPressTarget::AgentSettings( + AgentSettingsButton::AcpCancelDraft, + )), + ui.button_pressed(ButtonPressTarget::AgentSettings( + AgentSettingsButton::AcpSaveDraft, + )), ); y += card.size.y + CARD_GAP; } diff --git a/crates/op-editor-ui/src/widgets/agent_settings_builtin.rs b/crates/op-editor-ui/src/widgets/agent_settings_builtin.rs index 909c4e50f..9f07ebd11 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_builtin.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_builtin.rs @@ -316,7 +316,20 @@ pub fn paint_builtin_section( ); paint_builtin_agent_form(cx, theme, settings, ui, draft, None, card, now_ms); let form_h = expanded_card_height(settings, None); - paint_form_actions(cx, theme, ui, card, form_h, ui.builtin_agent_draft_ready()); + paint_form_actions( + cx, + theme, + ui, + card, + form_h, + ui.builtin_agent_draft_ready(), + ui.button_pressed(ButtonPressTarget::AgentSettings( + AgentSettingsButton::BuiltinCancelDraft, + )), + ui.button_pressed(ButtonPressTarget::AgentSettings( + AgentSettingsButton::BuiltinSaveDraft, + )), + ); y += card.size.y + CARD_GAP; } y diff --git a/crates/op-editor-ui/src/widgets/agent_settings_form_action_tests.rs b/crates/op-editor-ui/src/widgets/agent_settings_form_action_tests.rs new file mode 100644 index 000000000..9a0b79d4b --- /dev/null +++ b/crates/op-editor-ui/src/widgets/agent_settings_form_action_tests.rs @@ -0,0 +1,206 @@ +use crate::widgets::agent_settings_panel::AgentSettingsPanel; +use crate::widgets::{PaintCx, Widget}; +use crate::{Color, Point2D, Rect, RenderBackend, TextLayout}; +use op_editor_core::agent_settings::AgentSettingsTab; +use op_editor_core::editor_ui_state::ThemeMode; +use op_editor_core::{AgentSettingsButton, ButtonPressTarget, EditorState}; + +#[derive(Default)] +struct CaptureBackend { + round_fills: Vec<(Rect, Color)>, +} + +impl RenderBackend for CaptureBackend { + fn begin_frame(&mut self) {} + fn end_frame(&mut self) {} + fn fill_rect(&mut self, _: Rect, _: Color) {} + fn stroke_rect(&mut self, _: Rect, _: Color, _: f32) {} + fn draw_text(&mut self, _: &TextLayout, _: Point2D) {} + fn clip_rect(&mut self, _: Rect) {} + fn stroke_line(&mut self, _: Point2D, _: Point2D, _: Color, _: f32) {} + fn fill_round_rect(&mut self, rect: Rect, _: f32, color: Color) { + self.round_fills.push((rect, color)); + } + fn stroke_round_rect(&mut self, _: Rect, _: f32, _: Color, _: f32) {} + fn stroke_svg_path(&mut self, _: &str, _: Point2D, _: f32, _: Color, _: f32) {} + fn fill_oval(&mut self, _: Rect, _: Color) {} + fn save(&mut self) {} + fn restore(&mut self) {} + fn translate(&mut self, _: Point2D) {} + fn resize(&mut self, _: u32, _: u32) {} + fn dpi_scale(&self) -> f32 { + 1.0 + } + fn measure_text(&mut self, text: &str, size: f32) -> f32 { + text.chars().count() as f32 * size * 0.5 + } +} + +fn color_eq(a: Color, b: Color) -> bool { + (a.r - b.r).abs() < 1e-6 + && (a.g - b.g).abs() < 1e-6 + && (a.b - b.b).abs() < 1e-6 + && (a.a - b.a).abs() < 1e-6 +} + +fn rect_eq(a: Rect, b: Rect) -> bool { + (a.origin.x - b.origin.x).abs() < 0.01 + && (a.origin.y - b.origin.y).abs() < 0.01 + && (a.size.x - b.size.x).abs() < 0.01 + && (a.size.y - b.size.y).abs() < 0.01 +} + +fn content_metrics(panel: Rect) -> (f32, f32, f32) { + ( + panel.origin.x + 200.0 + 24.0, + panel.origin.y + 24.0, + panel.size.x - 200.0 - 48.0, + ) +} + +fn form_save_rect(card: Rect, form_h: f32) -> Rect { + Rect { + origin: Point2D::new( + card.origin.x + card.size.x - 12.0 - 68.0, + card.origin.y + form_h + 5.0, + ), + size: Point2D::new(68.0, 26.0), + } +} + +fn form_cancel_rect(card: Rect, form_h: f32) -> Rect { + let save = form_save_rect(card, form_h); + Rect { + origin: Point2D::new(save.origin.x - 8.0 - 68.0, save.origin.y), + size: Point2D::new(68.0, 26.0), + } +} + +fn builtin_draft_card(panel: Rect) -> Rect { + let (content_x, content_y, content_w) = content_metrics(panel); + Rect { + origin: Point2D::new(content_x, content_y + 12.0 + 28.0 + 28.0), + size: Point2D::new(content_w, 232.0), + } +} + +fn acp_draft_card_after_empty_builtin(panel: Rect) -> Rect { + let (content_x, content_y, content_w) = content_metrics(panel); + let acp_header_y = content_y + 12.0 + 28.0 + 28.0 + 64.0 + 28.0; + Rect { + origin: Point2D::new(content_x, acp_header_y + 28.0 + 28.0), + size: Point2D::new(content_w, 370.0), + } +} + +fn builtin_save_rect(panel: Rect) -> Rect { + form_save_rect(builtin_draft_card(panel), 196.0) +} + +fn builtin_cancel_rect(panel: Rect) -> Rect { + form_cancel_rect(builtin_draft_card(panel), 196.0) +} + +fn acp_save_rect(panel: Rect) -> Rect { + form_save_rect(acp_draft_card_after_empty_builtin(panel), 332.0) +} + +fn acp_cancel_rect(panel: Rect) -> Rect { + form_cancel_rect(acp_draft_card_after_empty_builtin(panel), 332.0) +} + +#[test] +fn pressed_builtin_draft_form_buttons_use_shared_feedback() { + for (button, expected_rect) in [ + ( + AgentSettingsButton::BuiltinCancelDraft, + builtin_cancel_rect as fn(Rect) -> Rect, + ), + ( + AgentSettingsButton::BuiltinSaveDraft, + builtin_save_rect as fn(Rect) -> Rect, + ), + ] { + let mut state = EditorState::default(); + state.editor_ui.theme_mode = ThemeMode::Light; + state.editor_ui.agent_settings.tab = AgentSettingsTab::Agents; + state.editor_ui.agent_settings.begin_builtin_agent_draft(); + state + .editor_ui + .agent_settings + .builtin_agent_draft + .as_mut() + .expect("draft should exist") + .api_key = "sk-test".into(); + state.editor_ui.pressed_button = Some(ButtonPressTarget::AgentSettings(button)); + let panel = AgentSettingsPanel::for_editor(&state); + let rect = panel.rect(1200.0, 800.0); + let target = expected_rect(rect); + let expected = panel + .theme + .button_hover + .with_alpha(panel.theme.button_hover.a * 1.8); + let mut backend = CaptureBackend::default(); + let mut cx = PaintCx { + backend: &mut backend, + }; + + panel.paint(&mut cx, rect); + + assert!( + backend + .round_fills + .iter() + .any(|(r, color)| rect_eq(*r, target) && color_eq(*color, expected)), + "pressed {button:?} should paint the shared pressed feedback token" + ); + } +} + +#[test] +fn pressed_acp_draft_form_buttons_use_shared_feedback() { + for (button, expected_rect) in [ + ( + AgentSettingsButton::AcpCancelDraft, + acp_cancel_rect as fn(Rect) -> Rect, + ), + ( + AgentSettingsButton::AcpSaveDraft, + acp_save_rect as fn(Rect) -> Rect, + ), + ] { + let mut state = EditorState::default(); + state.editor_ui.theme_mode = ThemeMode::Light; + state.editor_ui.agent_settings.tab = AgentSettingsTab::Agents; + state.editor_ui.agent_settings.begin_acp_agent_draft(); + state + .editor_ui + .agent_settings + .acp_agent_draft + .as_mut() + .expect("draft should exist") + .command = "op-agent".into(); + state.editor_ui.pressed_button = Some(ButtonPressTarget::AgentSettings(button)); + let panel = AgentSettingsPanel::for_editor(&state); + let rect = panel.rect(1200.0, 800.0); + let target = expected_rect(rect); + let expected = panel + .theme + .button_hover + .with_alpha(panel.theme.button_hover.a * 1.8); + let mut backend = CaptureBackend::default(); + let mut cx = PaintCx { + backend: &mut backend, + }; + + panel.paint(&mut cx, rect); + + assert!( + backend + .round_fills + .iter() + .any(|(r, color)| rect_eq(*r, target) && color_eq(*color, expected)), + "pressed {button:?} should paint the shared pressed feedback token" + ); + } +} diff --git a/crates/op-editor-ui/src/widgets/agent_settings_form_actions.rs b/crates/op-editor-ui/src/widgets/agent_settings_form_actions.rs index 6b0e72a38..69f5b32a9 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_form_actions.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_form_actions.rs @@ -2,8 +2,10 @@ use crate::theme::Theme; use crate::widgets::agent_settings_i18n::t as t_settings; +use crate::widgets::button::{paint_ghost_button_feedback, tokens_from_theme}; use crate::widgets::PaintCx; use crate::{Color, Point2D, Rect, TextLayout}; +use jian_widgets::components::button::{Button, ButtonVariant}; use op_editor_core::editor_ui_state::EditorUiState; const FORM_BTN_W: f32 = 68.0; @@ -16,22 +18,26 @@ pub fn paint_form_actions( card: Rect, form_h: f32, can_save: bool, + cancel_pressed: bool, + save_pressed: bool, ) { paint_text_button( cx, theme, cancel_button_rect(card, form_h), t_settings(ui, "common.cancel"), - false, + ButtonVariant::Outline, true, + cancel_pressed, ); paint_text_button( cx, theme, save_button_rect(card, form_h), t_settings(ui, "common.save"), - true, + ButtonVariant::Primary, can_save, + save_pressed, ); } @@ -60,23 +66,29 @@ fn paint_text_button( theme: &Theme, rect: Rect, label: &str, - primary: bool, + variant: ButtonVariant, enabled: bool, + pressed: bool, ) { - let bg = if primary && enabled { - theme.primary - } else { - theme.button_hover + let is_primary = matches!(variant, ButtonVariant::Primary); + Button { + label: "", + icon_d: None, + variant, + enabled, + hovered: !is_primary, + pressed, + font_size: 11.0, + } + .paint(cx.backend, rect, &tokens_from_theme(theme)); + if is_primary && enabled && pressed { + paint_ghost_button_feedback(cx.backend, theme, rect, false, true); + } + let fg = match (is_primary, enabled) { + (true, true) => theme.primary_foreground, + (_, true) => theme.foreground, + _ => theme.muted_foreground, }; - let fg = if primary && enabled { - theme.primary_foreground - } else if enabled { - theme.foreground - } else { - theme.muted_foreground - }; - cx.backend.fill_round_rect(rect, 6.0, bg); - cx.backend.stroke_round_rect(rect, 6.0, theme.border, 1.0); let tw = cx.backend.measure_text(label, 11.0); draw_text( cx, diff --git a/crates/op-editor-ui/src/widgets/editor_state_ext.rs b/crates/op-editor-ui/src/widgets/editor_state_ext.rs index 49867c02d..5c6b3afe5 100644 --- a/crates/op-editor-ui/src/widgets/editor_state_ext.rs +++ b/crates/op-editor-ui/src/widgets/editor_state_ext.rs @@ -106,8 +106,12 @@ pub fn agent_settings_button( W::AddAcpAgent => Some(O::AddAcpAgent), W::EditBuiltinAgent(index) => Some(O::BuiltinEdit(index)), W::RemoveBuiltinAgent(index) => Some(O::BuiltinRemove(index)), + W::SaveBuiltinAgentDraft => Some(O::BuiltinSaveDraft), + W::CancelBuiltinAgentDraft => Some(O::BuiltinCancelDraft), W::EditAcpAgent(index) => Some(O::AcpEdit(index)), W::RemoveAcpAgent(index) => Some(O::AcpRemove(index)), + W::SaveAcpAgentDraft => Some(O::AcpSaveDraft), + W::CancelAcpAgentDraft => Some(O::AcpCancelDraft), W::ToggleMcpServer => Some(O::McpServer), W::CopyMcpClientConfig => Some(O::McpClientConfigCopy), W::TestImageSearch => Some(O::ImageSearchTest), diff --git a/crates/op-editor-ui/src/widgets/mod.rs b/crates/op-editor-ui/src/widgets/mod.rs index 98b8a794a..ceae59d3c 100644 --- a/crates/op-editor-ui/src/widgets/mod.rs +++ b/crates/op-editor-ui/src/widgets/mod.rs @@ -132,6 +132,8 @@ mod agent_settings_caret; mod agent_settings_compact_action_tests; #[cfg(test)] mod agent_settings_connect_tests; +#[cfg(test)] +mod agent_settings_form_action_tests; mod agent_settings_form_actions; mod agent_settings_header_action; pub mod agent_settings_i18n; diff --git a/crates/op-host-native/src/widget_host.rs b/crates/op-host-native/src/widget_host.rs index a7e00582d..55d6b6ab6 100644 --- a/crates/op-host-native/src/widget_host.rs +++ b/crates/op-host-native/src/widget_host.rs @@ -40,6 +40,8 @@ mod agent_settings_acp_tests; mod agent_settings_compact_press_tests; mod agent_settings_draft_dispatch; #[cfg(test)] +mod agent_settings_form_press_tests; +#[cfg(test)] mod agent_settings_image_gen_tests; #[cfg(test)] mod agent_settings_tests; diff --git a/crates/op-host-native/src/widget_host/agent_settings_form_press_tests.rs b/crates/op-host-native/src/widget_host/agent_settings_form_press_tests.rs new file mode 100644 index 000000000..8370c1d15 --- /dev/null +++ b/crates/op-host-native/src/widget_host/agent_settings_form_press_tests.rs @@ -0,0 +1,139 @@ +use super::WidgetHostNative; +use op_editor_core::{AgentSettingsButton, ButtonPressTarget}; +use op_editor_ui::widgets::agent_settings_panel::AgentSettingsPanel; + +fn content_metrics(host: &WidgetHostNative) -> (f32, f32, f32) { + let panel = AgentSettingsPanel::for_editor(host.editor_state()); + let rect = panel.rect(1200.0, 800.0); + ( + rect.origin.x + 200.0 + 24.0, + rect.origin.y + 24.0, + rect.size.x - 200.0 - 48.0, + ) +} + +fn builtin_draft_card_y(content_y: f32) -> f32 { + content_y + 12.0 + 28.0 + 28.0 +} + +fn acp_draft_card_y(content_y: f32) -> f32 { + content_y + 12.0 + 28.0 + 28.0 + 64.0 + 28.0 + 28.0 + 28.0 +} + +#[test] +fn builtin_draft_save_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHostNative::new(); + host.editor_state_mut() + .editor_ui + .agent_settings + .begin_builtin_agent_draft(); + host.editor_state_mut() + .editor_ui + .agent_settings + .builtin_agent_draft + .as_mut() + .expect("draft should exist") + .api_key = "sk-test".into(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 34.0, + builtin_draft_card_y(content_y) + 196.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state().editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::BuiltinSaveDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state().editor_ui.pressed_button, None); +} + +#[test] +fn builtin_draft_cancel_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHostNative::new(); + host.editor_state_mut() + .editor_ui + .agent_settings + .begin_builtin_agent_draft(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 68.0 - 8.0 - 34.0, + builtin_draft_card_y(content_y) + 196.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state().editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::BuiltinCancelDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state().editor_ui.pressed_button, None); +} + +#[test] +fn acp_draft_save_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHostNative::new(); + host.editor_state_mut() + .editor_ui + .agent_settings + .begin_acp_agent_draft(); + host.editor_state_mut() + .editor_ui + .agent_settings + .acp_agent_draft + .as_mut() + .expect("draft should exist") + .command = "op-agent".into(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 34.0, + acp_draft_card_y(content_y) + 332.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state().editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::AcpSaveDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state().editor_ui.pressed_button, None); +} + +#[test] +fn acp_draft_cancel_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHostNative::new(); + host.editor_state_mut() + .editor_ui + .agent_settings + .begin_acp_agent_draft(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 68.0 - 8.0 - 34.0, + acp_draft_card_y(content_y) + 332.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state().editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::AcpCancelDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state().editor_ui.pressed_button, None); +} diff --git a/crates/op-host-web/src/widget_host.rs b/crates/op-host-web/src/widget_host.rs index 4d58c099e..167f640d9 100644 --- a/crates/op-host-web/src/widget_host.rs +++ b/crates/op-host-web/src/widget_host.rs @@ -44,6 +44,8 @@ use op_editor_ui::{Point2D, Rect, Theme}; mod a11y_bridge; #[cfg(test)] mod agent_settings_compact_press_tests; +#[cfg(test)] +mod agent_settings_form_press_tests; mod agent_settings_mcp_server; mod agent_settings_press; #[cfg(test)] diff --git a/crates/op-host-web/src/widget_host/agent_settings_form_press_tests.rs b/crates/op-host-web/src/widget_host/agent_settings_form_press_tests.rs new file mode 100644 index 000000000..86bf5d6ad --- /dev/null +++ b/crates/op-host-web/src/widget_host/agent_settings_form_press_tests.rs @@ -0,0 +1,139 @@ +use super::WidgetHost; +use op_editor_core::{AgentSettingsButton, ButtonPressTarget}; +use op_editor_ui::widgets::agent_settings_panel::AgentSettingsPanel; + +fn content_metrics(host: &WidgetHost) -> (f32, f32, f32) { + let panel = AgentSettingsPanel::for_editor(&host.editor_state); + let rect = panel.rect(1200.0, 800.0); + ( + rect.origin.x + 200.0 + 24.0, + rect.origin.y + 24.0, + rect.size.x - 200.0 - 48.0, + ) +} + +fn builtin_draft_card_y(content_y: f32) -> f32 { + content_y + 12.0 + 28.0 + 28.0 +} + +fn acp_draft_card_y(content_y: f32) -> f32 { + content_y + 12.0 + 28.0 + 28.0 + 64.0 + 28.0 + 28.0 + 28.0 +} + +#[test] +fn builtin_draft_save_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHost::new(); + host.editor_state + .editor_ui + .agent_settings + .begin_builtin_agent_draft(); + host.editor_state + .editor_ui + .agent_settings + .builtin_agent_draft + .as_mut() + .expect("draft should exist") + .api_key = "sk-test".into(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 34.0, + builtin_draft_card_y(content_y) + 196.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state.editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::BuiltinSaveDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state.editor_ui.pressed_button, None); +} + +#[test] +fn builtin_draft_cancel_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHost::new(); + host.editor_state + .editor_ui + .agent_settings + .begin_builtin_agent_draft(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 68.0 - 8.0 - 34.0, + builtin_draft_card_y(content_y) + 196.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state.editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::BuiltinCancelDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state.editor_ui.pressed_button, None); +} + +#[test] +fn acp_draft_save_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHost::new(); + host.editor_state + .editor_ui + .agent_settings + .begin_acp_agent_draft(); + host.editor_state + .editor_ui + .agent_settings + .acp_agent_draft + .as_mut() + .expect("draft should exist") + .command = "op-agent".into(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 34.0, + acp_draft_card_y(content_y) + 332.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state.editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::AcpSaveDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state.editor_ui.pressed_button, None); +} + +#[test] +fn acp_draft_cancel_press_sets_and_release_clears_agent_settings_button() { + let mut host = WidgetHost::new(); + host.editor_state + .editor_ui + .agent_settings + .begin_acp_agent_draft(); + let (content_x, content_y, content_w) = content_metrics(&host); + + assert!(host.dispatch_agent_settings_press( + content_x + content_w - 12.0 - 68.0 - 8.0 - 34.0, + acp_draft_card_y(content_y) + 332.0 + 18.0, + 1200.0, + 800.0, + )); + assert_eq!( + host.editor_state.editor_ui.pressed_button, + Some(ButtonPressTarget::AgentSettings( + AgentSettingsButton::AcpCancelDraft + )) + ); + + assert!(host.apply_release_with_viewport(1200.0, 800.0)); + assert_eq!(host.editor_state.editor_ui.pressed_button, None); +}