mirror of
https://github.com/danbulant/cushy
synced 2026-06-24 17:12:11 +00:00
Started a List widget
a la HTML's <ul> tag.
This commit is contained in:
parent
1b97b39857
commit
c2bd9911ca
3 changed files with 100 additions and 0 deletions
|
|
@ -39,6 +39,7 @@ use crate::utils::IgnorePoison;
|
||||||
use crate::value::{Dynamic, Generation, IntoDynamic, IntoValue, Validation, Value};
|
use crate::value::{Dynamic, Generation, IntoDynamic, IntoValue, Validation, Value};
|
||||||
use crate::widgets::checkbox::{Checkable, CheckboxState};
|
use crate::widgets::checkbox::{Checkable, CheckboxState};
|
||||||
use crate::widgets::layers::{OverlayLayer, Tooltipped};
|
use crate::widgets::layers::{OverlayLayer, Tooltipped};
|
||||||
|
use crate::widgets::list::List;
|
||||||
use crate::widgets::{
|
use crate::widgets::{
|
||||||
Align, Button, Checkbox, Collapse, Container, Disclose, Expand, Layers, Resize, Scroll, Space,
|
Align, Button, Checkbox, Collapse, Container, Disclose, Expand, Layers, Resize, Scroll, Space,
|
||||||
Stack, Style, Themed, ThemedMode, Validated, Wrap,
|
Stack, Style, Themed, ThemedMode, Validated, Wrap,
|
||||||
|
|
@ -2036,6 +2037,12 @@ impl WidgetList {
|
||||||
Wrap::new(self)
|
Wrap::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `self` as an unordered [`List`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn into_list(self) -> List {
|
||||||
|
List::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Synchronizes this list of children with another collection.
|
/// Synchronizes this list of children with another collection.
|
||||||
///
|
///
|
||||||
/// This function updates `collection` by calling `change_fn` for each
|
/// This function updates `collection` by calling `change_fn` for each
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ pub mod image;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod label;
|
pub mod label;
|
||||||
pub mod layers;
|
pub mod layers;
|
||||||
|
pub mod list;
|
||||||
mod mode_switch;
|
mod mode_switch;
|
||||||
pub mod progress;
|
pub mod progress;
|
||||||
pub mod radio;
|
pub mod radio;
|
||||||
|
|
|
||||||
92
src/widgets/list.rs
Normal file
92
src/widgets/list.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
//! A list of elements with optional item indicators.
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::grid::GridWidgets;
|
||||||
|
use super::input::CowString;
|
||||||
|
use super::Grid;
|
||||||
|
use crate::value::{IntoValue, MapEach, Source, Value};
|
||||||
|
use crate::widget::{MakeWidget, WidgetInstance, WidgetList};
|
||||||
|
|
||||||
|
/// A list of items displayed with an optional item indicator.
|
||||||
|
pub struct List {
|
||||||
|
style: Value<ListStyle>,
|
||||||
|
children: Value<WidgetList>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl List {
|
||||||
|
/// Returns a new list with the default [`ListStyle`]/
|
||||||
|
pub fn new(children: impl IntoValue<WidgetList>) -> Self {
|
||||||
|
Self {
|
||||||
|
children: children.into_value(),
|
||||||
|
style: Value::Constant(ListStyle::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The style of a [`List`] widget's item indicators.
|
||||||
|
#[derive(Default, Debug, Clone)]
|
||||||
|
pub enum ListStyle {
|
||||||
|
#[default]
|
||||||
|
Disc,
|
||||||
|
Custom(Arc<dyn ListIndicator>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for ListStyle {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Self::Custom(l0), Self::Custom(r0)) => Arc::ptr_eq(l0, r0),
|
||||||
|
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`ListStyle`] implementation that provides an optional indicator for a
|
||||||
|
/// given list index.
|
||||||
|
pub trait ListIndicator: Debug + Sync + Send + 'static {
|
||||||
|
/// Returns the indicator to use at `index`.
|
||||||
|
fn list_indicator(&self, index: usize) -> Option<CowString>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ListIndicator for ListStyle {
|
||||||
|
fn list_indicator(&self, index: usize) -> Option<CowString> {
|
||||||
|
match self {
|
||||||
|
ListStyle::Disc => Some(CowString::new("\u{2022}")),
|
||||||
|
ListStyle::Custom(style) => style.list_indicator(index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MakeWidget for List {
|
||||||
|
fn make_widget(self) -> WidgetInstance {
|
||||||
|
let rows = match (self.children, self.style) {
|
||||||
|
(children, Value::Constant(style)) => {
|
||||||
|
children.map_each(move |children| build_grid_widgets(&style, children))
|
||||||
|
}
|
||||||
|
(Value::Dynamic(children), Value::Dynamic(style)) => Value::Dynamic(
|
||||||
|
(&style, &children)
|
||||||
|
.map_each(|(style, children)| build_grid_widgets(style, children)),
|
||||||
|
),
|
||||||
|
(Value::Constant(children), Value::Dynamic(style)) => {
|
||||||
|
Value::Dynamic(style.map_each(move |style| build_grid_widgets(style, &children)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Grid::from_rows(rows).make_widget()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_grid_widgets(style: &ListStyle, children: &WidgetList) -> GridWidgets<2> {
|
||||||
|
// This is horrible. We should be be using synchronize_with to avoid
|
||||||
|
// recreating the gridwidgets every time.
|
||||||
|
children
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, child)| {
|
||||||
|
(
|
||||||
|
style.list_indicator(index).unwrap_or_default(),
|
||||||
|
child.clone().align_left().make_widget(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue