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
// SPDX-License-Identifier: MPL-2.0
//! A drop-down menu of mutually-exclusive selectable items.
use crate::prelude::*;
impl Ui {
/// Creates a new [`Combobox`].
pub fn create_combobox<'ui>(&'ui self) -> Result<&'ui mut Combobox, crate::Error> {
unsafe { call_libui_new_fn!(ui: self, fn: uiNewCombobox() -> Combobox) }
}
}
/// A drop-down menu of mutually-exclusive selectable items.
///
/// Comboboxes in *libui-ng* may only select a single item at a time. They are similar to
/// [radio buttons](crate::RadioButtons) in this regard, and in some cases they may be used
/// interchangeably, though radio buttons are better suited for four and fewer items.
#[subcontrol(handle = "uiCombobox")]
#[derive(Container)]
#[container(
child_count = "uiComboboxNumItems",
remove_child = "uiComboboxDelete",
clear = "uiComboboxClear",
)]
pub struct Combobox;
impl<'ui> Combobox<'ui> {
/// Appends a new item with the given text, returning its index.
///
/// The new item is appended to the bottom of the menu.
pub fn push_item(&self, text: impl Into<Vec<u8>>) -> Result<NonNegativeInt, crate::Error> {
let index = self.child_count();
let text = self.ui.make_cstring(text)?;
unsafe { uiComboboxAppend(self.as_ptr(), text.as_ptr()) };
Ok(index)
}
/// Inserts a new item with the given text before an existing item, returning the index of the
/// new item.
///
/// # Arguments
///
/// `before` is the index of the existing item that follows the new item. The returned index is
/// equivalent to `before`.
///
/// # Panics
///
/// Panics if `before` is out of bounds.
pub fn insert_item(
&self,
before: impl Into<NonNegativeInt>,
text: impl Into<Vec<u8>>,
) -> Result<NonNegativeInt, crate::Error> {
let before = before.into();
assert!(self.contains_child(before));
let text = self.ui.make_cstring(text)?;
unsafe { uiComboboxInsertAt(self.as_ptr(), before.to_libui(), text.as_ptr()) };
Ok(before)
}
/// The index of the currently-selected item.
///
/// If no item is selected, this returns `None`.
pub fn selected_item(&self) -> Option<NonNegativeInt> {
match unsafe { uiComboboxSelected(self.as_ptr()) } {
-1 => None,
it => Some(unsafe { NonNegativeInt::from_libui(it) }),
}
}
/// Selects the item with the given index.
///
/// This overrides any selections made by the user.
///
/// # Panics
///
/// Panics if `index` is out of bounds.
pub fn select_item(&self, index: impl Into<NonNegativeInt>) {
let index = index.into();
assert!(self.contains_child(index));
unsafe { uiComboboxSetSelected(self.as_ptr(), index.to_libui()) };
}
/// De-selects the currently-selected item.
///
/// This overrides any selections made by the user. If no item is selected, this does nothing.
#[inline]
pub fn deselect_item(&self) {
unsafe { uiComboboxSetSelected(self.as_ptr(), -1) };
}
/// Sets a callback for when the user selects an item.
///
/// This callback is unset by default. This is not activated when
/// [`select_item`](Self::select_item) is called.
#[bind_callback(fn = "uiComboboxOnSelected")]
pub fn on_item_selected(&self, f: fn()) {
f();
}
}