cosmic/widget/table/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::{
7    Entity, Model,
8    category::{ItemCategory, ItemInterface},
9};
10use std::collections::HashSet;
11
12/// Describes a type that has selectable items.
13pub trait Selectable {
14    /// Activate an item.
15    fn activate(&mut self, id: Entity);
16
17    /// Deactivate an item.
18    fn deactivate(&mut self, id: Entity);
19
20    /// Checks if the item is active.
21    fn is_active(&self, id: Entity) -> bool;
22}
23
24/// [`Model<SingleSelect>`] Ensures that only one key may be selected.
25#[derive(Debug, Default)]
26pub struct SingleSelect {
27    pub active: Entity,
28}
29
30impl<Item: ItemInterface<Category>, Category: ItemCategory> Selectable
31    for Model<SingleSelect, Item, Category>
32{
33    fn activate(&mut self, id: Entity) {
34        if !self.items.contains_key(id) {
35            return;
36        }
37
38        self.selection.active = id;
39    }
40
41    fn deactivate(&mut self, id: Entity) {
42        if id == self.selection.active {
43            self.selection.active = Entity::default();
44        }
45    }
46
47    fn is_active(&self, id: Entity) -> bool {
48        self.selection.active == id
49    }
50}
51
52impl<Item: ItemInterface<Category>, Category: ItemCategory> Model<SingleSelect, Item, Category> {
53    /// Get an immutable reference to the data associated with the active item.
54    #[must_use]
55    pub fn active_data<Data: 'static>(&self) -> Option<&Data> {
56        self.data(self.active())
57    }
58
59    /// Get a mutable reference to the data associated with the active item.
60    #[must_use]
61    pub fn active_data_mut<Data: 'static>(&mut self) -> Option<&mut Data> {
62        self.data_mut(self.active())
63    }
64
65    /// Deactivates the active item.
66    pub fn deactivate(&mut self) {
67        Selectable::deactivate(self, Entity::default());
68    }
69
70    /// The ID of the active item.
71    #[must_use]
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<Item: ItemInterface<Category>, Category: ItemCategory> Selectable
84    for Model<MultiSelect, Item, Category>
85{
86    fn activate(&mut self, id: Entity) {
87        if !self.items.contains_key(id) {
88            return;
89        }
90
91        if !self.selection.active.insert(id) {
92            self.selection.active.remove(&id);
93        }
94    }
95
96    fn deactivate(&mut self, id: Entity) {
97        self.selection.active.remove(&id);
98    }
99
100    fn is_active(&self, id: Entity) -> bool {
101        self.selection.active.contains(&id)
102    }
103}
104
105impl<Item: ItemInterface<Category>, Category: ItemCategory> Model<MultiSelect, Item, Category> {
106    /// Deactivates the item in the model.
107    pub fn deactivate(&mut self, id: Entity) {
108        Selectable::deactivate(self, id);
109    }
110
111    /// The IDs of the active items.
112    pub fn active(&self) -> impl Iterator<Item = Entity> + '_ {
113        self.selection.active.iter().copied()
114    }
115}