Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/slider #669

Merged
merged 6 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

## [@Unreleased] - @ReleaseDate

### Features

- **core**: Added `grab_pointer` to grabs all the pointer input. (#669 @wjian23)
- **widgets**: Added the widget of Slider (#669 @wjian23)

### Fixed

- **core**: fix mismatch of providers. (#669 @wjian23)
- **core**: Added DeclarerWithSubscription to let Widget `Expanded` accept pipe value. (#669 @wjian23)

## [0.4.0-alpha.18] - 2024-12-11

### Features
Expand Down
1 change: 1 addition & 0 deletions core/src/animation/keyframes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ impl<S: AnimateStateSetter> KeyFrames<S> {
Self { state, frames: keyframes.into_boxed_slice() }
}

#[allow(clippy::type_complexity)]
/// Converts the `KeyFrames` into a `LerpFnState` that can be used for
/// animations.
pub fn into_lerp_fn_state(
Expand Down
73 changes: 71 additions & 2 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@

pub mod key;
mod painting_style;
use std::ops::DerefMut;

pub use key::{Key, KeyWidget};
pub use painting_style::*;
pub mod image_widget;
pub mod keep_alive;
pub use keep_alive::*;
mod theme;
use smallvec::SmallVec;
pub use theme::*;
mod cursor;
pub use cursor::*;
Expand Down Expand Up @@ -959,13 +962,13 @@ impl<'a> FatObj<Widget<'a>> {
text_style,
scrollable,
layout_box,
mix_builtin,
request_focus,
class,
cursor,
constrained_box,
tooltips,
margin,
mix_builtin,
request_focus,
transform,
opacity,
visibility,
Expand Down Expand Up @@ -999,3 +1002,69 @@ impl<T> std::ops::DerefMut for FatObj<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.host }
}

/// DeclarerWithSubscription, a declarer with subscriptions
///
/// Used to wraps a declarer to make it the widget auto unsubscribe when
/// disposed. Normally you should not use this directly, most Widget types
/// derive with Declare attribute has support builtin widgets has the ability
/// of unsubscribing when disposed.
pub struct DeclarerWithSubscription<T> {
inner: T,
subscribes: SmallVec<[BoxSubscription<'static>; 1]>,
}

impl<T> DeclarerWithSubscription<T> {
pub fn new(host: T, subscribes: SmallVec<[BoxSubscription<'static>; 1]>) -> Self {
Self { inner: host, subscribes }
}
}

impl<T> Deref for DeclarerWithSubscription<T> {
type Target = T;

fn deref(&self) -> &Self::Target { &self.inner }
}

impl<T> DerefMut for DeclarerWithSubscription<T> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
}

impl<T> DeclarerWithSubscription<T> {
fn map<M>(self, f: impl FnOnce(T) -> M) -> DeclarerWithSubscription<M> {
DeclarerWithSubscription { inner: f(self.inner), subscribes: self.subscribes }
}
}

impl<'w, T, const M: usize> IntoWidgetStrict<'w, M> for DeclarerWithSubscription<T>
where
T: IntoWidget<'w, M>,
{
fn into_widget_strict(self) -> Widget<'w> {
let DeclarerWithSubscription { inner: host, subscribes } = self;
let w = host.into_widget();
if subscribes.is_empty() {
w
} else {
fn_widget! {
let w = FatObj::new(w);
@ $w {
on_disposed: move |_| {
subscribes.into_iter().for_each(|u| u.unsubscribe());
}
}
}
.into_widget()
}
}
}

impl<'w, T, C, const N: usize, const M: usize> WithChild<'w, C, N, M>
for DeclarerWithSubscription<T>
where
T: WithChild<'w, C, N, M> + 'w,
C: 'w,
{
type Target = DeclarerWithSubscription<T::Target>;
fn with_child(self, c: C) -> Self::Target { self.map(|w| w.with_child(c)) }
}
2 changes: 1 addition & 1 deletion core/src/builtin_widgets/global_anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub enum GlobalAnchorY {
/// }
/// }
/// }
/// App::run(w);
/// App::run(app);
/// ```
pub struct GlobalAnchor {
/// the horizontal global anchor
Expand Down
50 changes: 44 additions & 6 deletions core/src/builtin_widgets/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,17 @@ impl<'c> ComposeChild<'c> for Provider {
})
.provider;

fn_widget! {
// We push the provider into the build context to ensure that the widget build
// logic can access this provider.
let ctx = BuildCtx::get_mut();
ctx.current_providers.push(provider);
child.into_widget().on_build(|id| {
let provider = ctx.current_providers.pop().unwrap();
id.attach_data(provider, ctx.tree_mut());
})
let ctx = BuildCtx::get_mut();
ctx.current_providers.push(provider);
child.into_widget().on_build(move |id| {
let provider = ctx.current_providers.pop().unwrap();
id.attach_data(provider, ctx.tree_mut());
})
}
.into_widget()
}
}

Expand Down Expand Up @@ -260,6 +263,41 @@ mod tests {
assert_eq!(*value.read(), 1);
}

#[test]
fn with_multi_providers() {
reset_test_env!();

let (value1, w_value1) = split_value(0);
let (value2, w_value2) = split_value(0);
let w = fn_widget! {
let w_value1 = w_value1.clone_writer();
let w_value2 = w_value2.clone_writer();
@MockMulti {
@ {
Provider::new(Box::new(Queryable(1i32))).with_child(fn_widget! {
let v = Provider::of::<i32>(BuildCtx::get()).unwrap();
*$w_value1.write() = *v;
@ Void{}
})
}

@ {
Provider::new(Box::new(Queryable(2i32))).with_child(fn_widget! {
let v = Provider::of::<i32>(BuildCtx::get()).unwrap();
*$w_value2.write() = *v;
@ Void{}
})
}
}
};

let mut wnd = TestWindow::new(w);
wnd.draw_frame();

assert_eq!(*value1.read(), 1);
assert_eq!(*value2.read(), 2);
}

#[test]
fn provider_for_pipe() {
reset_test_env!();
Expand Down
8 changes: 4 additions & 4 deletions core/src/builtin_widgets/tooltips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ class_names! {
/// ```no_run
/// use ribir::prelude::*;
///
/// let w = fn_widget! {
/// @FilledButton{
/// let w = text! {
/// text: "hover to show tooltips!",
/// tooltips: "this is tooltips",
/// }
Expand Down Expand Up @@ -84,9 +83,10 @@ impl<'c> ComposeChild<'c> for Tooltips {

let wnd = BuildCtx::get().window();
let u = watch!($child.is_hover())
.delay(Duration::from_millis(150), AppCtx::scheduler())
.distinct_until_changed()
.subscribe(move |v| {
if v {
.subscribe(move |_| {
if $child.is_hover() {
$this.show(wnd.clone());
} else {
$this.hidden();
Expand Down
1 change: 1 addition & 0 deletions core/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
};

pub(crate) mod dispatcher;
pub use dispatcher::GrabPointer;
mod pointers;
pub use pointers::*;
use ribir_geom::Point;
Expand Down
Loading
Loading