use raui_app::app::declarative::DeclarativeApp;
use raui_core::{
animator::{AnimatedValue, Animation, AnimationMessage},
make_widget, pre_hooks,
view_model::{ViewModel, ViewModelValue},
widget::{
component::text_box::{TextBoxProps, text_box},
context::WidgetContext,
node::WidgetNode,
unit::text::TextBoxFont,
utils::Color,
},
};
const TICK: &str = "tick";
const DATA: &str = "data";
const COUNTER: &str = "counter";
struct AppData {
counter: ViewModelValue<usize>,
}
fn use_app(ctx: &mut WidgetContext) {
ctx.life_cycle.mount(|mut ctx| {
let mut view_model = ViewModel::produce(|properties| AppData {
counter: ViewModelValue::new(0, properties.notifier(COUNTER)),
});
view_model
.properties
.bindings(COUNTER)
.unwrap()
.bind(ctx.id.to_owned());
ctx.view_models.widget_register(DATA, view_model);
let _ = ctx.animator.change(
TICK,
Some(Animation::Looped(Box::new(Animation::Sequence(vec![
Animation::Value(AnimatedValue {
duration: 1.0,
..Default::default()
}),
Animation::Message(TICK.to_owned()),
])))),
);
});
ctx.life_cycle.change(|mut ctx| {
let mut app_data = ctx
.view_models
.widget_view_model_mut(DATA)
.unwrap()
.write::<AppData>()
.unwrap();
for msg in ctx.messenger.messages {
if let Some(msg) = msg.as_any().downcast_ref::<AnimationMessage>()
&& msg.0 == TICK
{
*app_data.counter += 1;
}
}
});
}
#[pre_hooks(use_app)]
fn app(mut ctx: WidgetContext) -> WidgetNode {
let counter = ctx
.view_models
.widget_view_model(DATA)
.and_then(|view_model| view_model.read::<AppData>().map(|data| *data.counter))
.unwrap_or_default();
make_widget!(text_box)
.with_props(TextBoxProps {
text: format!("Counter: {counter}"),
font: TextBoxFont {
name: "./demos/hello-world/resources/verdana.ttf".to_owned(),
size: 48.0,
},
color: Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
},
..Default::default()
})
.into()
}
fn main() {
DeclarativeApp::simple("View-Model - Widget", make_widget!(app));
}