First pass on ruin_app, raw expanded example
This commit is contained in:
192
lib/ruin_app/example/00_bootstrap_and_counter_raw.rs
Normal file
192
lib/ruin_app/example/00_bootstrap_and_counter_raw.rs
Normal file
@@ -0,0 +1,192 @@
|
||||
use ruin_app::{Component, prelude::*};
|
||||
|
||||
// This is the aspirational author-facing source we eventually want to support:
|
||||
//
|
||||
// ```ignore
|
||||
// #[ruin_runtime::async_main]
|
||||
// async fn main() -> ruin::Result<()> {
|
||||
// App::new()
|
||||
// .window(Window::new().title("RUIN Counter").size(960.0, 640.0))
|
||||
// .app_id("dev.ruin.counter")
|
||||
// .mount(view! { CounterApp {} })
|
||||
// #[component]
|
||||
// fn CounterApp() -> impl View {
|
||||
// let count = use_signal(|| 0);
|
||||
// let doubled = use_memo(move || count.get() * 2);
|
||||
//
|
||||
// use_window_title(move || format!("RUIN Counter ({})", count.get()));
|
||||
//
|
||||
// view! {
|
||||
// column(gap = 16, padding = 24) {
|
||||
// text(role = TextRole::Heading(1), size = 32, weight = FontWeight::Semibold) {
|
||||
// "RUIN counter"
|
||||
// }
|
||||
//
|
||||
// row(gap = 8) {
|
||||
// button(on_press = move |_| count.update(|value| *value -= 1)) { "-1" }
|
||||
// button(on_press = move |_| count.set(0)) { "Reset" }
|
||||
// button(on_press = move |_| count.update(|value| *value += 1)) { "+1" }
|
||||
// }
|
||||
//
|
||||
// block(padding = 16, gap = 8, background = surfaces::raised()) {
|
||||
// text(size = 18) { "count = "; count }
|
||||
// text(color = colors::muted()) { "double = "; doubled }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The hand-written code below is the kind of lower-level shape the proc macro should expand to.
|
||||
|
||||
#[ruin_runtime::async_main]
|
||||
async fn main() -> ruin_app::Result<()> {
|
||||
App::new()
|
||||
.window(
|
||||
Window::new()
|
||||
.title("RUIN Counter")
|
||||
.app_id("dev.ruin.counter")
|
||||
.size(960.0, 640.0),
|
||||
)
|
||||
.mount(CounterApp::builder().children(()))
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
struct CounterApp {
|
||||
count: Cell<i32>,
|
||||
doubled: Memo<i32>,
|
||||
}
|
||||
|
||||
const DECREMENT_BUTTON_ID: ElementId = ElementId::new(1);
|
||||
const RESET_BUTTON_ID: ElementId = ElementId::new(2);
|
||||
const INCREMENT_BUTTON_ID: ElementId = ElementId::new(3);
|
||||
|
||||
struct __CounterAppBuilder;
|
||||
|
||||
impl __CounterAppBuilder {
|
||||
fn children(self, _children: ()) -> CounterApp {
|
||||
CounterApp::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for CounterApp {
|
||||
type Builder = __CounterAppBuilder;
|
||||
|
||||
fn builder() -> Self::Builder {
|
||||
__CounterAppBuilder
|
||||
}
|
||||
}
|
||||
|
||||
impl CounterApp {
|
||||
fn new() -> Self {
|
||||
let count = cell(0_i32);
|
||||
let doubled = memo({
|
||||
let count = count.clone();
|
||||
move || count.get() * 2
|
||||
});
|
||||
Self { count, doubled }
|
||||
}
|
||||
|
||||
fn button(&self, label: &str, id: ElementId, fill: Color) -> Element {
|
||||
Element::column()
|
||||
.padding(Edges::symmetric(14.0, 10.0))
|
||||
.background(fill)
|
||||
.corner_radius(10.0)
|
||||
.cursor(CursorIcon::Pointer)
|
||||
.focusable(true)
|
||||
.id(id)
|
||||
.child(
|
||||
Element::text(label, body_text())
|
||||
.pointer_events(false)
|
||||
.focusable(false),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RootComponent for CounterApp {
|
||||
fn build(&self, cx: &BuildCx) -> View {
|
||||
let count = self.count.get();
|
||||
let doubled = self.doubled.get();
|
||||
|
||||
Element::column()
|
||||
.width(cx.viewport.width)
|
||||
.height(cx.viewport.height)
|
||||
.padding(Edges::all(24.0))
|
||||
.gap(16.0)
|
||||
.background(Color::rgb(0x0F, 0x16, 0x25))
|
||||
.child(
|
||||
Element::text("RUIN counter", title_text())
|
||||
.pointer_events(false)
|
||||
.focusable(false),
|
||||
)
|
||||
.child(
|
||||
Element::paragraph(
|
||||
"This is the raw, hand-written shape a future proc macro should lower the \
|
||||
ergonomic counter component into.",
|
||||
body_text().with_wrap(TextWrap::Word),
|
||||
)
|
||||
.pointer_events(false)
|
||||
.focusable(false),
|
||||
)
|
||||
.child(
|
||||
Element::row()
|
||||
.gap(8.0)
|
||||
.child(self.button("-1", DECREMENT_BUTTON_ID, Color::rgb(0x2B, 0x3A, 0x67)))
|
||||
.child(self.button("Reset", RESET_BUTTON_ID, Color::rgb(0x3D, 0x4B, 0x72)))
|
||||
.child(self.button("+1", INCREMENT_BUTTON_ID, Color::rgb(0x2B, 0x3A, 0x67))),
|
||||
)
|
||||
.child(
|
||||
Element::column()
|
||||
.padding(Edges::all(16.0))
|
||||
.gap(8.0)
|
||||
.background(Color::rgb(0x1B, 0x26, 0x3D))
|
||||
.corner_radius(12.0)
|
||||
.child(
|
||||
Element::text(format!("count = {count}"), body_text())
|
||||
.pointer_events(false)
|
||||
.focusable(false),
|
||||
)
|
||||
.child(
|
||||
Element::text(
|
||||
format!("double = {doubled}"),
|
||||
body_text().with_font_family(TextFontFamily::Monospace),
|
||||
)
|
||||
.pointer_events(false)
|
||||
.focusable(false),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn handle_pointer(&self, event: &ruin_ui::RoutedPointerEvent) {
|
||||
if !matches!(
|
||||
event.kind,
|
||||
ruin_ui::RoutedPointerEventKind::Up {
|
||||
button: PointerButton::Primary
|
||||
}
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
match event.target.element_id {
|
||||
Some(DECREMENT_BUTTON_ID) => {
|
||||
self.count.update(|value| *value -= 1);
|
||||
}
|
||||
Some(RESET_BUTTON_ID) => {
|
||||
let _ = self.count.set(0);
|
||||
}
|
||||
Some(INCREMENT_BUTTON_ID) => {
|
||||
self.count.update(|value| *value += 1);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn title_text() -> TextStyle {
|
||||
TextStyle::new(32.0, Color::rgb(0xFF, 0xFF, 0xFF))
|
||||
}
|
||||
|
||||
fn body_text() -> TextStyle {
|
||||
TextStyle::new(18.0, Color::rgb(0xDF, 0xE8, 0xF6)).with_line_height(24.0)
|
||||
}
|
||||
Reference in New Issue
Block a user