Write docs for iced and iced_native
This commit is contained in:
parent
ba56a561b2
commit
a7dba612f0
30 changed files with 877 additions and 214 deletions
|
|
@ -33,31 +33,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn width(&self) -> Length {
|
||||
self.widget.width()
|
||||
}
|
||||
|
||||
pub fn height(&self) -> Length {
|
||||
self.widget.height()
|
||||
}
|
||||
|
||||
pub fn layout(
|
||||
&self,
|
||||
renderer: &Renderer,
|
||||
limits: &layout::Limits,
|
||||
) -> layout::Node {
|
||||
self.widget.layout(renderer, limits)
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
self.widget.draw(renderer, layout, cursor_position)
|
||||
}
|
||||
|
||||
/// Applies a transformation to the produced message of the [`Element`].
|
||||
///
|
||||
/// This method is useful when you want to decouple different parts of your
|
||||
|
|
@ -225,6 +200,45 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the width of the [`Element`].
|
||||
///
|
||||
/// [`Element`]: struct.Element.html
|
||||
pub fn width(&self) -> Length {
|
||||
self.widget.width()
|
||||
}
|
||||
|
||||
/// Returns the height of the [`Element`].
|
||||
///
|
||||
/// [`Element`]: struct.Element.html
|
||||
pub fn height(&self) -> Length {
|
||||
self.widget.height()
|
||||
}
|
||||
|
||||
/// Computes the layout of the [`Element`] in the given [`Limits`].
|
||||
///
|
||||
/// [`Element`]: struct.Element.html
|
||||
/// [`Limits`]: layout/struct.Limits.html
|
||||
pub fn layout(
|
||||
&self,
|
||||
renderer: &Renderer,
|
||||
limits: &layout::Limits,
|
||||
) -> layout::Node {
|
||||
self.widget.layout(renderer, limits)
|
||||
}
|
||||
|
||||
/// Draws the [`Element`] and its children using the given [`Layout`].
|
||||
///
|
||||
/// [`Element`]: struct.Element.html
|
||||
/// [`Layout`]: layout/struct.Layout.html
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
) -> Renderer::Output {
|
||||
self.widget.draw(renderer, layout, cursor_position)
|
||||
}
|
||||
|
||||
pub(crate) fn hash_layout(&self, state: &mut Hasher) {
|
||||
self.widget.hash_layout(state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,11 +34,16 @@ pub enum Event {
|
|||
},
|
||||
|
||||
/// The mouse wheel was scrolled.
|
||||
WheelScrolled { delta: ScrollDelta },
|
||||
WheelScrolled {
|
||||
/// The scroll movement.
|
||||
delta: ScrollDelta,
|
||||
},
|
||||
}
|
||||
|
||||
/// A scroll movement.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ScrollDelta {
|
||||
/// A line-based scroll movement
|
||||
Lines {
|
||||
/// The number of horizontal lines scrolled
|
||||
x: f32,
|
||||
|
|
@ -46,6 +51,7 @@ pub enum ScrollDelta {
|
|||
/// The number of vertical lines scrolled
|
||||
y: f32,
|
||||
},
|
||||
/// A pixel-based scroll movement
|
||||
Pixels {
|
||||
/// The number of horizontal pixels scrolled
|
||||
x: f32,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Position your widgets properly.
|
||||
mod limits;
|
||||
mod node;
|
||||
|
||||
|
|
@ -8,6 +9,9 @@ pub use node::Node;
|
|||
|
||||
use crate::{Point, Rectangle, Vector};
|
||||
|
||||
/// The bounds of a [`Node`] and its children, using absolute coordinates.
|
||||
///
|
||||
/// [`Node`]: struct.Node.html
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Layout<'a> {
|
||||
position: Point,
|
||||
|
|
@ -28,6 +32,14 @@ impl<'a> Layout<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the bounds of the [`Layout`].
|
||||
///
|
||||
/// The returned [`Rectangle`] describes the position and size of a
|
||||
/// [`Node`].
|
||||
///
|
||||
/// [`Layout`]: struct.Layout.html
|
||||
/// [`Rectangle`]: struct.Rectangle.html
|
||||
/// [`Node`]: struct.Node.html
|
||||
pub fn bounds(&self) -> Rectangle {
|
||||
let bounds = self.node.bounds();
|
||||
|
||||
|
|
@ -39,6 +51,10 @@ impl<'a> Layout<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the [`Layout`] of the children of a [`Node`].
|
||||
///
|
||||
/// [`Layout`]: struct.Layout.html
|
||||
/// [`Node`]: struct.Node.html
|
||||
pub fn children(&'a self) -> impl Iterator<Item = Layout<'a>> {
|
||||
self.node.children().iter().map(move |node| {
|
||||
Layout::with_offset(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Distribute elements using a flex-based layout.
|
||||
// This code is heavily inspired by the [`druid`] codebase.
|
||||
//
|
||||
// [`druid`]: https://github.com/xi-editor/druid
|
||||
|
|
@ -20,9 +21,13 @@ use crate::{
|
|||
Align, Element, Size,
|
||||
};
|
||||
|
||||
/// The main axis of a flex layout.
|
||||
#[derive(Debug)]
|
||||
pub enum Axis {
|
||||
/// The horizontal axis
|
||||
Horizontal,
|
||||
|
||||
/// The vertical axis
|
||||
Vertical,
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +54,12 @@ impl Axis {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Remove `Message` type parameter
|
||||
/// Computes the flex layout with the given axis and limits, applying spacing,
|
||||
/// padding and alignment to the items as needed.
|
||||
///
|
||||
/// It returns a new layout [`Node`].
|
||||
///
|
||||
/// [`Node`]: ../struct.Node.html
|
||||
pub fn resolve<Message, Renderer>(
|
||||
axis: Axis,
|
||||
renderer: &Renderer,
|
||||
|
|
@ -57,7 +67,7 @@ pub fn resolve<Message, Renderer>(
|
|||
padding: f32,
|
||||
spacing: f32,
|
||||
align_items: Align,
|
||||
children: &[Element<'_, Message, Renderer>],
|
||||
items: &[Element<'_, Message, Renderer>],
|
||||
) -> Node
|
||||
where
|
||||
Renderer: crate::Renderer,
|
||||
|
|
@ -65,14 +75,14 @@ where
|
|||
let limits = limits.pad(padding);
|
||||
|
||||
let mut total_non_fill =
|
||||
spacing as f32 * (children.len() as i32 - 1).max(0) as f32;
|
||||
spacing as f32 * (items.len() as i32 - 1).max(0) as f32;
|
||||
let mut fill_sum = 0;
|
||||
let mut cross = axis.cross(limits.min());
|
||||
|
||||
let mut nodes: Vec<Node> = Vec::with_capacity(children.len());
|
||||
nodes.resize(children.len(), Node::default());
|
||||
let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
|
||||
nodes.resize(items.len(), Node::default());
|
||||
|
||||
for (i, child) in children.iter().enumerate() {
|
||||
for (i, child) in items.iter().enumerate() {
|
||||
let fill_factor = match axis {
|
||||
Axis::Horizontal => child.width(),
|
||||
Axis::Vertical => child.height(),
|
||||
|
|
@ -97,7 +107,7 @@ where
|
|||
let available = axis.main(limits.max());
|
||||
let remaining = (available - total_non_fill).max(0.0);
|
||||
|
||||
for (i, child) in children.iter().enumerate() {
|
||||
for (i, child) in items.iter().enumerate() {
|
||||
let fill_factor = match axis {
|
||||
Axis::Horizontal => child.width(),
|
||||
Axis::Vertical => child.height(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{Length, Size};
|
||||
|
||||
/// A set of size constraints for layouting.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Limits {
|
||||
min: Size,
|
||||
|
|
@ -8,12 +9,17 @@ pub struct Limits {
|
|||
}
|
||||
|
||||
impl Limits {
|
||||
/// No limits
|
||||
pub const NONE: Limits = Limits {
|
||||
min: Size::ZERO,
|
||||
max: Size::INFINITY,
|
||||
fill: Size::INFINITY,
|
||||
};
|
||||
|
||||
/// Creates new [`Limits`] with the given minimum and maximum [`Size`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
/// [`Size`]: ../struct.Size.html
|
||||
pub fn new(min: Size, max: Size) -> Limits {
|
||||
Limits {
|
||||
min,
|
||||
|
|
@ -22,14 +28,25 @@ impl Limits {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the minimum [`Size`] of the [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
/// [`Size`]: ../struct.Size.html
|
||||
pub fn min(&self) -> Size {
|
||||
self.min
|
||||
}
|
||||
|
||||
/// Returns the maximum [`Size`] of the [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
/// [`Size`]: ../struct.Size.html
|
||||
pub fn max(&self) -> Size {
|
||||
self.max
|
||||
}
|
||||
|
||||
/// Applies a width constraint to the current [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn width(mut self, width: Length) -> Limits {
|
||||
match width {
|
||||
Length::Shrink => {
|
||||
|
|
@ -51,6 +68,9 @@ impl Limits {
|
|||
self
|
||||
}
|
||||
|
||||
/// Applies a height constraint to the current [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn height(mut self, height: Length) -> Limits {
|
||||
match height {
|
||||
Length::Shrink => {
|
||||
|
|
@ -72,6 +92,9 @@ impl Limits {
|
|||
self
|
||||
}
|
||||
|
||||
/// Applies a minimum width constraint to the current [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn min_width(mut self, min_width: u32) -> Limits {
|
||||
self.min.width =
|
||||
self.min.width.max(min_width as f32).min(self.max.width);
|
||||
|
|
@ -79,6 +102,9 @@ impl Limits {
|
|||
self
|
||||
}
|
||||
|
||||
/// Applies a maximum width constraint to the current [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn max_width(mut self, max_width: u32) -> Limits {
|
||||
self.max.width =
|
||||
self.max.width.min(max_width as f32).max(self.min.width);
|
||||
|
|
@ -86,6 +112,19 @@ impl Limits {
|
|||
self
|
||||
}
|
||||
|
||||
/// Applies a minimum height constraint to the current [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn min_height(mut self, min_height: u32) -> Limits {
|
||||
self.min.height =
|
||||
self.min.height.max(min_height as f32).min(self.max.height);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Applies a maximum height constraint to the current [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn max_height(mut self, max_height: u32) -> Limits {
|
||||
self.max.height =
|
||||
self.max.height.min(max_height as f32).max(self.min.height);
|
||||
|
|
@ -93,10 +132,17 @@ impl Limits {
|
|||
self
|
||||
}
|
||||
|
||||
/// Shrinks the current [`Limits`] to account for the given padding.
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn pad(&self, padding: f32) -> Limits {
|
||||
self.shrink(Size::new(padding * 2.0, padding * 2.0))
|
||||
}
|
||||
|
||||
/// Shrinks the current [`Limits`] by the given [`Size`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
/// [`Size`]: ../struct.Size.html
|
||||
pub fn shrink(&self, size: Size) -> Limits {
|
||||
let min = Size::new(
|
||||
(self.min().width - size.width).max(0.0),
|
||||
|
|
@ -116,6 +162,9 @@ impl Limits {
|
|||
Limits { min, max, fill }
|
||||
}
|
||||
|
||||
/// Removes the minimum width constraint for the current [`Limits`].
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn loose(&self) -> Limits {
|
||||
Limits {
|
||||
min: Size::ZERO,
|
||||
|
|
@ -124,6 +173,10 @@ impl Limits {
|
|||
}
|
||||
}
|
||||
|
||||
/// Computes the resulting [`Size`] that fits the [`Limits`] given the
|
||||
/// intrinsic size of some content.
|
||||
///
|
||||
/// [`Limits`]: struct.Limits.html
|
||||
pub fn resolve(&self, intrinsic_size: Size) -> Size {
|
||||
Size::new(
|
||||
intrinsic_size
|
||||
|
|
|
|||
|
|
@ -1,16 +1,25 @@
|
|||
use crate::{Align, Rectangle, Size};
|
||||
|
||||
/// The bounds of an element and its children.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Node {
|
||||
pub bounds: Rectangle,
|
||||
pub(crate) bounds: Rectangle,
|
||||
children: Vec<Node>,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
/// Creates a new [`Node`] with the given [`Size`].
|
||||
///
|
||||
/// [`Node`]: struct.Node.html
|
||||
/// [`Size`]: ../struct.Size.html
|
||||
pub fn new(size: Size) -> Self {
|
||||
Self::with_children(size, Vec::new())
|
||||
}
|
||||
|
||||
/// Creates a new [`Node`] with the given [`Size`] and children.
|
||||
///
|
||||
/// [`Node`]: struct.Node.html
|
||||
/// [`Size`]: ../struct.Size.html
|
||||
pub fn with_children(size: Size, children: Vec<Node>) -> Self {
|
||||
Node {
|
||||
bounds: Rectangle {
|
||||
|
|
@ -23,19 +32,29 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the [`Size`] of the [`Node`].
|
||||
///
|
||||
/// [`Node`]: struct.Node.html
|
||||
/// [`Size`]: ../struct.Size.html
|
||||
pub fn size(&self) -> Size {
|
||||
Size::new(self.bounds.width, self.bounds.height)
|
||||
}
|
||||
|
||||
/// Returns the bounds of the [`Node`].
|
||||
///
|
||||
/// [`Node`]: struct.Node.html
|
||||
pub fn bounds(&self) -> Rectangle {
|
||||
self.bounds
|
||||
}
|
||||
|
||||
/// Returns the children of the [`Node`].
|
||||
///
|
||||
/// [`Node`]: struct.Node.html
|
||||
pub fn children(&self) -> &[Node] {
|
||||
&self.children
|
||||
}
|
||||
|
||||
pub fn align(
|
||||
pub(crate) fn align(
|
||||
&mut self,
|
||||
horizontal_alignment: Align,
|
||||
vertical_alignment: Align,
|
||||
|
|
|
|||
|
|
@ -1,162 +1,34 @@
|
|||
//! Iced is a renderer-agnostic GUI library focused on simplicity and
|
||||
//! type-safety. Inspired by [Elm].
|
||||
//! A renderer-agnostic native GUI runtime.
|
||||
//!
|
||||
//! # Features
|
||||
//! * Simple, easy-to-use, renderer-agnostic API
|
||||
//! * Responsive, flexbox-based layouting
|
||||
//! * Type-safe, reactive programming model
|
||||
//! * Built-in widgets
|
||||
//! * Custom widget support
|
||||
//! 
|
||||
//!
|
||||
//! Check out the [repository] and the [examples] for more details!
|
||||
//! `iced_native` takes [`iced_core`] and builds a native runtime on top of it,
|
||||
//! featuring:
|
||||
//!
|
||||
//! [examples]: https://github.com/hecrj/iced/tree/0.1.0/examples
|
||||
//! [repository]: https://github.com/hecrj/iced
|
||||
//! - A custom layout engine, greatly inspired by [`druid`]
|
||||
//! - Event handling for all the built-in widgets
|
||||
//! - A renderer-agnostic API
|
||||
//!
|
||||
//! To achieve this, it introduces a bunch of reusable interfaces:
|
||||
//!
|
||||
//! - A [`Widget`] trait, which is used to implement new widgets: from layout
|
||||
//! requirements to event and drawing logic.
|
||||
//! - A bunch of `Renderer` traits, meant to keep the crate renderer-agnostic.
|
||||
//! - A [`Windowed`] trait, leveraging [`raw-window-handle`], which can be
|
||||
//! implemented by graphical renderers that target _windows_. Window-based
|
||||
//! shells (like [`iced_winit`]) can use this trait to stay renderer-agnostic.
|
||||
//!
|
||||
//! # Usage
|
||||
//! Inspired by [The Elm Architecture], Iced expects you to split user
|
||||
//! interfaces into four different concepts:
|
||||
//!
|
||||
//! * __State__ — the state of your application
|
||||
//! * __Messages__ — user interactions or meaningful events that you care
|
||||
//! about
|
||||
//! * __View logic__ — a way to display your __state__ as widgets that
|
||||
//! may produce __messages__ on user interaction
|
||||
//! * __Update logic__ — a way to react to __messages__ and update your
|
||||
//! __state__
|
||||
//!
|
||||
//! We can build something to see how this works! Let's say we want a simple
|
||||
//! counter that can be incremented and decremented using two buttons.
|
||||
//!
|
||||
//! We start by modelling the __state__ of our application:
|
||||
//!
|
||||
//! ```
|
||||
//! use iced_native::button;
|
||||
//!
|
||||
//! struct Counter {
|
||||
//! // The counter value
|
||||
//! value: i32,
|
||||
//!
|
||||
//! // The local state of the two buttons
|
||||
//! increment_button: button::State,
|
||||
//! decrement_button: button::State,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Next, we need to define the possible user interactions of our counter:
|
||||
//! the button presses. These interactions are our __messages__:
|
||||
//!
|
||||
//! ```
|
||||
//! #[derive(Debug, Clone, Copy)]
|
||||
//! pub enum Message {
|
||||
//! IncrementPressed,
|
||||
//! DecrementPressed,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Now, let's show the actual counter by putting it all together in our
|
||||
//! __view logic__:
|
||||
//!
|
||||
//! ```
|
||||
//! # use iced_native::button;
|
||||
//! #
|
||||
//! # struct Counter {
|
||||
//! # // The counter value
|
||||
//! # value: i32,
|
||||
//! #
|
||||
//! # // The local state of the two buttons
|
||||
//! # increment_button: button::State,
|
||||
//! # decrement_button: button::State,
|
||||
//! # }
|
||||
//! #
|
||||
//! # #[derive(Debug, Clone, Copy)]
|
||||
//! # pub enum Message {
|
||||
//! # IncrementPressed,
|
||||
//! # DecrementPressed,
|
||||
//! # }
|
||||
//! #
|
||||
//! # mod iced_wgpu {
|
||||
//! # pub use iced_native::renderer::Null as Renderer;
|
||||
//! # }
|
||||
//! use iced_native::{Button, Column, Text};
|
||||
//! use iced_wgpu::Renderer; // Iced does not include a renderer! We need to bring our own!
|
||||
//!
|
||||
//! impl Counter {
|
||||
//! pub fn view(&mut self) -> Column<Message, Renderer> {
|
||||
//! // We use a column: a simple vertical layout
|
||||
//! Column::new()
|
||||
//! .push(
|
||||
//! // The increment button. We tell it to produce an
|
||||
//! // `IncrementPressed` message when pressed
|
||||
//! Button::new(&mut self.increment_button, Text::new("+"))
|
||||
//! .on_press(Message::IncrementPressed),
|
||||
//! )
|
||||
//! .push(
|
||||
//! // We show the value of the counter here
|
||||
//! Text::new(&self.value.to_string()).size(50),
|
||||
//! )
|
||||
//! .push(
|
||||
//! // The decrement button. We tell it to produce a
|
||||
//! // `DecrementPressed` message when pressed
|
||||
//! Button::new(&mut self.decrement_button, Text::new("-"))
|
||||
//! .on_press(Message::DecrementPressed),
|
||||
//! )
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Finally, we need to be able to react to any produced __messages__ and change
|
||||
//! our __state__ accordingly in our __update logic__:
|
||||
//!
|
||||
//! ```
|
||||
//! # use iced_native::button;
|
||||
//! #
|
||||
//! # struct Counter {
|
||||
//! # // The counter value
|
||||
//! # value: i32,
|
||||
//! #
|
||||
//! # // The local state of the two buttons
|
||||
//! # increment_button: button::State,
|
||||
//! # decrement_button: button::State,
|
||||
//! # }
|
||||
//! #
|
||||
//! # #[derive(Debug, Clone, Copy)]
|
||||
//! # pub enum Message {
|
||||
//! # IncrementPressed,
|
||||
//! # DecrementPressed,
|
||||
//! # }
|
||||
//! impl Counter {
|
||||
//! // ...
|
||||
//!
|
||||
//! pub fn update(&mut self, message: Message) {
|
||||
//! match message {
|
||||
//! Message::IncrementPressed => {
|
||||
//! self.value += 1;
|
||||
//! }
|
||||
//! Message::DecrementPressed => {
|
||||
//! self.value -= 1;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! And that's everything! We just wrote a whole user interface. Iced is now
|
||||
//! able to:
|
||||
//!
|
||||
//! 1. Take the result of our __view logic__ and layout its widgets.
|
||||
//! 1. Process events from our system and produce __messages__ for our
|
||||
//! __update logic__.
|
||||
//! 1. Draw the resulting user interface using our chosen __renderer__.
|
||||
//!
|
||||
//! Check out the [`UserInterface`] type to learn how to wire everything up!
|
||||
//!
|
||||
//! [Elm]: https://elm-lang.org/
|
||||
//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
|
||||
//! [documentation]: https://docs.rs/iced
|
||||
//! [examples]: https://github.com/hecrj/iced/tree/master/examples
|
||||
//! [`iced_core`]: https://github.com/hecrj/iced/tree/master/core
|
||||
//! [`iced_winit`]: https://github.com/hecrj/iced/tree/master/winit
|
||||
//! [`druid`]: https://github.com/xi-editor/druid
|
||||
//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
|
||||
//! [`Widget`]: widget/trait.Widget.html
|
||||
//! [`Windowed`]: renderer/trait.Windowed.html
|
||||
//! [`UserInterface`]: struct.UserInterface.html
|
||||
//#![deny(missing_docs)]
|
||||
#![deny(missing_docs)]
|
||||
//#![deny(missing_debug_implementations)]
|
||||
#![deny(unused_results)]
|
||||
#![deny(unsafe_code)]
|
||||
|
|
|
|||
|
|
@ -32,9 +32,21 @@ pub use windowed::{Target, Windowed};
|
|||
|
||||
use crate::{layout, Element};
|
||||
|
||||
/// A component that can take the state of a user interface and produce an
|
||||
/// output for its users.
|
||||
pub trait Renderer: Sized {
|
||||
/// The type of output of the [`Renderer`].
|
||||
///
|
||||
/// If you are implementing a graphical renderer, your output will most
|
||||
/// likely be a tree of visual primitives.
|
||||
///
|
||||
/// [`Renderer`]: trait.Renderer.html
|
||||
type Output;
|
||||
|
||||
/// Lays out the elements of a user interface.
|
||||
///
|
||||
/// You should override this if you need to perform any operations before or
|
||||
/// after layouting. For instance, trimming the measurements cache.
|
||||
fn layout<'a, Message>(
|
||||
&mut self,
|
||||
element: &Element<'a, Message, Self>,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::{
|
|||
Rectangle, Renderer, Size, VerticalAlignment,
|
||||
};
|
||||
|
||||
/// A renderer that does nothing.
|
||||
pub struct Null;
|
||||
|
||||
impl Renderer for Null {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,21 @@ use crate::MouseCursor;
|
|||
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
|
||||
/// A renderer that can target windows.
|
||||
pub trait Windowed: super::Renderer + Sized {
|
||||
/// The type of target.
|
||||
type Target: Target<Renderer = Self>;
|
||||
|
||||
/// Creates a new [`Windowed`] renderer.
|
||||
///
|
||||
/// [`Windowed`]: trait.Windowed.html
|
||||
fn new() -> Self;
|
||||
|
||||
/// Performs the drawing operations described in the output on the given
|
||||
/// target.
|
||||
///
|
||||
/// The overlay can be a bunch of debug text logs. It should be rendered on
|
||||
/// top of the GUI on most scenarios.
|
||||
fn draw<T: AsRef<str>>(
|
||||
&mut self,
|
||||
output: &Self::Output,
|
||||
|
|
@ -15,9 +25,15 @@ pub trait Windowed: super::Renderer + Sized {
|
|||
) -> MouseCursor;
|
||||
}
|
||||
|
||||
/// A rendering target.
|
||||
pub trait Target {
|
||||
/// The renderer of this target.
|
||||
type Renderer;
|
||||
|
||||
/// Creates a new rendering [`Target`] from the given window handle, width,
|
||||
/// height and dpi factor.
|
||||
///
|
||||
/// [`Target`]: trait.Target.html
|
||||
fn new<W: HasRawWindowHandle>(
|
||||
window: &W,
|
||||
width: u16,
|
||||
|
|
@ -26,6 +42,9 @@ pub trait Target {
|
|||
renderer: &Self::Renderer,
|
||||
) -> Self;
|
||||
|
||||
/// Resizes the current [`Target`].
|
||||
///
|
||||
/// [`Target`]: trait.Target.html
|
||||
fn resize(
|
||||
&mut self,
|
||||
width: u16,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::f32;
|
||||
|
||||
/// An amount of space in 2 dimensions.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Size {
|
||||
/// The width.
|
||||
|
|
@ -9,13 +10,26 @@ pub struct Size {
|
|||
}
|
||||
|
||||
impl Size {
|
||||
/// A [`Size`] with zero width and height.
|
||||
///
|
||||
/// [`Size`]: struct.Size.html
|
||||
pub const ZERO: Size = Size::new(0., 0.);
|
||||
|
||||
/// A [`Size`] with infinite width and height.
|
||||
///
|
||||
/// [`Size`]: struct.Size.html
|
||||
pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY);
|
||||
|
||||
/// A [`Size`] of infinite width and height.
|
||||
///
|
||||
/// [`Size`]: struct.Size.html
|
||||
pub const fn new(width: f32, height: f32) -> Self {
|
||||
Size { width, height }
|
||||
}
|
||||
|
||||
/// Increments the [`Size`] to account for the given padding.
|
||||
///
|
||||
/// [`Size`]: struct.Size.html
|
||||
pub fn pad(&self, padding: f32) -> Self {
|
||||
Size {
|
||||
width: self.width + padding * 2.0,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
pub mod button;
|
||||
pub mod checkbox;
|
||||
pub mod column;
|
||||
pub mod container;
|
||||
pub mod image;
|
||||
pub mod radio;
|
||||
pub mod row;
|
||||
|
|
@ -31,8 +32,6 @@ pub mod slider;
|
|||
pub mod text;
|
||||
pub mod text_input;
|
||||
|
||||
mod container;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use button::Button;
|
||||
#[doc(no_inline)]
|
||||
|
|
@ -69,8 +68,14 @@ pub trait Widget<Message, Renderer>
|
|||
where
|
||||
Renderer: crate::Renderer,
|
||||
{
|
||||
/// Returns the width of the [`Widget`].
|
||||
///
|
||||
/// [`Widget`]: trait.Widget.html
|
||||
fn width(&self) -> Length;
|
||||
|
||||
/// Returns the height of the [`Widget`].
|
||||
///
|
||||
/// [`Widget`]: trait.Widget.html
|
||||
fn height(&self) -> Length;
|
||||
|
||||
/// Returns the [`Node`] of the [`Widget`].
|
||||
|
|
|
|||
|
|
@ -166,15 +166,18 @@ where
|
|||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// Returns the default size of a [`Checkbox`].
|
||||
///
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
fn default_size(&self) -> u32;
|
||||
|
||||
/// Draws a [`Checkbox`].
|
||||
///
|
||||
/// It receives:
|
||||
/// * the current cursor position
|
||||
/// * the bounds of the [`Checkbox`]
|
||||
/// * the bounds of the label of the [`Checkbox`]
|
||||
/// * whether the [`Checkbox`] is checked or not
|
||||
/// * whether the [`Checkbox`] is selected or not
|
||||
/// * whether the mouse is over the [`Checkbox`] or not
|
||||
/// * the drawn label of the [`Checkbox`]
|
||||
///
|
||||
/// [`Checkbox`]: struct.Checkbox.html
|
||||
fn draw(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Distribute content vertically.
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -189,7 +190,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The renderer of a [`Column`].
|
||||
///
|
||||
/// Your [renderer] will need to implement this trait before being
|
||||
/// able to use a [`Column`] in your user interface.
|
||||
///
|
||||
/// [`Column`]: struct.Column.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// Draws a [`Column`].
|
||||
///
|
||||
/// It receives:
|
||||
/// - the children of the [`Column`]
|
||||
/// - the [`Layout`] of the [`Column`] and its children
|
||||
/// - the cursor position
|
||||
///
|
||||
/// [`Column`]: struct.Row.html
|
||||
/// [`Layout`]: ../layout/struct.Layout.html
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
content: &[Element<'_, Message, Self>],
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Decorate content and apply alignment.
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
|
|
|
|||
|
|
@ -116,6 +116,9 @@ where
|
|||
/// [`Image`]: struct.Image.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// Returns the dimensions of an [`Image`] located on the given path.
|
||||
///
|
||||
/// [`Image`]: struct.Image.html
|
||||
fn dimensions(&self, path: &str) -> (u32, u32);
|
||||
|
||||
/// Draws an [`Image`].
|
||||
|
|
|
|||
|
|
@ -174,15 +174,18 @@ where
|
|||
/// [`Radio`]: struct.Radio.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// Returns the default size of a [`Radio`] button.
|
||||
///
|
||||
/// [`Radio`]: struct.Radio.html
|
||||
fn default_size(&self) -> u32;
|
||||
|
||||
/// Draws a [`Radio`] button.
|
||||
///
|
||||
/// It receives:
|
||||
/// * the current cursor position
|
||||
/// * the bounds of the [`Radio`]
|
||||
/// * the bounds of the label of the [`Radio`]
|
||||
/// * whether the [`Radio`] is selected or not
|
||||
/// * whether the mouse is over the [`Radio`] or not
|
||||
/// * the drawn label of the [`Radio`]
|
||||
///
|
||||
/// [`Radio`]: struct.Radio.html
|
||||
fn draw(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Distribute content horizontally.
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -192,7 +193,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The renderer of a [`Row`].
|
||||
///
|
||||
/// Your [renderer] will need to implement this trait before being
|
||||
/// able to use a [`Row`] in your user interface.
|
||||
///
|
||||
/// [`Row`]: struct.Row.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// Draws a [`Row`].
|
||||
///
|
||||
/// It receives:
|
||||
/// - the children of the [`Row`]
|
||||
/// - the [`Layout`] of the [`Row`] and its children
|
||||
/// - the cursor position
|
||||
///
|
||||
/// [`Row`]: struct.Row.html
|
||||
/// [`Layout`]: ../layout/struct.Layout.html
|
||||
fn draw<Message>(
|
||||
&mut self,
|
||||
children: &[Element<'_, Message, Self>],
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Navigate an endless amount of content with a scrollbar.
|
||||
use crate::{
|
||||
column,
|
||||
input::{mouse, ButtonState},
|
||||
|
|
@ -361,7 +362,18 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
/// The renderer of a [`Scrollable`].
|
||||
///
|
||||
/// Your [renderer] will need to implement this trait before being
|
||||
/// able to use a [`Scrollable`] in your user interface.
|
||||
///
|
||||
/// [`Scrollable`]: struct.Scrollable.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// Returns whether the mouse is over the scrollbar given the bounds of
|
||||
/// the [`Scrollable`] and its contents.
|
||||
///
|
||||
/// [`Scrollable`]: struct.Scrollable.html
|
||||
fn is_mouse_over_scrollbar(
|
||||
&self,
|
||||
bounds: Rectangle,
|
||||
|
|
@ -369,6 +381,18 @@ pub trait Renderer: crate::Renderer + Sized {
|
|||
cursor_position: Point,
|
||||
) -> bool;
|
||||
|
||||
/// Draws the [`Scrollable`].
|
||||
///
|
||||
/// It receives:
|
||||
/// - the [`State`] of the [`Scrollable`]
|
||||
/// - the bounds of the [`Scrollable`]
|
||||
/// - whether the mouse is over the [`Scrollable`] or not
|
||||
/// - whether the mouse is over the scrollbar or not
|
||||
/// - the scrolling offset
|
||||
/// - the drawn content
|
||||
///
|
||||
/// [`Scrollable`]: struct.Scrollable.html
|
||||
/// [`State`]: struct.State.html
|
||||
fn draw(
|
||||
&mut self,
|
||||
scrollable: &State,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,28 @@ use crate::{
|
|||
|
||||
use std::{hash::Hash, ops::RangeInclusive};
|
||||
|
||||
/// An horizontal bar and a handle that selects a single value from a range of
|
||||
/// values.
|
||||
///
|
||||
/// A [`Slider`] will try to fill the horizontal space of its container.
|
||||
///
|
||||
/// [`Slider`]: struct.Slider.html
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::{slider, Slider};
|
||||
/// #
|
||||
/// pub enum Message {
|
||||
/// SliderChanged(f32),
|
||||
/// }
|
||||
///
|
||||
/// let state = &mut slider::State::new();
|
||||
/// let value = 50.0;
|
||||
///
|
||||
/// Slider::new(state, 0.0..=100.0, value, Message::SliderChanged);
|
||||
/// ```
|
||||
///
|
||||
/// 
|
||||
pub struct Slider<'a, Message> {
|
||||
state: &'a mut State,
|
||||
range: RangeInclusive<f32>,
|
||||
|
|
@ -180,6 +202,9 @@ where
|
|||
/// [`Slider`]: struct.Slider.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// Returns the height of the [`Slider`].
|
||||
///
|
||||
/// [`Slider`]: struct.Slider.html
|
||||
fn height(&self) -> u32;
|
||||
|
||||
/// Draws a [`Slider`].
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ impl Text {
|
|||
/// Create a new fragment of [`Text`] with the given contents.
|
||||
///
|
||||
/// [`Text`]: struct.Text.html
|
||||
pub fn new(label: &str) -> Self {
|
||||
pub fn new<T: Into<String>>(label: T) -> Self {
|
||||
Text {
|
||||
content: String::from(label),
|
||||
content: label.into(),
|
||||
size: None,
|
||||
color: None,
|
||||
font: Font::Default,
|
||||
|
|
@ -174,8 +174,15 @@ where
|
|||
/// [renderer]: ../../renderer/index.html
|
||||
/// [`UserInterface`]: ../../struct.UserInterface.html
|
||||
pub trait Renderer: crate::Renderer {
|
||||
/// Returns the default size of the [`Text`].
|
||||
///
|
||||
/// [`Text`]: struct.Text.html
|
||||
fn default_size(&self) -> u16;
|
||||
|
||||
/// Measures the [`Text`] in the given bounds and returns the minimum
|
||||
/// boundaries that can fit the contents.
|
||||
///
|
||||
/// [`Text`]: struct.Text.html
|
||||
fn measure(
|
||||
&self,
|
||||
content: &str,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,26 @@ use crate::{
|
|||
Widget,
|
||||
};
|
||||
|
||||
/// A widget that can be filled with text by using a keyboard.
|
||||
/// A field that can be filled with text.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::{text_input, TextInput};
|
||||
/// #
|
||||
/// enum Message {
|
||||
/// TextInputChanged(String),
|
||||
/// }
|
||||
///
|
||||
/// let mut state = text_input::State::new();
|
||||
/// let value = "Some text";
|
||||
///
|
||||
/// let input = TextInput::new(
|
||||
/// &mut state,
|
||||
/// "This is the placeholder...",
|
||||
/// value,
|
||||
/// Message::TextInputChanged,
|
||||
/// );
|
||||
/// ```
|
||||
pub struct TextInput<'a, Message> {
|
||||
state: &'a mut State,
|
||||
placeholder: String,
|
||||
|
|
@ -26,7 +45,14 @@ pub struct TextInput<'a, Message> {
|
|||
impl<'a, Message> TextInput<'a, Message> {
|
||||
/// Creates a new [`TextInput`].
|
||||
///
|
||||
/// It expects:
|
||||
/// - some [`State`]
|
||||
/// - a placeholder
|
||||
/// - the current value
|
||||
/// - a function that produces a message when the [`TextInput`] changes
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
/// [`State`]: struct.State.html
|
||||
pub fn new<F>(
|
||||
state: &'a mut State,
|
||||
placeholder: &str,
|
||||
|
|
@ -232,9 +258,32 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The renderer of a [`TextInput`].
|
||||
///
|
||||
/// Your [renderer] will need to implement this trait before being
|
||||
/// able to use a [`TextInput`] in your user interface.
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
/// [renderer]: ../../renderer/index.html
|
||||
pub trait Renderer: crate::Renderer + Sized {
|
||||
/// Returns the default size of the text of the [`TextInput`].
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
fn default_size(&self) -> u16;
|
||||
|
||||
/// Draws a [`TextInput`].
|
||||
///
|
||||
/// It receives:
|
||||
/// - its bounds of the [`TextInput`]
|
||||
/// - the bounds of the text (i.e. the current value)
|
||||
/// - the cursor position
|
||||
/// - the placeholder to show when the value is empty
|
||||
/// - the current [`Value`]
|
||||
/// - the current [`State`]
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
/// [`Value`]: struct.Value.html
|
||||
/// [`State`]: struct.State.html
|
||||
fn draw(
|
||||
&mut self,
|
||||
bounds: Rectangle,
|
||||
|
|
@ -289,6 +338,9 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns whether the [`TextInput`] is currently focused or not.
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
pub fn is_focused(&self) -> bool {
|
||||
self.is_focused
|
||||
}
|
||||
|
|
@ -303,7 +355,7 @@ impl State {
|
|||
/// Moves the cursor of a [`TextInput`] to the right.
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
pub fn move_cursor_right(&mut self, value: &Value) {
|
||||
pub(crate) fn move_cursor_right(&mut self, value: &Value) {
|
||||
let current = self.cursor_position(value);
|
||||
|
||||
if current < value.len() {
|
||||
|
|
@ -314,7 +366,7 @@ impl State {
|
|||
/// Moves the cursor of a [`TextInput`] to the left.
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
pub fn move_cursor_left(&mut self, value: &Value) {
|
||||
pub(crate) fn move_cursor_left(&mut self, value: &Value) {
|
||||
let current = self.cursor_position(value);
|
||||
|
||||
if current > 0 {
|
||||
|
|
@ -325,7 +377,7 @@ impl State {
|
|||
/// Moves the cursor of a [`TextInput`] to the end.
|
||||
///
|
||||
/// [`TextInput`]: struct.TextInput.html
|
||||
pub fn move_cursor_to_end(&mut self, value: &Value) {
|
||||
pub(crate) fn move_cursor_to_end(&mut self, value: &Value) {
|
||||
self.cursor_position = value.len();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue