// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
fn[C] compute_grid_size_estimate(
tree : ChicleTree[C],
children : Array[NodeId],
explicit_col_count : Int,
explicit_row_count : Int,
) -> (TrackCounts, TrackCounts) raise ChicleError {
let mut col_min = 0
let mut col_max = 0
let mut col_max_span = 0
let mut row_min = 0
let mut row_max = 0
let mut row_max_span = 0
for child_id in children {
let child = match tree.nodes.get(child_id) {
Some(c) => c
None => raise InvalidNodeId(child_id)
}
let col_position = child_min_line_max_line_span(
merged_placement_line(
child.style.grid_column,
child.style.grid_column_start,
),
explicit_col_count,
)
let row_position = child_min_line_max_line_span(
merged_placement_line(child.style.grid_row, child.style.grid_row_start),
explicit_row_count,
)
col_min = min_int(col_min, col_position.0)
col_max = max_int(col_max, col_position.1)
col_max_span = max_int(col_max_span, col_position.2)
row_min = min_int(row_min, row_position.0)
row_max = max_int(row_max, row_position.1)
row_max_span = max_int(row_max_span, row_position.2)
}
let negative_cols = if col_min < 0 { -col_min } else { 0 }
let mut positive_cols = if col_max > explicit_col_count {
col_max - explicit_col_count
} else {
0
}
let negative_rows = if row_min < 0 { -row_min } else { 0 }
let mut positive_rows = if row_max > explicit_row_count {
row_max - explicit_row_count
} else {
0
}
let total_cols = negative_cols + explicit_col_count + positive_cols
if total_cols < col_max_span {
positive_cols = col_max_span - explicit_col_count - negative_cols
}
let total_rows = negative_rows + explicit_row_count + positive_rows
if total_rows < row_max_span {
positive_rows = row_max_span - explicit_row_count - negative_rows
}
(
TrackCounts::from_raw(
negative_implicit=negative_cols,
explicit=explicit_col_count,
positive_implicit=positive_cols,
),
TrackCounts::from_raw(
negative_implicit=negative_rows,
explicit=explicit_row_count,
positive_implicit=positive_rows,
),
)
}
///|
fn child_min_line_max_line_span(
line : Line[GridPlacement],
explicit_track_count : Int,
) -> (Int, Int, Int) {
let resolved = axis_resolve_start_line_and_span(line, explicit_track_count)
let min_line = match resolved.0 {
Some(sl) => sl
None => 0
}
let max_line = match resolved.0 {
Some(sl) => sl + resolved.1
None => 0
}
let span = match (line.start, line.end) {
(PlaceAuto | PlaceSpan(_), PlaceAuto | PlaceSpan(_)) => resolved.1
_ => 1
}
(min_line, max_line, span)
}
///|
fn min_int(a : Int, b : Int) -> Int {
if a < b {
a
} else {
b
}
}
///|
fn max_int(a : Int, b : Int) -> Int {
if a > b {
a
} else {
b
}
}