| 14 | |
| 15 | |
| 16 | void SequentialLayout::step() { |
| 17 | Widget::step(); |
| 18 | |
| 19 | float boundWidth = X(box.size) - 2 * X(margin); |
| 20 | |
| 21 | // Sort widgets into rows (or columns if vertical) |
| 22 | std::vector<widget::Widget*> row; |
| 23 | math::Vec cursor = margin; |
| 24 | auto flushRow = [&]() { |
| 25 | // For center and right alignment, compute offset from the left margin |
| 26 | if (alignment != LEFT_ALIGNMENT) { |
| 27 | float rowWidth = 0.f; |
| 28 | for (widget::Widget* child : row) { |
| 29 | rowWidth += X(child->box.size) + X(spacing); |
| 30 | } |
| 31 | rowWidth -= X(spacing); |
| 32 | |
| 33 | if (alignment == CENTER_ALIGNMENT) |
| 34 | X(cursor) += (boundWidth - rowWidth) / 2; |
| 35 | else if (alignment == RIGHT_ALIGNMENT) |
| 36 | X(cursor) += boundWidth - rowWidth; |
| 37 | } |
| 38 | |
| 39 | // Set positions of widgets |
| 40 | float maxHeight = 0.f; |
| 41 | for (widget::Widget* child : row) { |
| 42 | child->box.pos = cursor; |
| 43 | X(cursor) += X(child->box.size) + X(spacing); |
| 44 | |
| 45 | if (Y(child->box.size) > maxHeight) |
| 46 | maxHeight = Y(child->box.size); |
| 47 | } |
| 48 | row.clear(); |
| 49 | |
| 50 | // Reset cursor to next line |
| 51 | X(cursor) = X(margin); |
| 52 | Y(cursor) += maxHeight + Y(spacing); |
| 53 | }; |
| 54 | |
| 55 | // Iterate through children until row is full |
| 56 | float rowWidth = 0.0; |
| 57 | for (widget::Widget* child : children) { |
| 58 | // Skip invisible children |
| 59 | if (!child->isVisible()) { |
| 60 | child->box.pos = math::Vec(); |
| 61 | continue; |
| 62 | } |
| 63 | |
| 64 | // Should we wrap the widget now? |
| 65 | if (wrap && !row.empty() && rowWidth + X(child->box.size) > boundWidth) { |
| 66 | flushRow(); |
| 67 | rowWidth = 0.0; |
| 68 | } |
| 69 | |
| 70 | row.push_back(child); |
| 71 | rowWidth += X(child->box.size) + X(spacing); |
| 72 | } |
| 73 | |