#[doc(inline)]
#[allow(unused_imports)]
use super::{
cellgrid::CellGrid,
style,
types::{ContentSize, Portion, PortionProperties, Property, PropertyMinimal},
};
use crate::core::{Size, renderer};
use iced_widget::{
Space,
core::{Element, Point},
};
pub struct Content<'a, Message, Theme, Renderer>
where
Renderer: renderer::Renderer,
Theme: style::Catalog,
{
pub elements: Vec<Element<'a, Message, Theme, Renderer>>,
pub active_up_left: Vec<bool>,
pub active_up_right: Vec<bool>,
pub active_down_left: Vec<bool>,
pub active_down_right: Vec<bool>,
pub layout: &'a ContentLayout,
}
pub struct ContentLayout {
pub range_left: Option<usize>, pub range_right: Option<(usize, usize)>,
pub range_up: Option<usize>, pub range_down: Option<(usize, usize)>,
pub cells_up_left: usize,
pub cells_up_right: usize,
pub cells_down_left: usize,
pub cells_down_right: usize,
pub cells_total: usize,
pub index_up_right: usize,
pub index_down_left: usize,
pub index_down_right: usize,
pub properties_left: PortionProperties,
pub properties_up: PortionProperties,
pub properties_right: PortionProperties,
pub properties_down: PortionProperties,
pub size_total: ContentSize,
pub size: ContentSize,
pub size_scrolling: ContentSize,
pub scrolled_offset: Option<Point>,
}
impl ContentLayout {
pub fn update(
&mut self,
columns: &Vec<PropertyMinimal>,
rows: &Vec<PropertyMinimal>,
horizontal: &Vec<f32>,
vertical: &Vec<f32>,
portion: &Portion,
) {
match portion {
Portion::Left | Portion::Right => {
let (size_total, size, size_scrolling, properties_left, properties_right) =
build_columns(columns, &self.range_left, &self.range_right, horizontal); self.size_total.pixels.width = size_total.pixels.width;
self.size.pixels.width = size.pixels.width;
self.size_scrolling.pixels.width = size_scrolling.pixels.width;
self.properties_left = properties_left;
self.properties_right = properties_right;
}
Portion::Up | Portion::Down => {
let (size_total, size, size_scrolling, properties_up, properties_down) =
build_rows(rows, &self.range_up, &self.range_down, vertical); self.size_total.pixels.height = size_total.pixels.height;
self.size.pixels.height = size.pixels.height;
self.size_scrolling.pixels.height = size_scrolling.pixels.height;
self.properties_up = properties_up;
self.properties_down = properties_down;
}
}
}
}
fn get_portion(
size_total: &mut f32,
size: &mut f32,
total: &mut usize,
visible: &mut usize,
minimal: &Vec<PropertyMinimal>,
end: usize,
) -> (Vec<Property>, f32) {
let mut properties = Vec::new();
let mut size_portion = 0.0;
while *total <= end {
let offset = *size;
let width = minimal[*total].size;
*size_total += width;
if !minimal[*total].hidden {
*size += width;
size_portion += width;
properties.push(Property {
offset,
index: *total,
size: width,
range: minimal[*total].range,
});
*visible += 1;
}
*total += 1;
}
(properties, size_portion)
}
fn get_page_breaks(
properties: &Vec<Property>,
size_portion: f32,
page_breaks: &Vec<f32>,
) -> Vec<f32> {
let mut breaks = Vec::new();
let end = properties[0].offset + size_portion;
for page in page_breaks {
if *page >= properties[0].offset && *page < end {
breaks.push(*page);
}
}
breaks.shrink_to(breaks.len());
breaks
}
pub fn build_columns(
columns: &Vec<PropertyMinimal>,
range_left: &Option<usize>,
range_right: &Option<(usize, usize)>,
page_breaks: &Vec<f32>,
) -> (
ContentSize,
ContentSize,
ContentSize,
PortionProperties,
PortionProperties,
) {
let mut size_total = 0.0; let mut size = 0.0; let mut total = 0;
let mut visible = 0;
let mut properties_left = PortionProperties::default();
let mut properties_right = PortionProperties::default();
if page_breaks.is_empty() {
if let Some(end) = range_left {
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
columns,
*end,
);
properties_left = PortionProperties {
size: size_portion,
properties,
pages: Vec::with_capacity(0),
};
}
if let Some((start, end)) = range_right {
while total < *start {
let width = columns[total].size;
size_total += width;
if !columns[total].hidden {
size += width;
visible += 1;
}
total += 1;
}
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
columns,
*end,
);
properties_right = PortionProperties {
size: size_portion,
properties,
pages: Vec::with_capacity(0),
};
}
} else {
if let Some(end) = range_left {
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
columns,
*end,
);
let pages = if !properties.is_empty() {
get_page_breaks(&properties, size_portion, &page_breaks)
} else {
Vec::with_capacity(0)
};
properties_left = PortionProperties {
size: size_portion,
properties,
pages,
};
}
if let Some((start, end)) = range_right {
while total < *start {
let width = columns[total].size;
size_total += width;
if !columns[total].hidden {
size += width;
visible += 1;
}
total += 1;
}
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
columns,
*end,
);
let pages = if !properties.is_empty() {
get_page_breaks(&properties, size_portion, &page_breaks)
} else {
Vec::with_capacity(0)
};
properties_right = PortionProperties {
size: size_portion,
properties,
pages,
};
}
}
let size_scrolling = ContentSize {
pixels: Size {
height: 0.0,
width: size - properties_left.size,
},
columns: visible - properties_left.len(),
rows: 0,
};
(
ContentSize {
pixels: Size {
width: size_total,
height: 0.0,
},
columns: total,
rows: 0,
},
ContentSize {
pixels: Size {
width: size,
height: 0.0,
},
columns: visible,
rows: 0,
},
size_scrolling,
properties_left,
properties_right,
)
}
pub fn build_rows(
rows: &Vec<PropertyMinimal>,
range_up: &Option<usize>,
range_down: &Option<(usize, usize)>,
page_breaks: &Vec<f32>,
) -> (
ContentSize,
ContentSize,
ContentSize,
PortionProperties,
PortionProperties,
) {
let mut size_total = 0.0; let mut size = 0.0; let mut total = 0;
let mut visible = 0;
let mut properties_up = PortionProperties::default();
let mut properties_down = PortionProperties::default();
if page_breaks.is_empty() {
if let Some(end) = range_up {
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
rows,
*end,
);
properties_up = PortionProperties {
size: size_portion,
properties,
pages: Vec::with_capacity(0),
};
}
if let Some((start, end)) = range_down {
while total < *start {
let height = rows[total].size;
size_total += height;
if !rows[total].hidden {
size += height;
visible += 1;
}
total += 1;
}
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
rows,
*end,
);
properties_down = PortionProperties {
size: size_portion,
properties,
pages: Vec::with_capacity(0),
};
}
} else {
if let Some(end) = range_up {
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
rows,
*end,
);
let pages = if !properties.is_empty() {
get_page_breaks(&properties, size_portion, &page_breaks)
} else {
Vec::with_capacity(0)
};
properties_up = PortionProperties {
size: size_portion,
properties,
pages,
};
}
if let Some((start, end)) = range_down {
while total < *start {
let height = rows[total].size;
size_total += height;
if !rows[total].hidden {
size += height;
visible += 1;
}
total += 1;
}
let (properties, size_portion) = get_portion(
&mut size_total,
&mut size,
&mut total,
&mut visible,
rows,
*end,
);
let pages = if !properties.is_empty() {
get_page_breaks(&properties, size_portion, &page_breaks)
} else {
Vec::with_capacity(0)
};
properties_down = PortionProperties {
size: size_portion,
properties,
pages,
};
}
}
let size_scrolling = ContentSize {
pixels: Size {
height: size - properties_up.size,
width: 0.0,
},
columns: 0,
rows: visible - properties_up.len(),
};
(
ContentSize {
pixels: Size {
width: 0.0,
height: size_total,
},
columns: 0,
rows: total,
},
ContentSize {
pixels: Size {
width: 0.0,
height: size,
},
columns: 0,
rows: visible,
},
size_scrolling,
properties_up,
properties_down,
)
}
pub struct ContentLayoutBuilder {
range_left: Option<usize>, range_up: Option<usize>, range_right: Option<(usize, usize)>,
range_down: Option<(usize, usize)>,
scrolled_offset: Option<Point>,
}
impl ContentLayoutBuilder {
pub fn new() -> Self {
Self {
range_left: None,
range_up: None,
range_right: None,
range_down: None,
scrolled_offset: None,
}
}
pub fn set_left_range(mut self, end: usize) -> Self {
self.range_left = Some(end);
self
}
pub fn set_up_range(mut self, end: usize) -> Self {
self.range_up = Some(end);
self
}
pub fn set_right_range(mut self, mut start: usize, mut end: usize) -> Self {
if end < start {
let t = start;
start = end;
end = t;
}
self.range_right = Some((start, end));
self
}
pub fn set_down_range(mut self, mut start: usize, mut end: usize) -> Self {
if end < start {
let t = start;
start = end;
end = t;
}
self.range_down = Some((start, end));
self
}
pub fn set_scrolled_offset(mut self, offset: Point) -> Self {
self.scrolled_offset = Some(offset);
self
}
pub fn build(
mut self,
columns: &Vec<PropertyMinimal>,
rows: &Vec<PropertyMinimal>,
horizontal: &Vec<f32>,
vertical: &Vec<f32>,
) -> ContentLayout {
if let Some(range) = self.range_left {
self.range_left = Some(range.min(columns.len()));
}
if let Some(range) = self.range_up {
self.range_up = Some(range.min(columns.len()));
}
if let Some(range) = self.range_right {
self.range_right = Some((range.0.min(columns.len()), range.1.min(columns.len())));
}
if let Some(range) = self.range_down {
self.range_down = Some((range.0.min(columns.len()), range.1.min(columns.len())));
}
if let Some(frozen) = self.range_left
&& let Some(scroll) = self.range_right
{
if scroll.1 <= frozen {
self.range_right = None;
} else if scroll.0 <= frozen {
self.range_right = Some((frozen + 1, scroll.1));
}
}
if let Some(frozen) = self.range_up
&& let Some(scroll) = self.range_down
{
if scroll.1 <= frozen {
self.range_down = None;
} else if scroll.0 <= frozen {
self.range_down = Some((frozen + 1, scroll.1));
}
}
let (mut size_total, mut size, mut size_scrolling, properties_left, properties_right) =
build_columns(columns, &self.range_left, &self.range_right, horizontal); let (size_total_y, size_y, size_scrolling_y, properties_up, properties_down) =
build_rows(rows, &self.range_up, &self.range_down, vertical); size_total.pixels.height = size_total_y.pixels.height;
size_total.rows = size_total_y.rows;
size.pixels.height = size_y.pixels.height;
size.rows = size_y.rows;
size_scrolling.pixels.height = size_scrolling_y.pixels.height;
size_scrolling.rows = size_scrolling_y.rows;
let mut cells_up_left = 1; let mut cells_up_right = 0;
let mut cells_down_left = 0;
let mut cells_down_right = 0;
let mut index_up_right = 0;
let mut index_down_left = 0;
let mut index_down_right = 0;
if self.range_left.is_some() {
cells_up_left += properties_left.len();
}
if self.range_up.is_some() {
cells_up_left += properties_up.len();
if self.range_left.is_some() {
cells_up_left += properties_left.len() * properties_up.len();
}
}
if self.range_right.is_some() {
index_up_right = cells_up_left;
cells_up_right = properties_right.len();
if self.range_up.is_some() {
cells_up_right += properties_right.len() * properties_up.len();
}
};
if self.range_down.is_some() {
index_down_left = index_up_right + cells_up_right;
cells_down_left = properties_down.len();
if self.range_left.is_some() {
cells_down_left += properties_down.len() * properties_left.len();
}
if self.range_right.is_some() {
index_down_right = index_down_left + cells_down_left;
cells_down_right = properties_down.len() * properties_right.len();
}
};
let cells_total = index_down_right + cells_down_right;
if let Some(offset) = self.scrolled_offset.as_mut() {
if !properties_right.is_empty() {
offset.x = offset.x.clamp(0.0, size_scrolling.pixels.width);
}
if !properties_down.is_empty() {
offset.y = offset.y.clamp(0.0, size_scrolling.pixels.height);
}
}
ContentLayout {
range_left: self.range_left,
range_up: self.range_up,
range_right: self.range_right,
range_down: self.range_down,
cells_up_left,
cells_up_right,
cells_down_left,
cells_down_right,
cells_total,
index_up_right,
index_down_left,
index_down_right,
properties_left,
properties_up,
properties_right,
properties_down,
size_total,
size,
size_scrolling,
scrolled_offset: self.scrolled_offset,
}
}
}
pub struct ContentBuilder<'a, Message, Theme, Renderer>
where
Renderer: renderer::Renderer,
Theme: style::Catalog,
{
corner: Option<Element<'a, Message, Theme, Renderer>>,
left_columns: Vec<Element<'a, Message, Theme, Renderer>>,
up_rows: Vec<Element<'a, Message, Theme, Renderer>>,
up_left_data: Vec<Element<'a, Message, Theme, Renderer>>,
up_left_active: Vec<bool>,
right_columns: Vec<Element<'a, Message, Theme, Renderer>>,
up_right_data: Vec<Element<'a, Message, Theme, Renderer>>,
up_right_active: Vec<bool>,
down_rows: Vec<Element<'a, Message, Theme, Renderer>>,
down_left_data: Vec<Element<'a, Message, Theme, Renderer>>,
down_left_active: Vec<bool>,
down_right_data: Vec<Element<'a, Message, Theme, Renderer>>,
down_right_active: Vec<bool>,
layout: &'a ContentLayout,
}
impl<'a, Message: 'a, Theme, Renderer> ContentBuilder<'a, Message, Theme, Renderer>
where
Renderer: renderer::Renderer,
Theme: style::Catalog,
{
pub fn new(layout: &'a ContentLayout) -> Self {
Self {
corner: None,
left_columns: Vec::new(),
up_rows: Vec::new(),
up_left_data: Vec::new(),
up_left_active: Vec::new(),
right_columns: Vec::new(),
up_right_data: Vec::new(),
up_right_active: Vec::new(),
down_rows: Vec::new(),
down_left_data: Vec::new(),
down_left_active: Vec::new(),
down_right_data: Vec::new(),
down_right_active: Vec::new(),
layout,
}
}
pub fn set_corner(&mut self, element: Element<'a, Message, Theme, Renderer>) {
self.corner = Some(element);
}
pub fn push_left_column(&mut self, element: Element<'a, Message, Theme, Renderer>) {
self.left_columns.push(element);
}
pub fn push_up_row(&mut self, element: Element<'a, Message, Theme, Renderer>) {
self.up_rows.push(element);
}
pub fn push_up_left_data(
&mut self,
element: Element<'a, Message, Theme, Renderer>,
active: bool,
) {
self.up_left_data.push(element);
self.up_left_active.push(active);
}
pub fn push_right_column(&mut self, element: Element<'a, Message, Theme, Renderer>) {
self.right_columns.push(element);
}
pub fn push_up_right_data(
&mut self,
element: Element<'a, Message, Theme, Renderer>,
active: bool,
) {
self.up_right_data.push(element);
self.up_right_active.push(active);
}
pub fn push_down_row(&mut self, element: Element<'a, Message, Theme, Renderer>) {
self.down_rows.push(element);
}
pub fn push_down_left_data(
&mut self,
element: Element<'a, Message, Theme, Renderer>,
active: bool,
) {
self.down_left_data.push(element);
self.down_left_active.push(active);
}
pub fn push_down_right_data(
&mut self,
element: Element<'a, Message, Theme, Renderer>,
active: bool,
) {
self.down_right_data.push(element);
self.down_right_active.push(active);
}
fn build(mut self) -> Content<'a, Message, Theme, Renderer> {
let mut active_up_left = Vec::with_capacity(self.layout.cells_up_left);
let mut active_up_right = Vec::with_capacity(self.layout.cells_up_right);
let mut active_down_left = Vec::with_capacity(self.layout.cells_down_left);
let mut active_down_right = Vec::with_capacity(self.layout.cells_down_right);
let mut elements = Vec::with_capacity(self.layout.cells_total);
elements.push(if let Some(corner) = self.corner {
corner
} else {
Space::new().into()
});
active_up_left.push(true);
if !self.layout.properties_left.is_empty() {
self.left_columns
.resize_with(self.layout.properties_left.len(), || Space::new().into());
elements.append(&mut self.left_columns);
let mut active = Vec::with_capacity(self.layout.properties_left.len());
active.resize_with(self.layout.properties_left.len(), || true);
active_up_left.append(&mut active);
}
if !self.layout.properties_up.is_empty() {
self.up_rows
.resize_with(self.layout.properties_up.len(), || Space::new().into());
elements.append(&mut self.up_rows);
let mut active = Vec::with_capacity(self.layout.properties_up.len());
active.resize_with(self.layout.properties_up.len(), || true);
active_up_left.append(&mut active);
if !self.layout.properties_left.is_empty() {
let count = self.layout.properties_left.len() * self.layout.properties_up.len();
self.up_left_data.resize_with(count, || Space::new().into());
elements.append(&mut self.up_left_data);
self.up_left_active.resize_with(count, || false);
active_up_left.append(&mut self.up_left_active);
}
}
if !self.layout.properties_right.is_empty() {
self.right_columns
.resize_with(self.layout.properties_right.len(), || Space::new().into());
elements.append(&mut self.right_columns);
let mut active = Vec::with_capacity(self.layout.properties_right.len());
active.resize_with(self.layout.properties_right.len(), || true);
active_up_right.append(&mut active);
if !self.layout.properties_up.is_empty() {
let count = self.layout.properties_right.len() * self.layout.properties_up.len();
self.up_right_data
.resize_with(count, || Space::new().into());
elements.append(&mut self.up_right_data);
self.up_right_active.resize_with(count, || false);
active_up_right.append(&mut self.up_right_active);
}
}
if !self.layout.properties_down.is_empty() {
self.down_rows
.resize_with(self.layout.properties_down.len(), || Space::new().into());
elements.append(&mut self.down_rows);
let mut active = Vec::with_capacity(self.layout.properties_down.len());
active.resize_with(self.layout.properties_down.len(), || true);
active_down_left.append(&mut active);
if !self.layout.properties_left.is_empty() {
let count = self.layout.properties_left.len() * self.layout.properties_down.len();
self.down_left_data
.resize_with(count, || Space::new().into());
elements.append(&mut self.down_left_data);
self.down_left_active.resize_with(count, || false);
active_down_left.append(&mut self.down_left_active);
}
if !self.layout.properties_right.is_empty() {
let count = self.layout.properties_right.len() * self.layout.properties_down.len();
self.down_right_data
.resize_with(count, || Space::new().into());
elements.append(&mut self.down_right_data);
self.down_right_active.resize_with(count, || false);
active_down_right.append(&mut self.down_right_active);
}
}
Content {
elements,
active_up_left,
active_up_right,
active_down_left,
active_down_right,
layout: self.layout,
}
}
}
impl<'a, Message, Theme, Renderer> From<ContentBuilder<'a, Message, Theme, Renderer>>
for Content<'a, Message, Theme, Renderer>
where
Message: Clone + 'a,
Renderer: renderer::Renderer + 'a,
Theme: style::Catalog + 'a,
{
fn from(
content: ContentBuilder<'a, Message, Theme, Renderer>,
) -> Content<'a, Message, Theme, Renderer> {
content.build()
}
}