Integrate scoped reference chooser and scenario form focus and reveal
This commit is contained in:
@@ -45,6 +45,22 @@ mod scenario_scroll {
|
||||
area,
|
||||
process: false,
|
||||
restore,
|
||||
reveal: None,
|
||||
})
|
||||
}
|
||||
pub(super) fn observe_canvas<'a, R: renderer::Renderer + 'a>(
|
||||
context: scenario::Context,
|
||||
restore: Option<scenario::ScrollRestore>,
|
||||
reveal: Option<scenario::ScrollReveal>,
|
||||
content: impl Into<Element<'a, Message, Theme, R>>,
|
||||
) -> Element<'a, Message, Theme, R> {
|
||||
Element::new(Observer {
|
||||
content: content.into(),
|
||||
context,
|
||||
area: scenario::ScrollArea::Canvas,
|
||||
process: false,
|
||||
restore,
|
||||
reveal,
|
||||
})
|
||||
}
|
||||
pub(super) fn observe_topology<'a>(
|
||||
@@ -63,6 +79,7 @@ mod scenario_scroll {
|
||||
area,
|
||||
process: true,
|
||||
restore: None,
|
||||
reveal: None,
|
||||
})
|
||||
}
|
||||
struct Observer<'a, R = Renderer> {
|
||||
@@ -71,12 +88,14 @@ mod scenario_scroll {
|
||||
area: scenario::ScrollArea,
|
||||
process: bool,
|
||||
restore: Option<scenario::ScrollRestore>,
|
||||
reveal: Option<scenario::ScrollReveal>,
|
||||
}
|
||||
type Report = Option<(bool, Id, Id, Vector)>;
|
||||
struct ObservedScroll {
|
||||
identity: (Id, Id),
|
||||
report: Report,
|
||||
restored: Option<Id>,
|
||||
revealed: Option<(Id, scenario::Slot)>,
|
||||
}
|
||||
#[derive(Default)]
|
||||
struct Translation(Option<Vector>);
|
||||
@@ -115,6 +134,41 @@ mod scenario_scroll {
|
||||
self.applied = true;
|
||||
}
|
||||
}
|
||||
struct RevealTranslation {
|
||||
request: scenario::ScrollReveal,
|
||||
applied: bool,
|
||||
}
|
||||
impl widget::Operation for RevealTranslation {
|
||||
fn traverse(&mut self, _: &mut dyn FnMut(&mut dyn widget::Operation)) {}
|
||||
fn scrollable(
|
||||
&mut self,
|
||||
_: Option<&widget::Id>,
|
||||
bounds: Rectangle,
|
||||
_: Rectangle,
|
||||
translation: Vector,
|
||||
state: &mut dyn widget::operation::Scrollable,
|
||||
) {
|
||||
let reveal = self.request;
|
||||
if !reveal.y.is_finite() || !reveal.padding.is_finite() || bounds.height <= 0. {
|
||||
return;
|
||||
}
|
||||
let padding = reveal.padding.max(0.).min(bounds.height / 2.);
|
||||
let y = if reveal.y - padding < translation.y {
|
||||
(reveal.y - padding).max(0.)
|
||||
} else if reveal.y + padding > translation.y + bounds.height {
|
||||
(reveal.y + padding - bounds.height).max(0.)
|
||||
} else {
|
||||
translation.y
|
||||
};
|
||||
// Preserve horizontal position and reveal only once per invocation
|
||||
// and explicit destination. Later ordinary scrolling stays ordinary.
|
||||
state.scroll_to(widget::operation::scrollable::AbsoluteOffset {
|
||||
x: None,
|
||||
y: Some(y),
|
||||
});
|
||||
self.applied = true;
|
||||
}
|
||||
}
|
||||
impl<R: renderer::Renderer> Observer<'_, R> {
|
||||
fn report(
|
||||
&mut self,
|
||||
@@ -142,6 +196,27 @@ mod scenario_scroll {
|
||||
);
|
||||
operation.applied.then_some(request.token)
|
||||
});
|
||||
if let Some(reveal) = self.reveal.filter(|request| {
|
||||
!self.process
|
||||
&& receipt.is_none()
|
||||
&& tree.state.downcast_ref::<ObservedScroll>().revealed
|
||||
!= Some((request.token, request.slot))
|
||||
}) {
|
||||
let mut operation = RevealTranslation {
|
||||
request: reveal,
|
||||
applied: false,
|
||||
};
|
||||
self.content.as_widget_mut().operate(
|
||||
&mut tree.children[0],
|
||||
layout,
|
||||
renderer,
|
||||
&mut operation,
|
||||
);
|
||||
if operation.applied {
|
||||
tree.state.downcast_mut::<ObservedScroll>().revealed =
|
||||
Some((reveal.token, reveal.slot));
|
||||
}
|
||||
}
|
||||
let mut offset = Translation::default();
|
||||
self.content.as_widget_mut().operate(
|
||||
&mut tree.children[0],
|
||||
@@ -202,6 +277,7 @@ mod scenario_scroll {
|
||||
identity: (self.context.document, self.context.scenario),
|
||||
report: None,
|
||||
restored: None,
|
||||
revealed: None,
|
||||
})
|
||||
}
|
||||
fn children(&self) -> Vec<widget::Tree> {
|
||||
|
||||
Reference in New Issue
Block a user