From 91c35e88adcdc28bc288a640107764578c07725e Mon Sep 17 00:00:00 2001 From: Adam Cosner Date: Sat, 4 Jan 2025 12:42:34 -0800 Subject: [PATCH] Made compact and standard table view into separate widgets --- examples/table-view/src/main.rs | 9 +- src/widget/mod.rs | 2 +- src/widget/table/mod.rs | 16 +- src/widget/table/widget/compact.rs | 249 ++++++++++++++++++ src/widget/table/widget/mod.rs | 384 +--------------------------- src/widget/table/widget/standard.rs | 298 +++++++++++++++++++++ src/widget/table/widget/state.rs | 8 - 7 files changed, 570 insertions(+), 396 deletions(-) create mode 100644 src/widget/table/widget/compact.rs create mode 100644 src/widget/table/widget/standard.rs delete mode 100644 src/widget/table/widget/state.rs diff --git a/examples/table-view/src/main.rs b/examples/table-view/src/main.rs index 3bea9b36..ea641144 100644 --- a/examples/table-view/src/main.rs +++ b/examples/table-view/src/main.rs @@ -6,9 +6,10 @@ use chrono::Datelike; use cosmic::app::{Core, Settings, Task}; use cosmic::iced_core::Size; +use cosmic::prelude::*; use cosmic::widget::table; use cosmic::widget::{self, nav_bar}; -use cosmic::{executor, iced, Element}; +use cosmic::{executor, iced}; #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] pub enum Category { @@ -194,15 +195,15 @@ impl cosmic::Application for App { fn view(&self) -> Element { cosmic::widget::responsive(|size| { if size.width < 600.0 { - widget::table(&self.table_model) + widget::compact_table(&self.table_model) .on_item_select(Message::ItemSelect) .on_category_select(Message::CategorySelect) - .element_compact() + .apply(Element::from) } else { widget::table(&self.table_model) .on_item_select(Message::ItemSelect) .on_category_select(Message::CategorySelect) - .element_standard() + .apply(Element::from) } }) .into() diff --git a/src/widget/mod.rs b/src/widget/mod.rs index e915e626..d6aa01e8 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -316,7 +316,7 @@ pub use spin_button::{spin_button, vertical as vertical_spin_button, SpinButton} pub mod tab_bar; pub mod table; -pub use table::table; +pub use table::{compact_table, table}; pub mod text; #[doc(inline)] diff --git a/src/widget/table/mod.rs b/src/widget/table/mod.rs index b5a5d0b7..c39a393d 100644 --- a/src/widget/table/mod.rs +++ b/src/widget/table/mod.rs @@ -9,7 +9,8 @@ pub use model::{ Entity, Model, }; pub mod widget; -pub use widget::TableView; +pub use widget::compact::CompactTableView; +pub use widget::standard::TableView; pub type SingleSelectTableView<'a, Item, Category, Message> = TableView<'a, SingleSelect, Item, Category, Message>; @@ -31,3 +32,16 @@ where { TableView::new(model) } + +pub fn compact_table<'a, SelectionMode, Item, Category, Message>( + model: &'a Model, +) -> CompactTableView<'a, SelectionMode, Item, Category, Message> +where + Message: Clone, + SelectionMode: Default, + Category: ItemCategory, + Item: ItemInterface, + Model: model::selection::Selectable, +{ + CompactTableView::new(model) +} diff --git a/src/widget/table/widget/compact.rs b/src/widget/table/widget/compact.rs new file mode 100644 index 00000000..62891fca --- /dev/null +++ b/src/widget/table/widget/compact.rs @@ -0,0 +1,249 @@ +use derive_setters::Setters; + +use crate::widget::table::model::{ + category::{ItemCategory, ItemInterface}, + selection::Selectable, + Entity, Model, +}; +use crate::{ + theme, + widget::{self, container, menu}, + Apply, Element, +}; +use iced::{Alignment, Border, Padding}; + +#[derive(Setters)] +#[must_use] +pub struct CompactTableView<'a, SelectionMode, Item, Category, Message> +where + Category: ItemCategory, + Item: ItemInterface, + Model: Selectable, + SelectionMode: Default, + Message: Clone + 'static, +{ + pub(super) model: &'a Model, + + #[setters(into)] + pub(super) element_padding: Padding, + + #[setters(into)] + pub(super) item_padding: Padding, + pub(super) item_spacing: u16, + + #[setters(into)] + pub(super) divider_padding: Padding, + + #[setters(skip)] + pub(super) item_context_tree: Option>>, + #[setters(skip)] + pub(super) category_context_tree: Option>>, + + #[setters(skip)] + pub(super) on_item_select: Option Message + 'a>>, + #[setters(skip)] + pub(super) on_item_context: Option Message + 'a>>, + #[setters(skip)] + pub(super) on_category_select: Option Message + 'a>>, + #[setters(skip)] + pub(super) on_category_context: Option Message + 'a>>, +} + +impl<'a, SelectionMode, Item, Category, Message> + From> for Element<'a, Message> +where + Category: ItemCategory, + Item: ItemInterface, + Model: Selectable, + SelectionMode: Default, + Message: Clone + 'static, +{ + fn from(val: CompactTableView<'a, SelectionMode, Item, Category, Message>) -> Self { + let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing; + val.model + .iter() + .map(|entity| { + let item = val.model.item(entity).unwrap(); + let selected = val.model.is_active(entity); + widget::column() + .spacing(val.item_spacing) + .push( + widget::divider::horizontal::default() + .apply(container) + .padding(val.divider_padding), + ) + .push( + widget::row() + .spacing(space_xxxs) + .align_y(Alignment::Center) + .push_maybe( + item.get_icon(Category::default()).map(|icon| icon.size(48)), + ) + .push( + widget::column() + .push(widget::text::body(item.get_text(Category::default()))) + .push({ + let mut elements = val + .model + .categories + .iter() + .skip_while(|cat| **cat != Category::default()) + .map(|category| { + vec![ + widget::text::caption(item.get_text(*category)) + .apply(Element::from), + widget::text::caption("-").apply(Element::from), + ] + }) + .flatten() + .collect::>>(); + elements.pop(); + elements + .apply(widget::row::with_children) + .spacing(space_xxxs) + .wrap() + }), + ) + .apply(container) + .padding(val.item_padding) + .width(iced::Length::Fill) + .class(theme::Container::custom(move |theme| { + widget::container::Style { + icon_color: if selected { + Some(theme.cosmic().on_accent_color().into()) + } else { + None + }, + text_color: if selected { + Some(theme.cosmic().on_accent_color().into()) + } else { + None + }, + background: if selected { + Some(iced::Background::Color( + theme.cosmic().accent_color().into(), + )) + } else { + None + }, + border: Border { + radius: theme.cosmic().radius_xs().into(), + ..Default::default() + }, + shadow: Default::default(), + } + })) + .apply(widget::mouse_area) + .apply(|ma| { + if let Some(on_item_select) = &val.on_item_select { + ma.on_press((on_item_select)(entity)) + } else { + ma + } + }), + ) + .apply(Element::from) + }) + .collect::>>() + .apply(widget::column::with_children) + .spacing(val.item_spacing) + .padding(val.element_padding) + .apply(Element::from) + } +} + +impl<'a, SelectionMode, Item, Category, Message> + CompactTableView<'a, SelectionMode, Item, Category, Message> +where + SelectionMode: Default, + Model: Selectable, + Category: ItemCategory, + Item: ItemInterface, + Message: Clone + 'static, +{ + pub fn new(model: &'a Model) -> Self { + let cosmic_theme::Spacing { + space_xxxs, + space_xxs, + .. + } = theme::active().cosmic().spacing; + + Self { + model, + element_padding: Padding::from(0), + + divider_padding: Padding::from(0).left(space_xxxs).right(space_xxxs), + + item_padding: Padding::from(space_xxs).into(), + item_spacing: 0, + + on_item_select: None, + on_item_context: None, + item_context_tree: None, + + on_category_select: None, + on_category_context: None, + category_context_tree: None, + } + } + + pub fn on_item_select(mut self, on_select: F) -> Self + where + F: Fn(Entity) -> Message + 'a, + { + self.on_item_select = Some(Box::new(on_select)); + self + } + + pub fn on_item_context(mut self, on_select: F) -> Self + where + F: Fn(Entity) -> Message + 'a, + { + self.on_item_context = Some(Box::new(on_select)); + self + } + + pub fn item_context(mut self, context_menu: Option>>) -> Self + where + Message: 'static, + { + self.item_context_tree = + context_menu.map(|menus| vec![menu::Tree::with_children(widget::row(), menus)]); + + if let Some(ref mut context_menu) = self.item_context_tree { + context_menu.iter_mut().for_each(menu::Tree::set_index); + } + + self + } + + pub fn category_context(mut self, context_menu: Option>>) -> Self + where + Message: 'static, + { + self.category_context_tree = + context_menu.map(|menus| vec![menu::Tree::with_children(widget::row(), menus)]); + + if let Some(ref mut context_menu) = self.category_context_tree { + context_menu.iter_mut().for_each(menu::Tree::set_index); + } + + self + } + + pub fn on_category_select(mut self, on_select: F) -> Self + where + F: Fn(Category, bool) -> Message + 'a, + { + self.on_category_select = Some(Box::new(on_select)); + self + } + + pub fn on_category_context(mut self, on_select: F) -> Self + where + F: Fn(Category) -> Message + 'a, + { + self.on_category_context = Some(Box::new(on_select)); + self + } +} diff --git a/src/widget/table/widget/mod.rs b/src/widget/table/widget/mod.rs index 85040900..0396796e 100644 --- a/src/widget/table/widget/mod.rs +++ b/src/widget/table/widget/mod.rs @@ -1,382 +1,2 @@ -mod state; -use derive_setters::Setters; -use state::State; - -use super::model::{ - category::{ItemCategory, ItemInterface}, - selection::Selectable, - Entity, Model, -}; -use crate::{ - ext::CollectionWidget, - theme, - widget::{self, container, divider, menu}, - Apply, Element, -}; -use iced::{Alignment, Border, Length, Padding}; - -// THIS IS A PLACEHOLDER UNTIL A MORE SOPHISTICATED WIDGET CAN BE DEVELOPED - -#[derive(Setters)] -#[must_use] -pub struct TableView<'a, SelectionMode, Item, Category, Message> -where - Category: ItemCategory, - Item: ItemInterface, - Model: Selectable, - SelectionMode: Default, - Message: Clone + 'static, -{ - pub(super) model: &'a Model, - - #[setters(into)] - pub(super) element_padding: Padding, - - #[setters(into)] - pub(super) item_padding: Padding, - pub(super) item_spacing: u16, - - #[setters(into)] - pub(super) divider_padding: Padding, - - #[setters(skip)] - pub(super) item_context_tree: Option>>, - #[setters(skip)] - pub(super) category_context_tree: Option>>, - - #[setters(skip)] - pub(super) on_item_select: Option Message + 'a>>, - #[setters(skip)] - pub(super) on_item_context: Option Message + 'a>>, - #[setters(skip)] - pub(super) on_category_select: Option Message + 'a>>, - #[setters(skip)] - pub(super) on_category_context: Option Message + 'a>>, -} - -impl<'a, SelectionMode, Item, Category, Message> - TableView<'a, SelectionMode, Item, Category, Message> -where - SelectionMode: Default, - Model: Selectable, - Category: ItemCategory, - Item: ItemInterface, - Message: Clone + 'static, -{ - pub fn new(model: &'a Model) -> Self { - let cosmic_theme::Spacing { - space_xxxs, - space_xxs, - .. - } = theme::active().cosmic().spacing; - - Self { - model, - item_spacing: 0, - element_padding: Padding::from(0), - divider_padding: Padding::from(0).left(space_xxxs).right(space_xxxs), - item_padding: Padding::from(space_xxs).into(), - on_item_select: None, - on_item_context: None, - item_context_tree: None, - on_category_select: None, - on_category_context: None, - category_context_tree: None, - } - } - - pub fn on_item_select(mut self, on_select: F) -> Self - where - F: Fn(Entity) -> Message + 'a, - { - self.on_item_select = Some(Box::new(on_select)); - self - } - - pub fn on_item_context(mut self, on_select: F) -> Self - where - F: Fn(Entity) -> Message + 'a, - { - self.on_item_context = Some(Box::new(on_select)); - self - } - - pub fn item_context(mut self, context_menu: Option>>) -> Self - where - Message: 'static, - { - self.item_context_tree = - context_menu.map(|menus| vec![menu::Tree::with_children(widget::row(), menus)]); - - if let Some(ref mut context_menu) = self.item_context_tree { - context_menu.iter_mut().for_each(menu::Tree::set_index); - } - - self - } - - pub fn category_context(mut self, context_menu: Option>>) -> Self - where - Message: 'static, - { - self.category_context_tree = - context_menu.map(|menus| vec![menu::Tree::with_children(widget::row(), menus)]); - - if let Some(ref mut context_menu) = self.category_context_tree { - context_menu.iter_mut().for_each(menu::Tree::set_index); - } - - self - } - - pub fn on_category_select(mut self, on_select: F) -> Self - where - F: Fn(Category, bool) -> Message + 'a, - { - self.on_category_select = Some(Box::new(on_select)); - self - } - - pub fn on_category_context(mut self, on_select: F) -> Self - where - F: Fn(Category) -> Message + 'a, - { - self.on_category_context = Some(Box::new(on_select)); - self - } - - /*#[must_use] - pub fn element_standard(&self) -> Element<'a, Message> { - let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing; - - let header_row = self - .model - .categories - .iter() - .map(|category| { - widget::row() - .spacing(space_xxxs) - .push(widget::text::heading(category.to_string())) - .push_maybe(if let Some(sort) = self.model.sort { - if sort.0 == *category { - match sort.1 { - true => Some(widget::icon::from_name("pan-up-symbolic").icon()), - false => Some(widget::icon::from_name("pan-down-symbolic").icon()), - } - } else { - None - } - } else { - None - }) - .apply(container) - .padding( - Padding::default() - .left(self.item_padding.left) - .right(self.item_padding.right), - ) - .width(category.width()) - .apply(widget::mouse_area) - .apply(|mouse_area| { - if let Some(ref on_category_select) = self.on_category_select { - mouse_area.on_press((on_category_select)( - *category, - if let Some(sort) = self.model.sort { - if sort.0 == *category { - !sort.1 - } else { - false - } - } else { - false - }, - )) - } else { - mouse_area - } - }) - .apply(Element::from) - }) - .collect::>>() - .apply(widget::row::with_children) - .apply(Element::from); - let items_full = if self.model.items.is_empty() { - vec![divider::horizontal::default() - .apply(container) - .padding(self.divider_padding) - .apply(Element::from)] - } else { - self.model - .iter() - .map(|entity| { - let item = self.model.item(entity).unwrap(); - let categories = &self.model.categories; - let selected = self.model.is_active(entity); - - vec![ - divider::horizontal::default() - .apply(container) - .padding(self.divider_padding) - .apply(Element::from), - categories - .iter() - .map(|category| { - widget::row() - .spacing(space_xxxs) - .push_maybe(item.get_icon(*category).map(|icon| icon.size(24))) - .push(widget::text::body(item.get_text(*category))) - .align_y(Alignment::Center) - .apply(container) - .width(category.width()) - .align_y(Alignment::Center) - .apply(Element::from) - }) - .collect::>>() - .apply(widget::row::with_children) - .apply(container) - .padding(self.item_padding) - .class(theme::Container::custom(move |theme| { - widget::container::Style { - icon_color: if selected { - Some(theme.cosmic().on_accent_color().into()) - } else { - None - }, - text_color: if selected { - Some(theme.cosmic().on_accent_color().into()) - } else { - None - }, - background: if selected { - Some(iced::Background::Color( - theme.cosmic().accent_color().into(), - )) - } else { - None - }, - border: Border { - radius: theme.cosmic().radius_xs().into(), - ..Default::default() - }, - shadow: Default::default(), - } - })) - .apply(widget::mouse_area) - .apply(|mouse_area| { - if let Some(ref on_item_select) = self.on_item_select { - mouse_area.on_press((on_item_select)(entity)) - } else { - mouse_area - } - }) - .apply(Element::from), - ] - }) - .flatten() - .collect::>>() - }; - vec![vec![header_row], items_full] - .into_iter() - .flatten() - .collect::>>() - .apply(widget::column::with_children) - .spacing(self.item_spacing) - .padding(self.element_padding) - .apply(Element::from) - } - - #[must_use] - pub fn element_compact(&self) -> Element<'a, Message> { - let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing; - self.model - .iter() - .map(|entity| { - let item = self.model.item(entity).unwrap(); - let selected = self.model.is_active(entity); - widget::column() - .spacing(self.item_spacing) - .push( - widget::divider::horizontal::default() - .apply(container) - .padding(self.divider_padding), - ) - .push( - widget::row() - .spacing(space_xxxs) - .align_y(Alignment::Center) - .push_maybe( - item.get_icon(Category::default()).map(|icon| icon.size(48)), - ) - .push( - widget::column() - .push(widget::text::body(item.get_text(Category::default()))) - .push({ - let mut elements = self - .model - .categories - .iter() - .skip_while(|cat| **cat != Category::default()) - .map(|category| { - vec![ - widget::text::caption(item.get_text(*category)) - .apply(Element::from), - widget::text::caption("-").apply(Element::from), - ] - }) - .flatten() - .collect::>>(); - elements.pop(); - elements - .apply(widget::row::with_children) - .spacing(space_xxxs) - .wrap() - }), - ) - .apply(container) - .padding(self.item_padding) - .width(iced::Length::Fill) - .class(theme::Container::custom(move |theme| { - widget::container::Style { - icon_color: if selected { - Some(theme.cosmic().on_accent_color().into()) - } else { - None - }, - text_color: if selected { - Some(theme.cosmic().on_accent_color().into()) - } else { - None - }, - background: if selected { - Some(iced::Background::Color( - theme.cosmic().accent_color().into(), - )) - } else { - None - }, - border: Border { - radius: theme.cosmic().radius_xs().into(), - ..Default::default() - }, - shadow: Default::default(), - } - })) - .apply(widget::mouse_area) - .apply(|ma| { - if let Some(on_item_select) = &self.on_item_select { - ma.on_press((on_item_select)(entity)) - } else { - ma - } - }), - ) - .apply(Element::from) - }) - .collect::>>() - .apply(widget::column::with_children) - .spacing(self.item_spacing) - .padding(self.element_padding) - .apply(Element::from) - } - */ -} +pub mod compact; +pub mod standard; diff --git a/src/widget/table/widget/standard.rs b/src/widget/table/widget/standard.rs new file mode 100644 index 00000000..f9450c70 --- /dev/null +++ b/src/widget/table/widget/standard.rs @@ -0,0 +1,298 @@ +use derive_setters::Setters; + +use crate::widget::table::model::{ + category::{ItemCategory, ItemInterface}, + selection::Selectable, + Entity, Model, +}; +use crate::{ + ext::CollectionWidget, + theme, + widget::{self, container, divider, menu}, + Apply, Element, +}; +use iced::{Alignment, Border, Length, Padding}; + +// THIS IS A PLACEHOLDER UNTIL A MORE SOPHISTICATED WIDGET CAN BE DEVELOPED + +#[derive(Setters)] +#[must_use] +pub struct TableView<'a, SelectionMode, Item, Category, Message> +where + Category: ItemCategory, + Item: ItemInterface, + Model: Selectable, + SelectionMode: Default, + Message: Clone + 'static, +{ + pub(super) model: &'a Model, + + #[setters(into)] + pub(super) element_padding: Padding, + + #[setters(into)] + pub(super) item_padding: Padding, + pub(super) item_spacing: u16, + + #[setters(into)] + pub(super) divider_padding: Padding, + + #[setters(skip)] + pub(super) item_context_tree: Option>>, + #[setters(skip)] + pub(super) category_context_tree: Option>>, + + #[setters(skip)] + pub(super) on_item_select: Option Message + 'a>>, + #[setters(skip)] + pub(super) on_item_context: Option Message + 'a>>, + #[setters(skip)] + pub(super) on_category_select: Option Message + 'a>>, + #[setters(skip)] + pub(super) on_category_context: Option Message + 'a>>, +} + +impl<'a, SelectionMode, Item, Category, Message> + From> for Element<'a, Message> +where + Category: ItemCategory, + Item: ItemInterface, + Model: Selectable, + SelectionMode: Default, + Message: Clone + 'static, +{ + fn from(val: TableView<'a, SelectionMode, Item, Category, Message>) -> Self { + let cosmic_theme::Spacing { space_xxxs, .. } = theme::active().cosmic().spacing; + + let header_row = val + .model + .categories + .iter() + .map(|category| { + widget::row() + .spacing(space_xxxs) + .push(widget::text::heading(category.to_string())) + .push_maybe(if let Some(sort) = val.model.sort { + if sort.0 == *category { + match sort.1 { + true => Some(widget::icon::from_name("pan-up-symbolic").icon()), + false => Some(widget::icon::from_name("pan-down-symbolic").icon()), + } + } else { + None + } + } else { + None + }) + .apply(container) + .padding( + Padding::default() + .left(val.item_padding.left) + .right(val.item_padding.right), + ) + .width(category.width()) + .apply(widget::mouse_area) + .apply(|mouse_area| { + if let Some(ref on_category_select) = val.on_category_select { + mouse_area.on_press((on_category_select)( + *category, + if let Some(sort) = val.model.sort { + if sort.0 == *category { + !sort.1 + } else { + false + } + } else { + false + }, + )) + } else { + mouse_area + } + }) + .apply(Element::from) + }) + .collect::>>() + .apply(widget::row::with_children) + .apply(Element::from); + let items_full = if val.model.items.is_empty() { + vec![divider::horizontal::default() + .apply(container) + .padding(val.divider_padding) + .apply(Element::from)] + } else { + val.model + .iter() + .map(|entity| { + let item = val.model.item(entity).unwrap(); + let categories = &val.model.categories; + let selected = val.model.is_active(entity); + + vec![ + divider::horizontal::default() + .apply(container) + .padding(val.divider_padding) + .apply(Element::from), + categories + .iter() + .map(|category| { + widget::row() + .spacing(space_xxxs) + .push_maybe(item.get_icon(*category).map(|icon| icon.size(24))) + .push(widget::text::body(item.get_text(*category))) + .align_y(Alignment::Center) + .apply(container) + .width(category.width()) + .align_y(Alignment::Center) + .apply(Element::from) + }) + .collect::>>() + .apply(widget::row::with_children) + .apply(container) + .padding(val.item_padding) + .class(theme::Container::custom(move |theme| { + widget::container::Style { + icon_color: if selected { + Some(theme.cosmic().on_accent_color().into()) + } else { + None + }, + text_color: if selected { + Some(theme.cosmic().on_accent_color().into()) + } else { + None + }, + background: if selected { + Some(iced::Background::Color( + theme.cosmic().accent_color().into(), + )) + } else { + None + }, + border: Border { + radius: theme.cosmic().radius_xs().into(), + ..Default::default() + }, + shadow: Default::default(), + } + })) + .apply(widget::mouse_area) + .apply(|mouse_area| { + if let Some(ref on_item_select) = val.on_item_select { + mouse_area.on_press((on_item_select)(entity)) + } else { + mouse_area + } + }) + .apply(Element::from), + ] + }) + .flatten() + .collect::>>() + }; + vec![vec![header_row], items_full] + .into_iter() + .flatten() + .collect::>>() + .apply(widget::column::with_children) + .spacing(val.item_spacing) + .padding(val.element_padding) + .apply(Element::from) + } +} + +impl<'a, SelectionMode, Item, Category, Message> + TableView<'a, SelectionMode, Item, Category, Message> +where + SelectionMode: Default, + Model: Selectable, + Category: ItemCategory, + Item: ItemInterface, + Message: Clone + 'static, +{ + pub fn new(model: &'a Model) -> Self { + let cosmic_theme::Spacing { + space_xxxs, + space_xxs, + .. + } = theme::active().cosmic().spacing; + + Self { + model, + element_padding: Padding::from(0), + + divider_padding: Padding::from(0).left(space_xxxs).right(space_xxxs), + + item_padding: Padding::from(space_xxs).into(), + item_spacing: 0, + + on_item_select: None, + on_item_context: None, + item_context_tree: None, + + on_category_select: None, + on_category_context: None, + category_context_tree: None, + } + } + + pub fn on_item_select(mut self, on_select: F) -> Self + where + F: Fn(Entity) -> Message + 'a, + { + self.on_item_select = Some(Box::new(on_select)); + self + } + + pub fn on_item_context(mut self, on_select: F) -> Self + where + F: Fn(Entity) -> Message + 'a, + { + self.on_item_context = Some(Box::new(on_select)); + self + } + + pub fn item_context(mut self, context_menu: Option>>) -> Self + where + Message: 'static, + { + self.item_context_tree = + context_menu.map(|menus| vec![menu::Tree::with_children(widget::row(), menus)]); + + if let Some(ref mut context_menu) = self.item_context_tree { + context_menu.iter_mut().for_each(menu::Tree::set_index); + } + + self + } + + pub fn category_context(mut self, context_menu: Option>>) -> Self + where + Message: 'static, + { + self.category_context_tree = + context_menu.map(|menus| vec![menu::Tree::with_children(widget::row(), menus)]); + + if let Some(ref mut context_menu) = self.category_context_tree { + context_menu.iter_mut().for_each(menu::Tree::set_index); + } + + self + } + + pub fn on_category_select(mut self, on_select: F) -> Self + where + F: Fn(Category, bool) -> Message + 'a, + { + self.on_category_select = Some(Box::new(on_select)); + self + } + + pub fn on_category_context(mut self, on_select: F) -> Self + where + F: Fn(Category) -> Message + 'a, + { + self.on_category_context = Some(Box::new(on_select)); + self + } +} diff --git a/src/widget/table/widget/state.rs b/src/widget/table/widget/state.rs deleted file mode 100644 index 4d529db4..00000000 --- a/src/widget/table/widget/state.rs +++ /dev/null @@ -1,8 +0,0 @@ -use slotmap::SecondaryMap; - -use crate::widget::table::Entity; - -pub struct State { - pub(super) num_items: usize, - pub(super) selected: SecondaryMap, -}