use core::cmp::max;
use alloc::vec;
use crate::{nav::NavPathNavigator, render::{Glyph, LayoutBlock, Layoutable, MergeBaseline, Renderer, LayoutComputationProperties}};
use super::function::Function;
pub fn layout_sqrt<T>(inner: &T, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> LayoutBlock
where T : Layoutable
{
let mut path = if let Some(p) = path {
if p.next() == 0 {
Some(p.step())
} else {
None
}
} else {
None
};
let inner_layout = inner.layout(renderer, (&mut path).as_mut(), properties);
let inner_area = inner_layout.area;
let sqrt_symbol_layout = LayoutBlock::from_glyph(renderer, Glyph::Sqrt {
inner_area
}, properties);
let x_offset = sqrt_symbol_layout.area.width - inner_layout.area.width - renderer.square_root_padding();
let y_offset = sqrt_symbol_layout.area.height - inner_layout.area.height;
sqrt_symbol_layout.merge_in_place(
&inner_layout.offset(x_offset, y_offset),
MergeBaseline::OtherAsBaseline
)
}
pub fn layout_fraction<T>(top: &T, bottom: &T, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> LayoutBlock
where T : Layoutable
{
let (mut top_path, mut bottom_path) = {
if let Some(p) = path {
if p.next() == 0 {
(Some(p.step()), None)
} else if p.next() == 1 {
(None, Some(p.step()))
} else {
panic!()
}
} else {
(None, None)
}
};
let top_layout = top.layout(
renderer,
(&mut top_path).as_mut(),
properties,
);
let bottom_layout = bottom.layout(
renderer,
(&mut bottom_path).as_mut(),
properties,
);
let line_width = max(
top_layout.area.width,
bottom_layout.area.width,
);
let line_layout = LayoutBlock::from_glyph(renderer, Glyph::Fraction {
inner_width: line_width
}, properties).move_below_other(&top_layout);
let bottom_layout = bottom_layout
.move_below_other(&line_layout);
top_layout
.merge_along_vertical_centre(&line_layout, MergeBaseline::OtherAsBaseline)
.merge_along_vertical_centre(&bottom_layout, MergeBaseline::SelfAsBaseline)
}
pub fn layout_parentheses<T>(inner: &T, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> LayoutBlock
where T : Layoutable
{
let mut path = if let Some(p) = path {
if p.next() == 0 {
Some(p.step())
} else {
None
}
} else {
None
};
let inner_layout = inner.layout(renderer, (&mut path).as_mut(), properties);
let inner_area = inner_layout.area;
let mut left_paren_layout = LayoutBlock::from_glyph(renderer, Glyph::LeftParenthesis {
inner_height: inner_area.height,
}, properties);
let mut right_paren_layout = LayoutBlock::from_glyph(renderer, Glyph::RightParenthesis {
inner_height: inner_area.height,
}, properties);
left_paren_layout.baseline = inner_layout.baseline;
right_paren_layout.baseline = inner_layout.baseline;
LayoutBlock::layout_horizontal(&[
left_paren_layout,
inner_layout,
right_paren_layout,
])
}
pub fn layout_power<T>(base: Option<&T>, exp: &T, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> LayoutBlock
where T : Layoutable
{
if base.is_none() {
let mut path = if let Some(p) = path {
if p.next() == 0 {
Some(p.step())
} else {
None
}
} else {
None
};
let mut exp_layout = exp.layout(
renderer, (&mut path).as_mut(),
properties.reduce_size(),
);
exp_layout.special.baseline_merge_with_high_precedence = true;
exp_layout.special.superscript = true;
return exp_layout
}
let base_layout = base.unwrap().layout(
renderer,
None,
properties,
);
let exp_layout = exp.layout(
renderer,
None,
properties.reduce_size(),
);
let base_layout = base_layout.offset(
0,
exp_layout.area.height
);
let exp_layout = exp_layout.offset(
base_layout.area.width,
0,
);
base_layout.merge_in_place(&exp_layout, MergeBaseline::SelfAsBaseline)
}
pub fn layout_function_call<T>(func: Function, args: &[T], renderer: &mut impl Renderer, mut path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> LayoutBlock
where T : Layoutable
{
let mut is_first_arg = true;
let mut arg_layouts = vec![];
for (i, arg) in args.iter().enumerate() {
let mut path = if let Some(ref mut p) = path {
if p.next() == i {
Some(p.step())
} else {
None
}
} else {
None
};
if !is_first_arg {
arg_layouts.push(LayoutBlock::from_glyph(renderer, Glyph::Comma, properties))
}
is_first_arg = false;
arg_layouts.push(arg.layout(renderer, (&mut path).as_mut(), properties));
}
let joined_arg_layout = LayoutBlock::layout_horizontal(&arg_layouts);
let func_glyph = Glyph::FunctionName { function: func };
let func_layout = LayoutBlock::from_glyph(renderer, func_glyph, properties);
let mut left_paren_layout = LayoutBlock::from_glyph(renderer, Glyph::LeftParenthesis {
inner_height: joined_arg_layout.area.height,
}, properties);
let mut right_paren_layout = LayoutBlock::from_glyph(renderer, Glyph::RightParenthesis {
inner_height: joined_arg_layout.area.height,
}, properties);
left_paren_layout.baseline = joined_arg_layout.baseline;
right_paren_layout.baseline = joined_arg_layout.baseline;
LayoutBlock::layout_horizontal(&[
func_layout,
left_paren_layout,
joined_arg_layout,
right_paren_layout,
])
}