use crate::frame::context::UpdateType;
use crate::layout::{Layout, LayoutItem};
use crate::map::Map;
use crate::response::Response;
use crate::ui::Ui;
use crate::widgets::WidgetSize;
use crate::{Offset, Padding, Pos};
use std::ops::Range;
pub struct RecycleLayout {
id: String,
items: Map<String, LayoutItem>,
padding: Padding,
item_space: f32, offset: Offset, total_count: usize, draw_count: usize,
display: Range<usize>, item_height: f32, size: WidgetSize,
}
impl RecycleLayout {
pub fn new() -> Self {
RecycleLayout {
id: crate::gen_unique_id(),
items: Map::new(),
padding: Padding::same(0.0),
item_space: 5.0,
offset: Offset::new(Pos::new()),
total_count: 0,
draw_count: 10,
display: 0..0,
item_height: 38.0,
size: WidgetSize::same(0.0, 0.0),
}
}
pub fn with_size(self, w: f32, h: f32) -> Self {
self.with_width(w).with_height(h)
}
pub fn with_width(mut self, w: f32) -> Self {
self.set_width(w);
self
}
pub fn with_item_height(mut self, h: f32) -> Self {
self.item_height = h;
self.draw_count = (self.size.dh * 1.5 / (self.item_height + self.item_space)).ceil() as usize;
self
}
pub fn set_width(&mut self, w: f32) {
self.size.dw = w;
}
pub fn with_height(mut self, h: f32) -> Self {
self.set_height(h);
self
}
pub fn set_height(&mut self, h: f32) {
self.size.dh = h;
self.draw_count = (self.size.dh * 1.5 / (self.item_height + self.item_space)).ceil() as usize;
}
pub fn with_space(mut self, s: f32) -> Self {
self.item_space = s;
self
}
pub fn with_padding(mut self, p: Padding) -> Self {
self.set_padding(p);
self
}
pub fn set_padding(&mut self, p: Padding) {
self.padding = p;
}
pub fn item_space(&self) -> f32 {
self.item_space
}
pub fn update_display(&mut self) {
let item_total_h = self.item_height + self.item_space;
let mut start = (-self.offset.y / item_total_h).floor().max(0.0) as usize;
let mut end = ((-self.offset.y + self.size.dh) / item_total_h).ceil().max(0.0) as usize;
if start > self.total_count {
start = self.total_count;
}
if end > self.total_count {
end = self.total_count;
}
self.display = start..end;
}
pub fn display_range(&self) -> &Range<usize> {
&self.display
}
pub fn add_item_empty(&mut self) {
self.total_count += 1;
self.size.rh += self.item_height + self.item_space;
}
pub fn remove_item(&mut self) {
self.total_count -= 1;
self.size.rh = self.size.rh - self.item_height - self.item_space;
if self.total_count < self.draw_count {
self.items.remove_map_by_index(0);
}
self.update_display();
}
pub fn draw_count(&self) -> usize {
self.draw_count
}
pub fn size(&self) -> &WidgetSize {
&self.size
}
}
impl Layout for RecycleLayout {
fn update(&mut self, ui: &mut Ui) -> Response<'_> {
let previous_rect = ui.draw_rect.clone();
match ui.update_type {
UpdateType::Init => {
self.update_display();
}
_ => {
ui.draw_rect.set_x_min(previous_rect.dx().min + self.padding.left);
ui.draw_rect.set_x_max(previous_rect.dx().max - self.padding.right);
ui.draw_rect.set_y_min(previous_rect.dy().min + self.padding.top);
ui.draw_rect.set_y_max(previous_rect.dy().max - self.padding.bottom);
let item_total_h = self.item_height + self.item_space;
let first_offset = -(-self.offset.y - self.display.start as f32 * item_total_h);
ui.draw_rect.set_y_min(previous_rect.dy().min + first_offset);
let mut start = self.display.start;
for item in self.items.iter_mut() {
let resp = item.update(ui);
ui.draw_rect.add_min_y(resp.size.dh + self.item_space);
start += 1;
if start >= self.total_count { break; }
}
}
}
ui.draw_rect = previous_rect;
Response::new(&self.id, self.size.clone())
}
fn items(&self) -> &Map<String, LayoutItem> {
&self.items
}
fn items_mut(&mut self) -> &mut Map<String, LayoutItem> {
&mut self.items
}
fn add_item(&mut self, item: LayoutItem) {
self.total_count += 1;
self.size.rh += self.item_height + self.item_space;
if self.items.len() < self.draw_count {
self.items.insert(item.id().to_string(), item);
}
}
fn set_offset(&mut self, offset: Offset) {
self.offset = offset;
self.update_display();
}
fn set_size(&mut self, w: f32, h: f32) {
self.set_width(w);
self.set_height(h);
}
}