pub struct Ui<T: Renderer> { /* private fields */ }Expand description
UI state. This is what’s used for laying out groups and drawing to the screen.
§The group stack
The group stack is what controls positioning at a given moment. Because paws is an immediate-mode GUI library, there is no intermediate state with nodes and what not. Everything is rendered to the screen directly.
However, during rendering, paws has to keep some information around for layouting. After all, that’s what it’s for: laying out rectangles on the screen. The way it maintains this state is through a stack of groups.
Groups are essentially just glorified rectangles with some extra layouting and rendering data. When you push a new group, the its position is placed relative to the previous group, at a vector called the cursor. When you pop this new group off the stack, the cursor of the group above is offset by the size of the group you just popped off. This allows you to cascade elements, flexbox-style, just without the overhead of holding a hundred or so nodes scattered across heap memory. The group stack grows as you nest more and more groups inside of each other, but old groups are not preserved after they’re popped off the stack.
Of course this paradigm makes laying out simple panels quite easy, but elements that need to preserve state may be a bit more challenging to implement. But worry not, structs come to your rescue! If you want to implement a more complex element that needs to preserve some state across frames, create a struct that’ll hold its data:
// let's assume this is our UI type:
use paws::NoRenderer;
type Ui = paws::Ui<NoRenderer>;
struct Slider {
value: f32,
min: f32,
max: f32,
}Then, implement a method on this struct that’ll render the element onto the screen, and process all incoming input events:
use paws::Layout;
impl Slider {
// for brevity, we'll assume no input events need to be processed, as that's outside
// of paws's scope.
fn process(&mut self, ui: &mut Ui, width: f32) {
// create a group that'll span a rectangle with the provided width and the parent
// group's height
ui.push((width, ui.height()), Layout::Freeform);
ui.draw(|ui| {
// ... do all the rendering work here ...
});
ui.pop();
}
}Then, simply keep a Slider somewhere outside of your event loop, and call process() when you want to place it
onto your UI.
let mut ui = Ui::new(NoRenderer);
let mut slider = Slider {
value: 0.0,
min: 0.0,
max: 32.0,
};
// ↓ this is your event loop! usually done by winit, SDL2, or some other library.
'app: loop {
// don't forget the root group!
ui.root(window_size, Layout::Vertical);
// ... other layout stuff goes here ...
// when time comes, process() the slider:
slider.process(&mut ui, 256.0);
}§Initialization
Most of the group-related methods described below will panic if there are no groups on the stack, with the exception
of Ui::new (obviously), and Ui::root. The latter is used to initialize the UI state so that at least one
group is present, but also to make sure that the group stack doesn’t grow to oblivion if the user forgets to pop a
group or two. (This isn’t a good excuse for not popping groups, but it’ll at least prevent your program from leaking
memory if you really do forget.)
§Panicking
All functions that mention the “current group” are guaranteed to panic if there are no groups on the stack. Other groups, such as the “parent group”, which is the group above the current group, may also appear, but are always followed up with a Panicking section that specify the requirements for these groups’ presence.
§Rendering
Because there’s usually no use to using a UI library without any actual rendering, the Ui type takes an extra
renderer type as a parameter. The methods from this type are available via the Deref and DerefMut traits,
except for names that collide with those defined on Ui itself (obviously).
The renderer can be retrieved as an immutable reference (for probing and measurements) using Ui::renderer,
and as a mutable reference (for doing actual rendering) using Ui::render.
§build!
For your convenience while building UIs, a macro is available to make all those pushes and pops get out of your
face. See build!’s documentation for more info.
Implementations§
Source§impl<T: Renderer> Ui<T>
impl<T: Renderer> Ui<T>
Sourcepub fn position(&self) -> Point
pub fn position(&self) -> Point
Returns the position of the topmost group, in absolute (screen) coordinates.
Sourcepub fn set_position(&mut self, new_position: Point)
pub fn set_position(&mut self, new_position: Point)
Sets the absolute position of the topmost group.
Sourcepub fn rect(&self) -> Rect
pub fn rect(&self) -> Rect
Returns the current group’s rectangle. The rectangle’s position is expressed in absolute coordinates.
Sourcepub fn remaining_size(&self) -> Vector
pub fn remaining_size(&self) -> Vector
Returns the “remaining size” of the current group. This is measured by subtracting the group’s cursor from its size, effectively giving you the size that remains in the group. In reversed layouts, the cursor is added instead, as it goes into the negative. On the freeform layout, this always returns (0, 0).
Sourcepub fn remaining_width(&self) -> f32
pub fn remaining_width(&self) -> f32
Returns the “remaining width” of the current group, as per the convention described in
Ui::remaining_size’s documentation.
Sourcepub fn remaining_height(&self) -> f32
pub fn remaining_height(&self) -> f32
Returns the “remaining height” of the current group, as per the convention described in
Ui::remaining_size’s documentation.
Sourcepub fn root(&mut self, size: impl Into<Vector>, layout: Layout)
pub fn root(&mut self, size: impl Into<Vector>, layout: Layout)
Clears the group stack and pushes the root group onto the stack, with the given size and layout. The root group is the first group that should be pushed onto the stack. It defines the size of the window, and the initial layout to be used.
Note that this root group must not be popped off manually, as it gets popped off every frame anyways, because the stack is cleared upon calling this function.
Sourcepub fn push(&mut self, size: impl Into<Vector>, layout: Layout)
pub fn push(&mut self, size: impl Into<Vector>, layout: Layout)
Pushes a group onto the group stack, with the given size and layout.
Sourcepub fn pop(&mut self)
pub fn pop(&mut self)
Pops a group off the group stack, updating the cursor of the group under it.
Sourcepub fn set_cursor(&mut self, new_cursor: Vector)
pub fn set_cursor(&mut self, new_cursor: Vector)
Sets the cursor position of the current group. This is most useful with freeform layouts.
Sourcepub fn pad(&mut self, padding: impl Into<Padding>)
pub fn pad(&mut self, padding: impl Into<Padding>)
Pads the current group with some amount of padding.
Sourcepub fn align(&mut self, alignment: Alignment)
pub fn align(&mut self, alignment: Alignment)
Aligns the current group in the parent group, with the provided alignment.
§Panics
If there are less than two groups (the parent and the subject) on the stack.
Sourcepub fn space(&mut self, amount: f32)
pub fn space(&mut self, amount: f32)
Inserts empty space between subgroups, by increasing or decreasing the cursor position by the given amount.
§Panics
- If there are no groups.
- On freeform layout, as it’s not clear which direction the spacing should be performed in.
Sourcepub fn fit(&mut self)
pub fn fit(&mut self)
Resizes the current group to fit its children. This function considers a few cases:
- on
Freeformlayout, it sets the width and height to the cursor, - on
Horizontallayout, it sets the width to the cursor’s X position, - on
Verticallayout, it sets the height to the cursor’s Y position. - on reversed layouts, it panics, as layouting there works a bit backwards and fitting currently doesn’t work properly. This might get solved in a future release.
§Panics
- If there are no groups.
- On reversed layouts, as noted above.
Source§impl<T: Renderer> Ui<T>
impl<T: Renderer> Ui<T>
Sourcepub fn draw<F>(&mut self, do_draw: F)where
F: FnOnce(&mut Self),
pub fn draw<F>(&mut self, do_draw: F)where
F: FnOnce(&mut Self),
Allows one to draw in the current group by translating the renderer’s matrix to the group’s position.
The renderer can be obtained inside of the callback by using Ui::render.
Sourcepub fn clip(&mut self)
pub fn clip(&mut self)
Clips drawing to only occur inside of the current group.
Any pixels outside of the group are discarded. Note that to undo the clip,
self.render().push() and self.render().pop() must be used.
Sourcepub fn fill(&mut self, color: impl Into<Color>)
pub fn fill(&mut self, color: impl Into<Color>)
Draws a rectangle that fills the current group with the given color.
Sourcepub fn fill_rounded(&mut self, color: impl Into<Color>, radius: f32)
pub fn fill_rounded(&mut self, color: impl Into<Color>, radius: f32)
Draws a rounded rectangle that fills the current group, with the given color and corner radius.
Sourcepub fn outline(&mut self, color: impl Into<Color>, thickness: f32)
pub fn outline(&mut self, color: impl Into<Color>, thickness: f32)
Draws a rectangle outline that creates a border around the current group, with the given color and line thickness.
Sourcepub fn outline_rounded(
&mut self,
color: impl Into<Color>,
radius: f32,
thickness: f32,
)
pub fn outline_rounded( &mut self, color: impl Into<Color>, radius: f32, thickness: f32, )
Draws a rounded rectangle outline that creates a border around the current group, with the given color, corner radius, and line thickness.
Sourcepub fn set_line_cap(&mut self, new_line_cap: LineCap)
pub fn set_line_cap(&mut self, new_line_cap: LineCap)
Sets the current group’s line cap for rendering lines. The root group’s default line cap is LineCap::Butt.
Sourcepub fn border_left(&mut self, color: impl Into<Color>, thickness: f32)
pub fn border_left(&mut self, color: impl Into<Color>, thickness: f32)
Draws a line spanning the left side of the current group, with the given color and line thickness.
Sourcepub fn border_top(&mut self, color: impl Into<Color>, thickness: f32)
pub fn border_top(&mut self, color: impl Into<Color>, thickness: f32)
Draws a line spanning the top side of the current group, with the given color and line thickness.
Sourcepub fn border_right(&mut self, color: impl Into<Color>, thickness: f32)
pub fn border_right(&mut self, color: impl Into<Color>, thickness: f32)
Draws a line spanning the right side of the current group, with the given color and line thickness.
Sourcepub fn border_bottom(&mut self, color: impl Into<Color>, thickness: f32)
pub fn border_bottom(&mut self, color: impl Into<Color>, thickness: f32)
Draws a line spanning the bottom side of the current group, with the given color and line thickness.
Trait Implementations§
Source§impl<T: Renderer> Deref for Ui<T>
Any Ui instance acts as if it were the underlying renderer.
In case any conflicts occur (such as with Ui::text and Renderer::text, Ui::render may be used to
specify that the renderer method should be called instead.
impl<T: Renderer> Deref for Ui<T>
Any Ui instance acts as if it were the underlying renderer.
In case any conflicts occur (such as with Ui::text and Renderer::text, Ui::render may be used to
specify that the renderer method should be called instead.
Source§impl<T: Renderer> DerefMut for Ui<T>
Any mutable Ui instance acts as if it were the underlying renderer.
In case any conflicts occur (such as with Ui::text and Renderer::text, Ui::renderer may be used to
specify that the renderer method should be called instead.
impl<T: Renderer> DerefMut for Ui<T>
Any mutable Ui instance acts as if it were the underlying renderer.
In case any conflicts occur (such as with Ui::text and Renderer::text, Ui::renderer may be used to
specify that the renderer method should be called instead.