Added scroll zoom commands.

This commit is contained in:
Samuel Guerra 2023-09-08 17:08:43 -03:00
parent 3b917a9391
commit d883982a24
7 changed files with 74 additions and 18 deletions

View File

@ -28,11 +28,13 @@
# Scroll
* Click in thumb drag and release outside thumb causes it to stay pressed.
* Implement touch scroll inertia.
* Implement `ScrollMode::ZOOM`.
- Touch gesture.
- Scroll wheel zoom.
- Commands.
- Scroll-to-fill.
# Touch Events

View File

@ -461,8 +461,8 @@ fn center_viewport(msg: impl UiNode) -> impl UiNode {
// the large images can take a moment to decode in debug builds, but the size
// is already known after read, so the "loading.." message ends-up off-screen
// because it is centered on the image.
x = zero_ui::widgets::scroll::SCROLL_HORIZONTAL_OFFSET_VAR.map(|&fct| Length::Relative(fct) - 1.vw() * fct);
y = zero_ui::widgets::scroll::SCROLL_VERTICAL_OFFSET_VAR.map(|&fct| Length::Relative(fct) - 1.vh() * fct);
x = zero_ui::widgets::scroll::SCROLL.horizontal_offset().map(|&fct| Length::Relative(fct) - 1.vw() * fct);
y = zero_ui::widgets::scroll::SCROLL.vertical_offset().map(|&fct| Length::Relative(fct) - 1.vh() * fct);
zero_ui::core::widget_base::can_auto_hide = false;
max_size = (1.vw(), 1.vh());
child_align = Align::CENTER;

View File

@ -105,7 +105,7 @@ fn scroll_to_btn(target: WidgetId, mode: ScrollToMode) -> impl UiNode {
child = Text!("Scroll To {} {}", target, if let ScrollToMode::Minimal{..} = &mode { "(minimal)" } else { "(center)" });
enabled = cmd.is_enabled();
on_click = hn!(|_| {
cmd.notify_param(commands::ScrollToRequest { widget_id: target, mode: mode.clone() });
cmd.notify_param(commands::ScrollToRequest { widget_id: target, mode: mode.clone(), zoom: None, });
});
}
}

View File

@ -102,7 +102,9 @@ fn on_build(wgt: &mut WidgetBuilding) {
let child = with_context_var(child, SCROLL_HORIZONTAL_OFFSET_VAR, var(0.fct()));
let child = with_context_var(child, OVERSCROLL_VERTICAL_OFFSET_VAR, var(0.fct()));
with_context_var(child, OVERSCROLL_HORIZONTAL_OFFSET_VAR, var(0.fct()))
let child = with_context_var(child, OVERSCROLL_HORIZONTAL_OFFSET_VAR, var(0.fct()));
with_context_var(child, SCROLL_SCALE_VAR, var(1.fct()))
});
}

View File

