Scroll to the focused preference from its unscrolled position
This commit is contained in:
42
src/app.rs
42
src/app.rs
@@ -1013,6 +1013,18 @@ impl App {
|
||||
pub(crate) fn subscription(&self) -> Subscription<Message> {
|
||||
let mut subscriptions = vec![
|
||||
keyboard::on_key_press(shortcut),
|
||||
// A focused text field takes escape for itself to drop its own
|
||||
// focus, so a dialog would never see it through `on_key_press`.
|
||||
iced::event::listen_with(|event, _, _| {
|
||||
matches!(
|
||||
event,
|
||||
iced::Event::Keyboard(keyboard::Event::KeyPressed {
|
||||
key: keyboard::Key::Named(keyboard::key::Named::Escape),
|
||||
..
|
||||
})
|
||||
)
|
||||
.then_some(Message::DismissPanel)
|
||||
}),
|
||||
window::close_requests().map(Message::WindowClosed),
|
||||
window::close_events().map(Message::WindowClosed),
|
||||
];
|
||||
@@ -1207,7 +1219,6 @@ fn shortcut(key: keyboard::Key, modifiers: keyboard::Modifiers) -> Option<Messag
|
||||
keyboard::Key::Character("m") if modifiers.command() && modifiers.shift() => {
|
||||
Some(Message::OpenModelManager)
|
||||
}
|
||||
keyboard::Key::Named(keyboard::key::Named::Escape) => Some(Message::DismissPanel),
|
||||
keyboard::Key::Named(keyboard::key::Named::Tab) => Some(if modifiers.shift() {
|
||||
Message::FocusPrevious
|
||||
} else {
|
||||
@@ -1308,12 +1319,12 @@ fn reveal_focused() -> Task<Message> {
|
||||
id: Option<&Id>,
|
||||
bounds: Rectangle,
|
||||
content_bounds: Rectangle,
|
||||
_translation: Vector,
|
||||
translation: Vector,
|
||||
) {
|
||||
if id != Some(&Id::from(preferences_scroll_id())) {
|
||||
return;
|
||||
}
|
||||
let Some(offset) = reveal_offset(self.field, bounds) else {
|
||||
let Some(offset) = reveal_offset(self.field, bounds, translation.y) else {
|
||||
return;
|
||||
};
|
||||
state.scroll_by(
|
||||
@@ -1331,14 +1342,19 @@ fn reveal_focused() -> Task<Message> {
|
||||
}
|
||||
|
||||
/// How far the scroll area has to move for `field` to sit fully inside
|
||||
/// `viewport`, or `None` when it already does. A field taller than the
|
||||
/// viewport lines up with its top edge.
|
||||
fn reveal_offset(field: iced::Rectangle, viewport: iced::Rectangle) -> Option<f32> {
|
||||
/// `viewport`, or `None` when it already does. A field taller than the viewport
|
||||
/// lines up with its top edge.
|
||||
///
|
||||
/// Layout places the content in its own unscrolled coordinates, so `field` only
|
||||
/// says where it sits once `scrolled` — the offset the area is already at — is
|
||||
/// taken off it.
|
||||
fn reveal_offset(field: iced::Rectangle, viewport: iced::Rectangle, scrolled: f32) -> Option<f32> {
|
||||
// Keep a row's worth of margin, so a revealed field never sits flush
|
||||
// against the edge of the viewport.
|
||||
const MARGIN: f32 = 12.0;
|
||||
let above = field.y - MARGIN - viewport.y;
|
||||
let below = field.y + field.height + MARGIN - (viewport.y + viewport.height);
|
||||
let top = field.y - scrolled;
|
||||
let above = top - MARGIN - viewport.y;
|
||||
let below = top + field.height + MARGIN - (viewport.y + viewport.height);
|
||||
if above < 0.0 {
|
||||
Some(above)
|
||||
} else if below > 0.0 {
|
||||
@@ -1464,11 +1480,15 @@ mod tests {
|
||||
width: 700.0,
|
||||
height: 30.0,
|
||||
};
|
||||
assert_eq!(reveal_offset(field(200.0), viewport), None);
|
||||
assert_eq!(reveal_offset(field(200.0), viewport, 0.0), None);
|
||||
// Above the fold: scroll back by the gap plus the margin.
|
||||
assert_eq!(reveal_offset(field(80.0), viewport), Some(-32.0));
|
||||
assert_eq!(reveal_offset(field(80.0), viewport, 0.0), Some(-32.0));
|
||||
// Below it: the bottom edge plus the margin comes into view.
|
||||
assert_eq!(reveal_offset(field(490.0), viewport), Some(32.0));
|
||||
assert_eq!(reveal_offset(field(490.0), viewport, 0.0), Some(32.0));
|
||||
// A field the scroll already brought into view stays put, and one
|
||||
// further down moves by the gap alone, not by the whole scroll.
|
||||
assert_eq!(reveal_offset(field(690.0), viewport, 500.0), None);
|
||||
assert_eq!(reveal_offset(field(990.0), viewport, 500.0), Some(32.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user