cosmic/widget/segmented_button/model/
selection.rs

1// Copyright 2022 System76 <info@system76.com>
2// SPDX-License-Identifier: MPL-2.0
3
4//! Describes logic specific to the single-select and multi-select modes of a model.
5
6use super::{Entity, Model};
7use std::collections::HashSet;
8
9/// Describes a type that has selectable items.
10pub trait Selectable {
11    /// Activate an item.
12    fn activate(&mut self, id: Entity);
13
14    /// Deactivate an item.
15    fn deactivate(&mut self, id: Entity);
16
17    /// Checks if the item is active.
18    fn is_active(&self, id: Entity) -> bool;
19}
20
21/// [`Model<SingleSelect>`] Ensures that only one key may be selected.
22#[derive(Debug, Default)]
23pub struct SingleSelect {
24    pub active: Entity,
25}
26
27impl Selectable for Model<SingleSelect> {
28    fn activate(&mut self, id: Entity) {
29        if !self.items.contains_key(id) {
30            return;
31        }
32
33        self.selection.active = id;
34    }
35
36    fn deactivate(&mut self, id: Entity) {
37        if id == self.selection.active {
38            self.selection.active = Entity::default();
39        }
40    }
41
42    #[inline]
43    fn is_active(&self, id: Entity) -> bool {
44        self.selection.active == id
45    }
46}
47
48impl Model<SingleSelect> {
49    /// Get an immutable reference to the data associated with the active item.
50    #[must_use]
51    #[inline]
52    pub fn active_data<Data: 'static>(&self) -> Option<&Data> {
53        self.data(self.active())
54    }
55
56    /// Get a mutable reference to the data associated with the active item.
57    #[must_use]
58    #[inline]
59    pub fn active_data_mut<Data: 'static>(&mut self) -> Option<&mut Data> {
60        self.data_mut(self.active())
61    }
62
63    /// Deactivates the active item.
64    #[inline]
65    pub fn deactivate(&mut self) {
66        Selectable::deactivate(self, Entity::default());
67    }
68
69    /// The ID of the active item.
70    #[must_use]
71    #[inline]
72    pub fn active(&self) -> Entity {
73        self.selection.active
74    }
75}
76
77/// [`Model<MultiSelect>`] permits multiple keys to be active at a time.
78#[derive(Debug, Default)]
79pub struct MultiSelect {
80    pub active: HashSet<Entity>,
81}
82
83impl Selectable for Model<MultiSelect> {
84    fn activate(&mut self, id: Entity) {
85        if !self.items.contains_key(id) {
86            return;
87        }
88
89        if !self.selection.active.insert(id) {
90            self.selection.active.remove(&id);
91        }
92    }
93
94    #[inline]
95    fn deactivate(&mut self, id: Entity) {
96        self.selection.active.remove(&id);
97    }
98
99    #[inline]
100    fn is_active(&self, id: Entity) -> bool {
101        self.selection.active.contains(&id)
102    }
103}
104
105impl Model<MultiSelect> {
106    /// Deactivates the item in the model.
107    #[inline]
108    pub fn deactivate(&mut self, id: Entity) {
109        Selectable::deactivate(self, id);
110    }
111
112    /// The IDs of the active items.
113    #[inline]
114    pub fn active(&self) -> impl Iterator<Item = Entity> + '_ {
115        self.selection.active.iter().copied()
116    }
117}