mirror of https://github.com/wayvr-org/wayvr.git
wgui: Swipe kinetic scrolling support (#504)
* wgui: use DeviceBitmask instead of usize * wgui: Swipe logic works (wip) * wgui: Kinetic scrolling, rubberband effect
This commit is contained in:
parent
9734955ebb
commit
6b81f07cc8
|
|
@ -1,12 +1,7 @@
|
||||||
#![allow(dead_code)]
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
// TODO: Remove later
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use wlx_common::{async_executor::AsyncExecutor, config_io};
|
|
||||||
|
|
||||||
use crate::util::networking::{self, WAYVR_SKYMAPS_ROOT, http_client};
|
use crate::util::networking::{self, WAYVR_SKYMAPS_ROOT, http_client};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use wlx_common::{async_executor::AsyncExecutor, config_io};
|
||||||
pub type SkymapUuid = uuid::Uuid;
|
pub type SkymapUuid = uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ pub fn create_button(par: CreateButtonParams) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn create_label(layout: &mut Layout, id_parent: WidgetID, content: Translation) -> anyhow::Result<()> {
|
pub fn create_label(layout: &mut Layout, id_parent: WidgetID, content: Translation) -> anyhow::Result<()> {
|
||||||
let label = WidgetLabel::create(
|
let label = WidgetLabel::create(
|
||||||
&mut layout.state,
|
&mut layout.state,
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
&wgui::event::Event::MouseWheel(MouseWheelEvent {
|
&wgui::event::Event::MouseWheel(MouseWheelEvent {
|
||||||
delta: Vec2::new(x, y),
|
delta: Vec2::new(x, y),
|
||||||
pos: mouse / scale,
|
pos: mouse / scale,
|
||||||
device: 0,
|
device: wgui::event::DeviceBitmask(0),
|
||||||
}),
|
}),
|
||||||
&mut (),
|
&mut (),
|
||||||
&mut (),
|
&mut (),
|
||||||
|
|
@ -157,7 +157,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
&wgui::event::Event::MouseWheel(MouseWheelEvent {
|
&wgui::event::Event::MouseWheel(MouseWheelEvent {
|
||||||
delta: Vec2::new(pos.x as f32 / 5.0, pos.y as f32 / 5.0),
|
delta: Vec2::new(pos.x as f32 / 5.0, pos.y as f32 / 5.0),
|
||||||
pos: mouse / scale,
|
pos: mouse / scale,
|
||||||
device: 0,
|
device: wgui::event::DeviceBitmask(0),
|
||||||
}),
|
}),
|
||||||
&mut (),
|
&mut (),
|
||||||
&mut (),
|
&mut (),
|
||||||
|
|
@ -177,7 +177,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
&wgui::event::Event::MouseDown(MouseButtonEvent {
|
&wgui::event::Event::MouseDown(MouseButtonEvent {
|
||||||
pos: mouse / scale,
|
pos: mouse / scale,
|
||||||
index: MouseButtonIndex::Left,
|
index: MouseButtonIndex::Left,
|
||||||
device: 0,
|
device: wgui::event::DeviceBitmask(0),
|
||||||
}),
|
}),
|
||||||
&mut (),
|
&mut (),
|
||||||
&mut (),
|
&mut (),
|
||||||
|
|
@ -190,7 +190,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
&wgui::event::Event::MouseUp(MouseButtonEvent {
|
&wgui::event::Event::MouseUp(MouseButtonEvent {
|
||||||
pos: mouse / scale,
|
pos: mouse / scale,
|
||||||
index: MouseButtonIndex::Left,
|
index: MouseButtonIndex::Left,
|
||||||
device: 0,
|
device: wgui::event::DeviceBitmask(0),
|
||||||
}),
|
}),
|
||||||
&mut (),
|
&mut (),
|
||||||
&mut (),
|
&mut (),
|
||||||
|
|
@ -209,7 +209,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.push_event(
|
.push_event(
|
||||||
&wgui::event::Event::MouseMotion(MouseMotionEvent {
|
&wgui::event::Event::MouseMotion(MouseMotionEvent {
|
||||||
pos: mouse / scale,
|
pos: mouse / scale,
|
||||||
device: 0,
|
device: wgui::event::DeviceBitmask(0),
|
||||||
}),
|
}),
|
||||||
&mut (),
|
&mut (),
|
||||||
&mut (),
|
&mut (),
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use wgui::{
|
||||||
slider::ComponentSlider,
|
slider::ComponentSlider,
|
||||||
},
|
},
|
||||||
event::{
|
event::{
|
||||||
Event as WguiEvent, EventCallback, EventListenerID, EventListenerKind,
|
DeviceBitmask, Event as WguiEvent, EventCallback, EventListenerID, EventListenerKind,
|
||||||
InternalStateChangeEvent, MouseButtonEvent, MouseButtonIndex, MouseLeaveEvent,
|
InternalStateChangeEvent, MouseButtonEvent, MouseButtonIndex, MouseLeaveEvent,
|
||||||
MouseMotionEvent, MouseWheelEvent,
|
MouseMotionEvent, MouseWheelEvent,
|
||||||
},
|
},
|
||||||
|
|
@ -368,7 +368,7 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||||
let e = WguiEvent::MouseWheel(MouseWheelEvent {
|
let e = WguiEvent::MouseWheel(MouseWheelEvent {
|
||||||
delta: vec2(delta.x, delta.y) / 8.0,
|
delta: vec2(delta.x, delta.y) / 8.0,
|
||||||
pos: hit.uv * self.layout.content_size,
|
pos: hit.uv * self.layout.content_size,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
self.push_event(app, &e);
|
self.push_event(app, &e);
|
||||||
}
|
}
|
||||||
|
|
@ -376,7 +376,7 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
||||||
let e = &WguiEvent::MouseMotion(MouseMotionEvent {
|
let e = &WguiEvent::MouseMotion(MouseMotionEvent {
|
||||||
pos: hit.uv * self.layout.content_size,
|
pos: hit.uv * self.layout.content_size,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.has_focus[hit.pointer] = true;
|
self.has_focus[hit.pointer] = true;
|
||||||
|
|
@ -397,7 +397,9 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||||
let e = WguiEvent::MouseLeave(MouseLeaveEvent { device: pointer });
|
let e = WguiEvent::MouseLeave(MouseLeaveEvent {
|
||||||
|
device: DeviceBitmask::from_usize(pointer),
|
||||||
|
});
|
||||||
self.has_focus[pointer] = false;
|
self.has_focus[pointer] = false;
|
||||||
self.push_event(app, &e);
|
self.push_event(app, &e);
|
||||||
}
|
}
|
||||||
|
|
@ -414,13 +416,13 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||||
WguiEvent::MouseDown(MouseButtonEvent {
|
WguiEvent::MouseDown(MouseButtonEvent {
|
||||||
pos: hit.uv * self.layout.content_size,
|
pos: hit.uv * self.layout.content_size,
|
||||||
index,
|
index,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
WguiEvent::MouseUp(MouseButtonEvent {
|
WguiEvent::MouseUp(MouseButtonEvent {
|
||||||
pos: hit.uv * self.layout.content_size,
|
pos: hit.uv * self.layout.content_size,
|
||||||
index,
|
index,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
self.push_event(app, &e);
|
self.push_event(app, &e);
|
||||||
|
|
@ -429,11 +431,11 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||||
if !pressed && !self.has_focus[hit.pointer] {
|
if !pressed && !self.has_focus[hit.pointer] {
|
||||||
let e = WguiEvent::MouseMotion(MouseMotionEvent {
|
let e = WguiEvent::MouseMotion(MouseMotionEvent {
|
||||||
pos: vec2(-1., -1.),
|
pos: vec2(-1., -1.),
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
self.push_event(app, &e);
|
self.push_event(app, &e);
|
||||||
let e = WguiEvent::MouseLeave(MouseLeaveEvent {
|
let e = WguiEvent::MouseLeave(MouseLeaveEvent {
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
self.push_event(app, &e);
|
self.push_event(app, &e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
|
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ use wayvr_ipc::{
|
||||||
};
|
};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
event::{
|
event::{
|
||||||
Event as WguiEvent, MouseButtonEvent, MouseButtonIndex, MouseLeaveEvent, MouseMotionEvent,
|
DeviceBitmask, Event as WguiEvent, MouseButtonEvent, MouseButtonIndex, MouseLeaveEvent,
|
||||||
MouseWheelEvent,
|
MouseMotionEvent, MouseWheelEvent,
|
||||||
},
|
},
|
||||||
gfx::cmd::WGfxClearMode,
|
gfx::cmd::WGfxClearMode,
|
||||||
renderer_vk::context::Context as WguiContext,
|
renderer_vk::context::Context as WguiContext,
|
||||||
|
|
@ -205,7 +205,7 @@ impl OverlayBackend for DashFrontend {
|
||||||
let e = WguiEvent::MouseWheel(MouseWheelEvent {
|
let e = WguiEvent::MouseWheel(MouseWheelEvent {
|
||||||
delta: vec2(delta.x, delta.y) / 8.0,
|
delta: vec2(delta.x, delta.y) / 8.0,
|
||||||
pos: hit.uv * self.inner.layout.content_size,
|
pos: hit.uv * self.inner.layout.content_size,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
self.push_event(&e);
|
self.push_event(&e);
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +213,7 @@ impl OverlayBackend for DashFrontend {
|
||||||
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
||||||
let e = &WguiEvent::MouseMotion(MouseMotionEvent {
|
let e = &WguiEvent::MouseMotion(MouseMotionEvent {
|
||||||
pos: hit.uv * self.inner.layout.content_size,
|
pos: hit.uv * self.inner.layout.content_size,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.has_focus[hit.pointer] = true;
|
self.has_focus[hit.pointer] = true;
|
||||||
|
|
@ -235,7 +235,9 @@ impl OverlayBackend for DashFrontend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_left(&mut self, _app: &mut AppState, pointer: usize) {
|
fn on_left(&mut self, _app: &mut AppState, pointer: usize) {
|
||||||
let e = WguiEvent::MouseLeave(MouseLeaveEvent { device: pointer });
|
let e = WguiEvent::MouseLeave(MouseLeaveEvent {
|
||||||
|
device: DeviceBitmask::from_usize(pointer),
|
||||||
|
});
|
||||||
self.has_focus[pointer] = false;
|
self.has_focus[pointer] = false;
|
||||||
self.push_event(&e);
|
self.push_event(&e);
|
||||||
}
|
}
|
||||||
|
|
@ -252,13 +254,13 @@ impl OverlayBackend for DashFrontend {
|
||||||
WguiEvent::MouseDown(MouseButtonEvent {
|
WguiEvent::MouseDown(MouseButtonEvent {
|
||||||
pos: hit.uv * self.inner.layout.content_size,
|
pos: hit.uv * self.inner.layout.content_size,
|
||||||
index,
|
index,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
WguiEvent::MouseUp(MouseButtonEvent {
|
WguiEvent::MouseUp(MouseButtonEvent {
|
||||||
pos: hit.uv * self.inner.layout.content_size,
|
pos: hit.uv * self.inner.layout.content_size,
|
||||||
index,
|
index,
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
self.push_event(&e);
|
self.push_event(&e);
|
||||||
|
|
@ -267,11 +269,11 @@ impl OverlayBackend for DashFrontend {
|
||||||
if !pressed && !self.has_focus[hit.pointer] {
|
if !pressed && !self.has_focus[hit.pointer] {
|
||||||
let e = WguiEvent::MouseMotion(MouseMotionEvent {
|
let e = WguiEvent::MouseMotion(MouseMotionEvent {
|
||||||
pos: vec2(-1., -1.),
|
pos: vec2(-1., -1.),
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
self.push_event(&e);
|
self.push_event(&e);
|
||||||
let e = WguiEvent::MouseLeave(MouseLeaveEvent {
|
let e = WguiEvent::MouseLeave(MouseLeaveEvent {
|
||||||
device: hit.pointer,
|
device: DeviceBitmask::from_usize(hit.pointer),
|
||||||
});
|
});
|
||||||
self.push_event(&e);
|
self.push_event(&e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,18 @@ fn register_event_mouse_leave(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_event_mouse_cancel(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID {
|
||||||
|
listeners.register(
|
||||||
|
EventListenerKind::MouseCancel,
|
||||||
|
Box::new(move |_common, _event_data, (), ()| {
|
||||||
|
let mut state = state.borrow_mut();
|
||||||
|
state.down = false;
|
||||||
|
state.hovered = false;
|
||||||
|
Ok(EventResult::Pass)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn register_event_mouse_press(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID {
|
fn register_event_mouse_press(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID {
|
||||||
listeners.register(
|
listeners.register(
|
||||||
EventListenerKind::MousePress,
|
EventListenerKind::MousePress,
|
||||||
|
|
@ -552,6 +564,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
let listeners = &mut root.widget.state().event_listeners;
|
let listeners = &mut root.widget.state().event_listeners;
|
||||||
let anim_mult = ess.layout.state.theme.animation_mult;
|
let anim_mult = ess.layout.state.theme.animation_mult;
|
||||||
vec![
|
vec![
|
||||||
|
register_event_mouse_cancel(state.clone(), listeners),
|
||||||
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
|
register_event_mouse_enter(data.clone(), state.clone(), listeners, params.tooltip, anim_mult),
|
||||||
register_event_mouse_leave(state.clone(), listeners, anim_mult),
|
register_event_mouse_leave(state.clone(), listeners, anim_mult),
|
||||||
register_event_mouse_press(state.clone(), listeners),
|
register_event_mouse_press(state.clone(), listeners),
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,17 @@ fn register_event_mouse_leave(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_event_mouse_cancel(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID {
|
||||||
|
listeners.register(
|
||||||
|
EventListenerKind::MouseCancel,
|
||||||
|
Box::new(move |_common, _event_data, (), ()| {
|
||||||
|
let mut state = state.borrow_mut();
|
||||||
|
state.down = false;
|
||||||
|
Ok(EventResult::Pass)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn register_event_mouse_press(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID {
|
fn register_event_mouse_press(state: Rc<RefCell<State>>, listeners: &mut EventListenerCollection) -> EventListenerID {
|
||||||
listeners.register(
|
listeners.register(
|
||||||
EventListenerKind::MousePress,
|
EventListenerKind::MousePress,
|
||||||
|
|
@ -439,6 +450,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
|
||||||
vec![
|
vec![
|
||||||
register_event_mouse_enter(state.clone(), listeners, params.tooltip, anim_mult),
|
register_event_mouse_enter(state.clone(), listeners, params.tooltip, anim_mult),
|
||||||
register_event_mouse_leave(state.clone(), listeners, anim_mult),
|
register_event_mouse_leave(state.clone(), listeners, anim_mult),
|
||||||
|
register_event_mouse_cancel(state.clone(), listeners),
|
||||||
register_event_mouse_press(state.clone(), listeners),
|
register_event_mouse_press(state.clone(), listeners),
|
||||||
register_event_mouse_release(data.clone(), state.clone(), listeners),
|
register_event_mouse_release(data.clone(), state.clone(), listeners),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
drawing::{self},
|
drawing::{self},
|
||||||
event::{
|
event::{
|
||||||
self, CallbackDataCommon, CallbackMetadata, EventAlterables, EventListenerCollection, EventListenerKind,
|
self, CallbackDataCommon, CallbackMetadata, DeviceBitmask, EventAlterables, EventListenerCollection,
|
||||||
StyleSetRequest,
|
EventListenerKind, StyleSetRequest,
|
||||||
},
|
},
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::{WidgetID, WidgetPair},
|
layout::{WidgetID, WidgetPair},
|
||||||
|
|
@ -77,7 +77,7 @@ pub struct Params {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
dragged_by: Option<usize>,
|
dragged_by: Option<DeviceBitmask>,
|
||||||
hovered: bool,
|
hovered: bool,
|
||||||
values: ValuesMinMax,
|
values: ValuesMinMax,
|
||||||
on_value_changed: Option<SliderValueChangedCallback>,
|
on_value_changed: Option<SliderValueChangedCallback>,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
layout::WidgetPair,
|
layout::WidgetPair,
|
||||||
widget::{ConstructEssentials, div::WidgetDiv},
|
widget::{ConstructEssentials, div::WidgetDiv},
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, fmt::Pointer, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use taffy::{
|
use taffy::{
|
||||||
AlignItems,
|
AlignItems,
|
||||||
prelude::{length, percent},
|
prelude::{length, percent},
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,17 @@ use crate::{
|
||||||
widget::{EventResult, WidgetData, WidgetObj},
|
widget::{EventResult, WidgetData, WidgetObj},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
||||||
|
pub struct DeviceBitmask(pub u8);
|
||||||
|
|
||||||
|
impl DeviceBitmask {
|
||||||
|
pub fn from_usize(mask: usize) -> Self {
|
||||||
|
// more than 8 input devices?
|
||||||
|
debug_assert!(mask & !0xff == 0);
|
||||||
|
Self(mask as u8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum MouseButtonIndex {
|
pub enum MouseButtonIndex {
|
||||||
Left,
|
Left,
|
||||||
|
|
@ -30,28 +41,28 @@ pub enum MouseButtonIndex {
|
||||||
pub struct MouseButtonEvent {
|
pub struct MouseButtonEvent {
|
||||||
pub index: MouseButtonIndex,
|
pub index: MouseButtonIndex,
|
||||||
pub pos: Vec2,
|
pub pos: Vec2,
|
||||||
pub device: usize,
|
pub device: DeviceBitmask,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct MousePosition {
|
pub struct MousePosition {
|
||||||
pub pos: Vec2,
|
pub pos: Vec2,
|
||||||
pub device: usize,
|
pub device: DeviceBitmask,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MouseLeaveEvent {
|
pub struct MouseLeaveEvent {
|
||||||
pub device: usize,
|
pub device: DeviceBitmask,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MouseMotionEvent {
|
pub struct MouseMotionEvent {
|
||||||
pub pos: Vec2,
|
pub pos: Vec2,
|
||||||
pub device: usize,
|
pub device: DeviceBitmask,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MouseWheelEvent {
|
pub struct MouseWheelEvent {
|
||||||
pub pos: Vec2, /* mouse position */
|
pub pos: Vec2, /* mouse position */
|
||||||
pub delta: Vec2, /* wheel delta */
|
pub delta: Vec2, /* wheel delta */
|
||||||
pub device: usize,
|
pub device: DeviceBitmask,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -70,6 +81,7 @@ pub enum Event {
|
||||||
MouseMotion(MouseMotionEvent),
|
MouseMotion(MouseMotionEvent),
|
||||||
MouseUp(MouseButtonEvent),
|
MouseUp(MouseButtonEvent),
|
||||||
MouseWheel(MouseWheelEvent),
|
MouseWheel(MouseWheelEvent),
|
||||||
|
MouseCancel, // Called if the user started scrolling by swiping above the button, to cancel all currently pressed buttons (prevent clicks)
|
||||||
TextInput(TextInputEvent),
|
TextInput(TextInputEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,6 +118,7 @@ pub struct EventAlterables {
|
||||||
pub dirty_widgets: Vec<WidgetID>,
|
pub dirty_widgets: Vec<WidgetID>,
|
||||||
pub components_to_refresh_once: Vec<ComponentWeak>,
|
pub components_to_refresh_once: Vec<ComponentWeak>,
|
||||||
pub style_set_requests: Vec<(WidgetID, StyleSetRequest)>,
|
pub style_set_requests: Vec<(WidgetID, StyleSetRequest)>,
|
||||||
|
pub global_events_to_emit: Vec<Event>,
|
||||||
pub animations: Vec<animation::Animation>,
|
pub animations: Vec<animation::Animation>,
|
||||||
pub widgets_to_tick: HashSet<WidgetID>, // widgets which needs to be ticked in the next `Layout::update()` fn
|
pub widgets_to_tick: HashSet<WidgetID>, // widgets which needs to be ticked in the next `Layout::update()` fn
|
||||||
pub transform_stack: TransformStack,
|
pub transform_stack: TransformStack,
|
||||||
|
|
@ -134,6 +147,10 @@ impl EventAlterables {
|
||||||
self.mark_redraw();
|
self.mark_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn emit_global_event(&mut self, event: Event) {
|
||||||
|
self.global_events_to_emit.push(event);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mark_tick(&mut self, widget_id: WidgetID) {
|
pub fn mark_tick(&mut self, widget_id: WidgetID) {
|
||||||
self.widgets_to_tick.insert(widget_id);
|
self.widgets_to_tick.insert(widget_id);
|
||||||
}
|
}
|
||||||
|
|
@ -224,9 +241,10 @@ impl CallbackMetadata {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum EventListenerKind {
|
pub enum EventListenerKind {
|
||||||
MousePress,
|
MousePress,
|
||||||
MouseRelease,
|
|
||||||
MouseEnter,
|
|
||||||
MouseMotion,
|
MouseMotion,
|
||||||
|
MouseRelease,
|
||||||
|
MouseCancel,
|
||||||
|
MouseEnter,
|
||||||
MouseLeave,
|
MouseLeave,
|
||||||
TextInput,
|
TextInput,
|
||||||
InternalStateChange,
|
InternalStateChange,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
drawing::{
|
drawing::{
|
||||||
self, ANSI_BOLD_CODE, ANSI_RESET_CODE, Boundary, PushScissorStackResult, push_scissor_stack, push_transform_stack,
|
self, ANSI_BOLD_CODE, ANSI_RESET_CODE, Boundary, PushScissorStackResult, push_scissor_stack, push_transform_stack,
|
||||||
},
|
},
|
||||||
event::{self, CallbackDataCommon, EventAlterables},
|
event::{self, CallbackDataCommon, Event, EventAlterables},
|
||||||
globals::WguiGlobals,
|
globals::WguiGlobals,
|
||||||
sound::WguiSoundType,
|
sound::WguiSoundType,
|
||||||
task::Tasks,
|
task::Tasks,
|
||||||
|
|
@ -173,6 +173,8 @@ pub struct Layout {
|
||||||
|
|
||||||
pub widgets_to_tick: Vec<WidgetID>,
|
pub widgets_to_tick: Vec<WidgetID>,
|
||||||
|
|
||||||
|
global_events_to_emit: Vec<Event>,
|
||||||
|
|
||||||
// *Main root*
|
// *Main root*
|
||||||
// contains content_root_widget and topmost widgets
|
// contains content_root_widget and topmost widgets
|
||||||
pub tree_root_widget: WidgetID,
|
pub tree_root_widget: WidgetID,
|
||||||
|
|
@ -450,19 +452,25 @@ impl Layout {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_none_or(PushScissorStackResult::should_display)
|
.is_none_or(PushScissorStackResult::should_display)
|
||||||
{
|
{
|
||||||
// check children first
|
let res_priority = widget.process_event_priority(
|
||||||
self.push_event_children(node_id, event, event_result, alterables, user_data)?;
|
&mut self.get_event_params(l, node_id, style, alterables),
|
||||||
|
widget_id,
|
||||||
|
event,
|
||||||
|
)?;
|
||||||
|
|
||||||
if event_result.can_propagate() {
|
if res_priority.can_propagate() {
|
||||||
let mut params = EventParams {
|
// check children first
|
||||||
state: &self.state,
|
self.push_event_children(node_id, event, event_result, alterables, user_data)?;
|
||||||
layout: l,
|
|
||||||
alterables,
|
|
||||||
node_id,
|
|
||||||
style,
|
|
||||||
};
|
|
||||||
|
|
||||||
widget.process_event(widget_id, node_id, event, event_result, user_data, &mut params)?;
|
if event_result.can_propagate() {
|
||||||
|
widget.process_event(
|
||||||
|
&mut self.get_event_params(l, node_id, style, alterables),
|
||||||
|
widget_id,
|
||||||
|
event,
|
||||||
|
event_result,
|
||||||
|
user_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,6 +482,22 @@ impl Layout {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_event_params<'a>(
|
||||||
|
&'a self,
|
||||||
|
l: &'a taffy::Layout,
|
||||||
|
node_id: taffy::NodeId,
|
||||||
|
style: &'a taffy::Style,
|
||||||
|
alterables: &'a mut EventAlterables,
|
||||||
|
) -> EventParams<'a> {
|
||||||
|
EventParams {
|
||||||
|
node_id,
|
||||||
|
style,
|
||||||
|
state: &self.state,
|
||||||
|
alterables,
|
||||||
|
taffy_layout: l,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn check_toggle_needs_redraw(&mut self) -> bool {
|
pub const fn check_toggle_needs_redraw(&mut self) -> bool {
|
||||||
if self.needs_redraw {
|
if self.needs_redraw {
|
||||||
self.needs_redraw = false;
|
self.needs_redraw = false;
|
||||||
|
|
@ -508,6 +532,18 @@ impl Layout {
|
||||||
&mut (user1, user2),
|
&mut (user1, user2),
|
||||||
)?;
|
)?;
|
||||||
self.process_alterables(alterables)?;
|
self.process_alterables(alterables)?;
|
||||||
|
|
||||||
|
let mut alterables = EventAlterables::default();
|
||||||
|
for event in std::mem::take(&mut self.global_events_to_emit) {
|
||||||
|
self.push_event_widget(
|
||||||
|
self.tree_root_node,
|
||||||
|
&event,
|
||||||
|
&mut event_result,
|
||||||
|
&mut alterables,
|
||||||
|
&mut (user1, user2),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(event_result)
|
Ok(event_result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,6 +616,7 @@ impl Layout {
|
||||||
sounds_to_play_once: Vec::new(),
|
sounds_to_play_once: Vec::new(),
|
||||||
focused_component: None,
|
focused_component: None,
|
||||||
alterables: Default::default(),
|
alterables: Default::default(),
|
||||||
|
global_events_to_emit: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -815,10 +852,12 @@ impl Layout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alterables.widgets_to_tick.is_empty() {
|
for widget_id in alterables.widgets_to_tick {
|
||||||
for widget_id in &alterables.widgets_to_tick {
|
self.widgets_to_tick.push(widget_id);
|
||||||
self.widgets_to_tick.push(*widget_id);
|
}
|
||||||
}
|
|
||||||
|
for event in alterables.global_events_to_emit {
|
||||||
|
self.global_events_to_emit.push(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in alterables.components_to_refresh_once {
|
for c in alterables.components_to_refresh_once {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use glam::Vec2;
|
use glam::{FloatExt, Vec2};
|
||||||
use taffy::{NodeId, TaffyTree};
|
use taffy::{NodeId, TaffyTree};
|
||||||
|
|
||||||
use super::drawing::RenderPrimitive;
|
use super::drawing::RenderPrimitive;
|
||||||
|
|
@ -8,7 +8,8 @@ use crate::{
|
||||||
any::AnyTrait,
|
any::AnyTrait,
|
||||||
drawing::{self, PrimitiveExtent},
|
drawing::{self, PrimitiveExtent},
|
||||||
event::{
|
event::{
|
||||||
self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables, EventListenerCollection,
|
self, CallbackData, CallbackDataCommon, CallbackMetadata, DeviceBitmask, Event, EventAlterables,
|
||||||
|
EventListenerCollection,
|
||||||
EventListenerKind::{self, InternalStateChange, MouseLeave},
|
EventListenerKind::{self, InternalStateChange, MouseLeave},
|
||||||
MouseWheelEvent,
|
MouseWheelEvent,
|
||||||
},
|
},
|
||||||
|
|
@ -25,57 +26,66 @@ pub mod rectangle;
|
||||||
pub mod sprite;
|
pub mod sprite;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
const SWIPE_START_THRESHOLD_UNITS: f32 = 16.0;
|
||||||
|
const KINETIC_VELOCITY_DAMPING: f32 = 0.92;
|
||||||
|
const KINETIC_VELOCITY_BRAKE: f32 = 0.85;
|
||||||
|
const RUBBERBANDING_DAMP: f32 = 0.8;
|
||||||
|
|
||||||
pub struct WidgetData {
|
pub struct WidgetData {
|
||||||
hovered: usize,
|
hovered: DeviceBitmask,
|
||||||
pressed: usize,
|
pressed: DeviceBitmask,
|
||||||
pub scrolling_target: Vec2, // normalized, 0.0-1.0. Not used in case if overflow != scroll
|
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
|
scrolling_cur: Vec2, // normalized, used for smooth scrolling animation
|
||||||
pub scrolling_cur_prev: Vec2, // for motion interpolation while rendering between ticks
|
scrolling_cur_prev: Vec2, // for motion interpolation while rendering between ticks
|
||||||
|
scrolling_velocity: Vec2,
|
||||||
|
press_down_start_mouse_pos: Option<Vec2>,
|
||||||
|
swipe_running: bool,
|
||||||
|
swipe_scroll_start: Vec2, // normalized, 0.0-1.0
|
||||||
pub transform: glam::Mat4,
|
pub transform: glam::Mat4,
|
||||||
pub cached_absolute_boundary: drawing::Boundary, // updated in Layout::push_event_widget
|
pub cached_absolute_boundary: drawing::Boundary, // updated in Layout::push_event_widget
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetData {
|
impl WidgetData {
|
||||||
pub const fn set_device_pressed(&mut self, device: usize, pressed: bool) -> bool {
|
pub const fn set_device_pressed(&mut self, device: DeviceBitmask, pressed: bool) -> bool {
|
||||||
let bit = 1 << device;
|
let bit = 1 << device.0;
|
||||||
let state_changed;
|
let state_changed;
|
||||||
if pressed {
|
if pressed {
|
||||||
state_changed = self.pressed == 0;
|
state_changed = self.pressed.0 == 0;
|
||||||
self.pressed |= bit;
|
self.pressed.0 |= bit;
|
||||||
} else {
|
} else {
|
||||||
state_changed = self.pressed == bit;
|
state_changed = self.pressed.0 == bit;
|
||||||
self.pressed &= !bit;
|
self.pressed.0 &= !bit;
|
||||||
}
|
}
|
||||||
state_changed
|
state_changed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn set_device_hovered(&mut self, device: usize, hovered: bool) -> bool {
|
pub const fn set_device_hovered(&mut self, device: DeviceBitmask, hovered: bool) -> bool {
|
||||||
let bit = 1 << device;
|
let bit = 1 << device.0;
|
||||||
let state_changed;
|
let state_changed;
|
||||||
if hovered {
|
if hovered {
|
||||||
state_changed = self.hovered == 0;
|
state_changed = self.hovered.0 == 0;
|
||||||
self.hovered |= bit;
|
self.hovered.0 |= bit;
|
||||||
} else {
|
} else {
|
||||||
state_changed = self.hovered == bit;
|
state_changed = self.hovered.0 == bit;
|
||||||
self.hovered &= !bit;
|
self.hovered.0 &= !bit;
|
||||||
}
|
}
|
||||||
state_changed
|
state_changed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn get_pressed(&self, device: usize) -> bool {
|
pub const fn get_pressed(&self, device: DeviceBitmask) -> bool {
|
||||||
self.pressed & (1 << device) != 0
|
self.pressed.0 & (1 << device.0) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn get_hovered(&self, device: usize) -> bool {
|
pub const fn get_hovered(&self, device: DeviceBitmask) -> bool {
|
||||||
self.hovered & (1 << device) != 0
|
self.hovered.0 & (1 << device.0) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn is_pressed(&self) -> bool {
|
pub const fn is_pressed(&self) -> bool {
|
||||||
self.pressed != 0
|
self.pressed.0 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn is_hovered(&self) -> bool {
|
pub const fn is_hovered(&self) -> bool {
|
||||||
self.hovered != 0
|
self.hovered.0 != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,13 +126,17 @@ impl WidgetState {
|
||||||
fn new(flags: WidgetStateFlags, obj: Box<dyn WidgetObj>) -> Self {
|
fn new(flags: WidgetStateFlags, obj: Box<dyn WidgetObj>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: WidgetData {
|
data: WidgetData {
|
||||||
hovered: 0,
|
hovered: DeviceBitmask(0),
|
||||||
pressed: 0,
|
pressed: DeviceBitmask(0),
|
||||||
scrolling_target: Vec2::default(),
|
scrolling_target: Vec2::default(),
|
||||||
scrolling_cur: Vec2::default(),
|
scrolling_cur: Vec2::default(),
|
||||||
scrolling_cur_prev: Vec2::default(),
|
scrolling_cur_prev: Vec2::default(),
|
||||||
transform: glam::Mat4::IDENTITY,
|
transform: glam::Mat4::IDENTITY,
|
||||||
cached_absolute_boundary: drawing::Boundary::default(),
|
cached_absolute_boundary: drawing::Boundary::default(),
|
||||||
|
press_down_start_mouse_pos: None,
|
||||||
|
swipe_running: false,
|
||||||
|
swipe_scroll_start: Vec2::default(),
|
||||||
|
scrolling_velocity: Vec2::default(),
|
||||||
},
|
},
|
||||||
obj,
|
obj,
|
||||||
event_listeners: EventListenerCollection::default(),
|
event_listeners: EventListenerCollection::default(),
|
||||||
|
|
@ -192,7 +206,7 @@ pub struct EventParams<'a> {
|
||||||
pub style: &'a taffy::Style,
|
pub style: &'a taffy::Style,
|
||||||
pub state: &'a LayoutState,
|
pub state: &'a LayoutState,
|
||||||
pub alterables: &'a mut EventAlterables,
|
pub alterables: &'a mut EventAlterables,
|
||||||
pub layout: &'a taffy::Layout,
|
pub taffy_layout: &'a taffy::Layout,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd)]
|
||||||
|
|
@ -221,6 +235,22 @@ fn get_scroll_enabled(style: &taffy::Style) -> (bool, bool) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OVERFLOW_START_THRESHOLD_UNITS: f32 = 3.0; // don't show scrollbars for nearly non-scrollable lists
|
||||||
|
|
||||||
|
fn get_scroll_active_axis(style: &taffy::Style, taffy_layout: &taffy::Layout) -> (bool, bool) {
|
||||||
|
let (enabled_horiz, enabled_vert) = get_scroll_enabled(style);
|
||||||
|
if !enabled_horiz && !enabled_vert {
|
||||||
|
return (false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let overflow = Vec2::new(taffy_layout.scroll_width(), taffy_layout.scroll_height());
|
||||||
|
|
||||||
|
(
|
||||||
|
overflow.x >= OVERFLOW_START_THRESHOLD_UNITS,
|
||||||
|
overflow.y >= OVERFLOW_START_THRESHOLD_UNITS,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ScrollbarInfo {
|
pub struct ScrollbarInfo {
|
||||||
// total contents size of the currently scrolling widget
|
// total contents size of the currently scrolling widget
|
||||||
content_size: Vec2,
|
content_size: Vec2,
|
||||||
|
|
@ -229,15 +259,13 @@ pub struct ScrollbarInfo {
|
||||||
handle_size: Vec2,
|
handle_size: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_scrollbar_info(l: &taffy::Layout) -> Option<ScrollbarInfo> {
|
pub fn get_scrollbar_info(taffy_layout: &taffy::Layout) -> Option<ScrollbarInfo> {
|
||||||
let overflow_start_threshold_units = 3.0; // don't show scrollbars for nearly non-scrollable lists
|
let overflow = Vec2::new(taffy_layout.scroll_width(), taffy_layout.scroll_height());
|
||||||
|
if overflow.x < OVERFLOW_START_THRESHOLD_UNITS && overflow.y < OVERFLOW_START_THRESHOLD_UNITS {
|
||||||
let overflow = Vec2::new(l.scroll_width(), l.scroll_height());
|
|
||||||
if overflow.x < overflow_start_threshold_units && overflow.y < overflow_start_threshold_units {
|
|
||||||
return None; // not overflowing
|
return None; // not overflowing
|
||||||
}
|
}
|
||||||
|
|
||||||
let content_size = Vec2::new(l.content_size.width, l.content_size.height);
|
let content_size = Vec2::new(taffy_layout.content_size.width, taffy_layout.content_size.height);
|
||||||
let handle_size = 1.0 - (overflow / content_size);
|
let handle_size = 1.0 - (overflow / content_size);
|
||||||
|
|
||||||
Some(ScrollbarInfo {
|
Some(ScrollbarInfo {
|
||||||
|
|
@ -246,6 +274,15 @@ pub fn get_scrollbar_info(l: &taffy::Layout) -> Option<ScrollbarInfo> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ScrollbarInfo {
|
||||||
|
fn get_potential_scroll_axis_multiplier(&self, taffy_layout: &taffy::Layout) -> Vec2 {
|
||||||
|
Vec2::new(
|
||||||
|
self.content_size.x - taffy_layout.content_box_width(),
|
||||||
|
self.content_size.y - taffy_layout.content_box_height(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl dyn WidgetObj {
|
impl dyn WidgetObj {
|
||||||
pub fn get_as<T: 'static>(&self) -> Option<&T> {
|
pub fn get_as<T: 'static>(&self) -> Option<&T> {
|
||||||
let any = self.as_any();
|
let any = self.as_any();
|
||||||
|
|
@ -348,6 +385,46 @@ impl WidgetState {
|
||||||
let scrolling_cur_prev = &mut self.data.scrolling_cur_prev;
|
let scrolling_cur_prev = &mut self.data.scrolling_cur_prev;
|
||||||
let scrolling_target = &mut self.data.scrolling_target;
|
let scrolling_target = &mut self.data.scrolling_target;
|
||||||
|
|
||||||
|
let mut perform_next_tick = false;
|
||||||
|
|
||||||
|
// check for boundaries
|
||||||
|
if !self.data.swipe_running {
|
||||||
|
// top bound
|
||||||
|
if scrolling_target.y < 0.0 {
|
||||||
|
self.data.scrolling_velocity.y *= KINETIC_VELOCITY_BRAKE;
|
||||||
|
scrolling_target.y *= RUBBERBANDING_DAMP;
|
||||||
|
perform_next_tick = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// left bound
|
||||||
|
if scrolling_target.x < 0.0 {
|
||||||
|
self.data.scrolling_velocity.x *= KINETIC_VELOCITY_BRAKE;
|
||||||
|
scrolling_target.x *= RUBBERBANDING_DAMP;
|
||||||
|
perform_next_tick = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// right bound
|
||||||
|
if scrolling_target.x > 1.0 {
|
||||||
|
self.data.scrolling_velocity.x *= KINETIC_VELOCITY_BRAKE;
|
||||||
|
scrolling_target.x = 1.0.lerp(scrolling_target.x, RUBBERBANDING_DAMP);
|
||||||
|
perform_next_tick = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom bound
|
||||||
|
if scrolling_target.y > 1.0 {
|
||||||
|
self.data.scrolling_velocity.y *= KINETIC_VELOCITY_BRAKE;
|
||||||
|
scrolling_target.y = 1.0.lerp(scrolling_target.y, RUBBERBANDING_DAMP);
|
||||||
|
perform_next_tick = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform kinetic velocity animation
|
||||||
|
if self.data.scrolling_velocity.length_squared() > 1e-9 {
|
||||||
|
*scrolling_target += self.data.scrolling_velocity;
|
||||||
|
self.data.scrolling_velocity *= KINETIC_VELOCITY_DAMPING;
|
||||||
|
perform_next_tick = true;
|
||||||
|
}
|
||||||
|
|
||||||
*scrolling_cur_prev = *scrolling_cur;
|
*scrolling_cur_prev = *scrolling_cur;
|
||||||
|
|
||||||
if scrolling_cur != scrolling_target {
|
if scrolling_cur != scrolling_target {
|
||||||
|
|
@ -355,8 +432,7 @@ impl WidgetState {
|
||||||
*scrolling_cur = scrolling_cur.lerp(*scrolling_target, 0.2);
|
*scrolling_cur = scrolling_cur.lerp(*scrolling_target, 0.2);
|
||||||
|
|
||||||
// trigger tick request again
|
// trigger tick request again
|
||||||
alterables.mark_tick(this_widget_id);
|
perform_next_tick = true;
|
||||||
alterables.mark_redraw();
|
|
||||||
|
|
||||||
let epsilon = 0.00001;
|
let epsilon = 0.00001;
|
||||||
if (scrolling_cur.x - scrolling_target.x).abs() < epsilon
|
if (scrolling_cur.x - scrolling_target.x).abs() < epsilon
|
||||||
|
|
@ -365,6 +441,11 @@ impl WidgetState {
|
||||||
*scrolling_cur = *scrolling_target;
|
*scrolling_cur = *scrolling_target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if perform_next_tick {
|
||||||
|
alterables.mark_tick(this_widget_id);
|
||||||
|
alterables.mark_redraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_scrollbars(&mut self, state: &mut DrawState, params: &DrawParams, info: &ScrollbarInfo) {
|
pub fn draw_scrollbars(&mut self, state: &mut DrawState, params: &DrawParams, info: &ScrollbarInfo) {
|
||||||
|
|
@ -432,13 +513,13 @@ impl WidgetState {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let l = params.layout;
|
let l = params.taffy_layout;
|
||||||
let overflow = Vec2::new(l.scroll_width(), l.scroll_height());
|
let overflow = Vec2::new(l.scroll_width(), l.scroll_height());
|
||||||
if overflow.x == 0.0 && overflow.y == 0.0 {
|
if overflow.x == 0.0 && overflow.y == 0.0 {
|
||||||
return false; // not overflowing
|
return false; // not overflowing
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(info) = get_scrollbar_info(params.layout) else {
|
let Some(info) = get_scrollbar_info(l) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -451,7 +532,7 @@ impl WidgetState {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mult = (1.0 / (content_box_length - content_length)) * step_pixels;
|
let mult = (1.0 / (content_box_length - content_length)) * step_pixels;
|
||||||
let new_scroll = (*scrolling_target + wheel_delta * mult).clamp(0.0, 1.0);
|
let new_scroll = *scrolling_target + wheel_delta * mult;
|
||||||
if *scrolling_target == new_scroll {
|
if *scrolling_target == new_scroll {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -479,20 +560,81 @@ impl WidgetState {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is called before calling children of this widget
|
||||||
|
pub fn process_event_priority(
|
||||||
|
&mut self,
|
||||||
|
params: &mut EventParams,
|
||||||
|
widget_id: WidgetID,
|
||||||
|
event: &Event,
|
||||||
|
) -> anyhow::Result<EventResult> {
|
||||||
|
match &event {
|
||||||
|
Event::MouseDown(e) => {
|
||||||
|
// firstly, check if this widget is scrollable at all
|
||||||
|
let (active_x, active_y) = get_scroll_active_axis(¶ms.style, ¶ms.taffy_layout);
|
||||||
|
if active_x || active_y {
|
||||||
|
self.data.press_down_start_mouse_pos = Some(e.pos);
|
||||||
|
self.data.swipe_scroll_start = self.data.scrolling_target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::MouseUp(_e) => {
|
||||||
|
if self.data.swipe_running {
|
||||||
|
self.data.swipe_running = false;
|
||||||
|
let kinetic_force = (self.data.scrolling_cur - self.data.scrolling_cur_prev) * 20.0;
|
||||||
|
self.data.scrolling_velocity += kinetic_force;
|
||||||
|
params.alterables.mark_tick(widget_id);
|
||||||
|
params.alterables.mark_redraw();
|
||||||
|
}
|
||||||
|
self.data.press_down_start_mouse_pos = None;
|
||||||
|
}
|
||||||
|
Event::MouseMotion(e) => {
|
||||||
|
if let Some(start_mouse_pos) = &self.data.press_down_start_mouse_pos {
|
||||||
|
let (active_x, active_y) = get_scroll_active_axis(¶ms.style, ¶ms.taffy_layout);
|
||||||
|
|
||||||
|
if !self.data.swipe_running {
|
||||||
|
if (active_x && (e.pos.x - start_mouse_pos.x).abs() >= SWIPE_START_THRESHOLD_UNITS)
|
||||||
|
|| (active_y && (e.pos.y - start_mouse_pos.y).abs() >= SWIPE_START_THRESHOLD_UNITS)
|
||||||
|
{
|
||||||
|
self.data.swipe_running = true;
|
||||||
|
params.alterables.emit_global_event(Event::MouseCancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.data.swipe_running
|
||||||
|
&& let Some(scrollbar_info) = get_scrollbar_info(params.taffy_layout)
|
||||||
|
{
|
||||||
|
let mouse_diff = e.pos - start_mouse_pos;
|
||||||
|
|
||||||
|
let mult = scrollbar_info.get_potential_scroll_axis_multiplier(params.taffy_layout);
|
||||||
|
|
||||||
|
let scroll_diff_x = if mult.x != 0.0 { -mouse_diff.x / mult.x } else { 0.0 };
|
||||||
|
let scroll_diff_y = if mult.y != 0.0 { -mouse_diff.y / mult.y } else { 0.0 };
|
||||||
|
|
||||||
|
self.data.scrolling_target = self.data.swipe_scroll_start + Vec2::new(scroll_diff_x, scroll_diff_y);
|
||||||
|
params.alterables.mark_tick(self.obj.get_id());
|
||||||
|
|
||||||
|
return Ok(EventResult::Consumed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(EventResult::Pass)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_event<'a, 'b, U1: 'static, U2: 'static>(
|
pub fn process_event<'a, 'b, U1: 'static, U2: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
params: &'a mut EventParams<'a>,
|
||||||
widget_id: WidgetID,
|
widget_id: WidgetID,
|
||||||
node_id: taffy::NodeId,
|
|
||||||
event: &Event,
|
event: &Event,
|
||||||
event_result: &'a mut EventResult,
|
event_result: &'a mut EventResult,
|
||||||
user_data: &'a mut (&'b mut U1, &'b mut U2),
|
user_data: &'a mut (&'b mut U1, &'b mut U2),
|
||||||
params: &'a mut EventParams<'a>,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let hovered = event.test_mouse_within_transform(params.alterables.transform_stack.get());
|
let hovered = event.test_mouse_within_transform(params.alterables.transform_stack.get());
|
||||||
|
|
||||||
let mut invoke_data = InvokeData {
|
let mut invoke_data = InvokeData {
|
||||||
widget_id,
|
widget_id,
|
||||||
node_id,
|
node_id: params.node_id,
|
||||||
event_result,
|
event_result,
|
||||||
user_data,
|
user_data,
|
||||||
params,
|
params,
|
||||||
|
|
@ -508,6 +650,9 @@ impl WidgetState {
|
||||||
CallbackMetadata::TextInput(e.clone()),
|
CallbackMetadata::TextInput(e.clone()),
|
||||||
)?);
|
)?);
|
||||||
}
|
}
|
||||||
|
Event::MouseCancel => {
|
||||||
|
res = Some(self.invoke_listeners(&mut invoke_data, EventListenerKind::MouseCancel, CallbackMetadata::None)?);
|
||||||
|
}
|
||||||
Event::MouseDown(e) => {
|
Event::MouseDown(e) => {
|
||||||
if hovered && self.data.set_device_pressed(e.device, true) {
|
if hovered && self.data.set_device_pressed(e.device, true) {
|
||||||
res = Some(self.invoke_listeners(
|
res = Some(self.invoke_listeners(
|
||||||
|
|
@ -528,7 +673,6 @@ impl WidgetState {
|
||||||
}
|
}
|
||||||
Event::MouseMotion(e) => {
|
Event::MouseMotion(e) => {
|
||||||
let hover_state_changed = self.data.set_device_hovered(e.device, hovered);
|
let hover_state_changed = self.data.set_device_hovered(e.device, hovered);
|
||||||
|
|
||||||
if hover_state_changed {
|
if hover_state_changed {
|
||||||
if self.data.is_hovered() {
|
if self.data.is_hovered() {
|
||||||
res =
|
res =
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue