|
@@ -15,7 +15,7 @@
|
|
|
*
|
|
*
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
* all copies or substantial portions of the Software.
|
|
* all copies or substantial portions of the Software.
|
|
|
- *
|
|
|
|
|
|
|
+ *
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
@@ -26,93 +26,116 @@
|
|
|
*
|
|
*
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-#include "LayoutTable.h"
|
|
|
|
|
-#include "../../Include/RmlUi/Core/ComputedValues.h"
|
|
|
|
|
-#include "../../Include/RmlUi/Core/Element.h"
|
|
|
|
|
-#include "../../Include/RmlUi/Core/Types.h"
|
|
|
|
|
|
|
+#include "TableFormattingContext.h"
|
|
|
|
|
+#include "../../../Include/RmlUi/Core/ComputedValues.h"
|
|
|
|
|
+#include "../../../Include/RmlUi/Core/Element.h"
|
|
|
|
|
+#include "../../../Include/RmlUi/Core/Types.h"
|
|
|
|
|
+#include "ContainerBox.h"
|
|
|
#include "LayoutDetails.h"
|
|
#include "LayoutDetails.h"
|
|
|
#include "LayoutEngine.h"
|
|
#include "LayoutEngine.h"
|
|
|
-#include "LayoutTableDetails.h"
|
|
|
|
|
|
|
+#include "TableFormattingDetails.h"
|
|
|
#include <algorithm>
|
|
#include <algorithm>
|
|
|
#include <numeric>
|
|
#include <numeric>
|
|
|
|
|
|
|
|
namespace Rml {
|
|
namespace Rml {
|
|
|
|
|
|
|
|
-Vector2f LayoutTable::FormatTable(Box& box, Vector2f min_size, Vector2f max_size, Element* element_table)
|
|
|
|
|
|
|
+UniquePtr<LayoutBox> TableFormattingContext::Format(ContainerBox* parent_container, Element* element_table, const Box* override_initial_box)
|
|
|
{
|
|
{
|
|
|
- const ComputedValues& computed_table = element_table->GetComputedValues();
|
|
|
|
|
-
|
|
|
|
|
- // Scrollbars are illegal in the table element.
|
|
|
|
|
- if (!(computed_table.overflow_x() == Style::Overflow::Visible || computed_table.overflow_x() == Style::Overflow::Hidden) ||
|
|
|
|
|
- !(computed_table.overflow_y() == Style::Overflow::Visible || computed_table.overflow_y() == Style::Overflow::Hidden))
|
|
|
|
|
|
|
+ auto table_wrapper_box = MakeUnique<TableWrapper>(element_table, parent_container);
|
|
|
|
|
+ if (table_wrapper_box->IsScrollContainer())
|
|
|
{
|
|
{
|
|
|
- Log::Message(Log::LT_WARNING, "Table elements can only have 'overflow' property values of 'visible' or 'hidden'. Table will not be formatted: %s.", element_table->GetAddress().c_str());
|
|
|
|
|
- return Vector2f(0);
|
|
|
|
|
|
|
+ Log::Message(Log::LT_WARNING, "Table elements can only have 'overflow' property values of 'visible'. Table will not be formatted: %s.",
|
|
|
|
|
+ element_table->GetAddress().c_str());
|
|
|
|
|
+ return table_wrapper_box;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const Vector2f box_content_size = box.GetSize();
|
|
|
|
|
- const bool table_auto_height = (box_content_size.y < 0.0f);
|
|
|
|
|
|
|
+ const Vector2f containing_block = LayoutDetails::GetContainingBlock(parent_container, element_table->GetPosition()).size;
|
|
|
|
|
+ RMLUI_ASSERT(containing_block.x >= 0.f);
|
|
|
|
|
+ const ComputedValues& computed_table = element_table->GetComputedValues();
|
|
|
|
|
+
|
|
|
|
|
+ // Build the initial box as specified by the table's style, as if it was a normal block element.
|
|
|
|
|
+ Box& box = table_wrapper_box->GetBox();
|
|
|
|
|
+ if (override_initial_box)
|
|
|
|
|
+ box = *override_initial_box;
|
|
|
|
|
+ else
|
|
|
|
|
+ LayoutDetails::BuildBox(box, containing_block, element_table, BuildBoxMode::Block);
|
|
|
|
|
|
|
|
- Vector2f table_content_offset = box.GetPosition();
|
|
|
|
|
- Vector2f table_initial_content_size = Vector2f(box_content_size.x, Math::Max(0.0f, box_content_size.y));
|
|
|
|
|
|
|
+ TableFormattingContext context;
|
|
|
|
|
+ context.element_table = element_table;
|
|
|
|
|
+ context.table_wrapper_box = table_wrapper_box.get();
|
|
|
|
|
|
|
|
- Math::SnapToPixelGrid(table_content_offset, table_initial_content_size);
|
|
|
|
|
|
|
+ LayoutDetails::GetMinMaxWidth(context.table_min_size.x, context.table_max_size.x, computed_table, box, containing_block.x);
|
|
|
|
|
+ LayoutDetails::GetMinMaxHeight(context.table_min_size.y, context.table_max_size.y, computed_table, box, containing_block.y);
|
|
|
|
|
+
|
|
|
|
|
+ // Format the table, this may adjust the box content size.
|
|
|
|
|
+ const Vector2f initial_content_size = box.GetSize();
|
|
|
|
|
+ context.table_auto_height = (initial_content_size.y < 0.0f);
|
|
|
|
|
+
|
|
|
|
|
+ context.table_content_offset = box.GetPosition();
|
|
|
|
|
+ context.table_initial_content_size = Vector2f(initial_content_size.x, Math::Max(0.0f, initial_content_size.y));
|
|
|
|
|
+ Math::SnapToPixelGrid(context.table_content_offset, context.table_initial_content_size);
|
|
|
|
|
|
|
|
// When width or height is set, they act as minimum width or height, just as in CSS.
|
|
// When width or height is set, they act as minimum width or height, just as in CSS.
|
|
|
if (computed_table.width().type != Style::Width::Auto)
|
|
if (computed_table.width().type != Style::Width::Auto)
|
|
|
- min_size.x = Math::Max(min_size.x, table_initial_content_size.x);
|
|
|
|
|
|
|
+ context.table_min_size.x = Math::Max(context.table_min_size.x, context.table_initial_content_size.x);
|
|
|
if (computed_table.height().type != Style::Height::Auto)
|
|
if (computed_table.height().type != Style::Height::Auto)
|
|
|
- min_size.y = Math::Max(min_size.y, table_initial_content_size.y);
|
|
|
|
|
|
|
+ context.table_min_size.y = Math::Max(context.table_min_size.y, context.table_initial_content_size.y);
|
|
|
|
|
+
|
|
|
|
|
+ context.table_gap = Vector2f(ResolveValue(computed_table.column_gap(), context.table_initial_content_size.x),
|
|
|
|
|
+ ResolveValue(computed_table.row_gap(), context.table_initial_content_size.y));
|
|
|
|
|
|
|
|
- const Vector2f table_gap = Vector2f(
|
|
|
|
|
- ResolveValue(computed_table.column_gap(), table_initial_content_size.x),
|
|
|
|
|
- ResolveValue(computed_table.row_gap(), table_initial_content_size.y)
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ context.grid.Build(element_table, *table_wrapper_box);
|
|
|
|
|
|
|
|
- TableGrid grid;
|
|
|
|
|
- grid.Build(element_table);
|
|
|
|
|
|
|
+ Vector2f table_content_size, table_overflow_size;
|
|
|
|
|
|
|
|
- // Construct the layout object and format the table.
|
|
|
|
|
- LayoutTable layout_table(element_table, grid, table_gap, table_content_offset, table_initial_content_size, table_auto_height, min_size, max_size);
|
|
|
|
|
|
|
+ // Format the table and its children.
|
|
|
|
|
+ context.FormatTable(table_content_size, table_overflow_size);
|
|
|
|
|
|
|
|
- layout_table.FormatTable();
|
|
|
|
|
|
|
+ RMLUI_ASSERT(table_content_size.y >= 0);
|
|
|
|
|
|
|
|
// Update the box size based on the new table size.
|
|
// Update the box size based on the new table size.
|
|
|
- box.SetContent(layout_table.table_resulting_content_size);
|
|
|
|
|
|
|
+ box.SetContent(table_content_size);
|
|
|
|
|
|
|
|
- return layout_table.table_content_overflow_size;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ if (table_content_size != initial_content_size)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Perform this step to re-evaluate any auto margins.
|
|
|
|
|
+ LayoutDetails::BuildBoxSizeAndMargins(box, context.table_min_size, context.table_max_size, containing_block, element_table,
|
|
|
|
|
+ BuildBoxMode::Block, true);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ table_wrapper_box->Close(table_overflow_size, box);
|
|
|
|
|
|
|
|
-LayoutTable::LayoutTable(Element* element_table, const TableGrid& grid, Vector2f table_gap, Vector2f table_content_offset,
|
|
|
|
|
- Vector2f table_initial_content_size, bool table_auto_height, Vector2f table_min_size, Vector2f table_max_size)
|
|
|
|
|
- : element_table(element_table), grid(grid), table_auto_height(table_auto_height), table_min_size(table_min_size), table_max_size(table_max_size),
|
|
|
|
|
- table_gap(table_gap), table_content_offset(table_content_offset), table_initial_content_size(table_initial_content_size)
|
|
|
|
|
-{
|
|
|
|
|
- table_resulting_content_size = table_initial_content_size;
|
|
|
|
|
|
|
+ return table_wrapper_box;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void LayoutTable::FormatTable()
|
|
|
|
|
|
|
+void TableFormattingContext::FormatTable(Vector2f& table_content_size, Vector2f& table_overflow_size) const
|
|
|
{
|
|
{
|
|
|
- DetermineColumnWidths();
|
|
|
|
|
|
|
+ // Defines the boxes for all columns in this table, one entry per table column (spanning columns will add multiple entries).
|
|
|
|
|
+ TrackBoxList columns;
|
|
|
|
|
+ // Defines the boxes for all rows in this table, one entry per table row.
|
|
|
|
|
+ TrackBoxList rows;
|
|
|
|
|
+ // Defines the boxes for all cells in this table.
|
|
|
|
|
+ BoxList cells;
|
|
|
|
|
+
|
|
|
|
|
+ DetermineColumnWidths(columns, table_content_size.x);
|
|
|
|
|
|
|
|
- InitializeCellBoxes();
|
|
|
|
|
|
|
+ InitializeCellBoxes(cells, columns);
|
|
|
|
|
|
|
|
- DetermineRowHeights();
|
|
|
|
|
|
|
+ DetermineRowHeights(rows, cells, table_content_size.y);
|
|
|
|
|
|
|
|
- FormatRows();
|
|
|
|
|
|
|
+ FormatRows(rows, table_content_size.x);
|
|
|
|
|
|
|
|
- FormatColumns();
|
|
|
|
|
|
|
+ FormatColumns(columns, table_content_size.y);
|
|
|
|
|
|
|
|
- FormatCells();
|
|
|
|
|
|
|
+ FormatCells(cells, table_overflow_size, rows, columns);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void LayoutTable::DetermineColumnWidths()
|
|
|
|
|
|
|
+void TableFormattingContext::DetermineColumnWidths(TrackBoxList& columns, float& table_content_width) const
|
|
|
{
|
|
{
|
|
|
// The column widths are determined entirely by any <col> elements preceding the first row, and <td> elements in the first row.
|
|
// The column widths are determined entirely by any <col> elements preceding the first row, and <td> elements in the first row.
|
|
|
// If <col> has a fixed width, that is used. Otherwise, if <td> has a fixed width, that is used. Otherwise the column is 'flexible' width.
|
|
// If <col> has a fixed width, that is used. Otherwise, if <td> has a fixed width, that is used. Otherwise the column is 'flexible' width.
|
|
|
// All flexible widths are then sized to evenly fill the width of the table.
|
|
// All flexible widths are then sized to evenly fill the width of the table.
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Both <col> and <colgroup> can have border/padding which extend beyond the size of <td> and <col>, respectively.
|
|
// Both <col> and <colgroup> can have border/padding which extend beyond the size of <td> and <col>, respectively.
|
|
|
// Margins for <td>, <col>, <colgroup> are merged to produce a single left/right margin for each column, located outside <colgroup>.
|
|
// Margins for <td>, <col>, <colgroup> are merged to produce a single left/right margin for each column, located outside <colgroup>.
|
|
|
|
|
|
|
@@ -169,10 +192,10 @@ void LayoutTable::DetermineColumnWidths()
|
|
|
const float columns_full_width = BuildColumnBoxes(columns, column_metrics, grid.columns, table_gap.x);
|
|
const float columns_full_width = BuildColumnBoxes(columns, column_metrics, grid.columns, table_gap.x);
|
|
|
|
|
|
|
|
// Adjust the table content width based on the accumulated column widths and spacing.
|
|
// Adjust the table content width based on the accumulated column widths and spacing.
|
|
|
- table_resulting_content_size.x = Math::Clamp(columns_full_width, table_min_size.x, table_max_size.x);
|
|
|
|
|
|
|
+ table_content_width = Math::Clamp(columns_full_width, table_min_size.x, table_max_size.x);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void LayoutTable::InitializeCellBoxes()
|
|
|
|
|
|
|
+void TableFormattingContext::InitializeCellBoxes(BoxList& cells, const TrackBoxList& columns) const
|
|
|
{
|
|
{
|
|
|
// Requires that column boxes are already generated.
|
|
// Requires that column boxes are already generated.
|
|
|
RMLUI_ASSERT(columns.size() == grid.columns.size());
|
|
RMLUI_ASSERT(columns.size() == grid.columns.size());
|
|
@@ -184,7 +207,7 @@ void LayoutTable::InitializeCellBoxes()
|
|
|
Box& box = cells[i];
|
|
Box& box = cells[i];
|
|
|
|
|
|
|
|
// Determine the cell's box for formatting later, we may get an indefinite (-1) vertical content size.
|
|
// Determine the cell's box for formatting later, we may get an indefinite (-1) vertical content size.
|
|
|
- LayoutDetails::BuildBox(box, table_initial_content_size, grid.cells[i].element_cell, BoxContext::FlexOrTable, 0.f);
|
|
|
|
|
|
|
+ LayoutDetails::BuildBox(box, table_initial_content_size, grid.cells[i].element_cell, BuildBoxMode::UnalignedBlock);
|
|
|
|
|
|
|
|
// Determine the cell's content width. Include any spanning columns in the cell width.
|
|
// Determine the cell's content width. Include any spanning columns in the cell width.
|
|
|
const float cell_border_width = GetSpanningCellBorderSize(columns, grid.cells[i].column_begin, grid.cells[i].column_last);
|
|
const float cell_border_width = GetSpanningCellBorderSize(columns, grid.cells[i].column_begin, grid.cells[i].column_last);
|
|
@@ -193,22 +216,22 @@ void LayoutTable::InitializeCellBoxes()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void LayoutTable::DetermineRowHeights()
|
|
|
|
|
|
|
+void TableFormattingContext::DetermineRowHeights(TrackBoxList& rows, BoxList& cells, float& table_content_height) const
|
|
|
{
|
|
{
|
|
|
/*
|
|
/*
|
|
|
- The table height algorithm works similar to the table width algorithm. The major difference is that 'auto' row height
|
|
|
|
|
- will use the height of the largest formatted cell in the row.
|
|
|
|
|
-
|
|
|
|
|
- Table row height:
|
|
|
|
|
- auto: Height of largest cell in row.
|
|
|
|
|
- length: Fixed size.
|
|
|
|
|
- percentage < 100%: Fixed size, resolved against table initial height.
|
|
|
|
|
- percentage >= 100%: Flexible size.
|
|
|
|
|
-
|
|
|
|
|
- Table height:
|
|
|
|
|
- auto: Height is sum of all rows.
|
|
|
|
|
- length/percentage: Fixed minimum size. If row height sum is larger, increase table size. If row sum is smaller, try to increase
|
|
|
|
|
- row heights, but respect max-heights. If table is still larger than row-sum, leave empty space.
|
|
|
|
|
|
|
+ The table height algorithm works similar to the table width algorithm. The major difference is that 'auto' row height
|
|
|
|
|
+ will use the height of the largest formatted cell in the row.
|
|
|
|
|
+
|
|
|
|
|
+ Table row height:
|
|
|
|
|
+ auto: Height of largest cell in row.
|
|
|
|
|
+ length: Fixed size.
|
|
|
|
|
+ percentage < 100%: Fixed size, resolved against table initial height.
|
|
|
|
|
+ percentage >= 100%: Flexible size.
|
|
|
|
|
+
|
|
|
|
|
+ Table height:
|
|
|
|
|
+ auto: Height is sum of all rows.
|
|
|
|
|
+ length/percentage: Fixed minimum size. If row height sum is larger, increase table size. If row sum is smaller, try to increase
|
|
|
|
|
+ row heights, but respect max-heights. If table is still larger than row-sum, leave empty space.
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
// Requires that cell boxes have been initialized.
|
|
// Requires that cell boxes have been initialized.
|
|
@@ -234,7 +257,7 @@ void LayoutTable::DetermineRowHeights()
|
|
|
{
|
|
{
|
|
|
// The padding/border/margin and widths of columns are used.
|
|
// The padding/border/margin and widths of columns are used.
|
|
|
const ComputedAxisSize computed = LayoutDetails::BuildComputedVerticalSize(element_row->GetComputedValues());
|
|
const ComputedAxisSize computed = LayoutDetails::BuildComputedVerticalSize(element_row->GetComputedValues());
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (computed.size.type == Style::LengthPercentageAuto::Percentage)
|
|
if (computed.size.type == Style::LengthPercentageAuto::Percentage)
|
|
|
percentage_size_used = true;
|
|
percentage_size_used = true;
|
|
|
|
|
|
|
@@ -244,11 +267,10 @@ void LayoutTable::DetermineRowHeights()
|
|
|
|
|
|
|
|
if (table_auto_height && percentage_size_used)
|
|
if (table_auto_height && percentage_size_used)
|
|
|
{
|
|
{
|
|
|
- Log::Message(Log::LT_WARNING,
|
|
|
|
|
|
|
+ Log::Message(Log::LT_WARNING,
|
|
|
"Table has one or more rows that use percentages for height. However, initial table height is undefined, thus "
|
|
"Table has one or more rows that use percentages for height. However, initial table height is undefined, thus "
|
|
|
"these rows will become flattened. Set a fixed height on the table, or use fixed or 'auto' row heights. In element: %s.",
|
|
"these rows will become flattened. Set a fixed height on the table, or use fixed or 'auto' row heights. In element: %s.",
|
|
|
- element_table->GetAddress().c_str()
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ element_table->GetAddress().c_str());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Next, find the height of rows that use auto height.
|
|
// Next, find the height of rows that use auto height.
|
|
@@ -260,8 +282,8 @@ void LayoutTable::DetermineRowHeights()
|
|
|
if (row_metric.sizing_mode == TrackSizingMode::Auto)
|
|
if (row_metric.sizing_mode == TrackSizingMode::Auto)
|
|
|
{
|
|
{
|
|
|
struct CellLastRowComp {
|
|
struct CellLastRowComp {
|
|
|
- bool operator() (const TableGrid::Cell& cell, int i) const { return cell.row_last < i; }
|
|
|
|
|
- bool operator() (int i, const TableGrid::Cell& cell) const { return i < cell.row_last; }
|
|
|
|
|
|
|
+ bool operator()(const TableGrid::Cell& cell, int i) const { return cell.row_last < i; }
|
|
|
|
|
+ bool operator()(int i, const TableGrid::Cell& cell) const { return i < cell.row_last; }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// Determine which cells end at this row.
|
|
// Determine which cells end at this row.
|
|
@@ -278,19 +300,20 @@ void LayoutTable::DetermineRowHeights()
|
|
|
// If both the row and the cell heights are 'auto', we need to format the cell to get its height.
|
|
// If both the row and the cell heights are 'auto', we need to format the cell to get its height.
|
|
|
if (box.GetSize().y < 0)
|
|
if (box.GetSize().y < 0)
|
|
|
{
|
|
{
|
|
|
- LayoutEngine::FormatElement(element_cell, table_initial_content_size, &box);
|
|
|
|
|
|
|
+ FormattingContext::FormatIndependent(table_wrapper_box, element_cell, &box, FormattingContextType::Block);
|
|
|
box.SetContent(element_cell->GetBox().GetSize());
|
|
box.SetContent(element_cell->GetBox().GetSize());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Find the height of the cell which applies only to this row.
|
|
|
|
|
|
|
+ // Find the height of the cell which applies only to this row.
|
|
|
// In case it spans multiple rows, we must first subtract the height of any previous rows it spans. It is
|
|
// In case it spans multiple rows, we must first subtract the height of any previous rows it spans. It is
|
|
|
// unsupported if any spanning rows are flexibly sized, in which case we consider their size to be zero.
|
|
// unsupported if any spanning rows are flexibly sized, in which case we consider their size to be zero.
|
|
|
const float gap_from_spanning_rows = table_gap.y * float(grid_cell.row_last - grid_cell.row_begin);
|
|
const float gap_from_spanning_rows = table_gap.y * float(grid_cell.row_last - grid_cell.row_begin);
|
|
|
|
|
|
|
|
- const float height_from_spanning_rows = std::accumulate(row_metrics.begin() + grid_cell.row_begin, row_metrics.begin() + grid_cell.row_last, gap_from_spanning_rows, [](float acc_height, const TrackMetric& metric) {
|
|
|
|
|
- return acc_height + metric.fixed_size + metric.column_padding_border_a + metric.column_padding_border_b
|
|
|
|
|
- + metric.group_padding_border_a + metric.group_padding_border_b + metric.sum_margin_a + metric.sum_margin_b;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const float height_from_spanning_rows = std::accumulate(row_metrics.begin() + grid_cell.row_begin,
|
|
|
|
|
+ row_metrics.begin() + grid_cell.row_last, gap_from_spanning_rows, [](float acc_height, const TrackMetric& metric) {
|
|
|
|
|
+ return acc_height + metric.fixed_size + metric.column_padding_border_a + metric.column_padding_border_b +
|
|
|
|
|
+ metric.group_padding_border_a + metric.group_padding_border_b + metric.sum_margin_a + metric.sum_margin_b;
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
const float cell_inrow_height = box.GetSizeAcross(Box::VERTICAL, Box::BORDER) - height_from_spanning_rows;
|
|
const float cell_inrow_height = box.GetSizeAcross(Box::VERTICAL, Box::BORDER) - height_from_spanning_rows;
|
|
|
|
|
|
|
@@ -307,26 +330,23 @@ void LayoutTable::DetermineRowHeights()
|
|
|
// Now all heights should be either fixed or flexible, resolve all flexible heights to fixed.
|
|
// Now all heights should be either fixed or flexible, resolve all flexible heights to fixed.
|
|
|
sizing.ResolveFlexibleSize();
|
|
sizing.ResolveFlexibleSize();
|
|
|
|
|
|
|
|
- // Generate the column results based on the metrics.
|
|
|
|
|
|
|
+ // Generate the row boxes based on the metrics.
|
|
|
const float rows_full_height = BuildRowBoxes(rows, row_metrics, grid.rows, table_gap.y);
|
|
const float rows_full_height = BuildRowBoxes(rows, row_metrics, grid.rows, table_gap.y);
|
|
|
|
|
|
|
|
- // Adjust the table content width based on the accumulated column widths and spacing.
|
|
|
|
|
- table_resulting_content_size.y = Math::Clamp(Math::Max(rows_full_height, table_initial_content_size.y), table_min_size.y, table_max_size.y);
|
|
|
|
|
|
|
+ // Adjust the table content height based on the accumulated row heights and spacing.
|
|
|
|
|
+ table_content_height = Math::Clamp(Math::Max(rows_full_height, table_initial_content_size.y), table_min_size.y, table_max_size.y);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void LayoutTable::FormatRows()
|
|
|
|
|
|
|
+void TableFormattingContext::FormatRows(const TrackBoxList& rows, float table_content_width) const
|
|
|
{
|
|
{
|
|
|
RMLUI_ASSERT(rows.size() == grid.rows.size());
|
|
RMLUI_ASSERT(rows.size() == grid.rows.size());
|
|
|
|
|
|
|
|
// Size and position the row and row group elements.
|
|
// Size and position the row and row group elements.
|
|
|
- auto FormatRow = [this](Element* element, float content_height, float offset_y) {
|
|
|
|
|
|
|
+ auto FormatRow = [this, table_content_width](Element* element, float content_height, float offset_y) {
|
|
|
Box box;
|
|
Box box;
|
|
|
- // We use inline context here because we only care about padding, border, and (non-auto) margin.
|
|
|
|
|
- LayoutDetails::BuildBox(box, table_initial_content_size, element, BoxContext::Inline, 0.0f);
|
|
|
|
|
- const Vector2f content_size(
|
|
|
|
|
- table_resulting_content_size.x - box.GetSizeAcross(Box::HORIZONTAL, Box::MARGIN, Box::PADDING),
|
|
|
|
|
- content_height
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ // We use inline build mode here because we only care about padding, border, and (non-auto) margin.
|
|
|
|
|
+ LayoutDetails::BuildBox(box, table_initial_content_size, element, BuildBoxMode::Inline);
|
|
|
|
|
+ const Vector2f content_size(table_content_width - box.GetSizeAcross(Box::HORIZONTAL, Box::MARGIN, Box::PADDING), content_height);
|
|
|
box.SetContent(content_size);
|
|
box.SetContent(content_size);
|
|
|
element->SetBox(box);
|
|
element->SetBox(box);
|
|
|
|
|
|
|
@@ -346,19 +366,16 @@ void LayoutTable::FormatRows()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void LayoutTable::FormatColumns()
|
|
|
|
|
|
|
+void TableFormattingContext::FormatColumns(const TrackBoxList& columns, float table_content_height) const
|
|
|
{
|
|
{
|
|
|
RMLUI_ASSERT(columns.size() == grid.columns.size());
|
|
RMLUI_ASSERT(columns.size() == grid.columns.size());
|
|
|
|
|
|
|
|
// Size and position the column and column group elements.
|
|
// Size and position the column and column group elements.
|
|
|
- auto FormatColumn = [this](Element* element, float content_width, float offset_x) {
|
|
|
|
|
|
|
+ auto FormatColumn = [this, table_content_height](Element* element, float content_width, float offset_x) {
|
|
|
Box box;
|
|
Box box;
|
|
|
- // We use inline context here because we only care about padding, border, and (non-auto) margin.
|
|
|
|
|
- LayoutDetails::BuildBox(box, table_initial_content_size, element, BoxContext::Inline, 0.0f);
|
|
|
|
|
- const Vector2f content_size(
|
|
|
|
|
- content_width,
|
|
|
|
|
- table_resulting_content_size.y - box.GetSizeAcross(Box::VERTICAL, Box::MARGIN, Box::PADDING)
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ // We use inline build mode here because we only care about padding, border, and (non-auto) margin.
|
|
|
|
|
+ LayoutDetails::BuildBox(box, table_initial_content_size, element, BuildBoxMode::Inline);
|
|
|
|
|
+ const Vector2f content_size(content_width, table_content_height - box.GetSizeAcross(Box::VERTICAL, Box::MARGIN, Box::PADDING));
|
|
|
box.SetContent(content_size);
|
|
box.SetContent(content_size);
|
|
|
element->SetBox(box);
|
|
element->SetBox(box);
|
|
|
|
|
|
|
@@ -378,7 +395,7 @@ void LayoutTable::FormatColumns()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void LayoutTable::FormatCells()
|
|
|
|
|
|
|
+void TableFormattingContext::FormatCells(BoxList& cells, Vector2f& table_overflow_size, const TrackBoxList& rows, const TrackBoxList& columns) const
|
|
|
{
|
|
{
|
|
|
RMLUI_ASSERT(cells.size() == grid.cells.size());
|
|
RMLUI_ASSERT(cells.size() == grid.cells.size());
|
|
|
|
|
|
|
@@ -391,11 +408,9 @@ void LayoutTable::FormatCells()
|
|
|
Style::VerticalAlign vertical_align = element_cell->GetComputedValues().vertical_align();
|
|
Style::VerticalAlign vertical_align = element_cell->GetComputedValues().vertical_align();
|
|
|
|
|
|
|
|
const float cell_border_height = GetSpanningCellBorderSize(rows, grid_cell.row_begin, grid_cell.row_last);
|
|
const float cell_border_height = GetSpanningCellBorderSize(rows, grid_cell.row_begin, grid_cell.row_last);
|
|
|
- const Vector2f cell_offset = table_content_offset + Vector2f(
|
|
|
|
|
- columns[grid_cell.column_begin].cell_offset,
|
|
|
|
|
- rows[grid_cell.row_begin].cell_offset
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const Vector2f cell_offset =
|
|
|
|
|
+ table_content_offset + Vector2f(columns[grid_cell.column_begin].cell_offset, rows[grid_cell.row_begin].cell_offset);
|
|
|
|
|
+
|
|
|
// Determine the height of the cell.
|
|
// Determine the height of the cell.
|
|
|
if (box.GetSize().y < 0)
|
|
if (box.GetSize().y < 0)
|
|
|
{
|
|
{
|
|
@@ -403,13 +418,14 @@ void LayoutTable::FormatCells()
|
|
|
if (is_aligned)
|
|
if (is_aligned)
|
|
|
{
|
|
{
|
|
|
// We need to format the cell to know how much padding to add.
|
|
// We need to format the cell to know how much padding to add.
|
|
|
- LayoutEngine::FormatElement(element_cell, table_initial_content_size, &box);
|
|
|
|
|
|
|
+ FormattingContext::FormatIndependent(table_wrapper_box, element_cell, &box, FormattingContextType::Block);
|
|
|
box.SetContent(element_cell->GetBox().GetSize());
|
|
box.SetContent(element_cell->GetBox().GetSize());
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
// We don't need to add any padding and can thus avoid formatting, just set the height to the row height.
|
|
// We don't need to add any padding and can thus avoid formatting, just set the height to the row height.
|
|
|
- box.SetContent(Vector2f(box.GetSize().x, Math::Max(0.0f, cell_border_height - box.GetSizeAcross(Box::VERTICAL, Box::BORDER, Box::PADDING))));
|
|
|
|
|
|
|
+ box.SetContent(
|
|
|
|
|
+ Vector2f(box.GetSize().x, Math::Max(0.0f, cell_border_height - box.GetSizeAcross(Box::VERTICAL, Box::BORDER, Box::PADDING))));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -435,6 +451,7 @@ void LayoutTable::FormatCells()
|
|
|
default:
|
|
default:
|
|
|
add_padding_top = 0.0f;
|
|
add_padding_top = 0.0f;
|
|
|
add_padding_bottom = available_height;
|
|
add_padding_bottom = available_height;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
box.SetEdge(Box::PADDING, Box::TOP, box.GetEdge(Box::PADDING, Box::TOP) + add_padding_top);
|
|
box.SetEdge(Box::PADDING, Box::TOP, box.GetEdge(Box::PADDING, Box::TOP) + add_padding_top);
|
|
@@ -445,17 +462,16 @@ void LayoutTable::FormatCells()
|
|
|
// @performance: We may have already formatted the element during the above procedures without the extra padding. In that case, we may
|
|
// @performance: We may have already formatted the element during the above procedures without the extra padding. In that case, we may
|
|
|
// instead set the new box and offset all descending elements whose offset parent is the cell, to account for the new padding box.
|
|
// instead set the new box and offset all descending elements whose offset parent is the cell, to account for the new padding box.
|
|
|
// That should be faster than formatting the element again, but there may be edge-cases not accounted for.
|
|
// That should be faster than formatting the element again, but there may be edge-cases not accounted for.
|
|
|
- Vector2f cell_visible_overflow_size;
|
|
|
|
|
- LayoutEngine::FormatElement(element_cell, table_initial_content_size, &box, &cell_visible_overflow_size);
|
|
|
|
|
|
|
+ auto cell_box = FormattingContext::FormatIndependent(table_wrapper_box, element_cell, &box, FormattingContextType::Block);
|
|
|
|
|
+ Vector2f cell_visible_overflow_size = cell_box->GetVisibleOverflowSize();
|
|
|
|
|
|
|
|
// Set the position of the element within the the table container
|
|
// Set the position of the element within the the table container
|
|
|
element_cell->SetOffset(cell_offset, element_table);
|
|
element_cell->SetOffset(cell_offset, element_table);
|
|
|
|
|
|
|
|
// The cell contents may overflow, propagate this to the table.
|
|
// The cell contents may overflow, propagate this to the table.
|
|
|
- table_content_overflow_size.x = Math::Max(table_content_overflow_size.x, cell_offset.x - table_content_offset.x + cell_visible_overflow_size.x);
|
|
|
|
|
- table_content_overflow_size.y = Math::Max(table_content_overflow_size.y, cell_offset.y - table_content_offset.y + cell_visible_overflow_size.y);
|
|
|
|
|
|
|
+ table_overflow_size.x = Math::Max(table_overflow_size.x, cell_offset.x - table_content_offset.x + cell_visible_overflow_size.x);
|
|
|
|
|
+ table_overflow_size.y = Math::Max(table_overflow_size.y, cell_offset.y - table_content_offset.y + cell_visible_overflow_size.y);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
} // namespace Rml
|
|
} // namespace Rml
|