#[cfg(declarative_view)]
fn main() {
use rust_widgets::core::{ObjectId, Rect, Size};
use rust_widgets::view::{Breakpoint, Node, Patch, View, ViewEngine};
use rust_widgets::widget::capability::CapabilityValue;
use rust_widgets::widget::{runtime, Widget, WidgetFactory};
struct App {
page: &'static str,
items: Vec<&'static str>,
}
impl View for App {
fn build(&self) -> Node {
Node::new("group_box")
.key("root")
.breakpoint(
Breakpoint::Compact,
Node::new("label")
.key("phone_bar")
.prop("text", CapabilityValue::String(String::from("Phone bar"))),
)
.breakpoint(
Breakpoint::Medium,
Node::new("label")
.key("rail")
.prop("text", CapabilityValue::String(String::from("Rail"))),
)
.breakpoint(
Breakpoint::Expanded,
Node::new("label")
.key("sidebar")
.prop("text", CapabilityValue::String(String::from("Sidebar"))),
)
.child(
Node::new("label")
.key("content")
.prop("text", CapabilityValue::String(self.page.to_string())),
)
.children_of(self.items.iter().map(|item| {
Node::new("label")
.key(*item)
.prop("text", CapabilityValue::String((*item).to_string()))
}))
}
}
fn creator(factory: &WidgetFactory) -> impl Fn(&Node) -> Option<ObjectId> + '_ {
move |node: &Node| {
let widget: Box<dyn Widget> = factory.create(
&node.widget,
Rect::new(0, 0, 200, 28),
node.key_str().unwrap_or("anon"),
)?;
runtime::register(widget)
}
}
fn child_keys(engine: &ViewEngine) -> Vec<String> {
engine
.current()
.map(|root| {
root.children
.iter()
.map(|child| child.key.clone().unwrap_or_else(|| String::from("<none>")))
.collect()
})
.unwrap_or_default()
}
fn describe(patches: &[Patch]) -> String {
if patches.is_empty() {
return String::from("no patches (the tree did not change)");
}
let names: Vec<String> = patches
.iter()
.map(|patch| match patch {
Patch::SetProperty { name, .. } => format!("SetProperty({name})"),
Patch::Remove { .. } => String::from("Remove"),
Patch::Insert { .. } => String::from("Insert"),
Patch::Move { .. } => String::from("Move"),
Patch::Replace { .. } => String::from("Replace"),
})
.collect();
format!("{} patch(es): {}", patches.len(), names.join(", "))
}
fn content_id(engine: &ViewEngine) -> Option<ObjectId> {
engine.layout().child_by_key(engine.layout().root(), "content")
}
let factory = WidgetFactory::new_with_defaults();
let mut engine = ViewEngine::new();
let state = App { page: "Dashboard", items: vec!["alpha", "beta"] };
println!("=== one view, three viewports ===");
println!(
" Breakpoint::Compact = width <= {}",
rust_widgets::widget::metrics::dimensions::BREAKPOINT_COMPACT_MAX
);
println!(
" Breakpoint::Medium = width <= {}",
rust_widgets::widget::metrics::dimensions::BREAKPOINT_MEDIUM_MAX
);
println!();
engine.set_viewport(Size::new(360, 800));
let mounted = engine.mount(&state, &creator(&factory));
println!(
"360x800 (Compact) : descriptor={:?} {} control(s) created, children={:?}",
engine.viewport().map(Breakpoint::of),
mounted.widgets_created,
child_keys(&engine)
);
let content_on_phone = content_id(&engine);
engine.set_viewport(Size::new(700, 900));
let report = engine.update(&state, &creator(&factory));
println!(
"700x900 (Medium) : descriptor={:?} {}",
engine.viewport().map(Breakpoint::of),
describe(&report.patches)
);
println!(" children={:?}", child_keys(&engine));
engine.set_viewport(Size::new(1400, 900));
let report = engine.update(&state, &creator(&factory));
println!(
"1400x900 (Expanded): descriptor={:?} {}",
engine.viewport().map(Breakpoint::of),
describe(&report.patches)
);
println!(" children={:?}", child_keys(&engine));
println!();
println!("=== identity across the three tiers ===");
println!(" content id at 360 : {:?}", content_on_phone);
println!(" content id at 1400 : {:?}", content_id(&engine));
println!(
" same control : {} (a scroll offset or caret in it survived the resize)",
content_on_phone == content_id(&engine)
);
println!(
" mounted tree size : {} node(s)",
engine.current().map(Node::node_count).unwrap_or(0)
);
let mut state = state;
state.page = "Reports";
let report = engine.update(&state, &creator(&factory));
println!();
println!("=== a state change at the same viewport ===");
println!(" rename the page : {}", describe(&report.patches));
}
#[cfg(not(declarative_view))]
fn main() {
println!(
"the declarative view layer is not compiled in this profile; \
run with --features desktop (or tablet/mobile) instead"
);
}