Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat: TableView widget #768

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
949a318
Implemented rudimentary table widget, currently not interactible
Adam-Cosner Dec 27, 2024
8021271
Merge branch 'master' of https://github.com/Adam-Cosner/libcosmic
Adam-Cosner Dec 27, 2024
8132f8f
Compact view implemented
Adam-Cosner Dec 30, 2024
19dfbcb
Merge branch 'pop-os:master' into master
Adam-Cosner Dec 30, 2024
fc531b5
Added table view example
Adam-Cosner Dec 30, 2024
e608192
Merge branch 'master' of https://github.com/Adam-Cosner/libcosmic
Adam-Cosner Dec 30, 2024
ad4ed38
Fixed table view issues with selection on compact view and some spaci…
Adam-Cosner Dec 30, 2024
5c96696
Merge branch 'pop-os:master' into master
Adam-Cosner Jan 1, 2025
825792e
Added custom widget version of table
Adam-Cosner Jan 2, 2025
dd9d1c0
Revert "Added custom widget version of table"
Adam-Cosner Jan 3, 2025
2401c2a
Added table function for generic table view creation
Adam-Cosner Jan 4, 2025
2305e25
Use derive_setters for TableView
Adam-Cosner Jan 4, 2025
91c35e8
Made compact and standard table view into separate widgets
Adam-Cosner Jan 4, 2025
4111fcb
Added doc inline to widget
Adam-Cosner Jan 5, 2025
68fdd8f
Added category context menus
Adam-Cosner Jan 6, 2025
9f2e554
Merge branch 'pop-os:master' into master
Adam-Cosner Jan 11, 2025
0b0e143
Merge branch 'master' of https://github.com/Adam-Cosner/libcosmic
Adam-Cosner Jan 11, 2025
ea4e6c6
Added item contexts and changed the context menu functions to take bu…
Adam-Cosner Jan 11, 2025
1e28f39
Ran cargo fmt
Adam-Cosner Jan 11, 2025
d4bce76
Fixed warnings
Adam-Cosner Jan 11, 2025
160070c
Added more mouse interaction options
Adam-Cosner Jan 11, 2025
b29d8f4
Merge branch 'pop-os:master' into master
Adam-Cosner Jan 14, 2025
d304592
Merge branch 'pop-os:master' into master
Adam-Cosner Jan 19, 2025
db4c3d7
Changed insert method and removed default requirement for Item
Adam-Cosner Jan 19, 2025
336277c
Merge branch 'pop-os:master' into master
Adam-Cosner Jan 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions examples/table-view/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -194,15 +195,15 @@ impl cosmic::Application for App {
fn view(&self) -> Element<Self::Message> {
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()
Expand Down
2 changes: 1 addition & 1 deletion src/widget/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
mmstick marked this conversation as resolved.
Show resolved Hide resolved

pub mod text;
#[doc(inline)]
Expand Down
16 changes: 15 additions & 1 deletion src/widget/table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand All @@ -31,3 +32,16 @@ where
{
TableView::new(model)
}

pub fn compact_table<'a, SelectionMode, Item, Category, Message>(
model: &'a Model<SelectionMode, Item, Category>,
) -> CompactTableView<'a, SelectionMode, Item, Category, Message>
where
Message: Clone,
SelectionMode: Default,
Category: ItemCategory,
Item: ItemInterface<Category>,
Model<SelectionMode, Item, Category>: model::selection::Selectable,
{
CompactTableView::new(model)
}
249 changes: 249 additions & 0 deletions src/widget/table/widget/compact.rs
Original file line number Diff line number Diff line change
@@ -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<Category>,
Model<SelectionMode, Item, Category>: Selectable,
SelectionMode: Default,
Message: Clone + 'static,
{
pub(super) model: &'a Model<SelectionMode, Item, Category>,

#[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<Vec<menu::Tree<'a, Message>>>,
#[setters(skip)]
pub(super) category_context_tree: Option<Vec<menu::Tree<'a, Message>>>,

#[setters(skip)]
pub(super) on_item_select: Option<Box<dyn Fn(Entity) -> Message + 'a>>,
#[setters(skip)]
pub(super) on_item_context: Option<Box<dyn Fn(Entity) -> Message + 'a>>,
#[setters(skip)]
pub(super) on_category_select: Option<Box<dyn Fn(Category, bool) -> Message + 'a>>,
#[setters(skip)]
pub(super) on_category_context: Option<Box<dyn Fn(Category) -> Message + 'a>>,
}

impl<'a, SelectionMode, Item, Category, Message>
From<CompactTableView<'a, SelectionMode, Item, Category, Message>> for Element<'a, Message>
where
Category: ItemCategory,
Item: ItemInterface<Category>,
Model<SelectionMode, Item, Category>: 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::<Vec<Element<'a, Message>>>();
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::<Vec<Element<'a, Message>>>()
.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<SelectionMode, Item, Category>: Selectable,
Category: ItemCategory,
Item: ItemInterface<Category>,
Message: Clone + 'static,
{
pub fn new(model: &'a Model<SelectionMode, Item, Category>) -> 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<F>(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<F>(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<Vec<menu::Tree<'a, Message>>>) -> 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<Vec<menu::Tree<'a, Message>>>) -> 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<F>(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<F>(mut self, on_select: F) -> Self
where
F: Fn(Category) -> Message + 'a,
{
self.on_category_context = Some(Box::new(on_select));
self
}
}
Loading
Loading