use gpui::{ App, IntoElement, ParentElement as _, SharedString, StyleRefinement, Styled, Window, prelude::FluentBuilder as _, }; use crate::{ ActiveTheme, StyledExt, group_box::{GroupBox, GroupBoxVariants}, label::Label, setting::{RenderOptions, SettingItem}, v_flex, }; /// A setting group that can contain multiple setting items. #[derive(Clone)] pub struct SettingGroup { style: StyleRefinement, pub(super) title: Option, pub(super) description: Option, pub(super) items: Vec, } impl Styled for SettingGroup { fn style(&mut self) -> &mut StyleRefinement { &mut self.style } } impl SettingGroup { /// Create a new setting group. pub fn new() -> Self { Self { style: StyleRefinement::default(), title: None, description: None, items: Vec::new(), } } /// Set the label of the setting group, default is None. pub fn title(mut self, title: impl Into) -> Self { self.title = Some(title.into()); self } /// Set the description of the setting group, default is None. pub fn description(mut self, description: impl Into) -> Self { self.description = Some(description.into()); self } /// Add a setting item to the group. pub fn item(mut self, item: SettingItem) -> Self { self.items.push(item); self } /// Add multiple setting items to the group. pub fn items(mut self, items: I) -> Self where I: IntoIterator, { self.items.extend(items); self } /// Return true if any of the setting items in the group match the given query. pub(super) fn is_match(&self, query: &str) -> bool { self.items.iter().any(|item| item.is_match(query)) } pub(super) fn is_resettable(&self, cx: &App) -> bool { self.items.iter().any(|item| item.is_resettable(cx)) } pub(crate) fn render( self, query: &str, options: &RenderOptions, window: &mut Window, cx: &mut App, ) -> impl IntoElement { GroupBox::new() .id(SharedString::from(format!("group-{}", options.group_ix))) .with_variant(options.group_variant) .when_some(self.title.clone(), |this, title| { this.title(v_flex().gap_1().child(title).when_some( self.description.clone(), |this, description| { this.child( Label::new(description) .text_sm() .text_color(cx.theme().muted_foreground), ) }, )) }) .gap_4() .children(self.items.iter().enumerate().filter_map(|(item_ix, item)| { if item.is_match(&query) { Some(item.clone().render_item( &RenderOptions { item_ix, ..*options }, window, cx, )) } else { None } })) .refine_style(&self.style) } pub(crate) fn reset(&self, window: &mut Window, cx: &mut App) { for item in &self.items { item.reset(window, cx); } } }