pub struct Region<'s> { /* private fields */ }
Expand description
Something you can put an Attachment
in.
You start with a Region
that occupies the whole screen and captures one input. Then you split
it to get more regions, and split those to get more, until you’ve got your whole layout. You can split a region
with anything that implements Splitter
, including the built-in ones in the “Implementors” section. When a
region gets split, some inputs – notably mouse movements – will only get passed to the regions that they happen
in.
In each region, you can put an Attachment
, which is what tuig-ui
calls UI elements. Attachments serve two
purposes:
- Handle user input in a way that makes sense for that element (e.g. a button returning
true
when it’s clicked) - Render the element to the screen (e.g. a button rendering its text and, when you click it, a fill color)
You can split regions and add attachments in whatever order you like, so e.g. you can change how you display bits depending on the state of user input, and refresh things on the same frame you get input.
Implementations§
source§impl<'s> Region<'s>
impl<'s> Region<'s>
sourcepub fn new(screen: &'s mut Screen, input: Action) -> Self
pub fn new(screen: &'s mut Screen, input: Action) -> Self
Create a new Region
encompassing an entire screen with a single input.
This is most typically called in your wrapper when you have input to handle, to create the root element you attach everything else into.
Examples found in repository?
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
fn run(mut iosys: Box<dyn IoSystem>) {
let mut ti = TextInput::new("> ", 5);
let mut clicks = 0;
let mut tui = |region: Region| {
let [l, m, r] = region.split(cols!(20 "| |" * "#" 11)).unwrap();
let [lt, lb] = l.split(rows!(* "=" 1)).unwrap();
let [rt, rb] = r.split(rows!(1 "=" *)).unwrap();
lt.attach(|i, sv| {
let txt = text![
"Hello! Your most recent ", red "action", " was: ",
bold green "{:?}"(i),
];
Textbox::new(txt).render_to(sv)
});
match lb.attach(&mut ti) {
TextInputResult::Autocomplete { res, .. } => *res = "mlem!".into(),
TextInputResult::Submit(line) => ti.store(line),
_ => (),
}
m.attach(|i, mut sv: ScreenView| sv.fill(char_for_input(&i)));
if rt.attach(Button("click me!").hotkey('4')) {
clicks += 1;
}
rb.attach(Textbox::new(text!("{} clicks"(clicks))));
true
};
let mut screen = Screen::new(iosys.size());
let mut input = Action::Redraw;
loop {
screen.resize(iosys.size());
let root = Region::new(&mut screen, input);
if !tui(root) {
break;
}
iosys.draw(&screen).expect("failed to render output");
input = iosys.input().expect("failed to get input");
if matches!(
input,
Action::Closed | Action::KeyPress { key: Key::Escape }
) {
break;
}
}
iosys.stop();
}
sourcepub fn split<S: Splitter<'s>>(self, splitter: S) -> S::Output
pub fn split<S: Splitter<'s>>(self, splitter: S) -> S::Output
Split the region into one or more children.
The child regions never overlap each other, and never extend beyond the bounds of the parent. If you want to overlap, wait for #61 to be completed.
This consumes the parent and returns the child regions. It doesn’t modify anything in-place. If you don’t use the children, why even bother doing the split?
Examples found in repository?
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
fn run(mut iosys: Box<dyn IoSystem>) {
let mut ti = TextInput::new("> ", 5);
let mut clicks = 0;
let mut tui = |region: Region| {
let [l, m, r] = region.split(cols!(20 "| |" * "#" 11)).unwrap();
let [lt, lb] = l.split(rows!(* "=" 1)).unwrap();
let [rt, rb] = r.split(rows!(1 "=" *)).unwrap();
lt.attach(|i, sv| {
let txt = text![
"Hello! Your most recent ", red "action", " was: ",
bold green "{:?}"(i),
];
Textbox::new(txt).render_to(sv)
});
match lb.attach(&mut ti) {
TextInputResult::Autocomplete { res, .. } => *res = "mlem!".into(),
TextInputResult::Submit(line) => ti.store(line),
_ => (),
}
m.attach(|i, mut sv: ScreenView| sv.fill(char_for_input(&i)));
if rt.attach(Button("click me!").hotkey('4')) {
clicks += 1;
}
rb.attach(Textbox::new(text!("{} clicks"(clicks))));
true
};
let mut screen = Screen::new(iosys.size());
let mut input = Action::Redraw;
loop {
screen.resize(iosys.size());
let root = Region::new(&mut screen, input);
if !tui(root) {
break;
}
iosys.draw(&screen).expect("failed to render output");
input = iosys.input().expect("failed to get input");
if matches!(
input,
Action::Closed | Action::KeyPress { key: Key::Escape }
) {
break;
}
}
iosys.stop();
}
sourcepub fn attach<A: Attachment<'s>>(self, attachment: A) -> A::Output
pub fn attach<A: Attachment<'s>>(self, attachment: A) -> A::Output
Attach something to this region, returning whatever it wants based on the input.
Remember that it’s common to implement Attachment
for &T
or &mut T
, especially for elements that need to
store state of some sort. If you’re getting weird errors about a type not implementing Attachment
when
you’re 100% sure it does, check the type’s docs and impl Attachment
block more carefully.
Examples found in repository?
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
fn run(mut iosys: Box<dyn IoSystem>) {
let mut ti = TextInput::new("> ", 5);
let mut clicks = 0;
let mut tui = |region: Region| {
let [l, m, r] = region.split(cols!(20 "| |" * "#" 11)).unwrap();
let [lt, lb] = l.split(rows!(* "=" 1)).unwrap();
let [rt, rb] = r.split(rows!(1 "=" *)).unwrap();
lt.attach(|i, sv| {
let txt = text![
"Hello! Your most recent ", red "action", " was: ",
bold green "{:?}"(i),
];
Textbox::new(txt).render_to(sv)
});
match lb.attach(&mut ti) {
TextInputResult::Autocomplete { res, .. } => *res = "mlem!".into(),
TextInputResult::Submit(line) => ti.store(line),
_ => (),
}
m.attach(|i, mut sv: ScreenView| sv.fill(char_for_input(&i)));
if rt.attach(Button("click me!").hotkey('4')) {
clicks += 1;
}
rb.attach(Textbox::new(text!("{} clicks"(clicks))));
true
};
let mut screen = Screen::new(iosys.size());
let mut input = Action::Redraw;
loop {
screen.resize(iosys.size());
let root = Region::new(&mut screen, input);
if !tui(root) {
break;
}
iosys.draw(&screen).expect("failed to render output");
input = iosys.input().expect("failed to get input");
if matches!(
input,
Action::Closed | Action::KeyPress { key: Key::Escape }
) {
break;
}
}
iosys.stop();
}
sourcepub fn text(self, text: Vec<Text>) -> TextboxData
pub fn text(self, text: Vec<Text>) -> TextboxData
Fill the whole region with some text.
If this runs out of space, it will cut off the bottom of the text. If you need more control over how it’s
displayed, create and attach a Textbox
directly.
Returns a TextboxData
, as usual.