mirror of
https://github.com/danbulant/cushy
synced 2026-07-05 19:20:36 +00:00
Extracting easing functions + Clippy
This commit is contained in:
parent
6726855ed0
commit
df748a991d
10 changed files with 75 additions and 409 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -659,6 +659,7 @@ dependencies = [
|
||||||
"alot",
|
"alot",
|
||||||
"arboard",
|
"arboard",
|
||||||
"cushy-macros",
|
"cushy-macros",
|
||||||
|
"easing-function",
|
||||||
"figures",
|
"figures",
|
||||||
"image",
|
"image",
|
||||||
"intentional",
|
"intentional",
|
||||||
|
|
@ -751,6 +752,11 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
|
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "easing-function"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/khonsulabs/easing-function#ecaf4c9615dcb155019ebee8f553531ea725bda5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ image = { version = "0.25.0", features = ["png"] }
|
||||||
plotters = { version = "0.3.5", default-features = false, optional = true }
|
plotters = { version = "0.3.5", default-features = false, optional = true }
|
||||||
nominals = "0.3.0"
|
nominals = "0.3.0"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
|
easing-function = { git = "https://github.com/khonsulabs/easing-function" }
|
||||||
|
|
||||||
|
|
||||||
# [patch.crates-io]
|
# [patch.crates-io]
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use cushy::value::{Dynamic, Source};
|
use cushy::value::{Dynamic, Source};
|
||||||
use cushy::widget::MakeWidget;
|
use cushy::widget::MakeWidget;
|
||||||
use cushy::widgets::slider::Slidable;
|
use cushy::widgets::slider::Slidable;
|
||||||
use cushy::widgets::Canvas;
|
use cushy::widgets::Canvas;
|
||||||
use cushy::Run;
|
use cushy::Run;
|
||||||
use kludgine::app::winit::keyboard::{Key, NamedKey};
|
|
||||||
use plotters::prelude::*;
|
use plotters::prelude::*;
|
||||||
|
|
||||||
// This is copied from the sierpinski.rs example in the plotters repository.
|
// This is copied from the sierpinski.rs example in the plotters repository.
|
||||||
|
|
@ -55,6 +52,9 @@ fn main() -> cushy::Result<()> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runs() {
|
fn runs() {
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use kludgine::app::winit::keyboard::{Key, NamedKey};
|
||||||
cushy::example!(plotters).animated(|r| {
|
cushy::example!(plotters).animated(|r| {
|
||||||
r.wait_for(Duration::from_millis(500)).unwrap();
|
r.wait_for(Duration::from_millis(500)).unwrap();
|
||||||
r.animate_keypress(
|
r.animate_keypress(
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ fn main() -> cushy::Result {
|
||||||
|
|
||||||
// Create our label by using `map_each` to format the name, first checking
|
// Create our label by using `map_each` to format the name, first checking
|
||||||
// if it is empty.
|
// if it is empty.
|
||||||
let greeting: Dynamic<String> = name.map_each(|name| {
|
let greeting = name.map_each(|name| {
|
||||||
let name = if name.is_empty() { "World" } else { name };
|
let name = if name.is_empty() { "World" } else { name };
|
||||||
format!("Hello, {name}!")
|
format!("Hello, {name}!")
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -37,17 +37,16 @@
|
||||||
//! assert_eq!(reader.get(), 100);
|
//! assert_eq!(reader.get(), 100);
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
pub mod easings;
|
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::ops::{ControlFlow, Deref, Div, DivAssign, Mul, MulAssign, Sub};
|
use std::ops::{ControlFlow, Deref, Div, DivAssign, Mul, MulAssign, Sub};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::OnceLock;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use alot::{LotId, Lots};
|
use alot::{LotId, Lots};
|
||||||
|
pub use easing_function::*;
|
||||||
use figures::units::{Lp, Px, UPx};
|
use figures::units::{Lp, Px, UPx};
|
||||||
use figures::{Angle, Fraction, Point, Ranged, Rect, Size, UnscaledUnit, Zero};
|
use figures::{Angle, Fraction, Point, Ranged, Rect, Size, UnscaledUnit, Zero};
|
||||||
use intentional::Cast;
|
use intentional::Cast;
|
||||||
|
|
@ -478,9 +477,9 @@ where
|
||||||
self.target.finish();
|
self.target.finish();
|
||||||
ControlFlow::Break(remaining_elapsed)
|
ControlFlow::Break(remaining_elapsed)
|
||||||
} else {
|
} else {
|
||||||
let progress = self.easing.ease(ZeroToOne::new(
|
let progress = self
|
||||||
self.elapsed.as_secs_f32() / self.duration.as_secs_f32(),
|
.easing
|
||||||
));
|
.ease(self.elapsed.as_secs_f32() / self.duration.as_secs_f32());
|
||||||
self.target.update(progress);
|
self.target.update(progress);
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
@ -828,6 +827,12 @@ pub use cushy_macros::LinearInterpolate;
|
||||||
macro_rules! impl_lerp_for_int {
|
macro_rules! impl_lerp_for_int {
|
||||||
($type:ident, $unsigned:ident, $float:ident) => {
|
($type:ident, $unsigned:ident, $float:ident) => {
|
||||||
impl LinearInterpolate for $type {
|
impl LinearInterpolate for $type {
|
||||||
|
#[allow(
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::cast_sign_loss,
|
||||||
|
clippy::cast_precision_loss,
|
||||||
|
clippy::cast_lossless
|
||||||
|
)]
|
||||||
fn lerp(&self, target: &Self, percent: f32) -> Self {
|
fn lerp(&self, target: &Self, percent: f32) -> Self {
|
||||||
let percent = $float::from(percent);
|
let percent = $float::from(percent);
|
||||||
let delta = target.abs_diff(*self);
|
let delta = target.abs_diff(*self);
|
||||||
|
|
@ -845,6 +850,12 @@ macro_rules! impl_lerp_for_int {
|
||||||
macro_rules! impl_lerp_for_uint {
|
macro_rules! impl_lerp_for_uint {
|
||||||
($type:ident, $float:ident) => {
|
($type:ident, $float:ident) => {
|
||||||
impl LinearInterpolate for $type {
|
impl LinearInterpolate for $type {
|
||||||
|
#[allow(
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::cast_sign_loss,
|
||||||
|
clippy::cast_precision_loss,
|
||||||
|
clippy::cast_lossless
|
||||||
|
)]
|
||||||
fn lerp(&self, target: &Self, percent: f32) -> Self {
|
fn lerp(&self, target: &Self, percent: f32) -> Self {
|
||||||
let percent = $float::from(percent);
|
let percent = $float::from(percent);
|
||||||
if let Some(delta) = target.checked_sub(*self) {
|
if let Some(delta) = target.checked_sub(*self) {
|
||||||
|
|
@ -1070,6 +1081,12 @@ pub trait PercentBetween {
|
||||||
macro_rules! impl_percent_between {
|
macro_rules! impl_percent_between {
|
||||||
($type:ident, $float:ident, $sub:ident) => {
|
($type:ident, $float:ident, $sub:ident) => {
|
||||||
impl PercentBetween for $type {
|
impl PercentBetween for $type {
|
||||||
|
#[allow(
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::cast_sign_loss,
|
||||||
|
clippy::cast_precision_loss,
|
||||||
|
clippy::cast_lossless
|
||||||
|
)]
|
||||||
fn percent_between(&self, min: &Self, max: &Self) -> ZeroToOne {
|
fn percent_between(&self, min: &Self, max: &Self) -> ZeroToOne {
|
||||||
assert!(min <= max, "percent_between requires min <= max");
|
assert!(min <= max, "percent_between requires min <= max");
|
||||||
assert!(
|
assert!(
|
||||||
|
|
@ -1451,24 +1468,6 @@ fn zero_to_one_div() {
|
||||||
assert_eq!(ZeroToOne::ONE / -0.5, ZeroToOne::ONE);
|
assert_eq!(ZeroToOne::ONE / -0.5, ZeroToOne::ONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An easing function for customizing animations.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum EasingFunction {
|
|
||||||
/// A function pointer to use as an easing function.
|
|
||||||
Fn(fn(ZeroToOne) -> f32),
|
|
||||||
/// A custom easing implementation.
|
|
||||||
Custom(Arc<dyn Easing>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Easing for EasingFunction {
|
|
||||||
fn ease(&self, progress: ZeroToOne) -> f32 {
|
|
||||||
match self {
|
|
||||||
EasingFunction::Fn(func) => func(progress),
|
|
||||||
EasingFunction::Custom(func) => func.ease(progress),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<EasingFunction> for Component {
|
impl From<EasingFunction> for Component {
|
||||||
fn from(value: EasingFunction) -> Self {
|
fn from(value: EasingFunction) -> Self {
|
||||||
Component::Easing(value)
|
Component::Easing(value)
|
||||||
|
|
@ -1491,20 +1490,3 @@ impl RequireInvalidation for EasingFunction {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for EasingFunction {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
match (self, other) {
|
|
||||||
(Self::Fn(l0), Self::Fn(r0)) => l0 == r0,
|
|
||||||
(Self::Custom(l0), Self::Custom(r0)) => Arc::ptr_eq(l0, r0),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs easing for value interpolation.
|
|
||||||
pub trait Easing: Debug + Send + Sync + 'static {
|
|
||||||
/// Eases a value ranging between zero and one. The resulting value does not
|
|
||||||
/// need to be bounded between zero and one.
|
|
||||||
fn ease(&self, progress: ZeroToOne) -> f32;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,342 +0,0 @@
|
||||||
//! Built-in [`Easing`] implementations.
|
|
||||||
|
|
||||||
use std::f32::consts::PI;
|
|
||||||
|
|
||||||
use crate::animation::{Easing, EasingFunction, ZeroToOne};
|
|
||||||
|
|
||||||
/// An [`Easing`] function that produces a steady, linear transition.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct Linear;
|
|
||||||
|
|
||||||
impl Easing for Linear {
|
|
||||||
fn ease(&self, progress: ZeroToOne) -> f32 {
|
|
||||||
*progress
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! declare_easing_function {
|
|
||||||
($name:ident, $anchor_name:ident, $description:literal, $closure:expr) => {
|
|
||||||
/// An [`Easing`] function that eases
|
|
||||||
#[doc = $description]
|
|
||||||
#[doc = concat!(".\n\nSee <https://easings.net/#", stringify!($anchor_name), "> for a visualization and more information.")]
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct $name;
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
/// Eases
|
|
||||||
#[doc = $description]
|
|
||||||
#[doc = concat!(".\n\nSee <https://easings.net/#", stringify!($anchor_name), "> for a visualization and more information.")]
|
|
||||||
#[must_use]
|
|
||||||
pub fn ease(progress: ZeroToOne) -> f32 {
|
|
||||||
let closure = force_closure_type($closure);
|
|
||||||
closure(*progress)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Easing for $name {
|
|
||||||
fn ease(&self, progress: ZeroToOne) -> f32 {
|
|
||||||
Self::ease(progress)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$name> for EasingFunction {
|
|
||||||
fn from(_function: $name) -> Self {
|
|
||||||
Self::Fn($name::ease)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// This prevents the closures from requiring the parameter to be type annotated.
|
|
||||||
fn force_closure_type(f: impl Fn(f32) -> f32) -> impl Fn(f32) -> f32 {
|
|
||||||
f
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutSine,
|
|
||||||
easeOutSine,
|
|
||||||
"out using a sine wave",
|
|
||||||
|percent| (percent * PI).sin() / 2.
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutSine,
|
|
||||||
easeInOutSine,
|
|
||||||
"in and out using a sine wave",
|
|
||||||
|percent| -((percent * PI).cos() - 1.) / 2.
|
|
||||||
);
|
|
||||||
|
|
||||||
fn squared(value: f32) -> f32 {
|
|
||||||
value * value
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInQuadradic,
|
|
||||||
easeInQuad,
|
|
||||||
"in using a quadradic (x^2) curve",
|
|
||||||
squared
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutQuadradic,
|
|
||||||
easeOutQuad,
|
|
||||||
"out using a quadradic (x^2) curve",
|
|
||||||
|percent| 1. - squared(1. - percent)
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutQuadradic,
|
|
||||||
easeInOutQuad,
|
|
||||||
"in and out using a quadradic (x^2) curve",
|
|
||||||
|percent| {
|
|
||||||
if percent < 0.5 {
|
|
||||||
2. * percent * percent
|
|
||||||
} else {
|
|
||||||
1. - squared(-2. * percent + 2.) / 2.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
fn cubed(value: f32) -> f32 {
|
|
||||||
value * value * value
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInCubic,
|
|
||||||
easeInCubic,
|
|
||||||
"in using a cubic (x^3) curve",
|
|
||||||
cubed
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutCubic,
|
|
||||||
easeOutCubic,
|
|
||||||
"out using a cubic (x^3) curve",
|
|
||||||
|percent| 1. - cubed(1. - percent)
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutCubic,
|
|
||||||
easeInOutCubic,
|
|
||||||
"in and out using a cubic (x^3) curve",
|
|
||||||
|percent| {
|
|
||||||
if percent < 0.5 {
|
|
||||||
4. * cubed(percent)
|
|
||||||
} else {
|
|
||||||
1. - cubed(-2. * percent + 2.) / 2.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
fn quarted(value: f32) -> f32 {
|
|
||||||
let sq = squared(value);
|
|
||||||
squared(sq)
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInQuartic,
|
|
||||||
easeInQuart,
|
|
||||||
"in using a quartic (x^4) curve",
|
|
||||||
quarted
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutQuartic,
|
|
||||||
easeOutQuart,
|
|
||||||
"out using a quartic (x^4) curve",
|
|
||||||
|percent| 1. - quarted(1. - percent)
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutQuartic,
|
|
||||||
easeInOutQuart,
|
|
||||||
"in and out using a quartic (x^4) curve",
|
|
||||||
|percent| {
|
|
||||||
if percent < 0.5 {
|
|
||||||
8. * quarted(percent)
|
|
||||||
} else {
|
|
||||||
1. - quarted(-2. * percent + 2.) / 2.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
fn quinted(value: f32) -> f32 {
|
|
||||||
let squared = squared(value);
|
|
||||||
let cubed = squared * value;
|
|
||||||
squared * cubed
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInQuintic,
|
|
||||||
easeInQuint,
|
|
||||||
"in using a quintic (x^5) curve",
|
|
||||||
quinted
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutQuintic,
|
|
||||||
easeOutQuint,
|
|
||||||
"out using a quintic (x^5) curve",
|
|
||||||
|percent| 1. - quinted(1. - percent)
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutQuintic,
|
|
||||||
easeInOutQuint,
|
|
||||||
"in and out using a quintic (x^5) curve",
|
|
||||||
|percent| {
|
|
||||||
if percent < 0.5 {
|
|
||||||
8. * quinted(percent)
|
|
||||||
} else {
|
|
||||||
1. - quinted(-2. * percent + 2.) / 2.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInExponential,
|
|
||||||
easeInExpo,
|
|
||||||
"in using an expenential curve",
|
|
||||||
|percent| { 2f32.powf(10. * percent - 10.) }
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutExponential,
|
|
||||||
easeOutExpo,
|
|
||||||
"out using an expenential curve",
|
|
||||||
|percent| { 1. - 2f32.powf(-10. * percent) }
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutExponential,
|
|
||||||
easeInOutExpo,
|
|
||||||
"in and out using an expenential curve",
|
|
||||||
|percent| if percent < 0.5 {
|
|
||||||
2f32.powf(20. * percent - 10.) / 2.
|
|
||||||
} else {
|
|
||||||
2. - 2f32.powf(-20. * percent + 10.) / 2.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInCircular,
|
|
||||||
easeInCirc,
|
|
||||||
"in using a curve resembling the top-left arc of a circle",
|
|
||||||
|percent| 1. - (1. - squared(percent)).sqrt()
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutCircular,
|
|
||||||
easeOutCirc,
|
|
||||||
"out using a curve resembling the top-left arc of a circle",
|
|
||||||
|percent| (1. - squared(percent - 1.)).sqrt()
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutCircular,
|
|
||||||
easeInOutCirc,
|
|
||||||
"in and out using a curve resembling the top-left arc of a circle",
|
|
||||||
|percent| {
|
|
||||||
if percent < 0.5 {
|
|
||||||
1. - (1. - squared(2. * percent)).sqrt() / 2.
|
|
||||||
} else {
|
|
||||||
(1. - squared(-2. * percent + 2.)).sqrt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const C1: f32 = 1.70158;
|
|
||||||
const C2: f32 = C1 * 1.525;
|
|
||||||
const C3: f32 = C1 + 1.;
|
|
||||||
const C4: f32 = (2. * PI) / 3.;
|
|
||||||
const C5: f32 = (2. * PI) / 4.5;
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInBack,
|
|
||||||
easeInBack,
|
|
||||||
"in using a curve that backs away initially",
|
|
||||||
|percent| {
|
|
||||||
let squared = squared(percent);
|
|
||||||
let cubed = squared + percent;
|
|
||||||
C3 * cubed - C1 * squared
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutBack,
|
|
||||||
easeOutBack,
|
|
||||||
"out using a curve that backs away initially",
|
|
||||||
|percent| {
|
|
||||||
let squared = squared(percent - 1.);
|
|
||||||
let cubed = squared + percent;
|
|
||||||
1. + C3 * cubed - C1 * squared
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutBack,
|
|
||||||
easeInOutBack,
|
|
||||||
"in and out using a curve that backs away initially",
|
|
||||||
|percent| {
|
|
||||||
if percent < 0.5 {
|
|
||||||
(squared(2. * percent) * ((C2 + 1.) * 2. * percent - C2)) / 2.
|
|
||||||
} else {
|
|
||||||
(squared(2. * percent - 2.) * ((C2 + 1.) * (percent * 2. - 2.) + C2) + 2.) / 2.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInElastic,
|
|
||||||
easeInElastic,
|
|
||||||
"in using a curve that bounces around the start initially then quickly accelerates",
|
|
||||||
|percent| { -(2f32.powf(10. * percent - 10.) * (percent * 10. - 10.75).sin() * C4) }
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutElastic,
|
|
||||||
easeOutElastic,
|
|
||||||
"out using a curve that bounces around the start initially then quickly accelerates",
|
|
||||||
|percent| { 2f32.powf(-10. * percent) * (percent * 10. - 0.75).sin() * C4 + 1. }
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInOutElastic,
|
|
||||||
easeInOutElastic,
|
|
||||||
"in and out using a curve that bounces around the start initially then quickly accelerates",
|
|
||||||
|percent| if percent < 0.5 {
|
|
||||||
-(2f32.powf(-20. * percent - 10.) * (percent * 20. - 11.125).sin() * C5 / 2.)
|
|
||||||
} else {
|
|
||||||
2f32.powf(-20. * percent + 10.) * (percent * 20. - 11.125).sin() * C5 / 2. + 1.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseInBounce,
|
|
||||||
easeInBounce,
|
|
||||||
"in using a curve that bounces progressively closer as it progresses",
|
|
||||||
|percent| 1. - EaseOutBounce.ease(ZeroToOne(percent))
|
|
||||||
);
|
|
||||||
|
|
||||||
declare_easing_function!(
|
|
||||||
EaseOutBounce,
|
|
||||||
easeOutBounce,
|
|
||||||
"out using a curve that bounces progressively closer as it progresses",
|
|
||||||
|percent| {
|
|
||||||
const N1: f32 = 7.5625;
|
|
||||||
const D1: f32 = 2.75;
|
|
||||||
|
|
||||||
if percent < 1. / D1 {
|
|
||||||
N1 * percent * percent
|
|
||||||
} else if percent < 2. / D1 {
|
|
||||||
let percent = percent - 1.5;
|
|
||||||
N1 * (percent / D1) * percent + 0.75
|
|
||||||
} else if percent < 2.5 / D1 {
|
|
||||||
let percent = percent - 2.25;
|
|
||||||
N1 * (percent / D1) * percent + 0.9375
|
|
||||||
} else {
|
|
||||||
let percent = percent - 2.625;
|
|
||||||
N1 * (percent / D1) * percent + 0.984_375
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
#![doc = include_str!("../.crate-docs.md")]
|
#![doc = include_str!("../.crate-docs.md")]
|
||||||
#![warn(clippy::pedantic, missing_docs)]
|
#![warn(clippy::pedantic, missing_docs)]
|
||||||
#![allow(clippy::module_name_repetitions, clippy::missing_errors_doc)]
|
#![allow(
|
||||||
|
clippy::module_name_repetitions,
|
||||||
|
clippy::missing_errors_doc,
|
||||||
|
clippy::doc_lazy_continuation
|
||||||
|
)]
|
||||||
|
|
||||||
// for proc-macros
|
// for proc-macros
|
||||||
extern crate self as cushy;
|
extern crate self as cushy;
|
||||||
|
|
|
||||||
|
|
@ -432,9 +432,9 @@ pub trait Destination<T> {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// - [`ReplaceError::NoChange`]: Returned when `new_value` is equal to the
|
/// - [`ReplaceError::NoChange`]: Returned when `new_value` is equal to the
|
||||||
/// currently stored value.
|
/// currently stored value.
|
||||||
/// - [`ReplaceError::Deadlock`]: Returned when the current thread already
|
/// - [`ReplaceError::Deadlock`]: Returned when the current thread already
|
||||||
/// has exclusive access to the contents of this dynamic.
|
/// has exclusive access to the contents of this dynamic.
|
||||||
fn try_replace(&self, new_value: T) -> Result<T, ReplaceError<T>>
|
fn try_replace(&self, new_value: T) -> Result<T, ReplaceError<T>>
|
||||||
where
|
where
|
||||||
T: PartialEq,
|
T: PartialEq,
|
||||||
|
|
|
||||||
|
|
@ -1129,6 +1129,15 @@ pub trait MakeWidget: Sized {
|
||||||
children
|
children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Chains `self` and `others` into a [`WidgetList`].
|
||||||
|
fn chain<W: MakeWidget>(self, others: impl IntoIterator<Item = W>) -> WidgetList {
|
||||||
|
let others = others.into_iter();
|
||||||
|
let mut widgets = WidgetList::with_capacity(others.size_hint().0 + 1);
|
||||||
|
widgets.push(self);
|
||||||
|
widgets.extend(others);
|
||||||
|
widgets
|
||||||
|
}
|
||||||
|
|
||||||
/// Expands `self` to grow to fill its parent.
|
/// Expands `self` to grow to fill its parent.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn expand(self) -> Expand {
|
fn expand(self) -> Expand {
|
||||||
|
|
@ -1616,7 +1625,7 @@ pub struct Callback<T = (), R = ()>(Box<dyn CallbackFunction<T, R>>);
|
||||||
impl<T, R> Debug for Callback<T, R> {
|
impl<T, R> Debug for Callback<T, R> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_tuple("Callback")
|
f.debug_tuple("Callback")
|
||||||
.field(&(self as *const Self))
|
.field(&std::ptr::from_ref::<Self>(self))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1666,7 +1675,7 @@ pub struct OnceCallback<T = (), R = ()>(Box<dyn OnceCallbackFunction<T, R>>);
|
||||||
impl<T, R> Debug for OnceCallback<T, R> {
|
impl<T, R> Debug for OnceCallback<T, R> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_tuple("OnceCallback")
|
f.debug_tuple("OnceCallback")
|
||||||
.field(&(self as *const Self))
|
.field(&std::ptr::from_ref::<Self>(self))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1995,6 +2004,16 @@ impl WidgetList {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Chains `self` and `others` into a [`WidgetList`].
|
||||||
|
pub fn chain<T, Iter>(mut self, iter: Iter) -> Self
|
||||||
|
where
|
||||||
|
Iter: IntoIterator<Item = T>,
|
||||||
|
T: MakeWidget,
|
||||||
|
{
|
||||||
|
self.extend(iter);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the number of widgets in this list.
|
/// Returns the number of widgets in this list.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,7 @@ impl<W> RunningWindow<W>
|
||||||
where
|
where
|
||||||
W: PlatformWindowImplementation,
|
W: PlatformWindowImplementation,
|
||||||
{
|
{
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
window: W,
|
window: W,
|
||||||
kludgine_id: KludgineId,
|
kludgine_id: KludgineId,
|
||||||
|
|
@ -1253,12 +1254,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare<W>(&mut self, window: W, graphics: &mut kludgine::Graphics<'_>)
|
fn new_frame(&mut self, graphics: &mut kludgine::Graphics<'_>) {
|
||||||
where
|
|
||||||
W: PlatformWindowImplementation,
|
|
||||||
{
|
|
||||||
let cushy = self.cushy.clone();
|
|
||||||
let _guard = cushy.enter_runtime();
|
|
||||||
if let Some(theme) = &mut self.theme {
|
if let Some(theme) = &mut self.theme {
|
||||||
if theme.has_updated() {
|
if theme.has_updated() {
|
||||||
self.current_theme = theme.get();
|
self.current_theme = theme.get();
|
||||||
|
|
@ -1278,6 +1274,16 @@ where
|
||||||
.new_frame(self.redraw_status.invalidations().drain());
|
.new_frame(self.redraw_status.invalidations().drain());
|
||||||
|
|
||||||
drop(zoom);
|
drop(zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare<W>(&mut self, window: W, graphics: &mut kludgine::Graphics<'_>)
|
||||||
|
where
|
||||||
|
W: PlatformWindowImplementation,
|
||||||
|
{
|
||||||
|
let cushy = self.cushy.clone();
|
||||||
|
let _guard = cushy.enter_runtime();
|
||||||
|
|
||||||
|
self.new_frame(graphics);
|
||||||
|
|
||||||
let resizable = window.is_resizable() || self.resize_to_fit;
|
let resizable = window.is_resizable() || self.resize_to_fit;
|
||||||
let mut window = RunningWindow::new(
|
let mut window = RunningWindow::new(
|
||||||
|
|
@ -2478,7 +2484,7 @@ impl VirtualState {
|
||||||
|
|
||||||
/// Window state that is able to be updated outside of event handling,
|
/// Window state that is able to be updated outside of event handling,
|
||||||
/// potentially via other threads depending on the application.
|
/// potentially via other threads depending on the application.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct WindowDynamicState {
|
pub struct WindowDynamicState {
|
||||||
/// The target of the next frame to draw.
|
/// The target of the next frame to draw.
|
||||||
pub redraw_target: Dynamic<RedrawTarget>,
|
pub redraw_target: Dynamic<RedrawTarget>,
|
||||||
|
|
@ -2490,16 +2496,6 @@ pub struct WindowDynamicState {
|
||||||
pub title: Dynamic<String>,
|
pub title: Dynamic<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WindowDynamicState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
redraw_target: Default::default(),
|
|
||||||
close_requested: Default::default(),
|
|
||||||
title: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A target for the next redraw of a window.
|
/// A target for the next redraw of a window.
|
||||||
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum RedrawTarget {
|
pub enum RedrawTarget {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue