Skip to main content

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