Using rust to update text
We will be using rust to modify the contents of a text node at runtime (no hot reloading).
Modify the cob file
Let's setup the cob file as below.
"scene"
AbsoluteNode{left:40%}
"cell"
Animated<BackgroundColor>{
idle:#FF0000 // You can input colours in other formats
hover:Hsla{ hue:120 saturation:1.0 lightness:0.50 alpha:1.0 }
press:Hsla{ hue:240 saturation:1.0 lightness:0.50 alpha:1.0 }
}
NodeShadow{color:#FF0000 spread_radius:10px blur_radius:5px}
"text"
TextLine{text:"Hello, World!, I am writing using cobweb "} // <-- will be overwritten
We split position logic into a child node called cell
which holds most of the positioning and styling logic.
cell
has a child called text
. Text is a minimal node responsible for just text stuff.
Why we split text from styling
This is more of an html/CSS pattern then anything particular with cobweb but it is worth mentioning here.
It just turns out to be easier to position nodes than it is to position text.
Rust
Updating text at runtime
Let's change the rust code to be as below.
fn build_ui(mut c: Commands, mut s: SceneBuilder) {
c.spawn(Camera2d);
c.ui_root()
.spawn_scene(("main.cob", "main_scene"), &mut s, |scene_handle| {
scene_handle
.get("cell::text")
.update_text("My runtime text");
});
}
We have changed spawn_scene_simple
to spawn_scene
.
When we load "main_scene"
from the cob file, we automatically load all the child nodes recursively. The second argument is a closure where we can use scene_handle
, which is similar to commands and has extension methods provided by cobweb.
Inside the closure we call get(cell::text)
which is basically a path syntax to go straight to the text node. It also possible to call edit
on "cell"
then call update_text
inside the resulting closure.
Recompile and run the program. You will see your text has changed to reflect the rust code.
Spawning new nodes
Cobweb can also spawn new scenes inside other scenes. Let's start with an example.
Below we have our new scene called number_text
.
If the concept of scenes was a bit confusing before, this should clarify it a bit more.
#scenes
"scene"
AbsoluteNode{left:40% flex_direction:Column}
"cell"
Animated<BackgroundColor>{
idle:#FF0000 // You can input colours in other formats
hover:Hsla{ hue:120 saturation:1.0 lightness:0.50 alpha:1.0 }
press:Hsla{ hue:240 saturation:1.0 lightness:0.50 alpha:1.0 }
}
NodeShadow{color:#FF0000 spread_radius:10px blur_radius:5px}
"text"
TextLine{text:"Hello, World!, I am writing using cobweb "}
"number_text"
"cell"
"text"
TextLine{text:"placeholder"}
Now let's change our rust code to spawn some scenes.
fn build_ui(mut c: Commands, mut s: SceneBuilder) {
c.spawn(Camera2d);
c.ui_root()
.spawn_scene(("main.cob", "main_scene"), &mut s, |scene_handle| {
scene_handle
.get("cell::text")
.update_text("My runtime text");
// Spawning new ui nodes inside our main scene
for i in (0..=10).into_iter() {
scene_handle.spawn_scene(("main.cob", "number_text"), |scene_handle| {
scene_handle.get("cell::text").update_text(i.to_string());
});
}
});
}
We now have some numbers that appear based on your code. We can still modify the cob files and change styling:
"number_text"
"cell"
"text"
TextLine{text:"placeholder"}
TextLineColor(Hsla{hue:45 saturation:1.0 lightness:0.5 alpha:1.0}) // <-- add this
Making nodes interactive
Setting our UI to react to the user is essential, and easy. Here we add on_pressed
for our "number_text"
node:
fn build_ui(mut c: Commands, mut s: SceneBuilder) {
c.spawn(Camera2d);
c.ui_root()
.spawn_scene(("main.cob", "main_scene"), &mut s, |scene_handle| {
scene_handle
.get("cell::text")
.update_text("My runtime text");
for i in (0..=10).into_iter() {
scene_handle.spawn_scene(("main.cob", "number_text"), |scene_handle| {
scene_handle.edit("cell::text", |scene_handle| {
scene_handle.update_text(i.to_string());
scene_handle.on_pressed(move |/* We can write arbitrary bevy parameters here*/|{
println!("You clicked {}", i);
});
});
});
}
});
}