use std::marker::PhantomData;
use crate::Ui;
use crate::sys;
pub struct ListClipper {
items_count: i32,
items_height: f32,
}
impl ListClipper {
pub const fn new(items_count: i32) -> Self {
ListClipper {
items_count,
items_height: -1.0,
}
}
pub const fn items_height(mut self, items_height: f32) -> Self {
self.items_height = items_height;
self
}
pub fn begin(self, ui: &Ui) -> ListClipperToken<'_> {
unsafe {
let ptr = sys::ImGuiListClipper_ImGuiListClipper();
if ptr.is_null() {
panic!("ImGuiListClipper_ImGuiListClipper() returned null");
}
sys::ImGuiListClipper_Begin(ptr, self.items_count, self.items_height);
ListClipperToken::new(ui, ptr)
}
}
}
pub struct ListClipperToken<'ui> {
list_clipper: *mut sys::ImGuiListClipper,
_phantom: PhantomData<&'ui Ui>,
consumed_workaround: bool,
}
impl<'ui> ListClipperToken<'ui> {
fn new(_: &Ui, list_clipper: *mut sys::ImGuiListClipper) -> Self {
Self {
list_clipper,
_phantom: PhantomData,
consumed_workaround: false,
}
}
pub fn step(&mut self) -> bool {
let is_imgui_1_88_or_higher = false;
if is_imgui_1_88_or_higher {
unsafe { sys::ImGuiListClipper_Step(self.list_clipper) }
} else {
if self.consumed_workaround {
panic!("ListClipperToken::step called after it has previously returned false");
}
let ret = unsafe { sys::ImGuiListClipper_Step(self.list_clipper) };
if !ret {
self.consumed_workaround = true;
}
ret
}
}
pub fn end(&mut self) {
unsafe {
sys::ImGuiListClipper_End(self.list_clipper);
}
}
pub fn display_start(&self) -> i32 {
unsafe { (*self.list_clipper).DisplayStart }
}
pub fn display_end(&self) -> i32 {
unsafe { (*self.list_clipper).DisplayEnd }
}
pub fn iter(self) -> ListClipperIterator<'ui> {
ListClipperIterator::new(self)
}
}
impl Drop for ListClipperToken<'_> {
fn drop(&mut self) {
unsafe {
sys::ImGuiListClipper_destroy(self.list_clipper);
};
}
}
pub struct ListClipperIterator<'ui> {
list_clipper: ListClipperToken<'ui>,
exhausted: bool,
last_value: Option<i32>,
}
impl<'ui> ListClipperIterator<'ui> {
fn new(list_clipper: ListClipperToken<'ui>) -> Self {
Self {
list_clipper,
exhausted: false,
last_value: None,
}
}
}
impl Iterator for ListClipperIterator<'_> {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if let Some(lv) = self.last_value {
let next_value = lv + 1;
if lv >= self.list_clipper.display_end() - 1 {
self.last_value = None;
} else {
self.last_value = Some(next_value);
}
}
if let Some(lv) = self.last_value {
Some(lv)
} else {
if self.exhausted {
None
} else {
let ret = self.list_clipper.step();
if !ret {
self.exhausted = true;
None
} else {
let start = self.list_clipper.display_start();
let end = self.list_clipper.display_end();
if start == end {
self.last_value = None;
} else {
self.last_value = Some(start);
}
Some(start)
}
}
}
}
}