1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-27 07:03:14 -04:00
Files
egui/crates/emath/src/vec2b.rs
valadaptive ac2466d14f Update ScrollArea drag velocity when drag stopped (#5175)
Fixes #5174.

The drag velocity was not being updated unless the cursor counted as
"dragging", which only happens when it's in motion. This effectively
guarantees that the drag velocity will never be zero, even if the cursor
is not moving, and results in spurious scroll velocity being applied
when the cursor is released.

Instead, we update the velocity only when the drag is stopped, which is
when the kinetic scrolling actually needs to begin. Note that we
immediately *apply* the scroll velocity on the same frame that we first
set it, to avoid a 1-frame gap where the scroll area doesn't move.

I believe that *not* setting `scroll_stuck_to_end` and `offset_target`
when the drag is released is the correct thing to do, as they should
apply immediately once the user stops dragging. Should we maybe clear
the drag velocity instead if `scroll_stuck_to_end` is true or
`offset_target` exists?

* Closes #5174
* [x] I have followed the instructions in the PR template
2024-10-02 18:12:36 +02:00

105 lines
2.2 KiB
Rust

use crate::Vec2;
/// Two bools, one for each axis (X and Y).
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Vec2b {
pub x: bool,
pub y: bool,
}
impl Vec2b {
pub const FALSE: Self = Self { x: false, y: false };
pub const TRUE: Self = Self { x: true, y: true };
#[inline]
pub fn new(x: bool, y: bool) -> Self {
Self { x, y }
}
#[inline]
pub fn any(&self) -> bool {
self.x || self.y
}
/// Are both `x` and `y` true?
#[inline]
pub fn all(&self) -> bool {
self.x && self.y
}
#[inline]
pub fn and(&self, other: impl Into<Self>) -> Self {
let other = other.into();
Self {
x: self.x && other.x,
y: self.y && other.y,
}
}
#[inline]
pub fn or(&self, other: impl Into<Self>) -> Self {
let other = other.into();
Self {
x: self.x || other.x,
y: self.y || other.y,
}
}
/// Convert to a float `Vec2` where the components are 1.0 for `true` and 0.0 for `false`.
#[inline]
pub fn to_vec2(self) -> Vec2 {
Vec2::new(self.x.into(), self.y.into())
}
}
impl From<bool> for Vec2b {
#[inline]
fn from(val: bool) -> Self {
Self { x: val, y: val }
}
}
impl From<[bool; 2]> for Vec2b {
#[inline]
fn from([x, y]: [bool; 2]) -> Self {
Self { x, y }
}
}
impl std::ops::Index<usize> for Vec2b {
type Output = bool;
#[inline(always)]
fn index(&self, index: usize) -> &bool {
match index {
0 => &self.x,
1 => &self.y,
_ => panic!("Vec2b index out of bounds: {index}"),
}
}
}
impl std::ops::IndexMut<usize> for Vec2b {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut bool {
match index {
0 => &mut self.x,
1 => &mut self.y,
_ => panic!("Vec2b index out of bounds: {index}"),
}
}
}
impl std::ops::Not for Vec2b {
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
Self {
x: !self.x,
y: !self.y,
}
}
}