#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::as_conversions
)]
use crate::Ui;
use crate::sys;
fn assert_non_negative_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
assert!(
value[0].is_finite() && value[1].is_finite(),
"{caller} {name} must contain finite values"
);
assert!(
value[0] >= 0.0 && value[1] >= 0.0,
"{caller} {name} must contain non-negative values"
);
}
fn validate_selectable_flags(caller: &str, flags: SelectableFlags) {
let unsupported = flags.bits() & !SelectableFlags::all().bits();
assert!(
unsupported == 0,
"{caller} received unsupported ImGuiSelectableFlags bits: 0x{unsupported:X}"
);
}
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SelectableFlags: i32 {
const NO_AUTO_CLOSE_POPUPS = sys::ImGuiSelectableFlags_NoAutoClosePopups as i32;
const SPAN_ALL_COLUMNS = sys::ImGuiSelectableFlags_SpanAllColumns as i32;
const ALLOW_DOUBLE_CLICK = sys::ImGuiSelectableFlags_AllowDoubleClick as i32;
const DISABLED = sys::ImGuiSelectableFlags_Disabled as i32;
const ALLOW_OVERLAP = sys::ImGuiSelectableFlags_AllowOverlap as i32;
const HIGHLIGHT = sys::ImGuiSelectableFlags_Highlight as i32;
const SELECT_ON_NAV = sys::ImGuiSelectableFlags_SelectOnNav as i32;
}
}
impl Ui {
#[doc(alias = "Selectable")]
pub fn selectable<T: AsRef<str>>(&self, label: T) -> bool {
self.selectable_config(label).build()
}
#[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,
}
}
}
#[derive(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> {
#[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,
}
}
pub fn flags(mut self, flags: SelectableFlags) -> Self {
self.flags = flags;
self
}
pub fn selected(mut self, selected: bool) -> Self {
self.selected = selected;
self
}
pub fn close_popups(mut self, value: bool) -> Self {
self.flags
.set(SelectableFlags::NO_AUTO_CLOSE_POPUPS, !value);
self
}
pub fn span_all_columns(mut self, value: bool) -> Self {
self.flags.set(SelectableFlags::SPAN_ALL_COLUMNS, value);
self
}
pub fn allow_double_click(mut self, value: bool) -> Self {
self.flags.set(SelectableFlags::ALLOW_DOUBLE_CLICK, value);
self
}
pub fn disabled(mut self, value: bool) -> Self {
self.flags.set(SelectableFlags::DISABLED, value);
self
}
pub fn size(mut self, size: impl Into<[f32; 2]>) -> Self {
self.size = size.into();
self
}
pub fn build(self) -> bool {
validate_selectable_flags("Selectable::build()", self.flags);
assert_non_negative_finite_vec2("Selectable::build()", "size", self.size);
let size_vec = sys::ImVec2 {
x: self.size[0],
y: self.size[1],
};
self.ui.run_with_bound_context(|| unsafe {
sys::igSelectable_Bool(
self.ui.scratch_txt(self.label),
self.selected,
self.flags.bits(),
size_vec,
)
})
}
pub fn build_with_ref(self, selected: &mut bool) -> bool {
validate_selectable_flags("Selectable::build_with_ref()", self.flags);
assert_non_negative_finite_vec2("Selectable::build_with_ref()", "size", self.size);
let size_vec = sys::ImVec2 {
x: self.size[0],
y: self.size[1],
};
self.ui.run_with_bound_context(|| unsafe {
sys::igSelectable_BoolPtr(
self.ui.scratch_txt(self.label),
selected as *mut bool,
self.flags.bits(),
size_vec,
)
})
}
}