Compare commits
2 commits
master
...
segmented-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f081161d97 | ||
|
|
9a0c338876 |
12 changed files with 84 additions and 60 deletions
|
|
@ -478,7 +478,7 @@ where
|
|||
}
|
||||
|
||||
/// Allows COSMIC to integrate with your application's [`nav_bar::Model`].
|
||||
fn nav_model(&self) -> Option<&nav_bar::Model> {
|
||||
fn nav_model(&self) -> Option<&nav_bar::Model<Message<Self::Message>>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ pub enum ColorPickerUpdate {
|
|||
}
|
||||
|
||||
#[derive(Setters)]
|
||||
pub struct ColorPickerModel {
|
||||
pub struct ColorPickerModel<Message> {
|
||||
#[setters(skip)]
|
||||
segmented_model: Model<SingleSelect>,
|
||||
segmented_model: Model<SingleSelect, Message>,
|
||||
#[setters(skip)]
|
||||
active_color: palette::Hsv,
|
||||
#[setters(skip)]
|
||||
|
|
@ -86,7 +86,7 @@ pub struct ColorPickerModel {
|
|||
copied_at: Option<Instant>,
|
||||
}
|
||||
|
||||
impl ColorPickerModel {
|
||||
impl<Message> ColorPickerModel<Message> {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
hex: impl Into<Cow<'static, str>> + Clone,
|
||||
|
|
@ -118,11 +118,11 @@ impl ColorPickerModel {
|
|||
|
||||
/// Get a color picker button that displays the applied color
|
||||
///
|
||||
pub fn picker_button<'a, Message: 'static, T: Fn(ColorPickerUpdate) -> Message>(
|
||||
pub fn picker_button<'a, T: Fn(ColorPickerUpdate) -> Message>(
|
||||
&self,
|
||||
f: T,
|
||||
icon_portion: Option<u16>,
|
||||
) -> crate::widget::Button<'a, Message, crate::Theme, crate::Renderer> {
|
||||
) -> crate::widget::Button<'a, Message, crate::Theme, crate::Renderer> where Message: 'static {
|
||||
color_button(
|
||||
Some(f(ColorPickerUpdate::ToggleColorPicker)),
|
||||
self.applied_color,
|
||||
|
|
@ -130,7 +130,7 @@ impl ColorPickerModel {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn update<Message>(&mut self, update: ColorPickerUpdate) -> Command<Message> {
|
||||
pub fn update(&mut self, update: ColorPickerUpdate) -> Command<Message> {
|
||||
match update {
|
||||
ColorPickerUpdate::ActiveColor(c) => {
|
||||
self.must_clear_cache.store(true, Ordering::SeqCst);
|
||||
|
|
@ -222,7 +222,7 @@ impl ColorPickerModel {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn builder<Message>(
|
||||
pub fn builder(
|
||||
&self,
|
||||
on_update: fn(ColorPickerUpdate) -> Message,
|
||||
) -> ColorPickerBuilder<Message> {
|
||||
|
|
@ -246,7 +246,7 @@ impl ColorPickerModel {
|
|||
#[derive(Setters, Clone)]
|
||||
pub struct ColorPickerBuilder<'a, Message> {
|
||||
#[setters(skip)]
|
||||
model: &'a Model<SingleSelect>,
|
||||
model: &'a Model<SingleSelect, Message>,
|
||||
#[setters(skip)]
|
||||
active_color: palette::Hsv,
|
||||
#[setters(skip)]
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ use crate::{theme, Theme};
|
|||
use super::dnd_destination::DragId;
|
||||
|
||||
pub type Id = segmented_button::Entity;
|
||||
pub type Model = segmented_button::SingleSelectModel;
|
||||
pub type Model<Message> = segmented_button::SingleSelectModel<Message>;
|
||||
|
||||
/// Navigation side panel for switching between views.
|
||||
///
|
||||
/// For details on the model, see the [`segmented_button`] module for more details.
|
||||
pub fn nav_bar<Message: Clone + 'static>(
|
||||
model: &segmented_button::SingleSelectModel,
|
||||
model: &Model<Message>,
|
||||
on_activate: fn(segmented_button::Entity) -> Message,
|
||||
) -> NavBar<Message> {
|
||||
NavBar {
|
||||
|
|
@ -35,7 +35,7 @@ pub fn nav_bar<Message: Clone + 'static>(
|
|||
/// Navigation side panel for switching between views.
|
||||
/// Can receive drag and drop events.
|
||||
pub fn nav_bar_dnd<Message, D: AllowedMimeTypes>(
|
||||
model: &segmented_button::SingleSelectModel,
|
||||
model: &Model<Message>,
|
||||
on_activate: fn(segmented_button::Entity) -> Message,
|
||||
on_dnd_enter: impl Fn(segmented_button::Entity, Vec<String>) -> Message + 'static,
|
||||
on_dnd_leave: impl Fn(segmented_button::Entity) -> Message + 'static,
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ pub struct Horizontal;
|
|||
///
|
||||
/// For details on the model, see the [`segmented_button`](super) module for more details.
|
||||
pub fn horizontal<SelectionMode: Default, Message>(
|
||||
model: &Model<SelectionMode>,
|
||||
model: &Model<SelectionMode, Message>,
|
||||
) -> SegmentedButton<Horizontal, SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
{
|
||||
SegmentedButton::new(model)
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ where
|
|||
impl<'a, SelectionMode, Message> SegmentedVariant
|
||||
for SegmentedButton<'a, Horizontal, SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
fn variant_appearance(
|
||||
|
|
|
|||
|
|
@ -8,38 +8,44 @@ use crate::widget::icon::Icon;
|
|||
use std::borrow::Cow;
|
||||
|
||||
/// A builder for a [`Model`].
|
||||
#[derive(Default)]
|
||||
pub struct ModelBuilder<SelectionMode: Default>(Model<SelectionMode>);
|
||||
pub struct ModelBuilder<SelectionMode: Default, Message>(Model<SelectionMode, Message>);
|
||||
|
||||
//TODO: Default derive ends up requiring Message to implement Default
|
||||
impl<SelectionMode: Default, Message> Default for ModelBuilder<SelectionMode, Message> {
|
||||
fn default() -> Self {
|
||||
Self(Model::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new item for the [`ModelBuilder`].
|
||||
pub struct BuilderEntity<SelectionMode: Default> {
|
||||
model: ModelBuilder<SelectionMode>,
|
||||
pub struct BuilderEntity<SelectionMode: Default, Message> {
|
||||
model: ModelBuilder<SelectionMode, Message>,
|
||||
id: Entity,
|
||||
}
|
||||
|
||||
impl<SelectionMode: Default> ModelBuilder<SelectionMode>
|
||||
impl<SelectionMode: Default, Message> ModelBuilder<SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
{
|
||||
/// Inserts a new item and its associated data into the model.
|
||||
#[must_use]
|
||||
pub fn insert(
|
||||
mut self,
|
||||
builder: impl Fn(BuilderEntity<SelectionMode>) -> BuilderEntity<SelectionMode>,
|
||||
builder: impl Fn(BuilderEntity<SelectionMode, Message>) -> BuilderEntity<SelectionMode, Message>,
|
||||
) -> Self {
|
||||
let id = self.0.insert().id();
|
||||
builder(BuilderEntity { model: self, id }).model
|
||||
}
|
||||
|
||||
/// Consumes the builder and returns the model.
|
||||
pub fn build(self) -> Model<SelectionMode> {
|
||||
pub fn build(self) -> Model<SelectionMode, Message> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<SelectionMode: Default> BuilderEntity<SelectionMode>
|
||||
impl<SelectionMode: Default, Message> BuilderEntity<SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
{
|
||||
/// Activates the newly-inserted item.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ use crate::widget::Icon;
|
|||
use super::{Entity, Model, Selectable};
|
||||
|
||||
/// A newly-inserted item which may have additional actions applied to it.
|
||||
pub struct EntityMut<'a, SelectionMode: Default> {
|
||||
pub struct EntityMut<'a, SelectionMode: Default, Message> {
|
||||
pub(super) id: Entity,
|
||||
pub(super) model: &'a mut Model<SelectionMode>,
|
||||
pub(super) model: &'a mut Model<SelectionMode, Message>,
|
||||
}
|
||||
|
||||
impl<'a, SelectionMode: Default> EntityMut<'a, SelectionMode>
|
||||
impl<'a, SelectionMode: Default, Message> EntityMut<'a, SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
{
|
||||
/// Activates the newly-inserted item.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ pub use self::entity::EntityMut;
|
|||
mod selection;
|
||||
pub use self::selection::{MultiSelect, Selectable, SingleSelect};
|
||||
|
||||
use crate::widget::Icon;
|
||||
use crate::{Element, widget::Icon};
|
||||
use slotmap::{SecondaryMap, SlotMap};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::borrow::Cow;
|
||||
|
|
@ -37,27 +37,29 @@ impl Default for Settings {
|
|||
}
|
||||
|
||||
/// A model for single-select button selection.
|
||||
pub type SingleSelectModel = Model<SingleSelect>;
|
||||
pub type SingleSelectModel<Message> = Model<SingleSelect, Message>;
|
||||
|
||||
/// Single-select variant of an [`EntityMut`].
|
||||
pub type SingleSelectEntityMut<'a> = EntityMut<'a, SingleSelect>;
|
||||
pub type SingleSelectEntityMut<'a, Message> = EntityMut<'a, SingleSelect, Message>;
|
||||
|
||||
/// A model for multi-select button selection.
|
||||
pub type MultiSelectModel = Model<MultiSelect>;
|
||||
pub type MultiSelectModel<Message> = Model<MultiSelect, Message>;
|
||||
|
||||
/// Multi-select variant of an [`EntityMut`].
|
||||
pub type MultiSelectEntityMut<'a> = EntityMut<'a, MultiSelect>;
|
||||
pub type MultiSelectEntityMut<'a, Message> = EntityMut<'a, MultiSelect, Message>;
|
||||
|
||||
/// The portion of the model used only by the application.
|
||||
#[derive(Debug, Default)]
|
||||
pub(super) struct Storage(HashMap<TypeId, SecondaryMap<Entity, Box<dyn Any>>>);
|
||||
|
||||
/// The model held by the application, containing the unique IDs and data of each inserted item.
|
||||
#[derive(Default)]
|
||||
pub struct Model<SelectionMode: Default> {
|
||||
pub struct Model<SelectionMode: Default, Message> {
|
||||
/// The content used for drawing segmented items.
|
||||
pub(super) items: SlotMap<Entity, Settings>,
|
||||
|
||||
/// Elements optionally-defined for each item.
|
||||
pub(super) elements: SecondaryMap<Entity, Element<'static, Message>>,
|
||||
|
||||
/// Icons optionally-defined for each item.
|
||||
pub(super) icons: SecondaryMap<Entity, Icon>,
|
||||
|
||||
|
|
@ -77,7 +79,23 @@ pub struct Model<SelectionMode: Default> {
|
|||
pub(super) storage: Storage,
|
||||
}
|
||||
|
||||
impl<SelectionMode: Default> Model<SelectionMode>
|
||||
//TODO: Default derive ends up requiring Message to implement Default
|
||||
impl<SelectionMode: Default, Message> Default for Model<SelectionMode, Message> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
items: SlotMap::default(),
|
||||
elements: SecondaryMap::default(),
|
||||
icons: SecondaryMap::default(),
|
||||
indents: SecondaryMap::default(),
|
||||
text: SecondaryMap::default(),
|
||||
order: VecDeque::default(),
|
||||
selection: SelectionMode::default(),
|
||||
storage: Storage::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<SelectionMode: Default, Message> Model<SelectionMode, Message>
|
||||
where
|
||||
Self: Selectable,
|
||||
{
|
||||
|
|
@ -110,7 +128,7 @@ where
|
|||
/// .build();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn builder() -> ModelBuilder<SelectionMode> {
|
||||
pub fn builder() -> ModelBuilder<SelectionMode, Message> {
|
||||
ModelBuilder::default()
|
||||
}
|
||||
|
||||
|
|
@ -259,7 +277,7 @@ where
|
|||
/// let id = model.insert().text("Item A").icon("custom-icon").id();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn insert(&mut self) -> EntityMut<SelectionMode> {
|
||||
pub fn insert(&mut self) -> EntityMut<SelectionMode, Message> {
|
||||
let id = self.items.insert(Settings::default());
|
||||
self.order.push_back(id);
|
||||
EntityMut { model: self, id }
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub struct SingleSelect {
|
|||
pub active: Entity,
|
||||
}
|
||||
|
||||
impl Selectable for Model<SingleSelect> {
|
||||
impl<Message> Selectable for Model<SingleSelect, Message> {
|
||||
fn activate(&mut self, id: Entity) {
|
||||
if !self.items.contains_key(id) {
|
||||
return;
|
||||
|
|
@ -44,7 +44,7 @@ impl Selectable for Model<SingleSelect> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Model<SingleSelect> {
|
||||
impl<Message> Model<SingleSelect, Message> {
|
||||
/// Get an immutable reference to the data associated with the active item.
|
||||
#[must_use]
|
||||
pub fn active_data<Data: 'static>(&self) -> Option<&Data> {
|
||||
|
|
@ -75,7 +75,7 @@ pub struct MultiSelect {
|
|||
pub active: HashSet<Entity>,
|
||||
}
|
||||
|
||||
impl Selectable for Model<MultiSelect> {
|
||||
impl<Message> Selectable for Model<MultiSelect, Message> {
|
||||
fn activate(&mut self, id: Entity) {
|
||||
if !self.items.contains_key(id) {
|
||||
return;
|
||||
|
|
@ -95,7 +95,7 @@ impl Selectable for Model<MultiSelect> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Model<MultiSelect> {
|
||||
impl<Message> Model<MultiSelect, Message> {
|
||||
/// Deactivates the item in the model.
|
||||
pub fn deactivate(&mut self, id: Entity) {
|
||||
Selectable::deactivate(self, id);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ pub type VerticalSegmentedButton<'a, SelectionMode, Message> =
|
|||
///
|
||||
/// For details on the model, see the [`segmented_button`](super) module for more details.
|
||||
pub fn vertical<SelectionMode, Message>(
|
||||
model: &Model<SelectionMode>,
|
||||
model: &Model<SelectionMode, Message>,
|
||||
) -> SegmentedButton<Vertical, SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
SegmentedButton::new(model)
|
||||
|
|
@ -33,7 +33,7 @@ where
|
|||
impl<'a, SelectionMode, Message> SegmentedVariant
|
||||
for SegmentedButton<'a, Vertical, SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
fn variant_appearance(
|
||||
|
|
|
|||
|
|
@ -71,12 +71,12 @@ pub trait SegmentedVariant {
|
|||
#[must_use]
|
||||
pub struct SegmentedButton<'a, Variant, SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
/// The model borrowed from the application create this widget.
|
||||
#[setters(skip)]
|
||||
pub(super) model: &'a Model<SelectionMode>,
|
||||
pub(super) model: &'a Model<SelectionMode, Message>,
|
||||
/// iced widget ID
|
||||
pub(super) id: Id,
|
||||
/// The icon used for the close button.
|
||||
|
|
@ -151,10 +151,10 @@ where
|
|||
impl<'a, Variant, SelectionMode, Message> SegmentedButton<'a, Variant, SelectionMode, Message>
|
||||
where
|
||||
Self: SegmentedVariant,
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
pub fn new(model: &'a Model<SelectionMode>) -> Self {
|
||||
pub fn new(model: &'a Model<SelectionMode, Message>) -> Self {
|
||||
Self {
|
||||
model,
|
||||
id: Id::unique(),
|
||||
|
|
@ -536,7 +536,7 @@ impl<'a, Variant, SelectionMode, Message> Widget<Message, crate::Theme, Renderer
|
|||
for SegmentedButton<'a, Variant, SelectionMode, Message>
|
||||
where
|
||||
Self: SegmentedVariant,
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
Message: 'static + Clone,
|
||||
{
|
||||
|
|
@ -1555,7 +1555,7 @@ impl<'a, Variant, SelectionMode, Message> From<SegmentedButton<'a, Variant, Sele
|
|||
where
|
||||
SegmentedButton<'a, Variant, SelectionMode, Message>: SegmentedVariant,
|
||||
Variant: 'static,
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
Message: 'static + Clone,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ use super::segmented_button::{
|
|||
///
|
||||
/// For details on the model, see the [`segmented_button`] module for more details.
|
||||
pub fn horizontal<SelectionMode: Default, Message>(
|
||||
model: &Model<SelectionMode>,
|
||||
model: &Model<SelectionMode, Message>,
|
||||
) -> HorizontalSegmentedButton<SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
{
|
||||
let theme = crate::theme::active();
|
||||
let space_s = theme.cosmic().space_s();
|
||||
|
|
@ -40,10 +40,10 @@ where
|
|||
///
|
||||
/// For details on the model, see the [`segmented_button`] module for more details.
|
||||
pub fn vertical<SelectionMode, Message>(
|
||||
model: &Model<SelectionMode>,
|
||||
model: &Model<SelectionMode, Message>,
|
||||
) -> VerticalSegmentedButton<SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
let theme = crate::theme::active();
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ use super::segmented_button::{
|
|||
///
|
||||
/// For details on the model, see the [`segmented_button`] module for more details.
|
||||
pub fn horizontal<SelectionMode: Default, Message>(
|
||||
model: &Model<SelectionMode>,
|
||||
model: &Model<SelectionMode, Message>,
|
||||
) -> HorizontalSegmentedButton<SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
{
|
||||
let theme = crate::theme::active();
|
||||
let space_s = theme.cosmic().space_s();
|
||||
|
|
@ -38,10 +38,10 @@ where
|
|||
/// The data for the widget comes from a model that is maintained the application.
|
||||
/// For details on the model, see the [`segmented_button`] module for more details.
|
||||
pub fn vertical<SelectionMode, Message>(
|
||||
model: &Model<SelectionMode>,
|
||||
model: &Model<SelectionMode, Message>,
|
||||
) -> VerticalSegmentedButton<SelectionMode, Message>
|
||||
where
|
||||
Model<SelectionMode>: Selectable,
|
||||
Model<SelectionMode, Message>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
let theme = crate::theme::active();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue