forked from pop-os/cosmic-settings
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsection.rs
126 lines (110 loc) · 3.26 KB
/
section.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only
use derive_setters::Setters;
use regex::Regex;
use std::borrow::Cow;
use crate::{Binder, Page};
slotmap::new_key_type! {
/// The unique ID of a section of page.
pub struct Entity;
}
pub type ShowWhileFn<Message> = Box<dyn for<'a> Fn(&'a dyn Page<Message>) -> bool>;
pub type ViewFn<Message> = Box<
dyn for<'a> Fn(
&'a Binder<Message>,
&'a dyn Page<Message>,
&'a Section<Message>,
) -> cosmic::Element<'a, Message>,
>;
/// A searchable sub-component of a page.
///
/// Searches can group multiple sections together.
#[derive(Setters)]
#[must_use]
pub struct Section<Message> {
#[setters(into)]
pub title: String,
#[setters(into)]
pub descriptions: Vec<Cow<'static, str>>,
#[setters(skip)]
pub show_while: Option<ShowWhileFn<Message>>,
#[setters(skip)]
pub view_fn: ViewFn<Message>,
#[setters(bool)]
pub search_ignore: bool,
}
impl<Message: 'static> Default for Section<Message> {
fn default() -> Self {
Self {
title: String::new(),
descriptions: Vec::new(),
show_while: None,
view_fn: Box::new(unimplemented),
search_ignore: false,
}
}
}
impl<Message: 'static> Section<Message> {
#[must_use]
pub fn search_matches(&self, rule: &Regex) -> bool {
if self.search_ignore {
return false;
}
if rule.is_match(self.title.as_str()) {
return true;
}
for description in &*self.descriptions {
if rule.is_match(description) {
return true;
}
}
false
}
pub fn show_while<Model: Page<Message>>(
mut self,
func: impl for<'a> Fn(&'a Model) -> bool + 'static,
) -> Self {
self.show_while = Some(Box::new(move |model: &dyn Page<Message>| {
let model = model.downcast_ref::<Model>().unwrap_or_else(|| {
panic!(
"page model type mismatch: expected {}",
std::any::type_name::<Model>()
)
});
func(model)
}));
self
}
/// # Panics
///
/// Will panic if the `Model` type does not match the page type.
pub fn view<Model: Page<Message>>(
mut self,
func: impl for<'a> Fn(
&'a Binder<Message>,
&'a Model,
&'a Section<Message>,
) -> cosmic::Element<'a, Message>
+ 'static,
) -> Self {
self.view_fn = Box::new(move |binder, model: &dyn Page<Message>, section| {
let model = model.downcast_ref::<Model>().unwrap_or_else(|| {
panic!(
"page model type mismatch: expected {}",
std::any::type_name::<Model>()
)
});
func(binder, model, section)
});
self
}
}
#[must_use]
pub fn unimplemented<'a, Message: 'static>(
_binder: &'a Binder<Message>,
_page: &'a dyn Page<Message>,
_section: &'a Section<Message>,
) -> cosmic::Element<'a, Message> {
cosmic::widget::settings::view_column(vec![cosmic::widget::settings::view_section("").into()])
.into()
}