feat(list_column): button list items
This commit is contained in:
parent
9cac422c24
commit
9b465a8b5c
6 changed files with 298 additions and 163 deletions
|
|
@ -27,7 +27,7 @@ pub enum Button {
|
||||||
IconVertical,
|
IconVertical,
|
||||||
Image,
|
Image,
|
||||||
Link,
|
Link,
|
||||||
ListItem,
|
ListItem([f32; 4]),
|
||||||
MenuFolder,
|
MenuFolder,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
MenuRoot,
|
MenuRoot,
|
||||||
|
|
@ -148,8 +148,8 @@ pub fn appearance(
|
||||||
appearance.text_color = Some(component.on.into());
|
appearance.text_color = Some(component.on.into());
|
||||||
corner_radii = &cosmic.corner_radii.radius_s;
|
corner_radii = &cosmic.corner_radii.radius_s;
|
||||||
}
|
}
|
||||||
Button::ListItem => {
|
Button::ListItem(radii) => {
|
||||||
corner_radii = &[0.0; 4];
|
corner_radii = radii;
|
||||||
let (background, text, icon) = color(&cosmic.background.component);
|
let (background, text, icon) = color(&cosmic.background.component);
|
||||||
|
|
||||||
if selected {
|
if selected {
|
||||||
|
|
@ -197,7 +197,7 @@ impl Catalog for crate::Theme {
|
||||||
return active(focused, self);
|
return active(focused, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
appearance(self, focused, selected, false, style, move |component| {
|
let mut s = appearance(self, focused, selected, false, style, move |component| {
|
||||||
let text_color = if matches!(
|
let text_color = if matches!(
|
||||||
style,
|
style,
|
||||||
Button::Icon | Button::IconVertical | Button::HeaderBar
|
Button::Icon | Button::IconVertical | Button::HeaderBar
|
||||||
|
|
@ -209,7 +209,15 @@ impl Catalog for crate::Theme {
|
||||||
};
|
};
|
||||||
|
|
||||||
(component.base.into(), text_color, text_color)
|
(component.base.into(), text_color, text_color)
|
||||||
})
|
});
|
||||||
|
|
||||||
|
if let Button::ListItem(_) = style {
|
||||||
|
if !selected {
|
||||||
|
s.background = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disabled(&self, style: &Self::Class) -> Style {
|
fn disabled(&self, style: &Self::Class) -> Style {
|
||||||
|
|
@ -237,7 +245,7 @@ impl Catalog for crate::Theme {
|
||||||
return hovered(focused, self);
|
return hovered(focused, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
appearance(
|
let mut s = appearance(
|
||||||
self,
|
self,
|
||||||
focused || matches!(style, Button::Image),
|
focused || matches!(style, Button::Image),
|
||||||
selected,
|
selected,
|
||||||
|
|
@ -256,7 +264,15 @@ impl Catalog for crate::Theme {
|
||||||
|
|
||||||
(component.hover.into(), text_color, text_color)
|
(component.hover.into(), text_color, text_color)
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
|
if let Button::ListItem(_) = style {
|
||||||
|
if !selected {
|
||||||
|
s.background = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pressed(&self, focused: bool, selected: bool, style: &Self::Class) -> Style {
|
fn pressed(&self, focused: bool, selected: bool, style: &Self::Class) -> Style {
|
||||||
|
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
// Copyright 2022 System76 <info@system76.com>
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
use iced_core::Padding;
|
|
||||||
use iced_widget::container::Catalog;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
Apply, Element, theme,
|
|
||||||
widget::{container, divider, space::vertical},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn list_column<'a, Message: 'static>() -> ListColumn<'a, Message> {
|
|
||||||
ListColumn::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub struct ListColumn<'a, Message> {
|
|
||||||
spacing: u16,
|
|
||||||
padding: Padding,
|
|
||||||
list_item_padding: Padding,
|
|
||||||
divider_padding: u16,
|
|
||||||
style: theme::Container<'a>,
|
|
||||||
children: Vec<Element<'a, Message>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Message: 'static> Default for ListColumn<'_, Message> {
|
|
||||||
fn default() -> Self {
|
|
||||||
let cosmic_theme::Spacing {
|
|
||||||
space_xxs, space_m, ..
|
|
||||||
} = theme::spacing();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
spacing: 0,
|
|
||||||
padding: Padding::from(0),
|
|
||||||
divider_padding: 16,
|
|
||||||
list_item_padding: [space_xxs, space_m].into(),
|
|
||||||
style: theme::Container::List,
|
|
||||||
children: Vec::with_capacity(4),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message: 'static> ListColumn<'a, Message> {
|
|
||||||
#[inline]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::should_implement_trait)]
|
|
||||||
pub fn add(self, item: impl Into<Element<'a, Message>>) -> Self {
|
|
||||||
#[inline(never)]
|
|
||||||
fn inner<'a, Message: 'static>(
|
|
||||||
mut this: ListColumn<'a, Message>,
|
|
||||||
item: Element<'a, Message>,
|
|
||||||
) -> ListColumn<'a, Message> {
|
|
||||||
if !this.children.is_empty() {
|
|
||||||
this.children.push(
|
|
||||||
container(divider::horizontal::default())
|
|
||||||
.padding([0, this.divider_padding])
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure a minimum height of 32.
|
|
||||||
let list_item = crate::widget::row![
|
|
||||||
container(item).align_y(iced::Alignment::Center),
|
|
||||||
vertical().height(iced::Length::Fixed(32.))
|
|
||||||
]
|
|
||||||
.padding(this.list_item_padding)
|
|
||||||
.align_y(iced::Alignment::Center);
|
|
||||||
|
|
||||||
this.children.push(list_item.into());
|
|
||||||
this
|
|
||||||
}
|
|
||||||
|
|
||||||
inner(self, item.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn spacing(mut self, spacing: u16) -> Self {
|
|
||||||
self.spacing = spacing;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the style variant of this [`Circular`].
|
|
||||||
#[inline]
|
|
||||||
pub fn style(mut self, style: <crate::Theme as Catalog>::Class<'a>) -> Self {
|
|
||||||
self.style = style;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
|
|
||||||
self.padding = padding.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn divider_padding(mut self, padding: u16) -> Self {
|
|
||||||
self.divider_padding = padding;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_item_padding(mut self, padding: impl Into<Padding>) -> Self {
|
|
||||||
self.list_item_padding = padding.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn into_element(self) -> Element<'a, Message> {
|
|
||||||
crate::widget::column::with_children(self.children)
|
|
||||||
.spacing(self.spacing)
|
|
||||||
.padding(self.padding)
|
|
||||||
.width(iced::Length::Fill)
|
|
||||||
.apply(container)
|
|
||||||
.padding([self.spacing, 0])
|
|
||||||
.class(self.style)
|
|
||||||
.width(iced::Length::Fill)
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message: 'static> From<ListColumn<'a, Message>> for Element<'a, Message> {
|
|
||||||
fn from(column: ListColumn<'a, Message>) -> Self {
|
|
||||||
column.into_element()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
188
src/widget/list/list_column.rs
Normal file
188
src/widget/list/list_column.rs
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
// Copyright 2022 System76 <info@system76.com>
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use crate::widget::container::Catalog;
|
||||||
|
use crate::widget::{button, column, container, divider, row, space::vertical};
|
||||||
|
use crate::{Apply, Element, theme};
|
||||||
|
use iced::{Length, Padding};
|
||||||
|
|
||||||
|
/// A button list item for use in a [`ListColumn`].
|
||||||
|
pub struct ListButton<'a, Message> {
|
||||||
|
content: Element<'a, Message>,
|
||||||
|
on_press: Option<Message>,
|
||||||
|
selected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`ListButton`] with the given content.
|
||||||
|
pub fn button<'a, Message>(content: impl Into<Element<'a, Message>>) -> ListButton<'a, Message> {
|
||||||
|
ListButton {
|
||||||
|
content: content.into(),
|
||||||
|
on_press: None,
|
||||||
|
selected: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message: 'static> ListButton<'a, Message> {
|
||||||
|
pub fn on_press(mut self, on_press: Message) -> Self {
|
||||||
|
self.on_press = Some(on_press);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_press_maybe(mut self, on_press: Option<Message>) -> Self {
|
||||||
|
self.on_press = on_press;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn selected(mut self, selected: bool) -> Self {
|
||||||
|
self.selected = selected;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ListItem<'a, Message> {
|
||||||
|
Element(Element<'a, Message>),
|
||||||
|
Button(ListButton<'a, Message>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait for types that can be added to a [`ListColumn`].
|
||||||
|
pub trait IntoListItem<'a, Message> {
|
||||||
|
fn into_list_item(self) -> ListItem<'a, Message>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message, T> IntoListItem<'a, Message> for T
|
||||||
|
where
|
||||||
|
T: Into<Element<'a, Message>>,
|
||||||
|
{
|
||||||
|
fn into_list_item(self) -> ListItem<'a, Message> {
|
||||||
|
ListItem::Element(self.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message> IntoListItem<'a, Message> for ListButton<'a, Message> {
|
||||||
|
fn into_list_item(self) -> ListItem<'a, Message> {
|
||||||
|
ListItem::Button(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub struct ListColumn<'a, Message> {
|
||||||
|
list_item_padding: Padding,
|
||||||
|
style: theme::Container<'a>,
|
||||||
|
children: Vec<ListItem<'a, Message>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn list_column<'a, Message: 'static>() -> ListColumn<'a, Message> {
|
||||||
|
ListColumn::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_capacity<'a, Message: 'static>(capacity: usize) -> ListColumn<'a, Message> {
|
||||||
|
let cosmic_theme::Spacing {
|
||||||
|
space_xxs, space_m, ..
|
||||||
|
} = theme::spacing();
|
||||||
|
|
||||||
|
ListColumn {
|
||||||
|
list_item_padding: [space_xxs, space_m].into(),
|
||||||
|
style: theme::Container::List,
|
||||||
|
children: Vec::with_capacity(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message: 'static> Default for ListColumn<'_, Message> {
|
||||||
|
fn default() -> Self {
|
||||||
|
with_capacity(4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message: Clone + 'static> ListColumn<'a, Message> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds an element to the list column.
|
||||||
|
#[allow(clippy::should_implement_trait)]
|
||||||
|
pub fn add(mut self, item: impl IntoListItem<'a, Message>) -> Self {
|
||||||
|
self.children.push(item.into_list_item());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the style variant of this [`ListColumn`].
|
||||||
|
#[inline]
|
||||||
|
pub fn style(mut self, style: <crate::Theme as Catalog>::Class<'a>) -> Self {
|
||||||
|
self.style = style;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_item_padding(mut self, padding: impl Into<Padding>) -> Self {
|
||||||
|
self.list_item_padding = padding.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn into_element(self) -> Element<'a, Message> {
|
||||||
|
let padding = self.list_item_padding;
|
||||||
|
let count = self.children.len();
|
||||||
|
let last_index = count.saturating_sub(1);
|
||||||
|
let radius_s = theme::active().cosmic().radius_s();
|
||||||
|
|
||||||
|
// Ensure minimum height of 32
|
||||||
|
let content_row = |content| {
|
||||||
|
row![container(content), vertical().height(32)].align_y(iced::Alignment::Center)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.children
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.fold(
|
||||||
|
column::with_capacity((2 * count).saturating_sub(1)),
|
||||||
|
|mut col, (i, item)| {
|
||||||
|
if i > 0 {
|
||||||
|
col = col.push(divider::horizontal::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
match item {
|
||||||
|
ListItem::Element(content) => {
|
||||||
|
col.push(content_row(content).padding(padding).width(Length::Fill))
|
||||||
|
}
|
||||||
|
ListItem::Button(ListButton {
|
||||||
|
content,
|
||||||
|
on_press,
|
||||||
|
selected,
|
||||||
|
}) => col.push(
|
||||||
|
content_row(content)
|
||||||
|
.apply(button::custom)
|
||||||
|
.padding(padding)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.on_press_maybe(on_press)
|
||||||
|
.selected(selected)
|
||||||
|
.class(theme::Button::ListItem(get_radius(
|
||||||
|
radius_s,
|
||||||
|
i == 0,
|
||||||
|
i == last_index,
|
||||||
|
))),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.width(Length::Fill)
|
||||||
|
.apply(container)
|
||||||
|
.class(self.style)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message: Clone + 'static> From<ListColumn<'a, Message>> for Element<'a, Message> {
|
||||||
|
fn from(column: ListColumn<'a, Message>) -> Self {
|
||||||
|
column.into_element()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_radius(radius: [f32; 4], first: bool, last: bool) -> [f32; 4] {
|
||||||
|
match (first, last) {
|
||||||
|
(true, true) => radius,
|
||||||
|
(true, false) => [radius[0], radius[1], 0.0, 0.0],
|
||||||
|
(false, true) => [0.0, 0.0, radius[2], radius[3]],
|
||||||
|
(false, false) => [0.0, 0.0, 0.0, 0.0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2022 System76 <info@system76.com>
|
// Copyright 2022 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
pub mod column;
|
pub mod list_column;
|
||||||
|
|
||||||
pub use self::column::{ListColumn, list_column};
|
pub use self::list_column::{ListButton, ListColumn, button, list_column};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Element, Theme, theme,
|
Element, Theme, theme,
|
||||||
widget::{FlexRow, Row, column, container, flex_row, row, text},
|
widget::{FlexRow, Row, column, container, flex_row, list, row, text},
|
||||||
};
|
};
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use iced_core::{Length, text::Wrapping};
|
use iced_core::{Length, text::Wrapping};
|
||||||
|
|
@ -114,39 +114,95 @@ impl<'a, Message: 'static> Item<'a, Message> {
|
||||||
flex_item_row(self.control_(widget.into()))
|
flex_item_row(self.control_(widget.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
fn label(self) -> Element<'a, Message> {
|
||||||
fn control_(self, widget: Element<'a, Message>) -> Vec<Element<'a, Message>> {
|
|
||||||
let mut contents = Vec::with_capacity(4);
|
|
||||||
|
|
||||||
if let Some(icon) = self.icon {
|
|
||||||
contents.push(icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(description) = self.description {
|
if let Some(description) = self.description {
|
||||||
let column = column::with_capacity(2)
|
column::with_capacity(2)
|
||||||
.spacing(2)
|
.spacing(2)
|
||||||
.push(text::body(self.title).wrapping(Wrapping::Word))
|
.push(text::body(self.title).wrapping(Wrapping::Word))
|
||||||
.push(text::caption(description).wrapping(Wrapping::Word))
|
.push(text::caption(description).wrapping(Wrapping::Word))
|
||||||
.width(Length::Fill);
|
.width(Length::Fill)
|
||||||
|
.into()
|
||||||
contents.push(column.into());
|
|
||||||
} else {
|
} else {
|
||||||
contents.push(text(self.title).width(Length::Fill).into());
|
text(self.title).width(Length::Fill).into()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn control_(mut self, widget: Element<'a, Message>) -> Vec<Element<'a, Message>> {
|
||||||
|
let mut contents = Vec::with_capacity(3);
|
||||||
|
if let Some(icon) = self.icon.take() {
|
||||||
|
contents.push(icon);
|
||||||
|
}
|
||||||
|
contents.push(self.label());
|
||||||
contents.push(widget);
|
contents.push(widget);
|
||||||
contents
|
contents
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn control_start(self, widget: impl Into<Element<'a, Message>>) -> Row<'a, Message, Theme> {
|
||||||
|
item_row(vec![widget.into(), self.label()])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toggler(
|
pub fn toggler(
|
||||||
self,
|
self,
|
||||||
is_checked: bool,
|
is_checked: bool,
|
||||||
message: impl Fn(bool) -> Message + 'static,
|
message: impl Fn(bool) -> Message + 'static,
|
||||||
) -> Row<'a, Message, Theme> {
|
) -> list::ListButton<'a, Message> {
|
||||||
self.control(
|
let on_press = message(!is_checked);
|
||||||
crate::widget::toggler(is_checked)
|
list::button(
|
||||||
.width(Length::Shrink)
|
self.control(
|
||||||
.on_toggle(message),
|
crate::widget::toggler(is_checked)
|
||||||
|
.width(Length::Shrink)
|
||||||
|
.on_toggle(message),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
.on_press(on_press)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggler_maybe(
|
||||||
|
self,
|
||||||
|
is_checked: bool,
|
||||||
|
message: Option<impl Fn(bool) -> Message + 'static>,
|
||||||
|
) -> list::ListButton<'a, Message> {
|
||||||
|
let on_press = message.as_ref().map(|f| f(!is_checked));
|
||||||
|
list::button(
|
||||||
|
self.control(
|
||||||
|
crate::widget::toggler(is_checked)
|
||||||
|
.width(Length::Shrink)
|
||||||
|
.on_toggle_maybe(message),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.on_press_maybe(on_press)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkbox(
|
||||||
|
self,
|
||||||
|
is_checked: bool,
|
||||||
|
message: impl Fn(bool) -> Message + 'static,
|
||||||
|
) -> list::ListButton<'a, Message> {
|
||||||
|
let on_press = message(!is_checked);
|
||||||
|
list::button(
|
||||||
|
self.control_start(
|
||||||
|
crate::widget::checkbox(is_checked)
|
||||||
|
.width(Length::Shrink)
|
||||||
|
.on_toggle(message),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.on_press(on_press)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkbox_maybe(
|
||||||
|
self,
|
||||||
|
is_checked: bool,
|
||||||
|
message: Option<impl Fn(bool) -> Message + 'static>,
|
||||||
|
) -> list::ListButton<'a, Message> {
|
||||||
|
let on_press = message.as_ref().map(|f| f(!is_checked));
|
||||||
|
list::button(
|
||||||
|
self.control_start(
|
||||||
|
crate::widget::checkbox(is_checked)
|
||||||
|
.width(Length::Shrink)
|
||||||
|
.on_toggle_maybe(message),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.on_press_maybe(on_press)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,19 @@
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use crate::Element;
|
use crate::Element;
|
||||||
|
use crate::widget::list_column::IntoListItem;
|
||||||
use crate::widget::{ListColumn, column, text};
|
use crate::widget::{ListColumn, column, text};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
/// A section within a settings view column.
|
/// A section within a settings view column.
|
||||||
pub fn section<'a, Message: 'static>() -> Section<'a, Message> {
|
pub fn section<'a, Message: Clone + 'static>() -> Section<'a, Message> {
|
||||||
with_column(ListColumn::default())
|
with_column(ListColumn::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A section with a pre-defined list column.
|
/// A section with a pre-defined list column.
|
||||||
pub fn with_column<Message: 'static>(children: ListColumn<'_, Message>) -> Section<'_, Message> {
|
pub fn with_column<Message: Clone + 'static>(
|
||||||
|
children: ListColumn<'_, Message>,
|
||||||
|
) -> Section<'_, Message> {
|
||||||
Section {
|
Section {
|
||||||
header: None,
|
header: None,
|
||||||
children,
|
children,
|
||||||
|
|
@ -24,9 +27,9 @@ pub struct Section<'a, Message> {
|
||||||
children: ListColumn<'a, Message>,
|
children: ListColumn<'a, Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message: 'static> Section<'a, Message> {
|
impl<'a, Message: Clone + 'static> Section<'a, Message> {
|
||||||
/// Define an optional title for the section.
|
/// Define an optional title for the section.
|
||||||
pub fn title(mut self, title: impl Into<Cow<'a, str>>) -> Self {
|
pub fn title(self, title: impl Into<Cow<'a, str>>) -> Self {
|
||||||
self.header(text::heading(title.into()))
|
self.header(text::heading(title.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,8 +41,8 @@ impl<'a, Message: 'static> Section<'a, Message> {
|
||||||
|
|
||||||
/// Add a child element to the section's list column.
|
/// Add a child element to the section's list column.
|
||||||
#[allow(clippy::should_implement_trait)]
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn add(mut self, item: impl Into<Element<'a, Message>>) -> Self {
|
pub fn add(mut self, item: impl IntoListItem<'a, Message>) -> Self {
|
||||||
self.children = self.children.add(item.into());
|
self.children = self.children.add(item);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +64,7 @@ impl<'a, Message: 'static> Section<'a, Message> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message: 'static> From<Section<'a, Message>> for Element<'a, Message> {
|
impl<'a, Message: Clone + 'static> From<Section<'a, Message>> for Element<'a, Message> {
|
||||||
fn from(data: Section<'a, Message>) -> Self {
|
fn from(data: Section<'a, Message>) -> Self {
|
||||||
column::with_capacity(2)
|
column::with_capacity(2)
|
||||||
.spacing(8)
|
.spacing(8)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue