Ui

Struct Ui 

Source
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>

Source

pub fn new(renderer: T) -> Self

Creates a new UI state with the given renderer.

Source

pub fn renderer(&self) -> &T

Returns an immutable reference to the renderer.

Source

pub fn render(&mut self) -> &mut T

Returns a mutable reference to the renderer.

Source

pub fn position(&self) -> Point

Returns the position of the topmost group, in absolute (screen) coordinates.

Source

pub fn set_position(&mut self, new_position: Point)

Sets the absolute position of the topmost group.

Source

pub fn size(&self) -> Vector

Returns the size of the topmost group.

Source

pub fn width(&self) -> f32

Returns the width of the topmost group.

Source

pub fn height(&self) -> f32

Returns the height of the topmost group.

Source

pub fn rect(&self) -> Rect

Returns the current group’s rectangle. The rectangle’s position is expressed in absolute coordinates.

Source

pub fn root_rect(&self) -> Rect

Returns the root group’s rectangle.

Source

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).

Source

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.

Source

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.

Source

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.

Source

pub fn push(&mut self, size: impl Into<Vector>, layout: Layout)

Pushes a group onto the group stack, with the given size and layout.

Source

pub fn pop(&mut self)

Pops a group off the group stack, updating the cursor of the group under it.

Source

pub fn cursor(&self) -> Vector

Returns the cursor position of the current group.

Source

pub fn set_cursor(&mut self, new_cursor: Vector)

Sets the cursor position of the current group. This is most useful with freeform layouts.

Source

pub fn offset(&mut self, by: Vector)

Offsets the cursor by the given amount.

Source

pub fn pad(&mut self, padding: impl Into<Padding>)

Pads the current group with some amount of padding.

Source

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.

Source

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.
Source

pub fn fit(&mut self)

Resizes the current group to fit its children. This function considers a few cases:

  • on Freeform layout, it sets the width and height to the cursor,
  • on Horizontal layout, it sets the width to the cursor’s X position,
  • on Vertical layout, 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>

Source

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.

Source

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.

Source

pub fn fill(&mut self, color: impl Into<Color>)

Draws a rectangle that fills the current group with the given color.

Source

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.

Source

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.

Source

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.

Source

pub fn line_cap(&self) -> LineCap

Returns the current group’s line cap.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn text( &mut self, font: &T::Font, text: &str, color: impl Into<Color>, alignment: Alignment, )

Draws text inside of the current group, with the given color and alignment inside of the group’s rectangle.

§Panics

If there are no groups on the stack, or if a font isn’t set.

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.

Source§

type Target = T

The renderer type.

Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
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.

Source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.

Auto Trait Implementations§

§

impl<T> Freeze for Ui<T>
where T: Freeze,

§

impl<T> RefUnwindSafe for Ui<T>
where T: RefUnwindSafe,

§

impl<T> Send for Ui<T>
where T: Send,

§

impl<T> Sync for Ui<T>
where T: Sync,

§

impl<T> Unpin for Ui<T>
where T: Unpin,

§

impl<T> UnwindSafe for Ui<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.