use super::{AlignContent, LengthPercentage, Style};
use crate::axis::{AbsoluteAxis, AbstractAxis};
use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine};
use crate::geometry::{Line, MinMax};
use crate::style_helpers::*;
use crate::sys::GridTrackVec;
use core::cmp::{max, min};
use core::convert::Infallible;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum GridAutoFlow {
Row,
Column,
RowDense,
ColumnDense,
}
impl Default for GridAutoFlow {
fn default() -> Self {
Self::Row
}
}
impl GridAutoFlow {
pub fn is_dense(&self) -> bool {
match self {
Self::Row | Self::Column => false,
Self::RowDense | Self::ColumnDense => true,
}
}
pub fn primary_axis(&self) -> AbsoluteAxis {
match self {
Self::Row | Self::RowDense => AbsoluteAxis::Horizontal,
Self::Column | Self::ColumnDense => AbsoluteAxis::Vertical,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum GenericGridPlacement<LineType: GridCoordinate> {
Auto,
Line(LineType),
Span(u16),
}
pub(crate) type OriginZeroGridPlacement = GenericGridPlacement<OriginZeroLine>;
pub type GridPlacement = GenericGridPlacement<GridLine>;
impl TaffyAuto for GridPlacement {
const AUTO: Self = Self::Auto;
}
impl TaffyGridLine for GridPlacement {
fn from_line_index(index: i16) -> Self {
GridPlacement::Line(GridLine::from(index))
}
}
impl TaffyGridLine for Line<GridPlacement> {
fn from_line_index(index: i16) -> Self {
Line { start: GridPlacement::from_line_index(index), end: GridPlacement::Auto }
}
}
impl TaffyGridSpan for GridPlacement {
fn from_span(span: u16) -> Self {
GridPlacement::Span(span)
}
}
impl TaffyGridSpan for Line<GridPlacement> {
fn from_span(span: u16) -> Self {
Line { start: GridPlacement::from_span(span), end: GridPlacement::Auto }
}
}
impl Default for GridPlacement {
fn default() -> Self {
Self::Auto
}
}
impl GridPlacement {
pub fn into_origin_zero_placement(self, explicit_track_count: u16) -> OriginZeroGridPlacement {
match self {
Self::Auto => OriginZeroGridPlacement::Auto,
Self::Span(span) => OriginZeroGridPlacement::Span(span),
Self::Line(line) => match line.as_i16() {
0 => OriginZeroGridPlacement::Auto,
_ => OriginZeroGridPlacement::Line(line.into_origin_zero_line(explicit_track_count)),
},
}
}
}
impl<T: GridCoordinate> Line<GenericGridPlacement<T>> {
#[inline]
pub fn is_definite(&self) -> bool {
matches!((self.start, self.end), (GenericGridPlacement::Line(_), _) | (_, GenericGridPlacement::Line(_)))
}
pub fn indefinite_span(&self) -> u16 {
use GenericGridPlacement as GP;
match (self.start, self.end) {
(GP::Line(_), GP::Auto) => 1,
(GP::Auto, GP::Line(_)) => 1,
(GP::Auto, GP::Auto) => 1,
(GP::Line(_), GP::Span(span)) => span,
(GP::Span(span), GP::Line(_)) => span,
(GP::Span(span), GP::Auto) => span,
(GP::Auto, GP::Span(span)) => span,
(GP::Span(span), GP::Span(_)) => span,
(GP::Line(_), GP::Line(_)) => panic!("indefinite_span should only be called on indefinite grid tracks"),
}
}
}
impl Line<GridPlacement> {
pub fn into_origin_zero(&self, explicit_track_count: u16) -> Line<OriginZeroGridPlacement> {
Line {
start: self.start.into_origin_zero_placement(explicit_track_count),
end: self.end.into_origin_zero_placement(explicit_track_count),
}
}
}
impl Line<OriginZeroGridPlacement> {
pub fn resolve_definite_grid_lines(&self) -> Line<OriginZeroLine> {
use OriginZeroGridPlacement as GP;
match (self.start, self.end) {
(GP::Line(line1), GP::Line(line2)) => {
if line1 == line2 {
Line { start: line1, end: line1 + 1 }
} else {
Line { start: min(line1, line2), end: max(line1, line2) }
}
}
(GP::Line(line), GP::Span(span)) => Line { start: line, end: line + span },
(GP::Line(line), GP::Auto) => Line { start: line, end: line + 1 },
(GP::Span(span), GP::Line(line)) => Line { start: line - span, end: line },
(GP::Auto, GP::Line(line)) => Line { start: line - 1, end: line },
_ => panic!("resolve_definite_grid_tracks should only be called on definite grid tracks"),
}
}
pub fn resolve_absolutely_positioned_grid_tracks(&self) -> Line<Option<OriginZeroLine>> {
use OriginZeroGridPlacement as GP;
match (self.start, self.end) {
(GP::Line(track1), GP::Line(track2)) => {
if track1 == track2 {
Line { start: Some(track1), end: Some(track1 + 1) }
} else {
Line { start: Some(min(track1, track2)), end: Some(max(track1, track2)) }
}
}
(GP::Line(track), GP::Span(span)) => Line { start: Some(track), end: Some(track + span) },
(GP::Line(track), GP::Auto) => Line { start: Some(track), end: None },
(GP::Span(span), GP::Line(track)) => Line { start: Some(track - span), end: Some(track) },
(GP::Auto, GP::Line(track)) => Line { start: None, end: Some(track) },
_ => Line { start: None, end: None },
}
}
pub fn resolve_indefinite_grid_tracks(&self, start: OriginZeroLine) -> Line<OriginZeroLine> {
use OriginZeroGridPlacement as GP;
match (self.start, self.end) {
(GP::Auto, GP::Auto) => Line { start, end: start + 1 },
(GP::Span(span), GP::Auto) => Line { start, end: start + span },
(GP::Auto, GP::Span(span)) => Line { start, end: start + span },
(GP::Span(span), GP::Span(_)) => Line { start, end: start + span },
_ => panic!("resolve_indefinite_grid_tracks should only be called on indefinite grid tracks"),
}
}
}
impl Default for Line<GridPlacement> {
fn default() -> Self {
Line { start: GridPlacement::Auto, end: GridPlacement::Auto }
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MaxTrackSizingFunction {
Fixed(LengthPercentage),
MinContent,
MaxContent,
FitContent(LengthPercentage),
Auto,
Fraction(f32),
}
impl TaffyAuto for MaxTrackSizingFunction {
const AUTO: Self = Self::Auto;
}
impl TaffyMinContent for MaxTrackSizingFunction {
const MIN_CONTENT: Self = Self::MinContent;
}
impl TaffyMaxContent for MaxTrackSizingFunction {
const MAX_CONTENT: Self = Self::MaxContent;
}
impl TaffyFitContent for MaxTrackSizingFunction {
fn fit_content(argument: LengthPercentage) -> Self {
Self::FitContent(argument)
}
}
impl TaffyZero for MaxTrackSizingFunction {
const ZERO: Self = Self::Fixed(LengthPercentage::ZERO);
}
impl FromPoints for MaxTrackSizingFunction {
fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
Self::Fixed(LengthPercentage::from_points(points))
}
}
impl FromPercent for MaxTrackSizingFunction {
fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
Self::Fixed(LengthPercentage::from_percent(percent))
}
}
impl FromFlex for MaxTrackSizingFunction {
fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
Self::Fraction(flex.into())
}
}
impl MaxTrackSizingFunction {
#[inline(always)]
pub fn is_intrinsic(&self) -> bool {
matches!(self, Self::MinContent | Self::MaxContent | Self::FitContent(_) | Self::Auto)
}
#[inline(always)]
pub fn is_max_content_alike(&self) -> bool {
matches!(self, Self::MaxContent | Self::FitContent(_) | Self::Auto)
}
#[inline(always)]
pub fn is_flexible(&self) -> bool {
matches!(self, Self::Fraction(_))
}
#[inline(always)]
pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
use MaxTrackSizingFunction::*;
match self {
Fixed(LengthPercentage::Points(size)) => Some(size),
Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
MinContent | MaxContent | FitContent(_) | Auto | Fraction(_) => None,
}
}
#[inline(always)]
pub fn definite_limit(self, parent_size: Option<f32>) -> Option<f32> {
use MaxTrackSizingFunction::FitContent;
match self {
FitContent(LengthPercentage::Points(size)) => Some(size),
FitContent(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
_ => self.definite_value(parent_size),
}
}
#[inline(always)]
pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
use MaxTrackSizingFunction::*;
match self {
Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | FitContent(_) | Auto | Fraction(_) => None,
}
}
#[inline(always)]
pub fn uses_percentage(self) -> bool {
use MaxTrackSizingFunction::*;
matches!(self, Fixed(LengthPercentage::Percent(_)) | FitContent(LengthPercentage::Percent(_)))
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MinTrackSizingFunction {
Fixed(LengthPercentage),
MinContent,
MaxContent,
Auto,
}
impl TaffyAuto for MinTrackSizingFunction {
const AUTO: Self = Self::Auto;
}
impl TaffyMinContent for MinTrackSizingFunction {
const MIN_CONTENT: Self = Self::MinContent;
}
impl TaffyMaxContent for MinTrackSizingFunction {
const MAX_CONTENT: Self = Self::MaxContent;
}
impl TaffyZero for MinTrackSizingFunction {
const ZERO: Self = Self::Fixed(LengthPercentage::ZERO);
}
impl FromPoints for MinTrackSizingFunction {
fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
Self::Fixed(LengthPercentage::from_points(points))
}
}
impl FromPercent for MinTrackSizingFunction {
fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
Self::Fixed(LengthPercentage::from_percent(percent))
}
}
impl MinTrackSizingFunction {
#[inline(always)]
pub fn is_intrinsic(&self) -> bool {
matches!(self, Self::MinContent | Self::MaxContent | Self::Auto)
}
#[inline(always)]
pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
use MinTrackSizingFunction::*;
match self {
Fixed(LengthPercentage::Points(size)) => Some(size),
Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
MinContent | MaxContent | Auto => None,
}
}
#[inline(always)]
pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
use MinTrackSizingFunction::*;
match self {
Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | Auto => None,
}
}
#[inline(always)]
pub fn uses_percentage(self) -> bool {
use MinTrackSizingFunction::*;
matches!(self, Fixed(LengthPercentage::Percent(_)))
}
}
pub type NonRepeatedTrackSizingFunction = MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>;
impl NonRepeatedTrackSizingFunction {
pub fn min_sizing_function(&self) -> MinTrackSizingFunction {
self.min
}
pub fn max_sizing_function(&self) -> MaxTrackSizingFunction {
self.max
}
pub fn has_fixed_component(&self) -> bool {
matches!(self.min, MinTrackSizingFunction::Fixed(_)) || matches!(self.max, MaxTrackSizingFunction::Fixed(_))
}
}
impl TaffyAuto for NonRepeatedTrackSizingFunction {
const AUTO: Self = Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::AUTO };
}
impl TaffyMinContent for NonRepeatedTrackSizingFunction {
const MIN_CONTENT: Self =
Self { min: MinTrackSizingFunction::MIN_CONTENT, max: MaxTrackSizingFunction::MIN_CONTENT };
}
impl TaffyMaxContent for NonRepeatedTrackSizingFunction {
const MAX_CONTENT: Self =
Self { min: MinTrackSizingFunction::MAX_CONTENT, max: MaxTrackSizingFunction::MAX_CONTENT };
}
impl TaffyFitContent for NonRepeatedTrackSizingFunction {
fn fit_content(argument: LengthPercentage) -> Self {
Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::FitContent(argument) }
}
}
impl TaffyZero for NonRepeatedTrackSizingFunction {
const ZERO: Self = Self { min: MinTrackSizingFunction::ZERO, max: MaxTrackSizingFunction::ZERO };
}
impl FromPoints for NonRepeatedTrackSizingFunction {
fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
Self { min: MinTrackSizingFunction::from_points(points), max: MaxTrackSizingFunction::from_points(points) }
}
}
impl FromPercent for NonRepeatedTrackSizingFunction {
fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
Self { min: MinTrackSizingFunction::from_percent(percent), max: MaxTrackSizingFunction::from_percent(percent) }
}
}
impl FromFlex for NonRepeatedTrackSizingFunction {
fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::from_flex(flex) }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum GridTrackRepetition {
AutoFill,
AutoFit,
Count(u16),
}
impl TryFrom<u16> for GridTrackRepetition {
type Error = Infallible;
fn try_from(value: u16) -> Result<Self, Infallible> {
Ok(Self::Count(value))
}
}
#[derive(Debug)]
pub struct InvalidStringRepetitionValue;
#[cfg(feature = "std")]
impl std::error::Error for InvalidStringRepetitionValue {}
impl core::fmt::Display for InvalidStringRepetitionValue {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("&str can only be converted to GridTrackRepetition if it's value is 'auto-fit' or 'auto-fill'")
}
}
impl<'a> TryFrom<&'a str> for GridTrackRepetition {
type Error = InvalidStringRepetitionValue;
fn try_from(value: &str) -> Result<Self, InvalidStringRepetitionValue> {
match value {
"auto-fit" => Ok(Self::AutoFit),
"auto-fill" => Ok(Self::AutoFill),
_ => Err(InvalidStringRepetitionValue),
}
}
}
#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TrackSizingFunction {
Single(NonRepeatedTrackSizingFunction),
Repeat(GridTrackRepetition, GridTrackVec<NonRepeatedTrackSizingFunction>),
}
impl TrackSizingFunction {
pub fn is_auto_repetition(&self) -> bool {
matches!(self, Self::Repeat(GridTrackRepetition::AutoFit | GridTrackRepetition::AutoFill, _))
}
}
impl TaffyAuto for TrackSizingFunction {
const AUTO: Self = Self::Single(NonRepeatedTrackSizingFunction::AUTO);
}
impl TaffyMinContent for TrackSizingFunction {
const MIN_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MIN_CONTENT);
}
impl TaffyMaxContent for TrackSizingFunction {
const MAX_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MAX_CONTENT);
}
impl TaffyFitContent for TrackSizingFunction {
fn fit_content(argument: LengthPercentage) -> Self {
Self::Single(NonRepeatedTrackSizingFunction::fit_content(argument))
}
}
impl TaffyZero for TrackSizingFunction {
const ZERO: Self = Self::Single(NonRepeatedTrackSizingFunction::ZERO);
}
impl FromPoints for TrackSizingFunction {
fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
Self::Single(NonRepeatedTrackSizingFunction::from_points(points))
}
}
impl FromPercent for TrackSizingFunction {
fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
Self::Single(NonRepeatedTrackSizingFunction::from_percent(percent))
}
}
impl FromFlex for TrackSizingFunction {
fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
Self::Single(NonRepeatedTrackSizingFunction::from_flex(flex))
}
}
impl From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> for TrackSizingFunction {
fn from(input: MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>) -> Self {
Self::Single(input)
}
}
impl Style {
pub(crate) fn grid_template_tracks(&self, axis: AbsoluteAxis) -> &GridTrackVec<TrackSizingFunction> {
match axis {
AbsoluteAxis::Horizontal => &self.grid_template_columns,
AbsoluteAxis::Vertical => &self.grid_template_rows,
}
}
pub(crate) fn grid_placement(&self, axis: AbsoluteAxis) -> Line<GridPlacement> {
match axis {
AbsoluteAxis::Horizontal => self.grid_column,
AbsoluteAxis::Vertical => self.grid_row,
}
}
pub(crate) fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent {
match axis {
AbstractAxis::Inline => self.justify_content.unwrap_or(AlignContent::Stretch),
AbstractAxis::Block => self.align_content.unwrap_or(AlignContent::Stretch),
}
}
}