gpui_component/setting/
group.rs1use gpui::{
2 App, IntoElement, ParentElement as _, SharedString, StyleRefinement, Styled, Window,
3 prelude::FluentBuilder as _,
4};
5
6use crate::{
7 ActiveTheme, StyledExt,
8 group_box::{GroupBox, GroupBoxVariants},
9 label::Label,
10 setting::{RenderOptions, SettingItem},
11 v_flex,
12};
13
14#[derive(Clone)]
16pub struct SettingGroup {
17 style: StyleRefinement,
18
19 pub(super) title: Option<SharedString>,
20 pub(super) description: Option<SharedString>,
21 pub(super) items: Vec<SettingItem>,
22}
23
24impl Styled for SettingGroup {
25 fn style(&mut self) -> &mut StyleRefinement {
26 &mut self.style
27 }
28}
29
30impl SettingGroup {
31 pub fn new() -> Self {
33 Self {
34 style: StyleRefinement::default(),
35 title: None,
36 description: None,
37 items: Vec::new(),
38 }
39 }
40
41 pub fn title(mut self, title: impl Into<SharedString>) -> Self {
43 self.title = Some(title.into());
44 self
45 }
46
47 pub fn description(mut self, description: impl Into<SharedString>) -> Self {
49 self.description = Some(description.into());
50 self
51 }
52
53 pub fn item(mut self, item: SettingItem) -> Self {
55 self.items.push(item);
56 self
57 }
58
59 pub fn items<I>(mut self, items: I) -> Self
61 where
62 I: IntoIterator<Item = SettingItem>,
63 {
64 self.items.extend(items);
65 self
66 }
67
68 pub(super) fn is_match(&self, query: &str, cx: &App) -> bool {
70 self.items.iter().any(|item| item.is_match(query, cx))
71 }
72
73 pub(super) fn is_resettable(&self, query: &str, cx: &App) -> bool {
74 self.items
75 .iter()
76 .any(|item| item.is_match(query, cx) && item.is_resettable(cx))
77 }
78
79 pub(crate) fn render(
80 self,
81 query: &str,
82 options: &RenderOptions,
83 window: &mut Window,
84 cx: &mut App,
85 ) -> impl IntoElement {
86 GroupBox::new()
87 .id(SharedString::from(format!("group-{}", options.group_ix())))
88 .with_variant(options.group_variant())
89 .when_some(self.title.clone(), |this, title| {
90 this.title(v_flex().gap_1().child(title).when_some(
91 self.description.clone(),
92 |this, description| {
93 this.child(
94 Label::new(description)
95 .text_sm()
96 .text_color(cx.theme().muted_foreground),
97 )
98 },
99 ))
100 })
101 .gap_4()
102 .children(self.items.iter().enumerate().filter_map(|(item_ix, item)| {
103 if item.is_match(&query, cx) {
104 Some(
105 item.clone()
106 .render_item(&options.with_item_ix(item_ix), window, cx),
107 )
108 } else {
109 None
110 }
111 }))
112 .refine_style(&self.style)
113 }
114
115 pub(crate) fn reset(&self, query: &str, window: &mut Window, cx: &mut App) {
116 for item in &self.items {
117 if item.is_match(query, cx) {
118 item.reset(window, cx);
119 }
120 }
121 }
122}