wgui: Smooth scrolling, TransformStack: fix scrollable area boundaries (mouse wheel), separate into raw_dim and visual_dim, refactoring
This commit is contained in:
@@ -6,10 +6,11 @@ use taffy::TraversePartialTree;
|
||||
|
||||
use crate::{
|
||||
drawing,
|
||||
event::EventAlterables,
|
||||
layout::Widget,
|
||||
renderer_vk::text::{TextShadow, custom_glyph::CustomGlyph},
|
||||
stack::{self, ScissorBoundary, ScissorStack, TransformStack},
|
||||
widget::{self},
|
||||
widget::{self, ScrollbarInfo, WidgetState},
|
||||
};
|
||||
|
||||
use super::{layout::Layout, widget::DrawState};
|
||||
@@ -34,8 +35,8 @@ impl Boundary {
|
||||
let transform = transform_stack.get();
|
||||
|
||||
Self {
|
||||
pos: Vec2::new(transform.abs_pos.x, transform.abs_pos.y),
|
||||
size: Vec2::new(transform.dim.x, transform.dim.y),
|
||||
pos: transform.abs_pos,
|
||||
size: transform.raw_dim,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ impl Boundary {
|
||||
|
||||
Self {
|
||||
pos: Vec2::ZERO,
|
||||
size: Vec2::new(transform.dim.x, transform.dim.y),
|
||||
size: transform.raw_dim,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,8 +153,9 @@ pub enum RenderPrimitive {
|
||||
}
|
||||
|
||||
pub struct DrawParams<'a> {
|
||||
pub layout: &'a Layout,
|
||||
pub layout: &'a mut Layout,
|
||||
pub debug_draw: bool,
|
||||
pub alpha: f32, // timestep alpha, 0.0 - 1.0, used for motion interpolation if rendering above tick rate: smoother animations or scrolling
|
||||
}
|
||||
|
||||
pub fn has_overflow_clip(style: &taffy::Style) -> bool {
|
||||
@@ -175,6 +177,45 @@ fn primitive_debug_rect(boundary: &Boundary, transform: &Mat4, color: drawing::C
|
||||
)
|
||||
}
|
||||
|
||||
pub fn push_transform_stack(
|
||||
transform_stack: &mut TransformStack,
|
||||
l: &taffy::Layout,
|
||||
scroll_shift: Vec2,
|
||||
widget_state: &WidgetState,
|
||||
) {
|
||||
let raw_dim = Vec2::new(l.size.width, l.size.height);
|
||||
let visual_dim = raw_dim + scroll_shift;
|
||||
|
||||
transform_stack.push(stack::Transform {
|
||||
rel_pos: Vec2::new(l.location.x, l.location.y) - scroll_shift,
|
||||
transform: widget_state.data.transform,
|
||||
raw_dim,
|
||||
visual_dim,
|
||||
abs_pos: Default::default(),
|
||||
transform_rel: Default::default(),
|
||||
});
|
||||
}
|
||||
|
||||
/// returns true if scissor has been pushed
|
||||
pub fn push_scissor_stack(
|
||||
transform_stack: &mut TransformStack,
|
||||
scissor_stack: &mut ScissorStack,
|
||||
scroll_shift: Vec2,
|
||||
info: &Option<ScrollbarInfo>,
|
||||
style: &taffy::Style,
|
||||
) -> bool {
|
||||
let scissor_pushed = info.is_some() && has_overflow_clip(style);
|
||||
if !scissor_pushed {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut boundary_absolute = drawing::Boundary::construct_absolute(transform_stack);
|
||||
boundary_absolute.pos += scroll_shift;
|
||||
scissor_stack.push(ScissorBoundary(boundary_absolute));
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn draw_widget(
|
||||
params: &DrawParams,
|
||||
state: &mut DrawState,
|
||||
@@ -189,17 +230,16 @@ fn draw_widget(
|
||||
|
||||
let mut widget_state = widget.state();
|
||||
|
||||
let (scroll_shift, info) = match widget::get_scrollbar_info(l) {
|
||||
Some(info) => (widget_state.get_scroll_shift(&info, l), Some(info)),
|
||||
None => (Vec2::default(), None),
|
||||
let (scroll_shift, wants_redraw, info) = match widget::get_scrollbar_info(l) {
|
||||
Some(info) => {
|
||||
let (scrolling, wants_redraw) = widget_state.get_scroll_shift_smooth(&info, l, params.alpha);
|
||||
(scrolling, wants_redraw, Some(info))
|
||||
}
|
||||
None => (Vec2::default(), false, None),
|
||||
};
|
||||
|
||||
state.transform_stack.push(stack::Transform {
|
||||
rel_pos: Vec2::new(l.location.x, l.location.y) - scroll_shift,
|
||||
transform: widget_state.data.transform,
|
||||
dim: Vec2::new(l.size.width, l.size.height),
|
||||
..Default::default()
|
||||
});
|
||||
// see layout.rs push_event_widget too
|
||||
push_transform_stack(state.transform_stack, l, scroll_shift, &widget_state);
|
||||
|
||||
if params.debug_draw {
|
||||
let boundary = drawing::Boundary::construct_relative(state.transform_stack);
|
||||
@@ -210,13 +250,9 @@ fn draw_widget(
|
||||
));
|
||||
}
|
||||
|
||||
let scissor_pushed = info.is_some() && has_overflow_clip(style);
|
||||
let scissor_pushed = push_scissor_stack(state.transform_stack, state.scissor_stack, scroll_shift, &info, style);
|
||||
|
||||
if scissor_pushed {
|
||||
let mut boundary_absolute = drawing::Boundary::construct_absolute(state.transform_stack);
|
||||
boundary_absolute.pos += scroll_shift;
|
||||
state.scissor_stack.push(ScissorBoundary(boundary_absolute));
|
||||
|
||||
if params.debug_draw {
|
||||
let mut boundary_relative = drawing::Boundary::construct_relative(state.transform_stack);
|
||||
boundary_relative.pos += scroll_shift;
|
||||
@@ -254,6 +290,10 @@ fn draw_widget(
|
||||
if let Some(info) = &info {
|
||||
widget_state.draw_scrollbars(state, &draw_params, info);
|
||||
}
|
||||
|
||||
if wants_redraw {
|
||||
state.alterables.mark_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taffy::NodeId) {
|
||||
@@ -279,7 +319,7 @@ fn draw_children(params: &DrawParams, state: &mut DrawState, parent_node_id: taf
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(params: &DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
|
||||
pub fn draw(params: &mut DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
|
||||
let mut primitives = Vec::<RenderPrimitive>::new();
|
||||
let mut transform_stack = TransformStack::new();
|
||||
let mut scissor_stack = ScissorStack::new();
|
||||
@@ -292,14 +332,18 @@ pub fn draw(params: &DrawParams) -> anyhow::Result<Vec<RenderPrimitive>> {
|
||||
panic!();
|
||||
};
|
||||
|
||||
let mut alterables = EventAlterables::default();
|
||||
|
||||
let mut state = DrawState {
|
||||
primitives: &mut primitives,
|
||||
transform_stack: &mut transform_stack,
|
||||
scissor_stack: &mut scissor_stack,
|
||||
layout: params.layout,
|
||||
alterables: &mut alterables,
|
||||
};
|
||||
|
||||
draw_widget(params, &mut state, params.layout.root_node, style, root_widget);
|
||||
params.layout.process_alterables(alterables)?;
|
||||
|
||||
Ok(primitives)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::{
|
||||
cell::{RefCell, RefMut},
|
||||
collections::HashSet,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
@@ -75,9 +76,9 @@ pub enum Event {
|
||||
impl Event {
|
||||
fn test_transform_pos(transform: &Transform, pos: Vec2) -> bool {
|
||||
pos.x >= transform.abs_pos.x
|
||||
&& pos.x < transform.abs_pos.x + transform.dim.x
|
||||
&& pos.x < transform.abs_pos.x + transform.visual_dim.x
|
||||
&& pos.y >= transform.abs_pos.y
|
||||
&& pos.y < transform.abs_pos.y + transform.dim.y
|
||||
&& pos.y < transform.abs_pos.y + transform.visual_dim.y
|
||||
}
|
||||
|
||||
pub fn test_mouse_within_transform(&self, transform: &Transform) -> bool {
|
||||
@@ -96,6 +97,7 @@ pub struct EventAlterables {
|
||||
pub dirty_nodes: Vec<taffy::NodeId>,
|
||||
pub style_set_requests: Vec<(taffy::NodeId, taffy::Style)>,
|
||||
pub animations: Vec<animation::Animation>,
|
||||
pub widgets_to_tick: HashSet<WidgetID>, // widgets which needs to be ticked in the next `Layout::update()` fn
|
||||
pub transform_stack: TransformStack,
|
||||
pub scissor_stack: ScissorStack,
|
||||
pub needs_redraw: bool,
|
||||
@@ -115,6 +117,10 @@ impl EventAlterables {
|
||||
self.dirty_nodes.push(node_id);
|
||||
}
|
||||
|
||||
pub fn mark_tick(&mut self, widget_id: WidgetID) {
|
||||
self.widgets_to_tick.insert(widget_id);
|
||||
}
|
||||
|
||||
pub const fn trigger_haptics(&mut self) {
|
||||
self.trigger_haptics = true;
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ use std::{
|
||||
use crate::{
|
||||
animation::Animations,
|
||||
components::{Component, InitData},
|
||||
drawing::{self, has_overflow_clip, Boundary},
|
||||
drawing::{self, Boundary, has_overflow_clip, push_scissor_stack, push_transform_stack},
|
||||
event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection},
|
||||
globals::WguiGlobals,
|
||||
stack::{self, ScissorBoundary},
|
||||
widget::{self, div::WidgetDiv, EventParams, WidgetObj, WidgetState},
|
||||
widget::{self, EventParams, WidgetObj, WidgetState, div::WidgetDiv},
|
||||
};
|
||||
|
||||
use glam::{vec2, Vec2};
|
||||
use slotmap::{new_key_type, HopSlotMap, SecondaryMap};
|
||||
use glam::{Vec2, vec2};
|
||||
use slotmap::{HopSlotMap, SecondaryMap, new_key_type};
|
||||
use taffy::{NodeId, TaffyTree, TraversePartialTree};
|
||||
|
||||
new_key_type! {
|
||||
@@ -112,7 +112,8 @@ pub struct LayoutState {
|
||||
pub struct Layout {
|
||||
pub state: LayoutState,
|
||||
|
||||
pub components_to_init: VecDeque<Component>,
|
||||
pub components_to_init: Vec<Component>,
|
||||
pub widgets_to_tick: Vec<WidgetID>,
|
||||
|
||||
pub root_widget: WidgetID,
|
||||
pub root_node: taffy::NodeId,
|
||||
@@ -218,25 +219,32 @@ impl Layout {
|
||||
self.needs_redraw = true;
|
||||
}
|
||||
|
||||
fn process_pending_components(&mut self) -> anyhow::Result<()> {
|
||||
let mut alterables = EventAlterables::default();
|
||||
|
||||
while let Some(c) = self.components_to_init.pop_front() {
|
||||
fn process_pending_components(&mut self, alterables: &mut EventAlterables) -> anyhow::Result<()> {
|
||||
for comp in &self.components_to_init {
|
||||
let mut common = CallbackDataCommon {
|
||||
state: &self.state,
|
||||
alterables: &mut alterables,
|
||||
alterables,
|
||||
};
|
||||
|
||||
c.0.init(&mut InitData { common: &mut common });
|
||||
comp.0.init(&mut InitData { common: &mut common });
|
||||
}
|
||||
|
||||
self.process_alterables(alterables)?;
|
||||
|
||||
self.components_to_init.clear();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_pending_widget_ticks(&mut self, alterables: &mut EventAlterables) {
|
||||
for widget_id in &self.widgets_to_tick {
|
||||
let Some(widget) = self.state.widgets.get(*widget_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
widget.state().tick(*widget_id, alterables);
|
||||
}
|
||||
self.widgets_to_tick.clear();
|
||||
}
|
||||
|
||||
pub fn defer_component_init(&mut self, component: Component) {
|
||||
self.components_to_init.push_back(component);
|
||||
self.components_to_init.push(component);
|
||||
}
|
||||
|
||||
fn push_event_children<U1, U2>(
|
||||
@@ -276,24 +284,20 @@ impl Layout {
|
||||
|
||||
let mut widget = widget.0.borrow_mut();
|
||||
let (scroll_shift, info) = match widget::get_scrollbar_info(l) {
|
||||
Some(info) => (widget.get_scroll_shift(&info, l), Some(info)),
|
||||
Some(info) => (widget.get_scroll_shift_raw(&info, l), Some(info)),
|
||||
None => (Vec2::default(), None),
|
||||
};
|
||||
|
||||
alterables.transform_stack.push(stack::Transform {
|
||||
rel_pos: Vec2::new(l.location.x, l.location.y) - scroll_shift,
|
||||
transform: widget.data.transform,
|
||||
dim: Vec2::new(l.size.width, l.size.height),
|
||||
..Default::default()
|
||||
});
|
||||
// see drawing.rs draw_widget too
|
||||
push_transform_stack(&mut alterables.transform_stack, l, scroll_shift, &widget);
|
||||
|
||||
// see drawing.rs too
|
||||
let scissor_pushed = info.is_some() && has_overflow_clip(style);
|
||||
if scissor_pushed {
|
||||
let mut boundary_absolute = drawing::Boundary::construct_absolute(&alterables.transform_stack);
|
||||
boundary_absolute.pos += scroll_shift;
|
||||
alterables.scissor_stack.push(ScissorBoundary(boundary_absolute));
|
||||
}
|
||||
let scissor_pushed = push_scissor_stack(
|
||||
&mut alterables.transform_stack,
|
||||
&mut alterables.scissor_stack,
|
||||
scroll_shift,
|
||||
&info,
|
||||
style,
|
||||
);
|
||||
|
||||
let mut iter_children = true;
|
||||
|
||||
@@ -399,7 +403,8 @@ impl Layout {
|
||||
needs_redraw: true,
|
||||
haptics_triggered: false,
|
||||
animations: Animations::default(),
|
||||
components_to_init: VecDeque::new(),
|
||||
components_to_init: Vec::new(),
|
||||
widgets_to_tick: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -467,9 +472,9 @@ impl Layout {
|
||||
pub fn tick(&mut self) -> anyhow::Result<()> {
|
||||
let mut alterables = EventAlterables::default();
|
||||
self.animations.tick(&self.state, &mut alterables);
|
||||
self.process_pending_components()?;
|
||||
self.process_pending_components(&mut alterables)?;
|
||||
self.process_pending_widget_ticks(&mut alterables);
|
||||
self.process_alterables(alterables)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -493,6 +498,12 @@ impl Layout {
|
||||
}
|
||||
}
|
||||
|
||||
if !alterables.widgets_to_tick.is_empty() {
|
||||
for widget_id in &alterables.widgets_to_tick {
|
||||
self.widgets_to_tick.push(*widget_id);
|
||||
}
|
||||
}
|
||||
|
||||
for request in alterables.style_set_requests {
|
||||
if let Err(e) = self.state.tree.set_style(request.0, request.1) {
|
||||
log::error!("failed to set style for taffy widget ID {:?}: {:?}", request.0, e);
|
||||
|
||||
@@ -53,8 +53,9 @@ impl<T: StackItem<T>, const STACK_MAX: usize> Default for GenericStack<T, STACK_
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Transform {
|
||||
pub rel_pos: Vec2,
|
||||
pub dim: Vec2, // for convenience
|
||||
pub abs_pos: Vec2, // for convenience, will be set after pushing
|
||||
pub visual_dim: Vec2, // for convenience
|
||||
pub raw_dim: Vec2, // for convenience
|
||||
pub abs_pos: Vec2, // for convenience, will be set after pushing
|
||||
pub transform: glam::Mat4,
|
||||
pub transform_rel: glam::Mat4,
|
||||
}
|
||||
@@ -64,7 +65,8 @@ impl Default for Transform {
|
||||
Self {
|
||||
abs_pos: Default::default(),
|
||||
rel_pos: Default::default(),
|
||||
dim: Default::default(),
|
||||
visual_dim: Default::default(),
|
||||
raw_dim: Default::default(),
|
||||
transform: Mat4::IDENTITY,
|
||||
transform_rel: Default::default(),
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ pub mod util;
|
||||
pub struct WidgetData {
|
||||
hovered: usize,
|
||||
pressed: usize,
|
||||
pub scrolling: Vec2, // normalized, 0.0-1.0. Not used in case if overflow != scroll
|
||||
pub scrolling_target: Vec2, // normalized, 0.0-1.0. Not used in case if overflow != scroll
|
||||
pub scrolling_cur: Vec2, // normalized, used for smooth scrolling animation
|
||||
pub scrolling_cur_prev: Vec2, // for motion interpolation while rendering between ticks
|
||||
pub transform: glam::Mat4,
|
||||
}
|
||||
|
||||
@@ -87,7 +89,9 @@ impl WidgetState {
|
||||
data: WidgetData {
|
||||
hovered: 0,
|
||||
pressed: 0,
|
||||
scrolling: Vec2::default(),
|
||||
scrolling_target: Vec2::default(),
|
||||
scrolling_cur: Vec2::default(),
|
||||
scrolling_cur_prev: Vec2::default(),
|
||||
transform: glam::Mat4::IDENTITY,
|
||||
},
|
||||
obj,
|
||||
@@ -101,6 +105,7 @@ pub struct DrawState<'a> {
|
||||
pub primitives: &'a mut Vec<RenderPrimitive>,
|
||||
pub transform_stack: &'a mut TransformStack,
|
||||
pub scissor_stack: &'a mut ScissorStack,
|
||||
pub alterables: &'a mut EventAlterables,
|
||||
}
|
||||
|
||||
// per-widget draw params
|
||||
@@ -116,6 +121,7 @@ pub trait WidgetObj: AnyTrait {
|
||||
fn set_id(&mut self, id: WidgetID); // always set at insertion
|
||||
|
||||
fn draw(&mut self, state: &mut DrawState, params: &DrawParams);
|
||||
|
||||
fn measure(
|
||||
&mut self,
|
||||
_known_dimensions: taffy::Size<Option<f32>>,
|
||||
@@ -133,12 +139,6 @@ pub struct EventParams<'a> {
|
||||
pub layout: &'a taffy::Layout,
|
||||
}
|
||||
|
||||
impl EventParams<'_> {
|
||||
pub const fn mark_redraw(&mut self) {
|
||||
self.alterables.needs_redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub enum EventResult {
|
||||
Pass, // widget acknowledged it and allows the event to pass to the children
|
||||
Consumed, // widget triggered an action, do not pass to children
|
||||
@@ -212,10 +212,27 @@ macro_rules! call_event {
|
||||
}
|
||||
|
||||
impl WidgetState {
|
||||
pub fn get_scroll_shift(&self, info: &ScrollbarInfo, l: &taffy::Layout) -> Vec2 {
|
||||
pub fn get_scroll_shift_smooth(&self, info: &ScrollbarInfo, l: &taffy::Layout, timestep_alpha: f32) -> (Vec2, bool) {
|
||||
let currently_animating = self.data.scrolling_cur != self.data.scrolling_cur_prev;
|
||||
|
||||
let scrolling = self
|
||||
.data
|
||||
.scrolling_cur_prev
|
||||
.lerp(self.data.scrolling_cur, timestep_alpha);
|
||||
|
||||
(
|
||||
Vec2::new(
|
||||
(info.content_size.x - l.content_box_width()) * scrolling.x,
|
||||
(info.content_size.y - l.content_box_height()) * scrolling.y,
|
||||
),
|
||||
currently_animating,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_scroll_shift_raw(&self, info: &ScrollbarInfo, l: &taffy::Layout) -> Vec2 {
|
||||
Vec2::new(
|
||||
(info.content_size.x - l.content_box_width()) * self.data.scrolling.x,
|
||||
(info.content_size.y - l.content_box_height()) * self.data.scrolling.y,
|
||||
(info.content_size.x - l.content_box_width()) * self.data.scrolling_target.x,
|
||||
(info.content_size.y - l.content_box_height()) * self.data.scrolling_target.y,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -223,6 +240,31 @@ impl WidgetState {
|
||||
self.obj.draw(state, params);
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, this_widget_id: WidgetID, alterables: &mut EventAlterables) {
|
||||
let scrolling_cur = &mut self.data.scrolling_cur;
|
||||
let scrolling_cur_prev = &mut self.data.scrolling_cur_prev;
|
||||
let scrolling_target = &mut self.data.scrolling_target;
|
||||
|
||||
*scrolling_cur_prev = *scrolling_cur;
|
||||
|
||||
if scrolling_cur != scrolling_target {
|
||||
// the magic part
|
||||
*scrolling_cur = scrolling_cur.lerp(*scrolling_target, 0.2);
|
||||
|
||||
// trigger tick request again
|
||||
alterables.mark_tick(this_widget_id);
|
||||
alterables.mark_redraw();
|
||||
|
||||
let epsilon = 0.00001;
|
||||
if (scrolling_cur.x - scrolling_target.x).abs() < epsilon
|
||||
&& (scrolling_cur.y - scrolling_target.y).abs() < epsilon
|
||||
{
|
||||
log::info!("stopped animating");
|
||||
*scrolling_cur = *scrolling_target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_scrollbars(&mut self, state: &mut DrawState, params: &DrawParams, info: &ScrollbarInfo) {
|
||||
let (enabled_horiz, enabled_vert) = get_scroll_enabled(params.style);
|
||||
if !enabled_horiz && !enabled_vert {
|
||||
@@ -248,10 +290,10 @@ impl WidgetState {
|
||||
PrimitiveExtent {
|
||||
boundary: drawing::Boundary::from_pos_size(
|
||||
Vec2::new(
|
||||
transform.abs_pos.x + transform.dim.x * (1.0 - info.handle_size.x) * self.data.scrolling.x,
|
||||
transform.abs_pos.y + transform.dim.y - thickness - margin,
|
||||
transform.abs_pos.x + transform.raw_dim.x * (1.0 - info.handle_size.x) * self.data.scrolling_cur.x,
|
||||
transform.abs_pos.y + transform.raw_dim.y - thickness - margin,
|
||||
),
|
||||
Vec2::new(transform.dim.x * info.handle_size.x, thickness),
|
||||
Vec2::new(transform.raw_dim.x * info.handle_size.x, thickness),
|
||||
),
|
||||
transform: transform.transform,
|
||||
},
|
||||
@@ -265,10 +307,10 @@ impl WidgetState {
|
||||
PrimitiveExtent {
|
||||
boundary: drawing::Boundary::from_pos_size(
|
||||
Vec2::new(
|
||||
transform.abs_pos.x + transform.dim.x - thickness - margin,
|
||||
transform.abs_pos.y + transform.dim.y * (1.0 - info.handle_size.y) * self.data.scrolling.y,
|
||||
transform.abs_pos.x + transform.raw_dim.x - thickness - margin,
|
||||
transform.abs_pos.y + transform.raw_dim.y * (1.0 - info.handle_size.y) * self.data.scrolling_cur.y,
|
||||
),
|
||||
Vec2::new(thickness, transform.dim.y * info.handle_size.y),
|
||||
Vec2::new(thickness, transform.raw_dim.y * info.handle_size.y),
|
||||
),
|
||||
transform: transform.transform,
|
||||
},
|
||||
@@ -293,25 +335,25 @@ impl WidgetState {
|
||||
return false;
|
||||
};
|
||||
|
||||
let step_pixels = 32.0;
|
||||
let step_pixels = 64.0;
|
||||
|
||||
if info.handle_size.x < 1.0 && wheel.pos.x != 0.0 {
|
||||
// Horizontal scrolling
|
||||
let mult = (1.0 / (l.content_box_width() - info.content_size.x)) * step_pixels;
|
||||
let new_scroll = (self.data.scrolling.x + wheel.shift.x * mult).clamp(0.0, 1.0);
|
||||
if self.data.scrolling.x != new_scroll {
|
||||
self.data.scrolling.x = new_scroll;
|
||||
params.mark_redraw();
|
||||
let new_scroll = (self.data.scrolling_target.x + wheel.shift.x * mult).clamp(0.0, 1.0);
|
||||
if self.data.scrolling_target.x != new_scroll {
|
||||
self.data.scrolling_target.x = new_scroll;
|
||||
params.alterables.mark_tick(self.obj.get_id());
|
||||
}
|
||||
}
|
||||
|
||||
if info.handle_size.y < 1.0 && wheel.pos.y != 0.0 {
|
||||
// Vertical scrolling
|
||||
let mult = (1.0 / (l.content_box_height() - info.content_size.y)) * step_pixels;
|
||||
let new_scroll = (self.data.scrolling.y + wheel.shift.y * mult).clamp(0.0, 1.0);
|
||||
if self.data.scrolling.y != new_scroll {
|
||||
self.data.scrolling.y = new_scroll;
|
||||
params.mark_redraw();
|
||||
let new_scroll = (self.data.scrolling_target.y + wheel.shift.y * mult).clamp(0.0, 1.0);
|
||||
if self.data.scrolling_target.y != new_scroll {
|
||||
self.data.scrolling_target.y = new_scroll;
|
||||
params.alterables.mark_tick(self.obj.get_id());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user