@ -165,7 +165,8 @@ command! {
shortcut_filter: ShortcutFilter::FOCUSED | ShortcutFilter::CMD_ENABLED,
};
/// Represents the action of scrolling until a child widget is fully visible.
/// Represents the action of scrolling until a child widget is fully visible, the command can
/// also adjust the zoom scale.
///
/// # Metadata
///
@ -178,6 +179,25 @@ command! {
///
/// You can use the [`scroll_to`] function to invoke this command in all parent scrolls automatically.
pub static SCROLL_TO_CMD;
/// Represents the **zoom in** action.
pub static ZOOM_IN_CMD = {
name: "Zoom In",
shortcut: shortcut!(CTRL+'+'),
shortcut_filter: ShortcutFilter::FOCUSED | ShortcutFilter::CMD_ENABLED,
};
/// Represents the **zoom out** action.
pub static ZOOM_OUT_CMD = {
name: "Zoom Out",
shortcut: shortcut!(CTRL+'-'),
shortcut_filter: ShortcutFilter::FOCUSED | ShortcutFilter::CMD_ENABLED,
};
/// Represents the **reset zoom** action.
pub static ZOOM_RESET_CMD = {
name: "Reset Zoom",
};
}
/// Parameters for the scroll and page commands.
@ -250,6 +270,13 @@ pub struct ScrollToRequest {
/// How much the scroll position will change to showcase the target widget.
pub mode: ScrollToMode,
/// Optional zoom scale target.
///
/// If set the offsets and scale will animate so that the `mode`
/// is fullfilled when this zoom factor is reached. If not set the scroll will happen in
/// the current zoom scale.
pub zoom: Option<Factor>,
}
impl ScrollToRequest {
/// Pack the request into a command parameter.
@ -265,6 +292,7 @@ impl ScrollToRequest {
p.downcast_ref::<WidgetId>().map(|id| ScrollToRequest {
widget_id: *id,
mode: ScrollToMode::default(),
zoom: None,
})
}
}
@ -287,7 +315,8 @@ impl_from_and_into_var! {
fn from(widget_id: WidgetId) -> ScrollToRequest {
ScrollToRequest {
widget_id,
mode: ScrollToMode::default()
mode: ScrollToMode::default(),
zoom: None,
}
}
}
@ -374,13 +403,12 @@ impl IntoValue<Option<ScrollToMode>> for ScrollToMode {}
///
/// [`is_scroll`]: WidgetInfoExt::is_scroll
pub fn scroll_to(target: impl Into<WidgetId>, mode: impl Into<ScrollToMode>) {
let target = target.into();
for w in crate::core::window::WINDOWS.widget_trees() {
if let Some(target) = w.get(target) {
scroll_to_info(&target, mode.into());
break;
}
}
scroll_to_impl(target.into(), mode.into(), None)
}
/// Like [`scroll_to`], but also adjusts the zoom scale.
pub fn scroll_to_zoom(target: impl Into<WidgetId>, mode: impl Into<ScrollToMode>, zoom: impl Into<Factor>) {
scroll_to_impl(target.into(), mode.into(), Some(zoom.into()))
}
/// Scroll all parent [`is_scroll`] widgets of `target` so that it becomes visible.
@ -389,13 +417,31 @@ pub fn scroll_to(target: impl Into<WidgetId>, mode: impl Into<ScrollToMode>) {
///
/// [`is_scroll`]: WidgetInfoExt::is_scroll
pub fn scroll_to_info(target: &crate::core::widget_info::WidgetInfo, mode: impl Into<ScrollToMode>) {
scroll_to_info_impl(target, mode.into(), None)
}
/// Like [`scroll_to_info`], but also adjusts the zoom scale.
pub fn scroll_to_info_zoom(target: &crate::core::widget_info::WidgetInfo, mode: impl Into<ScrollToMode>, zoom: impl Into<Factor>) {
scroll_to_info_impl(target, mode.into(), Some(zoom.into()))
}
fn scroll_to_impl(target: WidgetId, mode: ScrollToMode, zoom: Option<Factor>) {
for w in crate::core::window::WINDOWS.widget_trees() {
if let Some(target) = w.get(target) {
scroll_to_info_impl(&target, mode, zoom);
break;
}
}
}
fn scroll_to_info_impl(target: &crate::core::widget_info::WidgetInfo, mode: ScrollToMode, zoom: Option<Factor>) {
let mut t = target.id();
let mode = mode.into();
for a in target.ancestors() {
if a.is_scroll() {
SCROLL_TO_CMD.scoped(a.id()).notify_param(ScrollToRequest {
widget_id: t,
mode: mode.clone(),
zoom,
});
t = a.id();
}

View File

@ -209,6 +209,8 @@ pub fn define_viewport_unit(child: impl UiNode, enabled: impl IntoVar<bool>) ->
}
/// Smooth scrolling config.
///
/// Defines the easing animation applied to scroll offset and zoom value changes.
#[property(CONTEXT, default(SMOOTH_SCROLLING_VAR), widget_impl(Scroll))]
pub fn smooth_scrolling(child: impl UiNode, config: impl IntoVar<SmoothScrolling>) -> impl UiNode {
with_context_var(child, SMOOTH_SCROLLING_VAR, config)

View File

@ -54,13 +54,11 @@ impl_from_and_into_var! {
context_var! {
/// Vertical offset of the parent scroll.
///
/// The value is a percentage of `content.height - viewport.height`. This variable is usually read-write,
/// scrollable content can modify it to scroll the parent.
/// The value is a percentage of `content.height - viewport.height`.
pub(super) static SCROLL_VERTICAL_OFFSET_VAR: Factor = 0.fct();
/// Horizontal offset of the parent scroll.
///
/// The value is a percentage of `content.width - viewport.width`. This variable is usually read-write,
/// scrollable content can modify it to scroll the parent.
/// The value is a percentage of `content.width - viewport.width`.
pub(super) static SCROLL_HORIZONTAL_OFFSET_VAR: Factor = 0.fct();
/// Extra vertical offset requested that could not be fulfilled because [`SCROLL_VERTICAL_OFFSET_VAR`]
@ -91,8 +89,13 @@ context_var! {
pub(super) static SCROLL_VIEWPORT_SIZE_VAR: PxSize = PxSize::zero();
/// Latest computed content size of the parent scroll.
///
/// The size is scaled if zoom is set.
pub(super) static SCROLL_CONTENT_SIZE_VAR: PxSize = PxSize::zero();
/// Zoom scaling of the parent scroll.
pub(super) static SCROLL_SCALE_VAR: Factor = 1.fct();
}
context_local! {
@ -594,6 +597,7 @@ impl SCROLL {
todo!()
}
/// Returns `true` if the content can be scaled and the current scale is more than the min.
pub fn can_zoom_out(&self) -> bool {
todo!()
}