use crate::input::core::coordinator::LayerId;
use crate::input::{InputCoordinator, Sense, WidgetKind};
use crate::types::{Rect, WidgetId};
use super::state::ScrollState;
pub fn register_track(
coord: &mut InputCoordinator,
id: impl Into<WidgetId>,
rect: Rect,
layer: &LayerId,
) {
coord.register_atomic(id, WidgetKind::ScrollbarTrack, rect, Sense::CLICK, layer);
}
pub fn register_thumb(
coord: &mut InputCoordinator,
id: impl Into<WidgetId>,
thumb_rect: Rect,
inflation_x: f64,
layer: &LayerId,
) {
let inflated = Rect::new(
thumb_rect.x - inflation_x,
thumb_rect.y,
thumb_rect.width + inflation_x * 2.0,
thumb_rect.height,
);
coord.register_atomic(id, WidgetKind::ScrollbarHandle, inflated, Sense::DRAG, layer);
}
pub fn handle_scroll_wheel(
state: &mut ScrollState,
delta_y: f64,
content_height: f64,
viewport_height: f64,
) -> bool {
state.handle_wheel(delta_y, content_height, viewport_height)
}
pub fn start_thumb_drag(state: &mut ScrollState, y: f64) {
state.start_drag(y);
}
pub fn update_thumb_drag(
state: &mut ScrollState,
y: f64,
track_height: f64,
content_height: f64,
viewport_height: f64,
) {
state.handle_drag(y, track_height, content_height, viewport_height);
}
pub fn end_thumb_drag(state: &mut ScrollState) {
state.end_drag();
}
pub fn handle_track_click(
state: &mut ScrollState,
click_y: f64,
track_rect: Rect,
content_height: f64,
viewport_height: f64,
) {
state.handle_track_click(
click_y,
track_rect.y,
track_rect.height,
content_height,
viewport_height,
);
}
pub struct ScrollableInfo {
pub track_rect: Option<Rect>,
pub handle_rect: Option<Rect>,
pub content_height: f64,
pub viewport_height: f64,
}
const HIT_TOLERANCE_X: f64 = 5.0;
pub fn try_start_scrollbar_drag(
x: f64,
y: f64,
entries: &mut [(&ScrollableInfo, &mut ScrollState)],
) -> bool {
for (info, state) in entries.iter_mut() {
if let Some(hr) = info.handle_rect {
let hit = x >= hr.x - HIT_TOLERANCE_X
&& x <= hr.x + hr.width + HIT_TOLERANCE_X
&& y >= hr.y
&& y <= hr.y + hr.height;
if hit {
state.start_drag(y);
return true;
}
}
}
false
}
pub fn try_handle_scrollbar_drag(
y: f64,
entries: &mut [(&ScrollableInfo, &mut ScrollState)],
) -> bool {
for (info, state) in entries.iter_mut() {
if state.is_dragging {
if let Some(tr) = info.track_rect {
state.handle_drag(y, tr.height, info.content_height, info.viewport_height);
return true;
}
}
}
false
}
pub fn try_end_scrollbar_drag(entries: &mut [(&ScrollableInfo, &mut ScrollState)]) -> bool {
let mut any = false;
for (_, state) in entries.iter_mut() {
if state.is_dragging {
state.end_drag();
any = true;
}
}
any
}
pub fn try_handle_wheel(
x: f64,
y: f64,
delta_y: f64,
entries: &mut [(&ScrollableInfo, &mut ScrollState)],
) -> bool {
for (info, state) in entries.iter_mut() {
if let Some(tr) = info.track_rect {
let in_viewport = x >= tr.x && x <= tr.x + tr.width
&& y >= tr.y && y <= tr.y + tr.height;
if in_viewport {
return state.handle_wheel(delta_y, info.content_height, info.viewport_height);
}
}
}
false
}
pub fn try_handle_track_click(
x: f64,
y: f64,
entries: &mut [(&ScrollableInfo, &mut ScrollState)],
) -> bool {
for (info, state) in entries.iter_mut() {
if let Some(tr) = info.track_rect {
let hit_track = x >= tr.x - HIT_TOLERANCE_X
&& x <= tr.x + tr.width + HIT_TOLERANCE_X
&& y >= tr.y
&& y <= tr.y + tr.height;
if !hit_track {
continue;
}
if let Some(hr) = info.handle_rect {
let on_handle = x >= hr.x - HIT_TOLERANCE_X
&& x <= hr.x + hr.width + HIT_TOLERANCE_X
&& y >= hr.y
&& y <= hr.y + hr.height;
if on_handle {
continue;
}
}
state.handle_track_click(y, tr.y, tr.height, info.content_height, info.viewport_height);
return true;
}
}
false
}