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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use bitflags::bitflags;

use crate::math::MintVec2;
use crate::sys;
use crate::Ui;

bitflags!(
    /// Flags for selectables
    #[repr(transparent)]
    pub struct SelectableFlags: u32 {
        /// Clicking this don't close parent popup window
        const DONT_CLOSE_POPUPS = sys::ImGuiSelectableFlags_DontClosePopups;
        /// Selectable frame can span all columns (text will still fit in current column)
        const SPAN_ALL_COLUMNS = sys::ImGuiSelectableFlags_SpanAllColumns;
        /// Generate press events on double clicks too
        const ALLOW_DOUBLE_CLICK = sys::ImGuiSelectableFlags_AllowDoubleClick;
        /// Cannot be selected, display greyed out text
        const DISABLED = sys::ImGuiSelectableFlags_Disabled;
        /// (WIP) Hit testing to allow subsequent willdgets to overlap this one
        const ALLOW_ITEM_OVERLAP = sys::ImGuiSelectableFlags_AllowItemOverlap;
    }
);

impl Ui {
    /// Constructs a new simple selectable.
    ///
    /// Use [selectable_config] for a builder with additional options.
    ///
    /// [selectable_config]: Self::selectable_config
    #[doc(alias = "Selectable")]
    pub fn selectable<T: AsRef<str>>(&self, label: T) -> bool {
        self.selectable_config(label).build()
    }

    /// Constructs a new selectable builder.
    #[doc(alias = "Selectable")]
    pub fn selectable_config<T: AsRef<str>>(&self, label: T) -> Selectable<'_, T> {
        Selectable {
            label,
            selected: false,
            flags: SelectableFlags::empty(),
            size: [0.0, 0.0],
            ui: self,
        }
    }
}

/// Builder for a selectable widget.
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct Selectable<'ui, T> {
    label: T,
    selected: bool,
    flags: SelectableFlags,
    size: [f32; 2],
    ui: &'ui Ui,
}

impl<'ui, T: AsRef<str>> Selectable<'ui, T> {
    /// Constructs a new selectable builder.
    #[doc(alias = "Selectable")]
    #[deprecated(
        since = "0.9.0",
        note = "use `ui.selectable` or `ui.selectable_config`"
    )]
    pub fn new(label: T, ui: &'ui Ui) -> Self {
        Selectable {
            label,
            selected: false,
            flags: SelectableFlags::empty(),
            size: [0.0, 0.0],
            ui,
        }
    }
    /// Replaces all current settings with the given flags
    pub fn flags(mut self, flags: SelectableFlags) -> Self {
        self.flags = flags;
        self
    }
    /// Sets the selected state of the selectable
    pub fn selected(mut self, selected: bool) -> Self {
        self.selected = selected;
        self
    }
    /// Enables/disables closing parent popup window on click.
    ///
    /// Default: enabled
    pub fn close_popups(mut self, value: bool) -> Self {
        self.flags.set(SelectableFlags::DONT_CLOSE_POPUPS, !value);
        self
    }
    /// Enables/disables full column span (text will still fit in the current column).
    ///
    /// Default: disabled
    pub fn span_all_columns(mut self, value: bool) -> Self {
        self.flags.set(SelectableFlags::SPAN_ALL_COLUMNS, value);
        self
    }
    /// Enables/disables click event generation on double clicks.
    ///
    /// Default: disabled
    pub fn allow_double_click(mut self, value: bool) -> Self {
        self.flags.set(SelectableFlags::ALLOW_DOUBLE_CLICK, value);
        self
    }
    /// Enables/disables the selectable.
    ///
    /// When disabled, it cannot be selected and the text uses the disabled text color.
    ///
    /// Default: disabled
    pub fn disabled(mut self, value: bool) -> Self {
        self.flags.set(SelectableFlags::DISABLED, value);
        self
    }
    /// Sets the size of the selectable.
    ///
    /// For the X axis:
    ///
    /// - `> 0.0`: use given width
    /// - `= 0.0`: use remaining width
    ///
    /// For the Y axis:
    ///
    /// - `> 0.0`: use given height
    /// - `= 0.0`: use label height
    pub fn size(mut self, size: impl Into<MintVec2>) -> Self {
        self.size = size.into().into();
        self
    }

    /// Builds the selectable.
    ///
    /// Returns true if the selectable was clicked.
    pub fn build(self) -> bool {
        unsafe {
            sys::igSelectable_Bool(
                self.ui.scratch_txt(self.label),
                self.selected,
                self.flags.bits() as i32,
                self.size.into(),
            )
        }
    }

    /// Builds the selectable using a mutable reference to selected state.
    pub fn build_with_ref(self, selected: &mut bool) -> bool {
        if self.selected(*selected).build() {
            *selected = !*selected;
            true
        } else {
            false
        }
    }
}