use azul_core::geom::{LogicalPosition, LogicalSize};
#[cfg(all(feature = "text_layout", feature = "font_loading"))]
use crate::solver3::display_list::DisplayList;
#[cfg(not(all(feature = "text_layout", feature = "font_loading")))]
#[derive(Debug, Clone, Default)]
pub struct DisplayList;
#[derive(Debug, Clone)]
pub enum FragmentationContext {
Continuous {
width: f32,
container: Fragmentainer,
},
Paged {
page_size: LogicalSize,
pages: Vec<Fragmentainer>,
},
#[allow(dead_code)]
MultiColumn {
column_width: f32,
column_height: f32,
gap: f32,
columns: Vec<Fragmentainer>,
},
#[allow(dead_code)]
Regions {
regions: Vec<Fragmentainer>,
},
}
#[derive(Debug, Clone)]
pub struct Fragmentainer {
pub size: LogicalSize,
pub used_block_size: f32,
pub is_fixed_size: bool,
pub content: Vec<LayoutBox>,
}
#[derive(Debug, Clone)]
pub struct LayoutBox {
}
impl Fragmentainer {
pub fn new(size: LogicalSize, is_fixed_size: bool) -> Self {
Self {
size,
used_block_size: 0.0,
is_fixed_size,
content: Vec::new(),
}
}
pub fn remaining_space(&self) -> f32 {
if self.is_fixed_size {
(self.size.height - self.used_block_size).max(0.0)
} else {
f32::MAX }
}
pub fn is_full(&self) -> bool {
self.is_fixed_size && self.remaining_space() < 1.0
}
pub fn can_fit(&self, block_size: f32) -> bool {
self.remaining_space() >= block_size
}
pub fn use_space(&mut self, size: f32) {
self.used_block_size += size;
}
}
impl FragmentationContext {
pub fn new_continuous(width: f32) -> Self {
Self::Continuous {
width,
container: Fragmentainer::new(
LogicalSize::new(width, f32::MAX),
false, ),
}
}
pub fn new_paged(page_size: LogicalSize) -> Self {
Self::Paged {
page_size,
pages: vec![Fragmentainer::new(page_size, true)],
}
}
pub fn fragmentainer_count(&self) -> usize {
match self {
Self::Continuous { .. } => 1,
Self::Paged { pages, .. } => pages.len(),
Self::MultiColumn { columns, .. } => columns.len(),
Self::Regions { regions } => regions.len(),
}
}
pub fn current(&self) -> &Fragmentainer {
match self {
Self::Continuous { container, .. } => container,
Self::Paged { pages, .. } => pages
.last()
.expect("Paged context must have at least one page"),
Self::MultiColumn { columns, .. } => columns
.last()
.expect("MultiColumn context must have at least one column"),
Self::Regions { regions } => regions
.last()
.expect("Regions context must have at least one region"),
}
}
pub fn current_mut(&mut self) -> &mut Fragmentainer {
match self {
Self::Continuous { container, .. } => container,
Self::Paged { pages, .. } => pages
.last_mut()
.expect("Paged context must have at least one page"),
Self::MultiColumn { columns, .. } => columns
.last_mut()
.expect("MultiColumn context must have at least one column"),
Self::Regions { regions } => regions
.last_mut()
.expect("Regions context must have at least one region"),
}
}
pub fn advance(&mut self) -> Result<(), String> {
match self {
Self::Continuous { .. } => {
Ok(())
}
Self::Paged { page_size, pages } => {
pages.push(Fragmentainer::new(*page_size, true));
Ok(())
}
Self::MultiColumn {
column_width,
column_height,
columns,
..
} => {
columns.push(Fragmentainer::new(
LogicalSize::new(*column_width, *column_height),
true,
));
Ok(())
}
Self::Regions { .. } => {
Err("No more regions available for content overflow".to_string())
}
}
}
pub fn fragmentainers(&self) -> Vec<&Fragmentainer> {
match self {
Self::Continuous { container, .. } => vec![container],
Self::Paged { pages, .. } => pages.iter().collect(),
Self::MultiColumn { columns, .. } => columns.iter().collect(),
Self::Regions { regions } => regions.iter().collect(),
}
}
pub fn page_size(&self) -> Option<LogicalSize> {
match self {
Self::Paged { page_size, .. } => Some(*page_size),
_ => None,
}
}
pub fn page_content_height(&self) -> f32 {
match self {
Self::Continuous { .. } => f32::MAX,
Self::Paged { page_size, .. } => page_size.height,
Self::MultiColumn { column_height, .. } => *column_height,
Self::Regions { regions } => regions.first().map(|r| r.size.height).unwrap_or(f32::MAX),
}
}
pub fn is_paged(&self) -> bool {
matches!(self, Self::Paged { .. })
}
}
#[derive(Debug, Clone)]
pub struct FragmentationState {
pub current_page: usize,
pub current_page_y: f32,
pub available_height: f32,
pub page_content_height: f32,
pub margins_top: f32,
pub margins_bottom: f32,
pub total_pages: usize,
}
impl FragmentationState {
pub fn new(page_content_height: f32, margins_top: f32, margins_bottom: f32) -> Self {
Self {
current_page: 0,
current_page_y: 0.0,
available_height: page_content_height,
page_content_height,
margins_top,
margins_bottom,
total_pages: 1,
}
}
pub fn can_fit(&self, height: f32) -> bool {
self.available_height >= height
}
pub fn would_fit_on_empty_page(&self, height: f32) -> bool {
height <= self.page_content_height
}
pub fn use_space(&mut self, height: f32) {
self.current_page_y += height;
self.available_height = (self.page_content_height - self.current_page_y).max(0.0);
}
pub fn advance_page(&mut self) {
self.current_page += 1;
self.current_page_y = 0.0;
self.available_height = self.page_content_height;
self.total_pages = self.total_pages.max(self.current_page + 1);
}
pub fn page_for_y(&self, y: f32) -> usize {
if self.page_content_height <= 0.0 {
return 0;
}
(y / self.page_content_height).floor() as usize
}
pub fn page_y_offset(&self, page: usize) -> f32 {
page as f32 * self.page_content_height
}
}