Merge branch 'master' into update-winit

This commit is contained in:
Héctor Ramón Jiménez 2024-01-16 12:02:42 +01:00
commit 534c7dd7b0
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
93 changed files with 1642 additions and 970 deletions

View file

@ -26,12 +26,11 @@ mod quad {
where
Renderer: renderer::Renderer,
{
fn width(&self) -> Length {
Length::Shrink
}
fn height(&self) -> Length {
Length::Shrink
fn size(&self) -> Size<Length> {
Size {
width: Length::Shrink,
height: Length::Shrink,
}
}
fn layout(

View file

@ -33,12 +33,11 @@ mod circle {
where
Renderer: renderer::Renderer,
{
fn width(&self) -> Length {
Length::Shrink
}
fn height(&self) -> Length {
Length::Shrink
fn size(&self) -> Size<Length> {
Size {
width: Length::Shrink,
height: Length::Shrink,
}
}
fn layout(

View file

@ -73,16 +73,15 @@ impl Application for Example {
}
fn view(&self) -> Element<Message> {
let downloads = Column::with_children(
self.downloads.iter().map(Download::view).collect(),
)
.push(
button("Add another download")
.on_press(Message::Add)
.padding(10),
)
.spacing(20)
.align_items(Alignment::End);
let downloads =
Column::with_children(self.downloads.iter().map(Download::view))
.push(
button("Add another download")
.on_press(Message::Add)
.padding(10),
)
.spacing(20)
.align_items(Alignment::End);
container(downloads)
.width(Length::Fill)

View file

@ -12,4 +12,4 @@ iced.features = ["highlighter", "tokio", "debug"]
tokio.workspace = true
tokio.features = ["fs"]
rfd = "0.12"
rfd = "0.13"

View file

@ -82,8 +82,7 @@ impl Application for Events {
self.last
.iter()
.map(|event| text(format!("{event:?}")).size(40))
.map(Element::from)
.collect(),
.map(Element::from),
);
let toggle = checkbox(

View file

@ -146,7 +146,8 @@ impl Application for GameOfLife {
.view()
.map(move |message| Message::Grid(message, version)),
controls,
];
]
.height(Length::Fill);
container(content)
.width(Length::Fill)
@ -178,7 +179,6 @@ fn view_controls<'a>(
slider(1.0..=1000.0, speed as f32, Message::SpeedChanged),
text(format!("x{speed}")).size(16),
]
.width(Length::Fill)
.align_items(Alignment::Center)
.spacing(10);

View file

@ -16,12 +16,11 @@ mod rainbow {
}
impl<Message> Widget<Message, Renderer> for Rainbow {
fn width(&self) -> Length {
Length::Fill
}
fn height(&self) -> Length {
Length::Shrink
fn size(&self) -> Size<Length> {
Size {
width: Length::Fill,
height: Length::Shrink,
}
}
fn layout(
@ -30,9 +29,9 @@ mod rainbow {
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
let size = limits.width(Length::Fill).resolve(Size::ZERO);
let width = limits.max().width;
layout::Node::new(Size::new(size.width, size.width))
layout::Node::new(Size::new(width, width))
}
fn draw(

View file

@ -81,32 +81,25 @@ impl Program for Controls {
);
Row::new()
.width(Length::Fill)
.height(Length::Fill)
.align_items(Alignment::End)
.push(
Column::new()
.width(Length::Fill)
.align_items(Alignment::End)
.push(
Column::new()
.padding(10)
.spacing(10)
.push(
Text::new("Background color")
.style(Color::WHITE),
)
.push(sliders)
.push(
Text::new(format!("{background_color:?}"))
.size(14)
.style(Color::WHITE),
)
.push(
text_input("Placeholder", text)
.on_input(Message::TextChanged),
),
),
Column::new().align_items(Alignment::End).push(
Column::new()
.padding(10)
.spacing(10)
.push(Text::new("Background color").style(Color::WHITE))
.push(sliders)
.push(
Text::new(format!("{background_color:?}"))
.size(14)
.style(Color::WHITE),
)
.push(
text_input("Placeholder", text)
.on_input(Message::TextChanged),
),
),
)
.into()
}

View file

@ -0,0 +1,9 @@
[package]
name = "layout"
version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
publish = false
[dependencies]
iced = { path = "../..", features = ["canvas"] }

367
examples/layout/src/main.rs Normal file
View file

@ -0,0 +1,367 @@
use iced::executor;
use iced::keyboard;
use iced::mouse;
use iced::theme;
use iced::widget::{
button, canvas, checkbox, column, container, horizontal_space, pick_list,
row, scrollable, text, vertical_rule,
};
use iced::{
color, Alignment, Application, Color, Command, Element, Font, Length,
Point, Rectangle, Renderer, Settings, Subscription, Theme,
};
pub fn main() -> iced::Result {
Layout::run(Settings::default())
}
#[derive(Debug)]
struct Layout {
example: Example,
explain: bool,
theme: Theme,
}
#[derive(Debug, Clone)]
enum Message {
Next,
Previous,
ExplainToggled(bool),
ThemeSelected(Theme),
}
impl Application for Layout {
type Message = Message;
type Theme = Theme;
type Executor = executor::Default;
type Flags = ();
fn new(_flags: Self::Flags) -> (Self, Command<Message>) {
(
Self {
example: Example::default(),
explain: false,
theme: Theme::Light,
},
Command::none(),
)
}
fn title(&self) -> String {
format!("{} - Layout - Iced", self.example.title)
}
fn update(&mut self, message: Self::Message) -> Command<Message> {
match message {
Message::Next => {
self.example = self.example.next();
}
Message::Previous => {
self.example = self.example.previous();
}
Message::ExplainToggled(explain) => {
self.explain = explain;
}
Message::ThemeSelected(theme) => {
self.theme = theme;
}
}
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
keyboard::on_key_release(|key_code, _modifiers| match key_code {
keyboard::KeyCode::Left => Some(Message::Previous),
keyboard::KeyCode::Right => Some(Message::Next),
_ => None,
})
}
fn view(&self) -> Element<Message> {
let header = row![
text(self.example.title).size(20).font(Font::MONOSPACE),
horizontal_space(Length::Fill),
checkbox("Explain", self.explain, Message::ExplainToggled),
pick_list(
Theme::ALL,
Some(self.theme.clone()),
Message::ThemeSelected
),
]
.spacing(20)
.align_items(Alignment::Center);
let example = container(if self.explain {
self.example.view().explain(color!(0x0000ff))
} else {
self.example.view()
})
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Appearance::default()
.with_border(palette.background.strong.color, 4.0)
})
.padding(4)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y();
let controls = row([
(!self.example.is_first()).then_some(
button("← Previous")
.padding([5, 10])
.on_press(Message::Previous)
.into(),
),
Some(horizontal_space(Length::Fill).into()),
(!self.example.is_last()).then_some(
button("Next →")
.padding([5, 10])
.on_press(Message::Next)
.into(),
),
]
.into_iter()
.flatten());
column![header, example, controls]
.spacing(10)
.padding(20)
.into()
}
fn theme(&self) -> Theme {
self.theme.clone()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Example {
title: &'static str,
view: fn() -> Element<'static, Message>,
}
impl Example {
const LIST: &'static [Self] = &[
Self {
title: "Centered",
view: centered,
},
Self {
title: "Column",
view: column_,
},
Self {
title: "Row",
view: row_,
},
Self {
title: "Space",
view: space,
},
Self {
title: "Application",
view: application,
},
Self {
title: "Nested Quotes",
view: nested_quotes,
},
];
fn is_first(self) -> bool {
Self::LIST.first() == Some(&self)
}
fn is_last(self) -> bool {
Self::LIST.last() == Some(&self)
}
fn previous(self) -> Self {
let Some(index) =
Self::LIST.iter().position(|&example| example == self)
else {
return self;
};
Self::LIST
.get(index.saturating_sub(1))
.copied()
.unwrap_or(self)
}
fn next(self) -> Self {
let Some(index) =
Self::LIST.iter().position(|&example| example == self)
else {
return self;
};
Self::LIST.get(index + 1).copied().unwrap_or(self)
}
fn view(&self) -> Element<Message> {
(self.view)()
}
}
impl Default for Example {
fn default() -> Self {
Self::LIST[0]
}
}
fn centered<'a>() -> Element<'a, Message> {
container(text("I am centered!").size(50))
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
fn column_<'a>() -> Element<'a, Message> {
column![
"A column can be used to",
"lay out widgets vertically.",
square(50),
square(50),
square(50),
"The amount of space between",
"elements can be configured!",
]
.spacing(40)
.into()
}
fn row_<'a>() -> Element<'a, Message> {
row![
"A row works like a column...",
square(50),
square(50),
square(50),
"but lays out widgets horizontally!",
]
.spacing(40)
.into()
}
fn space<'a>() -> Element<'a, Message> {
row!["Left!", horizontal_space(Length::Fill), "Right!"].into()
}
fn application<'a>() -> Element<'a, Message> {
let header = container(
row![
square(40),
horizontal_space(Length::Fill),
"Header!",
horizontal_space(Length::Fill),
square(40),
]
.padding(10)
.align_items(Alignment::Center),
)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Appearance::default()
.with_border(palette.background.strong.color, 1)
});
let sidebar = container(
column!["Sidebar!", square(50), square(50)]
.spacing(40)
.padding(10)
.width(200)
.align_items(Alignment::Center),
)
.style(theme::Container::Box)
.height(Length::Fill)
.center_y();
let content = container(
scrollable(
column![
"Content!",
square(400),
square(200),
square(400),
"The end"
]
.spacing(40)
.align_items(Alignment::Center)
.width(Length::Fill),
)
.height(Length::Fill),
)
.padding(10);
column![header, row![sidebar, content]].into()
}
fn nested_quotes<'a>() -> Element<'a, Message> {
(1..5)
.fold(column![text("Original text")].padding(10), |quotes, i| {
column![
container(
row![vertical_rule(2), quotes].height(Length::Shrink)
)
.style(|theme: &Theme| {
let palette = theme.extended_palette();
container::Appearance::default().with_background(
if palette.is_dark {
Color {
a: 0.01,
..Color::WHITE
}
} else {
Color {
a: 0.08,
..Color::BLACK
}
},
)
}),
text(format!("Reply {i}"))
]
.spacing(10)
.padding(10)
})
.into()
}
fn square<'a>(size: impl Into<Length> + Copy) -> Element<'a, Message> {
struct Square;
impl canvas::Program<Message> for Square {
type State = ();
fn draw(
&self,
_state: &Self::State,
renderer: &Renderer,
theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<canvas::Geometry> {
let mut frame = canvas::Frame::new(renderer, bounds.size());
let palette = theme.extended_palette();
frame.fill_rectangle(
Point::ORIGIN,
bounds.size(),
palette.background.strong.color,
);
vec![frame.into_geometry()]
}
}
canvas(Square).width(size).height(size).into()
}

View file

@ -178,35 +178,23 @@ impl Sandbox for App {
}
});
column(
items
.into_iter()
.map(|item| {
let button = button("Delete")
.on_press(Message::DeleteItem(item.clone()))
.style(theme::Button::Destructive);
column(items.into_iter().map(|item| {
let button = button("Delete")
.on_press(Message::DeleteItem(item.clone()))
.style(theme::Button::Destructive);
row![
text(&item.name)
.style(theme::Text::Color(item.color.into())),
horizontal_space(Length::Fill),
pick_list(
Color::ALL,
Some(item.color),
move |color| {
Message::ItemColorChanged(
item.clone(),
color,
)
}
),
button
]
.spacing(20)
.into()
})
.collect(),
)
row![
text(&item.name)
.style(theme::Text::Color(item.color.into())),
horizontal_space(Length::Fill),
pick_list(Color::ALL, Some(item.color), move |color| {
Message::ItemColorChanged(item.clone(), color)
}),
button
]
.spacing(20)
.into()
}))
.spacing(10)
});

View file

@ -244,12 +244,11 @@ where
tree::State::new(State::default())
}
fn width(&self) -> Length {
Length::Fixed(self.size)
}
fn height(&self) -> Length {
Length::Fixed(self.size)
fn size(&self) -> Size<Length> {
Size {
width: Length::Fixed(self.size),
height: Length::Fixed(self.size),
}
}
fn layout(
@ -258,10 +257,7 @@ where
_renderer: &iced::Renderer<Theme>,
limits: &layout::Limits,
) -> layout::Node {
let limits = limits.width(self.size).height(self.size);
let size = limits.resolve(Size::ZERO);
layout::Node::new(size)
layout::atomic(limits, self.size, self.size)
}
fn on_event(

View file

@ -165,12 +165,11 @@ where
tree::State::new(State::default())
}
fn width(&self) -> Length {
self.width
}
fn height(&self) -> Length {
self.height
fn size(&self) -> Size<Length> {
Size {
width: self.width,
height: self.height,
}
}
fn layout(
@ -179,10 +178,7 @@ where
_renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
let limits = limits.width(self.width).height(self.height);
let size = limits.resolve(Size::ZERO);
layout::Node::new(size)
layout::atomic(limits, self.width, self.height)
}
fn on_event(

View file

@ -96,15 +96,14 @@ impl Application for LoadingSpinners {
container(
column.push(
row(vec![
text("Cycle duration:").into(),
row![
text("Cycle duration:"),
slider(1.0..=1000.0, self.cycle_duration * 100.0, |x| {
Message::CycleDurationChanged(x / 100.0)
})
.width(200.0)
.into(),
text(format!("{:.2}s", self.cycle_duration)).into(),
])
.width(200.0),
text(format!("{:.2}s", self.cycle_duration)),
]
.align_items(iced::Alignment::Center)
.spacing(20.0),
),

View file

@ -282,12 +282,8 @@ mod modal {
tree.diff_children(&[&self.base, &self.modal]);
}
fn width(&self) -> Length {
self.base.as_widget().width()
}
fn height(&self) -> Length {
self.base.as_widget().height()
fn size(&self) -> Size<Length> {
self.base.as_widget().size()
}
fn layout(
@ -421,17 +417,14 @@ mod modal {
.width(Length::Fill)
.height(Length::Fill);
let mut child = self
let child = self
.content
.as_widget()
.layout(self.tree, renderer, &limits);
.layout(self.tree, renderer, &limits)
.align(Alignment::Center, Alignment::Center, limits.max());
child.align(Alignment::Center, Alignment::Center, limits.max());
let mut node = layout::Node::with_children(self.size, vec![child]);
node.move_to(position);
node
layout::Node::with_children(self.size, vec![child])
.move_to(position)
}
fn on_event(

View file

@ -297,7 +297,6 @@ fn view_content<'a>(
text(format!("{}x{}", size.width, size.height)).size(24),
controls,
]
.width(Length::Fill)
.spacing(10)
.align_items(Alignment::Center);

View file

@ -1,4 +1,4 @@
use iced::widget::{column, container, pick_list, scrollable, vertical_space};
use iced::widget::{column, pick_list, scrollable, vertical_space};
use iced::{Alignment, Element, Length, Sandbox, Settings};
pub fn main() -> iced::Result {
@ -52,12 +52,7 @@ impl Sandbox for Example {
.align_items(Alignment::Center)
.spacing(10);
container(scrollable(content))
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
scrollable(content).into()
}
}

View file

@ -147,63 +147,54 @@ impl Application for ScrollableDemo {
text("Scroller width:"),
scroller_width_slider,
]
.spacing(10)
.width(Length::Fill);
.spacing(10);
let scroll_orientation_controls = column(vec![
text("Scrollbar direction:").into(),
let scroll_orientation_controls = column![
text("Scrollbar direction:"),
radio(
"Vertical",
Direction::Vertical,
Some(self.scrollable_direction),
Message::SwitchDirection,
)
.into(),
),
radio(
"Horizontal",
Direction::Horizontal,
Some(self.scrollable_direction),
Message::SwitchDirection,
)
.into(),
),
radio(
"Both!",
Direction::Multi,
Some(self.scrollable_direction),
Message::SwitchDirection,
)
.into(),
])
.spacing(10)
.width(Length::Fill);
),
]
.spacing(10);
let scroll_alignment_controls = column(vec![
text("Scrollable alignment:").into(),
let scroll_alignment_controls = column![
text("Scrollable alignment:"),
radio(
"Start",
scrollable::Alignment::Start,
Some(self.alignment),
Message::AlignmentChanged,
)
.into(),
),
radio(
"End",
scrollable::Alignment::End,
Some(self.alignment),
Message::AlignmentChanged,
)
.into(),
])
.spacing(10)
.width(Length::Fill);
]
.spacing(10);
let scroll_controls = row![
scroll_slider_controls,
scroll_orientation_controls,
scroll_alignment_controls
]
.spacing(20)
.width(Length::Fill);
.spacing(20);
let scroll_to_end_button = || {
button("Scroll to end")
@ -229,11 +220,11 @@ impl Application for ScrollableDemo {
text("End!"),
scroll_to_beginning_button(),
]
.width(Length::Fill)
.align_items(Alignment::Center)
.padding([40, 0, 40, 0])
.spacing(40),
)
.width(Length::Fill)
.height(Length::Fill)
.direction(scrollable::Direction::Vertical(
Properties::new()
@ -259,6 +250,7 @@ impl Application for ScrollableDemo {
.padding([0, 40, 0, 40])
.spacing(40),
)
.width(Length::Fill)
.height(Length::Fill)
.direction(scrollable::Direction::Horizontal(
Properties::new()
@ -301,6 +293,7 @@ impl Application for ScrollableDemo {
.padding([0, 40, 0, 40])
.spacing(40),
)
.width(Length::Fill)
.height(Length::Fill)
.direction({
let properties = Properties::new()
@ -341,20 +334,11 @@ impl Application for ScrollableDemo {
let content: Element<Message> =
column![scroll_controls, scrollable_content, progress_bars]
.width(Length::Fill)
.height(Length::Fill)
.align_items(Alignment::Center)
.spacing(10)
.into();
Element::from(
container(content)
.width(Length::Fill)
.height(Length::Fill)
.padding(40)
.center_x()
.center_y(),
)
container(content).padding(20).center_x().center_y().into()
}
fn theme(&self) -> Self::Theme {

View file

@ -79,12 +79,10 @@ impl Application for SierpinskiEmulator {
row![
text(format!("Iteration: {:?}", self.graph.iteration)),
slider(0..=10000, self.graph.iteration, Message::IterationSet)
.width(Length::Fill)
]
.padding(10)
.spacing(20),
]
.width(Length::Fill)
.align_items(iced::Alignment::Center)
.into()
}

View file

@ -53,13 +53,16 @@ impl Sandbox for Styling {
self.theme = match theme {
ThemeType::Light => Theme::Light,
ThemeType::Dark => Theme::Dark,
ThemeType::Custom => Theme::custom(theme::Palette {
background: Color::from_rgb(1.0, 0.9, 1.0),
text: Color::BLACK,
primary: Color::from_rgb(0.5, 0.5, 0.0),
success: Color::from_rgb(0.0, 1.0, 0.0),
danger: Color::from_rgb(1.0, 0.0, 0.0),
}),
ThemeType::Custom => Theme::custom(
String::from("Custom"),
theme::Palette {
background: Color::from_rgb(1.0, 0.9, 1.0),
text: Color::BLACK,
primary: Color::from_rgb(0.5, 0.5, 0.0),
success: Color::from_rgb(0.0, 1.0, 0.0),
danger: Color::from_rgb(1.0, 0.0, 0.0),
},
),
}
}
Message::InputChanged(value) => self.input_value = value,
@ -104,10 +107,11 @@ impl Sandbox for Styling {
let progress_bar = progress_bar(0.0..=100.0, self.slider_value);
let scrollable = scrollable(
column!["Scroll me!", vertical_space(800), "You did it!"]
.width(Length::Fill),
)
let scrollable = scrollable(column![
"Scroll me!",
vertical_space(800),
"You did it!"
])
.width(Length::Fill)
.height(100);

View file

@ -63,7 +63,6 @@ impl Sandbox for Tiger {
container(apply_color_filter).width(Length::Fill).center_x()
]
.spacing(20)
.width(Length::Fill)
.height(Length::Fill),
)
.width(Length::Fill)

View file

@ -107,9 +107,7 @@ impl Application for App {
fn view<'a>(&'a self) -> Element<'a, Message> {
let subtitle = |title, content: Element<'a, Message>| {
column![text(title).size(14), content]
.width(Length::Fill)
.spacing(5)
column![text(title).size(14), content].spacing(5)
};
let mut add_toast = button("Add Toast");
@ -154,14 +152,11 @@ impl Application for App {
Message::Timeout
)
.step(1.0)
.width(Length::Fill)
]
.spacing(5)
.into()
),
column![add_toast]
.width(Length::Fill)
.align_items(Alignment::End)
column![add_toast].align_items(Alignment::End)
]
.spacing(10)
.max_width(200),
@ -319,12 +314,8 @@ mod toast {
}
impl<'a, Message> Widget<Message, Renderer> for Manager<'a, Message> {
fn width(&self) -> Length {
self.content.as_widget().width()
}
fn height(&self) -> Length {
self.content.as_widget().height()
fn size(&self) -> Size<Length> {
self.content.as_widget().size()
}
fn layout(
@ -514,14 +505,14 @@ mod toast {
position: Point,
_translation: Vector,
) -> layout::Node {
let limits = layout::Limits::new(Size::ZERO, bounds)
.width(Length::Fill)
.height(Length::Fill);
let limits = layout::Limits::new(Size::ZERO, bounds);
layout::flex::resolve(
layout::flex::Axis::Vertical,
renderer,
&limits,
Length::Fill,
Length::Fill,
10.into(),
10.0,
Alignment::End,

View file

@ -254,13 +254,7 @@ impl Application for Todos {
.spacing(20)
.max_width(800);
scrollable(
container(content)
.width(Length::Fill)
.padding(40)
.center_x(),
)
.into()
scrollable(container(content).padding(40).center_x()).into()
}
}
}
@ -472,7 +466,6 @@ fn empty_message(message: &str) -> Element<'_, Message> {
.horizontal_alignment(alignment::Horizontal::Center)
.style(Color::from([0.7, 0.7, 0.7])),
)
.width(Length::Fill)
.height(200)
.center_y()
.into()

View file

@ -509,7 +509,6 @@ impl<'a> Step {
)
})
.map(Element::from)
.collect()
)
.spacing(10)
]
@ -692,11 +691,7 @@ fn ferris<'a>(
}
fn button<'a, Message: Clone>(label: &str) -> Button<'a, Message> {
iced::widget::button(
text(label).horizontal_alignment(alignment::Horizontal::Center),
)
.padding(12)
.width(100)
iced::widget::button(text(label)).padding([12, 24])
}
fn color_slider<'a>(

View file

@ -3,7 +3,7 @@ mod echo;
use iced::alignment::{self, Alignment};
use iced::executor;
use iced::widget::{
button, column, container, row, scrollable, text, text_input, Column,
button, column, container, row, scrollable, text, text_input,
};
use iced::{
Application, Color, Command, Element, Length, Settings, Subscription, Theme,
@ -108,15 +108,9 @@ impl Application for WebSocket {
.into()
} else {
scrollable(
Column::with_children(
self.messages
.iter()
.cloned()
.map(text)
.map(Element::from)
.collect(),
column(
self.messages.iter().cloned().map(text).map(Element::from),
)
.width(Length::Fill)
.spacing(10),
)
.id(MESSAGE_LOG.clone())
@ -131,7 +125,7 @@ impl Application for WebSocket {
let mut button = button(
text("Send")
.height(Length::Fill)
.height(40)
.vertical_alignment(alignment::Vertical::Center),
)
.padding([0, 20]);
@ -149,7 +143,6 @@ impl Application for WebSocket {
};
column![message_log, new_message_input]
.width(Length::Fill)
.height(Length::Fill)
.padding(20)
.spacing(10)