mirror of
https://github.com/flectar/mail.git
synced 2026-11-11 17:57:54 +00:00
156 lines
5.0 KiB
Rust
156 lines
5.0 KiB
Rust
use slint::platform::{
|
|
Platform, PointerEventButton, WindowAdapter, WindowEvent,
|
|
software_renderer::{MinimalSoftwareWindow, RepaintBufferType},
|
|
};
|
|
use std::{cell::Cell, rc::Rc};
|
|
|
|
slint::slint! {
|
|
import { Button } from "../ui/components/button.slint";
|
|
import { IconButton, TextLink } from "../ui/components/controls.slint";
|
|
import { SettingsLinkRow } from "../ui/components/settings-components.slint";
|
|
|
|
export component FocusHarness inherits Window {
|
|
preferred-width: 240px;
|
|
preferred-height: 260px;
|
|
out property <bool> button-ring: labeled.focus-visible;
|
|
out property <bool> icon-ring: icon.focus-visible;
|
|
out property <bool> link-ring: link.focus-visible;
|
|
out property <bool> text-link-ring: text-link.focus-visible;
|
|
callback button-activated();
|
|
callback icon-activated();
|
|
callback link-activated();
|
|
callback text-link-activated();
|
|
|
|
labeled := Button {
|
|
x: 20px; y: 20px; width: 140px;
|
|
text: "Action";
|
|
clicked => { root.button-activated(); }
|
|
}
|
|
icon := IconButton {
|
|
x: 20px; y: 80px;
|
|
tooltip-text: "More";
|
|
clicked => { root.icon-activated(); }
|
|
}
|
|
link := SettingsLinkRow {
|
|
x: 20px; y: 130px; width: 200px;
|
|
text: "Website";
|
|
description: "Opens in the browser";
|
|
clicked => { root.link-activated(); }
|
|
}
|
|
text-link := TextLink {
|
|
x: 20px; y: 196px;
|
|
text: "Privacy policy";
|
|
clicked => { root.text-link-activated(); }
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Headless(Rc<MinimalSoftwareWindow>);
|
|
|
|
impl Platform for Headless {
|
|
fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
|
|
Ok(self.0.clone())
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pointer_activation_hides_rings_and_keyboard_use_restores_them() {
|
|
let window = MinimalSoftwareWindow::new(RepaintBufferType::ReusedBuffer);
|
|
slint::platform::set_platform(Box::new(Headless(window))).unwrap();
|
|
let ui = FocusHarness::new().unwrap();
|
|
ui.window().set_size(slint::PhysicalSize::new(240, 260));
|
|
ui.show().unwrap();
|
|
|
|
let button_clicks = Rc::new(Cell::new(0));
|
|
let icon_clicks = Rc::new(Cell::new(0));
|
|
let link_clicks = Rc::new(Cell::new(0));
|
|
let text_link_clicks = Rc::new(Cell::new(0));
|
|
let count = button_clicks.clone();
|
|
ui.on_button_activated(move || count.set(count.get() + 1));
|
|
let count = icon_clicks.clone();
|
|
ui.on_icon_activated(move || count.set(count.get() + 1));
|
|
let count = link_clicks.clone();
|
|
ui.on_link_activated(move || count.set(count.get() + 1));
|
|
let count = text_link_clicks.clone();
|
|
ui.on_text_link_activated(move || count.set(count.get() + 1));
|
|
|
|
let pointer = |x, y| {
|
|
let position = slint::LogicalPosition::new(x, y);
|
|
ui.window().dispatch_event(WindowEvent::PointerPressed {
|
|
position,
|
|
button: PointerEventButton::Left,
|
|
});
|
|
ui.window().dispatch_event(WindowEvent::PointerReleased {
|
|
position,
|
|
button: PointerEventButton::Left,
|
|
});
|
|
};
|
|
let key = |key: slint::SharedString| {
|
|
ui.window()
|
|
.dispatch_event(WindowEvent::KeyPressed { text: key.clone() });
|
|
ui.window()
|
|
.dispatch_event(WindowEvent::KeyReleased { text: key });
|
|
};
|
|
|
|
pointer(60.0, 36.0);
|
|
assert_eq!(button_clicks.get(), 1);
|
|
assert!(
|
|
!ui.get_button_ring(),
|
|
"a click must not leave a button outline"
|
|
);
|
|
|
|
key(slint::platform::Key::Return.into());
|
|
assert_eq!(
|
|
button_clicks.get(),
|
|
2,
|
|
"the clicked button retains keyboard operation"
|
|
);
|
|
assert!(ui.get_button_ring(), "keyboard use should reveal its focus");
|
|
|
|
pointer(60.0, 36.0);
|
|
assert!(
|
|
!ui.get_button_ring(),
|
|
"clicking an already focused button clears the ring"
|
|
);
|
|
|
|
key(slint::platform::Key::Tab.into());
|
|
assert!(ui.get_icon_ring(), "Tab focus must stay visible");
|
|
key(slint::platform::Key::Space.into());
|
|
assert_eq!(icon_clicks.get(), 1);
|
|
|
|
pointer(36.0, 96.0);
|
|
assert_eq!(icon_clicks.get(), 2);
|
|
assert!(
|
|
!ui.get_icon_ring(),
|
|
"an icon click must clear its keyboard ring"
|
|
);
|
|
|
|
key(slint::platform::Key::Tab.into());
|
|
assert!(ui.get_link_ring(), "Tab must reach a settings link");
|
|
key(slint::platform::Key::Return.into());
|
|
assert_eq!(link_clicks.get(), 1, "Return opens the focused link");
|
|
|
|
pointer(120.0, 150.0);
|
|
assert_eq!(link_clicks.get(), 2);
|
|
assert!(
|
|
!ui.get_link_ring(),
|
|
"a link click must clear its keyboard ring"
|
|
);
|
|
|
|
key(slint::platform::Key::Tab.into());
|
|
assert!(ui.get_text_link_ring(), "Tab must reach a text link");
|
|
key(slint::platform::Key::Space.into());
|
|
assert_eq!(
|
|
text_link_clicks.get(),
|
|
1,
|
|
"Space opens the focused text link"
|
|
);
|
|
|
|
pointer(40.0, 218.0);
|
|
assert_eq!(text_link_clicks.get(), 2);
|
|
assert!(
|
|
!ui.get_text_link_ring(),
|
|
"a text link click must clear its keyboard ring"
|
|
);
|
|
}
|