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 provider #618

Merged
merged 8 commits into from
Aug 20, 2024
59 changes: 57 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,64 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

## [@Unreleased] - @ReleaseDate

### Features

- **core**: Support for modifying the theme at runtime. (#618 @M-Adoo)
<img src="./static/theme-switch.gif" style="transform:scale(0.5);"/>

The code:

```rust
use ribir::prelude::*;

let w = fn_widget! {
@Text {
on_tap: |e| {
// Query the `Palette` of the application theme.
let mut p = Palette::write_of(e);
if p.brightness == Brightness::Light {
p.brightness = Brightness::Dark;
} else {
p.brightness = Brightness::Light;
}
},
text : "Click me!"
}
};

App::run(w);
```

- **core**: Added `Provider` widget to share data between sub-tree. (#618 @M-Adoo)
```rust
Provider::new(Box::new(State::value(0i32))).with_child(fn_widget! {
@SizedBox {
size: Size::new(1.,1.),
on_tap: |e| {
// Access the provider in a callback.
let mut v = Provider::write_of::<i32>(e).unwrap();
*v += 1;
},
@Text {
text: {
// Access the provider in any descendants
let v = Provider::of::<Stateful<i32>>(ctx!());
let v = v.unwrap().clone_writer();
pipe!($v.to_string())
}
}
}
});
```

- **core**: Added `Overlay::of` to allow querying the overlay in event callbacks. (#618 @M-Adoo)
- **core**: Added `WidgetCtx::query`, `WidgetCtx::query_write`, `WidgetCtx::query_of_widget` and `WidgetCtx::query_write_of_widget`. (#618 @M-Adoo)

### Breaking

- **core**: Removed `Overlay::new_with_handle` and `OverlayCloseHandle`. (#618 @M-Adoo)
- **core**: `GenWidget::gen_widget` no longer requires a `&mut BuildCtx` parameter. (#616 @M-Adoo)
- **core**: Removed `FullTheme` and `InheritTheme`, now only using `Theme`. Any part of the theme, such as `Palette`, can be directly used to overwrite its corresponding theme component. (#618 @M-Adoo)

## [0.4.0-alpha.5] - 2024-08-14

Expand Down Expand Up @@ -62,10 +117,10 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he

### Breaking

- Removed `WidgetCtx::query_widget_type` and `WidgetCtx::query_type` (#618 @M-Adoo)
- Removed `ChildFrom` and `FromAnother` traits (#612 @M-Adoo)
- Removed `SingleParent` and `MultiParent` traits. (#612 @M-Adoo)
- Removed `PairChild` and `PairWithChild` traits. User can use a generic type instead. (#612 @M-Adoo)
- Allow only the child to be converted to a widget or a type that implements the Into trait. (#612 @M-Adoo)
- Removed the all builder traits such as WidgetBuilder and ComposeBuilder and so on. (#612 @M-Adoo)
- All implicit child conversions have been removed, except for conversions to Widget. (#612 @M-Adoo)

Expand Down Expand Up @@ -94,7 +149,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he
...
}
}
```
```

### Changed

Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn main() {
use ribir::prelude::*;

fn main() {
let counter = |ctx: &BuildCtx| {
let counter = |ctx: &mut BuildCtx| {
let cnt = Stateful::new(0);

let c_cnt = cnt.clone_writer();
Expand Down Expand Up @@ -106,8 +106,7 @@ More [Examples]
- **Non-intrusive state** converts your data to a listenable state and updates the view according to the change of the state.
- **Layout system** learning and inspired by [Flutter] Sublinear layout, but not the same.
- **Event system** is a composition event system, that supports event bubbling and capture. Allow to compose with any widget, and exists only if you use it.
- **Theme system** supports full and inherit/partial themes, so you can use it to override or dynamically switch the theme of the subtree. Include palette, icons, animate transitions, the decoration widget of the widget, etc. In a very rough state and the API will be redesigned soon.
- **Animations** based on the state but no side effect, it's almost stable in concept, but not many predefined animations yet.
- **Theme System**: Supports using different themes for various parts of the sub-tree and enables theme modifications at runtime.
- **Painter** converts the view to 2D paths.
- **GPU render** is a backend of the **Painter**, do path tessellation so that you can easily render the triangles in any GPU render engine. A [wgpu] implementation is provided as the default GPU render engine. Tessellation base on [lyon].
- **Text** support basic text typography and IME input, in a usable but rough stage.
Expand Down
11 changes: 6 additions & 5 deletions core/src/animation/stagger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ mod tests {
use super::*;
use crate::{reset_test_env, test_helper::*};

fn stagger_run_and_stop() -> Widget<'static> {
widget_layout_test!(
stagger_run_and_stop,
fn_widget! {
let stagger = Stagger::new(Duration::from_millis(100), transitions::EASE_IN.of(ctx!()));
let mut mock_box = @MockBox { size: Size::new(100., 100.) };
Expand All @@ -252,10 +253,10 @@ mod tests {
assert!(!stagger.is_running());

mock_box
}
.into_widget()
}
widget_layout_test!(stagger_run_and_stop, width == 100., height == 100.,);
},
width == 100.,
height == 100.,
);

#[test]
fn stagger_not_running_after_all_animation_end() {
Expand Down
28 changes: 13 additions & 15 deletions core/src/builtin_widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
//! declare syntax, so other objects can use the builtin fields and methods like
//! self fields and methods.

pub mod key;
use std::cell::Cell;

pub mod key;
pub use key::{Key, KeyWidget};
pub mod image_widget;
pub mod keep_alive;
Expand Down Expand Up @@ -64,10 +64,12 @@ mod mix_builtin;
pub use mix_builtin::*;
pub mod container;
pub use container::*;
mod provider;
pub use provider::*;

use crate::prelude::*;

#[derive(Clone)]
#[derive(Clone, Default)]
/// LazyWidgetId is a widget id that will be valid after widget build.
pub struct LazyWidgetId(Sc<Cell<Option<WidgetId>>>);

Expand Down Expand Up @@ -136,14 +138,10 @@ impl LazyWidgetId {
/// Bind a widget to the LazyWidgetId, and return a widget that will set the
/// id to the LazyWidgetId after build.
pub fn bind(self, widget: Widget) -> Widget {
let f = move |ctx: &BuildCtx| {
let id = widget.build(ctx);
widget.on_build(move |id, _| {
assert!(self.id().is_none(), "The LazyWidgetID only allows binding to one widget.");
self.0.set(Some(id));
id
};

InnerWidget::LazyBuild(Box::new(f)).into()
})
}

pub fn id(&self) -> Option<WidgetId> { self.0.get() }
Expand All @@ -157,10 +155,6 @@ impl LazyWidgetId {
fn ref_count(&self) -> usize { self.0.ref_count() }
}

impl Default for LazyWidgetId {
fn default() -> Self { Self(Sc::new(Cell::new(None))) }
}

impl<T> FatObj<T> {
/// Create a new `FatObj` with the given host object.
pub fn new(host: T) -> Self {
Expand Down Expand Up @@ -849,7 +843,7 @@ impl<T> FatObj<T> {
) -> Self {
let builtin = get_builtin(&mut self);
let (v, o) = init.declare_into().unzip();
set_value(&mut *builtin.write(), v);
set_value(&mut *builtin.silent(), v);
if let Some(o) = o {
let c_builtin = builtin.clone_writer();
let u = o.subscribe(move |(_, v)| {
Expand Down Expand Up @@ -878,7 +872,9 @@ where
impl<'a> FatObj<Widget<'a>> {
fn compose(self) -> Widget<'a> {
let mut host = self.host;
host = self.host_id.clone().bind(host);
if self.host_id.0.ref_count() > 1 {
host = self.host_id.clone().bind(host);
}
if let Some(mix_builtin) = self.mix_builtin {
host = mix_builtin.with_child(host).into_widget()
}
Expand Down Expand Up @@ -942,7 +938,9 @@ impl<'a> FatObj<Widget<'a>> {
if let Some(h) = self.keep_alive_unsubscribe_handle {
host = host.attach_anonymous_data(h);
}
let host = self.id.clone().bind(host);
if self.id.0.ref_count() > 1 {
host = self.id.clone().bind(host);
}
host
}
}
Expand Down
23 changes: 13 additions & 10 deletions core/src/builtin_widgets/align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,82 +168,85 @@ mod tests {
const CHILD_SIZE: Size = Size::new(10., 10.);
const WND_SIZE: Size = Size::new(100., 100.);

fn h_align(h_align: HAlign) -> impl IntoWidget<'static, FN> {
fn h_align(h_align: HAlign) -> GenWidget {
fn_widget! {
@HAlignWidget {
h_align,
@MockBox { size: CHILD_SIZE }
}
}
.into()
}
fn left_align() -> impl IntoWidget<'static, FN> { h_align(HAlign::Left) }

widget_layout_test!(
left_align,
h_align(HAlign::Left),
wnd_size = WND_SIZE,
{ path = [0], width == 100., height == 10.,}
{ path = [0, 0], size == CHILD_SIZE, }
);

fn h_center_align() -> impl IntoWidget<'static, FN> { h_align(HAlign::Center) }
widget_layout_test!(
h_center_align,
h_align(HAlign::Center),
wnd_size = WND_SIZE,
{ path = [0], width == 100., height == 10.,}
{ path = [0, 0], x == 45., size == CHILD_SIZE,}
);

fn right_align() -> impl IntoWidget<'static, FN> { h_align(HAlign::Right) }
widget_layout_test!(
right_align,
h_align(HAlign::Right),
wnd_size = WND_SIZE,
{ path = [0], width == 100., height == 10.,}
{ path = [0, 0], x == 90., size == CHILD_SIZE,}
);

fn h_stretch_algin() -> impl IntoWidget<'static, FN> { h_align(HAlign::Stretch) }
widget_layout_test!(
h_stretch_algin,
h_align(HAlign::Stretch),
wnd_size = WND_SIZE,
{ path = [0], width == 100., height == 10.,}
{ path = [0, 0], x == 0., width == 100., height == 10.,}
);

fn v_align(v_align: VAlign) -> impl IntoWidget<'static, FN> {
fn v_align(v_align: VAlign) -> GenWidget {
fn_widget! {
@VAlignWidget {
v_align,
@MockBox { size: CHILD_SIZE }
}
}
.into()
}

fn top_align() -> impl IntoWidget<'static, FN> { v_align(VAlign::Top) }
widget_layout_test!(
top_align,
v_align(VAlign::Top),
wnd_size = WND_SIZE,
{ path = [0], width == 10., height == 100.,}
{ path = [0, 0], size == CHILD_SIZE,}
);

fn v_center_align() -> impl IntoWidget<'static, FN> { v_align(VAlign::Center) }
widget_layout_test!(
v_center_align,
v_align(VAlign::Center),
wnd_size = WND_SIZE,
{ path = [0], width == 10., height == 100.,}
{ path = [0, 0], y == 45., size == CHILD_SIZE,}
);

fn bottom_align() -> impl IntoWidget<'static, FN> { v_align(VAlign::Bottom) }
widget_layout_test!(
bottom_align,
v_align(VAlign::Bottom),
wnd_size = WND_SIZE,
{ path = [0], width == 10., height == 100.,}
{ path = [0, 0], y == 90., size == CHILD_SIZE,}
);

fn v_stretch_align() -> impl IntoWidget<'static, FN> { v_align(VAlign::Stretch) }
widget_layout_test!(
v_stretch_align,
v_align(VAlign::Stretch),
wnd_size = WND_SIZE,
{ path = [0], width == 10., height == 100.,}
{ path = [0, 0], width == 10., height == 100.,}
Expand Down
32 changes: 12 additions & 20 deletions core/src/builtin_widgets/anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,61 +205,53 @@ mod test {
const CHILD_SIZE: Size = Size::new(50., 50.);
const WND_SIZE: Size = Size::new(100., 100.);

fn pixel_left_top() -> impl IntoWidget<'static, FN> {
widget_layout_test!(
pixel_left_top,
fn_widget! {
@MockBox {
size: CHILD_SIZE,
anchor: Anchor::left_top(1., 1.),
}
}
}
widget_layout_test!(
pixel_left_top,
},
wnd_size = WND_SIZE,
{ path = [0, 0], y == 1., }
{ path = [0, 0], x == 1., }
);

fn pixel_left_bottom() -> impl IntoWidget<'static, FN> {
widget_layout_test!(
pixel_left_bottom,
fn_widget! {
@MockBox {
size: CHILD_SIZE,
anchor: Anchor::left_bottom(1., 1.),
}
}
}
widget_layout_test!(
pixel_left_bottom,
},
wnd_size = WND_SIZE,
{ path = [0, 0], y == 49.,}
{ path = [0, 0], x == 1., }
);

fn pixel_top_right() -> impl IntoWidget<'static, FN> {
widget_layout_test!(
pixel_top_right,
fn_widget! {
@MockBox {
size: CHILD_SIZE,
anchor: Anchor::right_top(1., 1.),
}
}
}
widget_layout_test!(
pixel_top_right,
},
wnd_size = WND_SIZE,
{ path = [0, 0], y == 1.,}
{ path = [0, 0], x == 49.,}
);

fn pixel_bottom_right() -> impl IntoWidget<'static, FN> {
widget_layout_test!(
pixel_bottom_right,
fn_widget! {
@MockBox {
size: CHILD_SIZE,
anchor: Anchor::right_bottom(1., 1.)
}
}
}
widget_layout_test!(
pixel_bottom_right,
},
wnd_size = WND_SIZE,
{ path = [0, 0], y == 49.,}
{ path = [0, 0], x == 49.,}
Expand Down
Loading
Loading