layout method

  1. @override
PwBox layout(
  1. Context context,
  2. BoxConstraints constraints
)
override

layout API.

Implementation

@override
PwBox layout(Context context, BoxConstraints constraints) {
  final bool horiz = direction == Axis.horizontal;
  final double maxMain = horiz ? constraints.maxWidth : constraints.maxHeight;
  final double maxCross = horiz ? constraints.maxHeight : constraints.maxWidth;
  final bool mainBounded = horiz
      ? constraints.hasBoundedWidth
      : constraints.hasBoundedHeight;
  final List<PwBox?> boxes = List<PwBox?>.filled(children.length, null);
  var allocated = 0.0;
  var totalFlex = 0;
  for (int i = 0; i < children.length; i++) {
    final Widget raw = children[i];
    final int flex = raw is Flexible ? raw.flex : 0;
    if (flex > 0) {
      totalFlex += flex;
      continue;
    }
    final Widget inner = raw is Flexible ? raw.child : raw;
    final BoxConstraints childCs = horiz
        ? BoxConstraints(
            maxWidth: mainBounded ? (maxMain - allocated).clamp(0, maxMain) : double.infinity,
            maxHeight: maxCross,
            minHeight: crossAxisAlignment == CrossAxisAlignment.stretch
                ? (maxCross.isFinite ? maxCross : 0)
                : 0,
          )
        : BoxConstraints(
            maxWidth: maxCross,
            minWidth: crossAxisAlignment == CrossAxisAlignment.stretch
                ? (maxCross.isFinite ? maxCross : 0)
                : 0,
            maxHeight: mainBounded
                ? (maxMain - allocated).clamp(0, maxMain)
                : double.infinity,
          );
    final PwBox box = inner.layout(context, childCs);
    boxes[i] = box;
    allocated += horiz ? box.size.width : box.size.height;
  }
  final double flexSpace = mainBounded
      ? (maxMain - allocated).clamp(0, maxMain)
      : 0;
  for (int i = 0; i < children.length; i++) {
    if (boxes[i] != null) {
      continue;
    }
    final Widget raw = children[i];
    final int flex = raw is Flexible ? raw.flex : 1;
    final FlexFit fit = raw is Flexible ? raw.fit : FlexFit.loose;
    final Widget inner = raw is Flexible ? raw.child : raw;
    final double share = totalFlex <= 0 ? 0 : flexSpace * flex / totalFlex;
    final BoxConstraints childCs = horiz
        ? BoxConstraints(
            minWidth: fit == FlexFit.tight ? share : 0,
            maxWidth: share,
            maxHeight: maxCross,
            minHeight: crossAxisAlignment == CrossAxisAlignment.stretch &&
                    maxCross.isFinite
                ? maxCross
                : 0,
          )
        : BoxConstraints(
            minHeight: fit == FlexFit.tight ? share : 0,
            maxHeight: share,
            maxWidth: maxCross,
            minWidth: crossAxisAlignment == CrossAxisAlignment.stretch &&
                    maxCross.isFinite
                ? maxCross
                : 0,
          );
    final PwBox box = inner.layout(context, childCs);
    boxes[i] = box;
    allocated += horiz ? box.size.width : box.size.height;
  }
  var cross = 0.0;
  for (final PwBox? box in boxes) {
    if (box == null) {
      continue;
    }
    final double c = horiz ? box.size.height : box.size.width;
    if (c > cross) {
      cross = c;
    }
  }
  if (crossAxisAlignment == CrossAxisAlignment.stretch && maxCross.isFinite) {
    cross = maxCross;
  }
  final double main = mainAxisSize == MainAxisSize.max &&
          mainBounded &&
          allocated < maxMain
      ? maxMain
      : allocated;
  final PwSize size = constraints.constrain(
    horiz ? PwSize(main, cross) : PwSize(cross, main),
  );
  final List<(PwBox, PwOffset)> placed = <(PwBox, PwOffset)>[];
  final List<double> mains = <double>[
    for (final PwBox? box in boxes)
      box == null ? 0 : (horiz ? box.size.width : box.size.height),
  ];
  var cursor = 0.0;
  var gap = 0.0;
  final double leftover = (main - allocated).clamp(0, double.infinity);
  final bool reverseMain =
      horiz && context.textDirection == TextDirection.rtl;
  switch (mainAxisAlignment) {
    case MainAxisAlignment.start:
      cursor = reverseMain ? leftover : 0;
    case MainAxisAlignment.end:
      cursor = reverseMain ? 0 : leftover;
    case MainAxisAlignment.center:
      cursor = leftover / 2;
    case MainAxisAlignment.spaceBetween:
      gap = boxes.length > 1 ? leftover / (boxes.length - 1) : 0;
    case MainAxisAlignment.spaceAround:
      gap = boxes.isEmpty ? 0 : leftover / boxes.length;
      cursor = gap / 2;
    case MainAxisAlignment.spaceEvenly:
      gap = leftover / (boxes.length + 1);
      cursor = gap;
  }
  final List<int> order = <int>[
    for (int i = 0; i < boxes.length; i++)
      reverseMain ? boxes.length - 1 - i : i,
  ];
  for (final int i in order) {
    final PwBox box = boxes[i]!;
    final double crossOff = switch (crossAxisAlignment) {
      CrossAxisAlignment.start => _crossStart(
        horiz: horiz,
        rtl: context.textDirection == TextDirection.rtl,
        size: size,
        box: box,
      ),
      CrossAxisAlignment.end => _crossEnd(
        horiz: horiz,
        rtl: context.textDirection == TextDirection.rtl,
        size: size,
        box: box,
      ),
      CrossAxisAlignment.center => horiz
          ? (size.height - box.size.height) / 2
          : (size.width - box.size.width) / 2,
      CrossAxisAlignment.stretch => 0,
    };
    placed.add((
      box,
      horiz ? PwOffset(cursor, crossOff) : PwOffset(crossOff, cursor),
    ));
    cursor += mains[i] + gap;
  }
  return GroupBox(size, placed);
}