pub struct View<'a, Msg> { /* private fields */ }Expand description
Collects the nodes of one container while an application’s view runs.
Implementations§
Source§impl<'a, Msg: 'static> View<'a, Msg>
impl<'a, Msg: 'static> View<'a, Msg>
Sourcepub fn size(&self) -> Size
pub fn size(&self) -> Size
The room the application is drawing into: the whole terminal, in columns and rows.
This is the value for an application’s own layout decision, such as “below 48 columns,
fold the three columns into one”: if ui.size().width < 48 { .. } else { .. } in view.
The application’s view fills the screen, so at the top of view this is exactly the
area it lays out. Every nested builder reports the same value: the children of column,
row, stack, page and add_with, the parts of an AppShell, SidePanel,
Splitter or Popover, the content of a Modal or other layer. The view is built
before layout divides the screen, so a container’s own share is not known yet while its
children are being built; the number never pretends to be that share. A widget that
adapts to its own rectangle (a column that shortens its labels) does so in measure and
paint, which receive it.
Reading it performs no I/O: it is the size of the frame the framework is about to draw,
which it already holds. After a terminal resize the next frame reports the new size, and
Harness::resize does the same in tests.
Sourcepub fn idle_for(&self) -> Duration
pub fn idle_for(&self) -> Duration
How long no input has reached this terminal: the time since the last key, mouse event or paste the runtime received, or since the application started when none came yet.
Everything the user does in this terminal counts: a key going down, repeating or coming
up, a mouse button, the wheel, the pointer moving over the window, a paste, and the end of
a Handoff, because the program that had the terminal was
being used meanwhile. A terminal resize does not count: a window manager or a monitor
change resizes a window nobody is sitting at. Messages, background work and timers do not
count either; they are the application, not the user. Other programs and other terminals
are out of reach: this is idleness here, not idleness of the machine.
Reading the value keeps it current on screen: while view reads it, the runtime draws
again each time it passes a whole second, and stops once view no longer reads it. A
view that shows minutes therefore redraws once a second while it shows them; one that
only needs to act after a silence uses View::on_idle, which wakes the application
once, at that moment, without drawing in between.
Harness::advance moves it forward in tests, and
every simulated input starts it again from zero.
Sourcepub fn on_idle(
&mut self,
after: Duration,
message: impl Fn(bool) -> Msg + 'static,
)
pub fn on_idle( &mut self, after: Duration, message: impl Fn(bool) -> Msg + 'static, )
Tells the application when no input has arrived for after, and when input comes back.
message(true) is delivered once, at the moment the silence reaches after: the runtime
wakes for it even when nothing else happens, and does not draw in between. The first
input afterwards delivers message(false), before that input reaches any widget, and
starts the next wait. What counts as input is listed at View::idle_for.
use std::time::Duration;
use qframe::prelude::*;
#[derive(Default)]
struct Focus {
away: bool,
}
impl App for Focus {
type Msg = bool;
fn update(&mut self, away: bool) -> Command<bool> {
self.away = away;
Command::none()
}
fn view(&self, ui: &mut View<'_, bool>) {
ui.on_idle(Duration::from_secs(300), |away| away);
ui.add(Text::new(if self.away { "away" } else { "working" }));
}
}
let mut app = Harness::new(Focus::default(), 20, 1);
app.advance(Duration::from_secs(299));
assert!(app.screen().contains("working"));
app.advance(Duration::from_secs(1));
assert!(app.screen().contains("away"));
app.press("x");
assert!(app.screen().contains("working"));Declare the watch in every frame it should stay active, like a widget: the runtime
answers the watches of the latest frame. One that is no longer declared is not told the
silence ended. A watch declared when the silence has already lasted after is told at
once. Watches with different after are independent, so an application can dim the
screen after one minute and pause a timer after five.
Sourcepub fn add_with<W: Container<Msg>>(
&mut self,
widget: W,
build: impl FnOnce(&mut View<'_, Msg>),
) -> NodeMut<'_, Msg>
pub fn add_with<W: Container<Msg>>( &mut self, widget: W, build: impl FnOnce(&mut View<'_, Msg>), ) -> NodeMut<'_, Msg>
Adds a widget that contains other widgets, built by build.
Sourcepub fn column(
&mut self,
build: impl FnOnce(&mut View<'_, Msg>),
) -> NodeMut<'_, Msg>
pub fn column( &mut self, build: impl FnOnce(&mut View<'_, Msg>), ) -> NodeMut<'_, Msg>
Adds a column whose children are built by build.
Sourcepub fn row(
&mut self,
build: impl FnOnce(&mut View<'_, Msg>),
) -> NodeMut<'_, Msg>
pub fn row( &mut self, build: impl FnOnce(&mut View<'_, Msg>), ) -> NodeMut<'_, Msg>
Adds a row whose children are built by build.
Sourcepub fn stack(
&mut self,
build: impl FnOnce(&mut View<'_, Msg>),
) -> NodeMut<'_, Msg>
pub fn stack( &mut self, build: impl FnOnce(&mut View<'_, Msg>), ) -> NodeMut<'_, Msg>
Adds a stack: children are drawn on top of each other in the same area, later ones on top.
Sourcepub fn place(
&mut self,
rect: Rect,
build: impl FnOnce(&mut View<'_, Msg>),
) -> NodeMut<'_, Msg>
pub fn place( &mut self, rect: Rect, build: impl FnOnce(&mut View<'_, Msg>), ) -> NodeMut<'_, Msg>
Adds children at rect, for a stack whose children sit where the application says, such
as windows on a desktop.
Inside a stack, rect counts from the stack’s top left corner, whatever
the stack’s alignment: the children fill it, drawn on top of each other. A rectangle may
reach past the stack on any side, also to negative coordinates; what lies outside is not
drawn and takes no pointer. Children added later are drawn on top and get the pointer
first where they overlap, so the order of the calls is the stacking order. A placed child
may draw one cell past its right and bottom edges, where a window drops its shadow; that
cell never takes the pointer.
Outside a stack only the size of rect counts.
Name every placed child whose position in the stack can change, as when a clicked window
comes to the front: ui.place(rect, ..).id("htop"). Its state, and a drag it is in the
middle of, follow the name.
use qframe::prelude::*;
struct Desk;
impl App for Desk {
type Msg = ();
fn update(&mut self, (): ()) -> Command<()> {
Command::none()
}
fn view(&self, ui: &mut View<'_, ()>) {
ui.stack(|ui| {
ui.place(Rect::new(2, 1, 6, 1), |ui| {
ui.add(Text::new("below"));
})
.id("first");
ui.place(Rect::new(6, 1, 5, 1), |ui| {
ui.add(Text::new("above"));
})
.id("second");
})
.fill();
}
}
let app = Harness::new(Desk, 12, 2);
assert_eq!(app.screen(), "\n beloabove\n");Sourcepub fn page(
&mut self,
key: impl Into<String>,
build: impl FnOnce(&mut View<'_, Msg>),
) -> NodeMut<'_, Msg>
pub fn page( &mut self, key: impl Into<String>, build: impl FnOnce(&mut View<'_, Msg>), ) -> NodeMut<'_, Msg>
Adds a column that remembers its widgets’ state (focus, scroll, cursors) while it is not
shown. Give every page of a router its own key.
Sourcepub fn map<Inner: 'static>(
&mut self,
map: impl Fn(Inner) -> Msg + 'static,
build: impl FnOnce(&mut View<'_, Inner>),
) -> NodeMut<'_, Msg>
pub fn map<Inner: 'static>( &mut self, map: impl Fn(Inner) -> Msg + 'static, build: impl FnOnce(&mut View<'_, Inner>), ) -> NodeMut<'_, Msg>
Adds a column whose children are built by build with messages of their own type
Inner, each converted by map on its way to the application. A screen with its own
messages writes its view for them, and the application places it in one line:
use qframe::prelude::*;
mod search {
use qframe::prelude::*;
#[derive(Clone)]
pub enum Msg {
Run,
}
pub fn view(ui: &mut View<'_, Msg>) {
ui.add(Button::new("Search").on_press(Msg::Run));
}
}
enum Msg {
Search(search::Msg),
}
fn view(ui: &mut View<'_, Msg>) {
ui.map(Msg::Search, search::view).fill();
}Everything the screen does inside arrives converted: the messages of its widgets and
handlers, the children of add_with and nested containers, layers such
as a Modal and the widgets in them, overlays such as an open dropdown. Focus, memory and
ids work as for any column; Command::map converts the
commands the screen’s update returns the same way.
Auto Trait Implementations§
impl<'a, Msg> !RefUnwindSafe for View<'a, Msg>
impl<'a, Msg> !Send for View<'a, Msg>
impl<'a, Msg> !Sync for View<'a, Msg>
impl<'a, Msg> !UnwindSafe for View<'a, Msg>
impl<'a, Msg> Freeze for View<'a, Msg>
impl<'a, Msg> Unpin for View<'a, Msg>
impl<'a, Msg> UnsafeUnpin for View<'a, Msg>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more