///|
/// Cached column widths and row heights. Options invalidate only affected axes.
pub struct CompleteDimension {
mut widths : Array[Int]?
mut heights : Array[Int]?
} derive(Eq, Debug)
///|
pub fn CompleteDimension::default() -> CompleteDimension {
{ widths: None, heights: None, }
}
///|
pub fn CompleteDimension::is_complete(self : CompleteDimension) -> Bool {
self.widths is Some(_) && self.heights is Some(_)
}
///|
pub fn CompleteDimension::is_empty(self : CompleteDimension) -> Bool {
self.widths is None && self.heights is None
}
///|
pub fn CompleteDimension::set_widths(
self : CompleteDimension,
widths : Array[Int],
) -> Unit {
self.widths = Some(widths.map(value => Int::max(0, value)))
}
///|
pub fn CompleteDimension::set_heights(
self : CompleteDimension,
heights : Array[Int],
) -> Unit {
self.heights = Some(heights.map(value => Int::max(0, value)))
}
///|
pub fn CompleteDimension::clear_width(self : CompleteDimension) -> Unit {
self.widths = None
}
///|
pub fn CompleteDimension::clear_height(self : CompleteDimension) -> Unit {
self.heights = None
}
///|
pub fn CompleteDimension::clear(self : CompleteDimension) -> Unit {
self.clear_width()
self.clear_height()
}
///|
pub fn CompleteDimension::get_widths(self : CompleteDimension) -> Array[Int]? {
self.widths.map(Array::copy)
}
///|
pub fn CompleteDimension::get_heights(self : CompleteDimension) -> Array[Int]? {
self.heights.map(Array::copy)
}
///|
pub fn CompleteDimension::get_width(self : CompleteDimension, col : Int) -> Int {
self.widths.unwrap()[col]
}
///|
pub fn CompleteDimension::get_height(
self : CompleteDimension,
row : Int,
) -> Int {
self.heights.unwrap()[row]
}
///|
/// Invalidate the cached axes affected by an option's change hint.
/// None keeps the cache; row hints clear heights, column hints clear widths,
/// and cell/global hints clear both. Measurement is deferred until `estimate`.
pub fn CompleteDimension::invalidate(
self : CompleteDimension,
hint : Entity?,
) -> Unit {
match hint {
None => ()
Some(Global | Cell(_, _)) => self.clear()
Some(Col(_)) => self.clear_width()
Some(Row(_)) => self.clear_height()
}
}
///|
/// Recompute missing axes or arrays too short for the current records.
/// Longer arrays remain valid, matching explicit width and height lists.
pub fn CompleteDimension::estimate(
self : CompleteDimension,
table : Table,
) -> Unit {
let records = @papergrid.IterRecords::new(table.rows)
let missing_width = self.widths is None ||
(self.widths is Some(widths) && widths.length() < records.count_cols())
let missing_height = self.heights is None ||
(self.heights is Some(heights) && heights.length() < records.count_rows())
if !missing_width && !missing_height {
return
}
let (widths, heights) = @papergrid.IterGridDimension::measure_rendered(
records,
table.config,
)
if missing_width {
self.widths = Some(widths)
}
if missing_height {
self.heights = Some(heights)
}
}
///|
/// Return an independent snapshot of the dimension cache without measuring.
pub fn Table::dimension_snapshot(self : Table) -> CompleteDimension {
{
widths: self.dimension.get_widths(),
heights: self.dimension.get_heights(),
}
}
///|
/// Return the shared dimension cache. Changes affect this table directly.
/// Clear it after changing records or configuration through raw mutable access.
pub fn Table::dimension_cache(self : Table) -> CompleteDimension {
self.dimension
}
///|
pub fn Table::total_width(self : Table) -> Int {
let dims = self.dimension_snapshot()
dims.estimate(self)
table_width(self, dims.get_widths().unwrap()[:self.count_cols()].to_owned())
}
///|
pub fn Table::total_height(self : Table) -> Int {
let dims = self.dimension_snapshot()
dims.estimate(self)
dims
.get_heights()
.unwrap()
.iter()
.take(self.count_rows())
.fold(init=0, (sum, value) => sum + value) +
self.config.count_horizontal(self.count_rows()) +
self.config.margin_top +
self.config.margin_bottom
}
///|
// Legacy mutators are public entry points too. Raw option changes defer cache
// invalidation to the enclosing option's combined hint.
fn Table::finish_legacy_change(self : Table) -> Table {
if self.option_depth == 0 {
self.dimension.clear()
}
self
}
///|
pub extend CompleteDimension with Eq::{not_equal, equal}
///|
pub extend CompleteDimension with @debug.Debug::{to_repr}