checkbox.rs

  1mod checkbox_with_label;
  2
  3pub use checkbox_with_label::*;
  4
  5use gpui::{div, prelude::*, ElementId, IntoElement, Styled, WindowContext};
  6
  7use crate::prelude::*;
  8use crate::{Color, Icon, IconName, Selection};
  9
 10/// # Checkbox
 11///
 12/// Checkboxes are used for multiple choices, not for mutually exclusive choices.
 13/// Each checkbox works independently from other checkboxes in the list,
 14/// therefore checking an additional box does not affect any other selections.
 15#[derive(IntoElement)]
 16pub struct Checkbox {
 17    id: ElementId,
 18    checked: Selection,
 19    disabled: bool,
 20    on_click: Option<Box<dyn Fn(&Selection, &mut WindowContext) + 'static>>,
 21}
 22
 23impl Checkbox {
 24    pub fn new(id: impl Into<ElementId>, checked: Selection) -> Self {
 25        Self {
 26            id: id.into(),
 27            checked,
 28            disabled: false,
 29            on_click: None,
 30        }
 31    }
 32
 33    pub fn disabled(mut self, disabled: bool) -> Self {
 34        self.disabled = disabled;
 35        self
 36    }
 37
 38    pub fn on_click(mut self, handler: impl Fn(&Selection, &mut WindowContext) + 'static) -> Self {
 39        self.on_click = Some(Box::new(handler));
 40        self
 41    }
 42}
 43
 44impl RenderOnce for Checkbox {
 45    fn render(self, cx: &mut WindowContext) -> impl IntoElement {
 46        let group_id = format!("checkbox_group_{:?}", self.id);
 47
 48        let icon = match self.checked {
 49            Selection::Selected => Some(Icon::new(IconName::Check).size(IconSize::Small).color(
 50                if self.disabled {
 51                    Color::Disabled
 52                } else {
 53                    Color::Selected
 54                },
 55            )),
 56            Selection::Indeterminate => Some(
 57                Icon::new(IconName::Dash)
 58                    .size(IconSize::Small)
 59                    .color(if self.disabled {
 60                        Color::Disabled
 61                    } else {
 62                        Color::Selected
 63                    }),
 64            ),
 65            Selection::Unselected => None,
 66        };
 67
 68        let selected =
 69            self.checked == Selection::Selected || self.checked == Selection::Indeterminate;
 70
 71        let (bg_color, border_color) = match (self.disabled, selected) {
 72            (true, _) => (
 73                cx.theme().colors().ghost_element_disabled,
 74                cx.theme().colors().border_disabled,
 75            ),
 76            (false, true) => (
 77                cx.theme().colors().element_selected,
 78                cx.theme().colors().border,
 79            ),
 80            (false, false) => (
 81                cx.theme().colors().element_background,
 82                cx.theme().colors().border,
 83            ),
 84        };
 85
 86        h_flex()
 87            .id(self.id)
 88            .justify_center()
 89            .items_center()
 90            .size(crate::styles::custom_spacing(cx, 20.))
 91            .group(group_id.clone())
 92            .child(
 93                div()
 94                    .flex()
 95                    .flex_none()
 96                    .justify_center()
 97                    .items_center()
 98                    .m(Spacing::Small.px(cx))
 99                    .size(crate::styles::custom_spacing(cx, 16.))
100                    .rounded_sm()
101                    .bg(bg_color)
102                    .border_1()
103                    .border_color(border_color)
104                    .when(!self.disabled, |this| {
105                        this.group_hover(group_id.clone(), |el| {
106                            el.bg(cx.theme().colors().element_hover)
107                        })
108                    })
109                    .children(icon),
110            )
111            .when_some(
112                self.on_click.filter(|_| !self.disabled),
113                |this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
114            )
115    }
116}