chore: re-export iced row and column

This removes the custom row and column implementations and uses the iced ones directly.
This commit is contained in:
Vukašin Vojinović 2026-04-01 23:24:53 +02:00 committed by Michael Murphy
parent a9e0671075
commit fdf3369cea
20 changed files with 103 additions and 227 deletions

View file

@ -132,7 +132,7 @@ impl cosmic::Application for App {
fn view(&self) -> Element<'_, Self::Message> {
let show_about_button = widget::button::text("Show about").on_press(Message::ToggleAbout);
let centered = cosmic::widget::container(
widget::column()
widget::column::with_capacity(1)
.push(show_about_button)
.width(Length::Fill)
.height(Length::Shrink)

View file

@ -54,7 +54,7 @@ impl widget::menu::Action for Action {
/// Runs application with these settings
#[rustfmt::skip]
fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
@ -190,7 +190,7 @@ impl cosmic::Application for App {
.map_or("No page selected", String::as_str);
let centered = widget::container(
widget::column()
widget::column::with_capacity(5)
.push(widget::text::body(page_content))
.push(
widget::text_input::text_input("", &self.input_1)

View file

@ -85,8 +85,6 @@ impl cosmic::Application for App {
/// Creates a view after each update.
fn view(&self) -> Element<'_, Self::Message> {
let mut content = cosmic::widget::column().spacing(12);
let calendar = cosmic::widget::calendar(
&self.calendar_model,
|date| Message::DateSelected(date),
@ -95,9 +93,7 @@ impl cosmic::Application for App {
Weekday::Sunday,
);
content = content.push(calendar);
let centered = cosmic::widget::container(content)
let centered = cosmic::widget::container(calendar)
.width(iced::Length::Fill)
.height(iced::Length::Shrink)
.align_x(iced::Alignment::Center)

View file

@ -80,7 +80,7 @@ impl cosmic::Application for App {
/// Creates a view after each update.
fn view(&self) -> Element<'_, Self::Message> {
let mut content = cosmic::widget::column().spacing(12);
let mut content = cosmic::widget::column::with_capacity(self.images.len()).spacing(12);
for (id, image) in self.images.iter().enumerate() {
content = content.push(

View file

@ -64,7 +64,7 @@ impl cosmic::Application for App {
/// Creates a view after each update.
fn view(&self) -> Element<'_, Self::Message> {
widget::row().into()
widget::Row::new().into()
}
}

View file

@ -99,7 +99,9 @@ impl cosmic::Application for App {
let inline = cosmic::widget::inline_input("", &self.input).on_input(Message::Input);
let column = cosmic::widget::column().push(editable).push(inline);
let column = cosmic::widget::column::with_capacity(2)
.push(editable)
.push(inline);
let centered = cosmic::widget::container(column.width(200))
.width(iced::Length::Fill)

View file

@ -19,72 +19,6 @@ impl<Message: 'static> ElementExt for crate::Element<'_, Message> {
}
}
/// Additional methods for the [`Column`] and [`Row`] widgets.
pub trait CollectionWidget<'a, Message: 'a>:
Widget<Message, crate::Theme, crate::Renderer>
where
Self: Sized,
{
/// Moves all the elements of `other` into `self`, leaving `other` empty.
#[must_use]
fn append<E>(self, other: &mut Vec<E>) -> Self
where
E: Into<crate::Element<'a, Message>>;
/// Appends all elements in an iterator to the widget.
#[must_use]
fn extend<E>(mut self, iterator: impl Iterator<Item = E>) -> Self
where
E: Into<crate::Element<'a, Message>>,
{
for item in iterator {
self = self.push(item.into());
}
self
}
/// Pushes an element into the widget.
#[must_use]
fn push(self, element: impl Into<crate::Element<'a, Message>>) -> Self;
/// Conditionally pushes an element to the widget.
#[must_use]
fn push_maybe(self, element: Option<impl Into<crate::Element<'a, Message>>>) -> Self {
if let Some(element) = element {
self.push(element.into())
} else {
self
}
}
}
impl<'a, Message: 'a> CollectionWidget<'a, Message> for crate::widget::Column<'a, Message> {
fn append<E>(self, other: &mut Vec<E>) -> Self
where
E: Into<crate::Element<'a, Message>>,
{
self.extend(other.drain(..).map(Into::into))
}
fn push(self, element: impl Into<crate::Element<'a, Message>>) -> Self {
self.push(element)
}
}
impl<'a, Message: 'a> CollectionWidget<'a, Message> for crate::widget::Row<'a, Message> {
fn append<E>(self, other: &mut Vec<E>) -> Self
where
E: Into<crate::Element<'a, Message>>,
{
self.extend(other.drain(..).map(Into::into))
}
fn push(self, element: impl Into<crate::Element<'a, Message>>) -> Self {
self.push(element)
}
}
pub trait ColorExt {
/// Combines color with background to create appearance of transparency.
#[must_use]

View file

@ -47,32 +47,40 @@ pub struct About {
fn add_contributors(contributors: Vec<(&str, &str)>) -> Vec<(String, String)> {
contributors
.into_iter()
.map(|(name, email)| (name.to_string(), format!("mailto:{email}")))
.map(|(name, email)| (name.into(), format!("mailto:{email}")))
.collect()
}
macro_rules! set_contributors {
($field:ident, $doc:expr) => {
#[doc = $doc]
pub fn $field(mut self, contributors: impl Into<Vec<(&'a str, &'a str)>>) -> Self {
self.$field = add_contributors(contributors.into());
self
}
};
}
impl<'a> About {
set_contributors!(artists, "Artists who contributed to the application.");
set_contributors!(designers, "Designers who contributed to the application.");
set_contributors!(developers, "Developers who contributed to the application.");
set_contributors!(
documenters,
"Documenters who contributed to the application."
);
set_contributors!(
translators,
"Translators who contributed to the application."
);
/// Artists who contributed to the application.
pub fn artists(mut self, contributors: impl Into<Vec<(&'a str, &'a str)>>) -> Self {
self.artists = add_contributors(contributors.into());
self
}
/// Designers who contributed to the application.
pub fn designers(mut self, contributors: impl Into<Vec<(&'a str, &'a str)>>) -> Self {
self.designers = add_contributors(contributors.into());
self
}
/// Developers who contributed to the application.
pub fn developers(mut self, contributors: impl Into<Vec<(&'a str, &'a str)>>) -> Self {
self.developers = add_contributors(contributors.into());
self
}
/// Documenters who contributed to the application.
pub fn documenters(mut self, contributors: impl Into<Vec<(&'a str, &'a str)>>) -> Self {
self.documenters = add_contributors(contributors.into());
self
}
/// Translators who contributed to the application.
pub fn translators(mut self, contributors: impl Into<Vec<(&'a str, &'a str)>>) -> Self {
self.translators = add_contributors(contributors.into());
self
}
/// Links associated with the application.
pub fn links<K: Into<String>, V: Into<String>>(
@ -97,7 +105,7 @@ pub fn about<'a, Message: Clone + 'static>(
} = crate::theme::spacing();
let section_button = |name: &'a str, url: &'a str| -> Element<'a, Message> {
widget::row()
widget::row::with_capacity(3)
.push(widget::text(name))
.push(space::horizontal())
.push_maybe(
@ -158,7 +166,7 @@ pub fn about<'a, Message: Clone + 'static>(
let copyright = about.copyright.as_ref().map(widget::text::body);
let comments = about.comments.as_ref().map(widget::text::body);
widget::column()
widget::column::with_capacity(10)
.push_maybe(header)
.push_maybe(links_section)
.push_maybe(developers_section)

View file

@ -3,10 +3,7 @@
use super::{Builder, ButtonClass};
use crate::Element;
use crate::widget::{
icon::{self, Handle},
tooltip,
};
use crate::widget::{icon::Handle, tooltip};
use apply::Apply;
use iced_core::{Alignment, Length, Padding, font::Weight, text::LineHeight, widget::Id};
use std::borrow::Cow;
@ -133,7 +130,7 @@ impl<Message> Button<'_, Message> {
}
impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Message> {
fn from(mut builder: Button<'a, Message>) -> Element<'a, Message> {
fn from(builder: Button<'a, Message>) -> Element<'a, Message> {
let mut content = Vec::with_capacity(2);
content.push(

View file

@ -212,7 +212,7 @@ where
let content_list = column::with_children([
row::with_children([
column().push(date).push(day).into(),
column([date.into(), day.into()]).into(),
crate::widget::space::horizontal()
.width(Length::Fill)
.into(),

View file

@ -32,7 +32,7 @@ pub fn context_menu<'a, Message: 'static + Clone>(
content: content.into(),
context_menu: context_menu.map(|menus| {
vec![menu::Tree::with_children(
crate::Element::from(crate::widget::row::<'static, Message>()),
crate::Element::from(crate::widget::Row::new()),
menus,
)]
}),

View file

@ -243,10 +243,13 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
cursor: iced_core::mouse::Cursor,
viewport: &iced_core::Rectangle,
) {
for ((e, s), l) in self.elems().zip(&tree.children).zip(layout.children()) {
e.as_widget()
.draw(s, renderer, theme, style, l, cursor, viewport);
}
self.elems()
.zip(&tree.children)
.zip(layout.children())
.for_each(|((e, s), l)| {
e.as_widget()
.draw(s, renderer, theme, style, l, cursor, viewport);
});
}
fn update(
@ -260,14 +263,13 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
shell: &mut iced_core::Shell<'_, Message>,
viewport: &iced_core::Rectangle,
) {
for ((e, s), l) in self
.elems_mut()
self.elems_mut()
.zip(&mut state.children)
.zip(layout.children())
{
e.as_widget_mut()
.update(s, event, l, cursor, renderer, clipboard, shell, viewport);
}
.for_each(|((e, s), l)| {
e.as_widget_mut()
.update(s, event, l, cursor, renderer, clipboard, shell, viewport);
});
}
fn mouse_interaction(
@ -296,13 +298,12 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
renderer: &crate::Renderer,
operation: &mut dyn iced_core::widget::Operation<()>,
) {
for ((e, s), l) in self
.elems_mut()
self.elems_mut()
.zip(&mut state.children)
.zip(layout.children())
{
e.as_widget_mut().operate(s, l, renderer, operation);
}
.for_each(|((e, s), l)| {
e.as_widget_mut().operate(s, l, renderer, operation);
});
}
fn overlay<'b>(
@ -313,27 +314,13 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
viewport: &iced_core::Rectangle,
translation: Vector,
) -> Option<iced_core::overlay::Element<'b, Message, crate::Theme, crate::Renderer>> {
let mut layouts = layout.children();
let mut try_overlay = |elem: &'b mut Element<'a, Message>,
state: &'b mut tree::Tree|
-> Option<
iced_core::overlay::Element<'b, Message, crate::Theme, crate::Renderer>,
> {
elem.as_widget_mut()
.overlay(state, layouts.next()?, renderer, viewport, translation)
};
if let Some(center) = &mut self.center {
let (start_slice, end_center) = state.children.split_at_mut(1);
let (end_slice, center_slice) = end_center.split_at_mut(1);
try_overlay(&mut self.start, &mut start_slice[0])
.or_else(|| try_overlay(&mut self.end, &mut end_slice[0]))
.or_else(|| try_overlay(center, &mut center_slice[0]))
} else {
let (start_slice, end_slice) = state.children.split_at_mut(1);
try_overlay(&mut self.start, &mut start_slice[0])
.or_else(|| try_overlay(&mut self.end, &mut end_slice[0]))
}
self.elems_mut()
.zip(&mut state.children)
.zip(layout.children())
.find_map(|((e, s), l)| {
e.as_widget_mut()
.overlay(s, l, renderer, viewport, translation)
})
}
fn drag_destinations(
@ -343,10 +330,13 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
renderer: &crate::Renderer,
dnd_rectangles: &mut iced_core::clipboard::DndDestinationRectangles,
) {
for ((e, s), l) in self.elems().zip(&state.children).zip(layout.children()) {
e.as_widget()
.drag_destinations(s, l, renderer, dnd_rectangles);
}
self.elems()
.zip(&state.children)
.zip(layout.children())
.for_each(|((e, s), l)| {
e.as_widget()
.drag_destinations(s, l, renderer, dnd_rectangles);
});
}
#[cfg(feature = "a11y")]
@ -431,7 +421,7 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
let mut widget = HeaderBarWidget::new(start, center, end)
.apply(widget::container)
.class(crate::theme::Container::HeaderBar {
.class(theme::Container::HeaderBar {
focused: self.focused,
sharp_corners: self.sharp_corners,
transparent: self.transparent,
@ -463,7 +453,7 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
widget::icon::from_name($name)
.apply(widget::button::icon)
.padding(8)
.class(crate::theme::Button::HeaderBar)
.class(theme::Button::HeaderBar)
.selected(self.focused)
.icon_size($size)
.on_press($on_press)

View file

@ -63,7 +63,7 @@ impl<'a, Message: 'static> ListColumn<'a, Message> {
}
// Ensure a minimum height of 32.
let list_item = iced::widget::row![
let list_item = crate::widget::row![
container(item).align_y(iced::Alignment::Center),
vertical().height(iced::Length::Fixed(32.))
]

View file

@ -24,7 +24,7 @@
//! .on_press(Message::LaunchUrl(REPOSITORY))
//! .padding(0);
//!
//! let content = widget::column()
//! let content = widget::column::with_capacity(3)
//! .push(widget::icon::from_name("my-app-icon"))
//! .push(widget::text::title3("My App Name"))
//! .push(link)
@ -53,6 +53,9 @@ pub use iced::widget::{Canvas, canvas};
#[doc(inline)]
pub use iced::widget::{Checkbox, checkbox};
#[doc(inline)]
pub use iced::widget::{Column, column};
#[doc(inline)]
pub use iced::widget::{ComboBox, combo_box};
@ -80,6 +83,9 @@ pub use iced::widget::{ProgressBar, progress_bar};
#[doc(inline)]
pub use iced::widget::{Responsive, responsive};
#[doc(inline)]
pub use iced::widget::{Row, row};
#[doc(inline)]
pub use iced::widget::{Slider, VerticalSlider, slider, vertical_slider};
@ -135,34 +141,6 @@ pub mod context_drawer;
#[doc(inline)]
pub use context_drawer::{ContextDrawer, context_drawer};
#[doc(inline)]
pub use column::{Column, column};
pub mod column {
//! A container which aligns its children in a column.
pub type Column<'a, Message> = iced::widget::Column<'a, Message, crate::Theme, crate::Renderer>;
#[must_use]
/// A container which aligns its children in a column.
pub fn column<'a, Message>() -> Column<'a, Message> {
Column::new()
}
#[must_use]
/// A pre-allocated [`column`].
pub fn with_capacity<'a, Message>(capacity: usize) -> Column<'a, Message> {
Column::with_capacity(capacity)
}
#[must_use]
/// A [`column`] that will be assigned an [`Iterator`] of children.
pub fn with_children<'a, Message>(
children: impl IntoIterator<Item = crate::Element<'a, Message>>,
) -> Column<'a, Message> {
Column::with_children(children)
}
}
pub mod layer_container;
#[doc(inline)]
pub use layer_container::{LayerContainer, layer_container};
@ -287,35 +265,6 @@ pub mod rectangle_tracker;
#[doc(inline)]
pub use rectangle_tracker::{RectangleTracker, rectangle_tracking_container};
#[doc(inline)]
pub use row::{Row, row};
pub mod row {
//! A container which aligns its children in a row.
pub type Row<'a, Message> = iced::widget::Row<'a, Message, crate::Theme, crate::Renderer>;
#[must_use]
/// A container which aligns its children in a row.
pub fn row<'a, Message>() -> Row<'a, Message> {
Row::new()
}
#[must_use]
/// A pre-allocated [`row`].
pub fn with_capacity<'a, Message>(capacity: usize) -> Row<'a, Message> {
Row::with_capacity(capacity)
}
#[must_use]
/// A [`row`] that will be assigned an [`Iterator`] of children.
pub fn with_children<'a, Message>(
children: impl IntoIterator<Item = crate::Element<'a, Message>>,
) -> Row<'a, Message> {
Row::with_children(children)
}
}
pub mod scrollable;
#[doc(inline)]
pub use scrollable::scrollable;

View file

@ -305,7 +305,7 @@ where
{
self.context_menu = context_menu.map(|menus| {
vec![menu::Tree::with_children(
crate::Element::from(crate::widget::row::<'static, Message>()),
crate::Element::from(crate::widget::Row::new()),
menus,
)]
});
@ -1481,7 +1481,7 @@ where
}
}
} else {
if let Item::Tab(key) = std::mem::replace(&mut state.hovered, Item::None) {
if let Item::Tab(_key) = std::mem::replace(&mut state.hovered, Item::None) {
for key in self.model.order.iter().copied() {
self.update_entity_paragraph(state, key);
}
@ -2139,7 +2139,7 @@ where
tree: &'b mut Tree,
layout: iced_core::Layout<'b>,
_renderer: &Renderer,
viewport: &iced_core::Rectangle,
_viewport: &iced_core::Rectangle,
translation: Vector,
) -> Option<iced_core::overlay::Element<'b, Message, crate::Theme, Renderer>> {
let state = tree.state.downcast_mut::<LocalState>();

View file

@ -4,7 +4,7 @@
use std::borrow::Cow;
use crate::{
Element, theme,
Element, Theme, theme,
widget::{FlexRow, Row, column, container, flex_row, row, text},
};
use derive_setters::Setters;
@ -18,12 +18,12 @@ use taffy::AlignContent;
pub fn item<'a, Message: 'static>(
title: impl Into<Cow<'a, str>> + 'a,
widget: impl Into<Element<'a, Message>> + 'a,
) -> Row<'a, Message> {
) -> Row<'a, Message, Theme> {
#[inline(never)]
fn inner<'a, Message: 'static>(
title: Cow<'a, str>,
widget: Element<'a, Message>,
) -> Row<'a, Message> {
) -> Row<'a, Message, Theme> {
item_row(vec![
text(title).wrapping(Wrapping::Word).into(),
space::horizontal().into(),
@ -37,7 +37,7 @@ pub fn item<'a, Message: 'static>(
/// A settings item aligned in a row
#[must_use]
#[allow(clippy::module_name_repetitions)]
pub fn item_row<Message>(children: Vec<Element<Message>>) -> Row<Message> {
pub fn item_row<Message>(children: Vec<Element<Message>>) -> Row<Message, Theme> {
row::with_children(children)
.spacing(theme::spacing().space_xs)
.align_y(iced::Alignment::Center)
@ -105,7 +105,7 @@ pub struct Item<'a, Message> {
impl<'a, Message: 'static> Item<'a, Message> {
/// Assigns a control to the item.
pub fn control(self, widget: impl Into<Element<'a, Message>>) -> Row<'a, Message> {
pub fn control(self, widget: impl Into<Element<'a, Message>>) -> Row<'a, Message, Theme> {
item_row(self.control_(widget.into()))
}
@ -142,7 +142,7 @@ impl<'a, Message: 'static> Item<'a, Message> {
self,
is_checked: bool,
message: impl Fn(bool) -> Message + 'static,
) -> Row<'a, Message> {
) -> Row<'a, Message, Theme> {
self.control(
crate::widget::toggler(is_checked)
.width(Length::Shrink)

View file

@ -8,10 +8,10 @@ pub use self::item::{flex_item, flex_item_row, item, item_row};
pub use self::section::{Section, section};
use crate::widget::{Column, column};
use crate::{Element, theme};
use crate::{Element, Theme, theme};
/// A column with a predefined style for creating a settings panel
#[must_use]
pub fn view_column<Message: 'static>(children: Vec<Element<Message>>) -> Column<Message> {
pub fn view_column<Message: 'static>(children: Vec<Element<Message>>) -> Column<Message, Theme> {
column::with_children(children).spacing(theme::spacing().space_m)
}

View file

@ -65,7 +65,7 @@ where
let selected = val.model.is_active(entity);
let context_menu = (val.item_context_builder)(item);
widget::column()
widget::column::with_capacity(2)
.spacing(val.item_spacing)
.push(
widget::divider::horizontal::default()
@ -73,7 +73,7 @@ where
.padding(val.divider_padding),
)
.push(
widget::row()
widget::row::with_capacity(2)
.spacing(space_xxxs)
.align_y(Alignment::Center)
.push_maybe(
@ -81,7 +81,7 @@ where
.map(|icon| icon.size(val.icon_size)),
)
.push(
widget::column()
widget::column::with_capacity(2)
.push(widget::text::body(item.get_text(Category::default())))
.push({
let mut elements = val

View file

@ -99,7 +99,7 @@ where
};
// Build the category header
widget::row()
widget::row::with_capacity(2)
.spacing(val.icon_spacing)
.push(widget::text::heading(category.to_string()))
.push_maybe(match sort_state {
@ -152,7 +152,7 @@ where
categories
.iter()
.map(|category| {
widget::row()
widget::row::with_capacity(2)
.spacing(val.icon_spacing)
.push_maybe(
item.get_icon(*category)

View file

@ -34,10 +34,10 @@ pub fn toaster<'a, Message: Clone + 'static>(
} = theme.cosmic().spacing;
let make_toast = move |(id, toast): (ToastId, &'a Toast<Message>)| {
let row = row()
let row = row::with_capacity(2)
.push(text(&toast.message))
.push(
row()
row::with_capacity(2)
.push_maybe(toast.action.as_ref().map(|action| {
button::text(&action.description).on_press((action.message)(id))
}))