Merge remote-tracking branch 'jlewin/alt/table'
This commit is contained in:
commit
27d4a596b8
7 changed files with 282 additions and 136 deletions
|
|
@ -20,12 +20,17 @@ namespace Markdig.Renderers.Agg
|
|||
public class ParagraphX : FlowLeftRightWithWrapping, IHardBreak
|
||||
{
|
||||
public ParagraphX(bool bottomMargin)
|
||||
{
|
||||
{
|
||||
// Adding HAnchor and initial fixed width properties to resolve excess vertical whitespace added during collapse to width 0
|
||||
//
|
||||
// TODO: Revise impact to FlowLeftRightWithWrapping
|
||||
this.HAnchor = HAnchor.Stretch;
|
||||
this.Width = 5000;
|
||||
if (bottomMargin)
|
||||
{
|
||||
Margin = new BorderDouble(0, 0, 0, 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public class ParagraphRenderer :
|
||||
|
|
|
|||
|
|
@ -1,126 +0,0 @@
|
|||
// Copyright (c) Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Markdig.Extensions.Tables;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.MatterControl;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTableRenderer : AggObjectRenderer<Table>
|
||||
{
|
||||
protected override void Write(AggRenderer renderer, Table table)
|
||||
{
|
||||
if (renderer == null) throw new ArgumentNullException(nameof(renderer));
|
||||
if (table == null) throw new ArgumentNullException(nameof(table));
|
||||
|
||||
var aggTable = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.Fit,
|
||||
VAnchor = VAnchor.Fit,
|
||||
Margin = new BorderDouble(top: 12),
|
||||
};
|
||||
|
||||
// TODO: Use Markdig parser data to drive column/cell widths
|
||||
//foreach (var tableColumnDefinition in table.ColumnDefinitions)
|
||||
// Width = (tableColumnDefinition?.Width ?? 0) != 0 ? tableColumnDefinition.Width : <or auto>
|
||||
|
||||
renderer.Push(aggTable);
|
||||
|
||||
foreach (var rowObj in table)
|
||||
{
|
||||
var row = (TableRow)rowObj;
|
||||
|
||||
var aggRow = new AggTableRow()
|
||||
{
|
||||
IsHeadingRow = row.IsHeader,
|
||||
};
|
||||
|
||||
renderer.Push(aggRow);
|
||||
|
||||
if (row.IsHeader)
|
||||
{
|
||||
// Update to desired header row styling and/or moving into AggTableRow for consistency
|
||||
aggRow.BackgroundColor = MatterHackers.MatterControl.AppContext.Theme.TabBarBackground;
|
||||
}
|
||||
|
||||
for (var i = 0; i < row.Count; i++)
|
||||
{
|
||||
var cellObj = row[i];
|
||||
var cell = (TableCell)cellObj;
|
||||
|
||||
// Fixed width cells just to get something initially on screen
|
||||
var aggCellBox = new GuiWidget()
|
||||
{
|
||||
Width = 200,
|
||||
Height = 25,
|
||||
};
|
||||
|
||||
// TODO: Cell Width - implement next, might be easy to track and perform in AggTableRow
|
||||
/* (Spec)
|
||||
* If any line of the markdown source is longer than the column width (see --columns), then the
|
||||
* table will take up the full text width and the cell contents will wrap, with the relative cell
|
||||
* widths determined by the number of dashes in the line separating the table header from the table
|
||||
* body. (For example ---|- would make the first column 3/4 and the second column 1/4 of the full
|
||||
* text width.) On the other hand, if no lines are wider than column width, then cell contents will
|
||||
* not be wrapped, and the cells will be sized to their contents.
|
||||
*/
|
||||
|
||||
// Cell box above enforces boundaries, use flow for layout
|
||||
var aggCellFlow = new FlowLayoutWidget()
|
||||
{
|
||||
HAnchor = HAnchor.Stretch,
|
||||
};
|
||||
|
||||
if (table.ColumnDefinitions.Count > 0)
|
||||
{
|
||||
// TODO: Ideally we'd be driving column width from metadata rather than hard-coded
|
||||
// See example below from WPF implementation
|
||||
//
|
||||
// Grab the column definition, or fall back to a default
|
||||
var columnIndex = cell.ColumnIndex < 0 || cell.ColumnIndex >= table.ColumnDefinitions.Count
|
||||
? i
|
||||
: cell.ColumnIndex;
|
||||
columnIndex = columnIndex >= table.ColumnDefinitions.Count ? table.ColumnDefinitions.Count - 1 : columnIndex;
|
||||
|
||||
// TODO: revise alignment via Agg types that produce aligned text
|
||||
var columnDefinition = table.ColumnDefinitions[columnIndex];
|
||||
var alignment = columnDefinition.Alignment;
|
||||
if (alignment.HasValue)
|
||||
{
|
||||
switch (alignment)
|
||||
{
|
||||
case TableColumnAlign.Center:
|
||||
aggCellFlow.HAnchor |= HAnchor.Center;
|
||||
break;
|
||||
case TableColumnAlign.Right:
|
||||
aggCellFlow.HAnchor |= HAnchor.Right;
|
||||
break;
|
||||
case TableColumnAlign.Left:
|
||||
aggCellFlow.HAnchor |= HAnchor.Left;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderer.Push(aggCellBox);
|
||||
renderer.Push(aggCellFlow);
|
||||
renderer.Write(cell);
|
||||
renderer.Pop();
|
||||
renderer.Pop();
|
||||
}
|
||||
|
||||
// Pop row
|
||||
renderer.Pop();
|
||||
}
|
||||
|
||||
// Pop table
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
MatterControlLib/Utilities/MarkdigAgg/Tables/AggTable.cs
Normal file
38
MatterControlLib/Utilities/MarkdigAgg/Tables/AggTable.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Markdig.Extensions.Tables;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTable : FlowLayoutWidget
|
||||
{
|
||||
|
||||
public List<AggTableColumn> Columns { get; }
|
||||
|
||||
public List<AggTableRow> Rows { get; }
|
||||
|
||||
public AggTable(Table table) : base(FlowDirection.TopToBottom)
|
||||
{
|
||||
this.Columns = table.ColumnDefinitions.Select(c => new AggTableColumn(c)).ToList();
|
||||
}
|
||||
|
||||
public override void OnLayout(LayoutEventArgs layoutEventArgs)
|
||||
{
|
||||
if (this.Columns?.Count > 0)
|
||||
{
|
||||
foreach (var column in this.Columns)
|
||||
{
|
||||
column.SetCellWidths();
|
||||
}
|
||||
}
|
||||
|
||||
base.OnLayout(layoutEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
MatterControlLib/Utilities/MarkdigAgg/Tables/AggTableCell.cs
Normal file
53
MatterControlLib/Utilities/MarkdigAgg/Tables/AggTableCell.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2016-2017 Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
// Parent container to restrict bounds
|
||||
public class AggTableCell : GuiWidget
|
||||
{
|
||||
public AggTableCell()
|
||||
{
|
||||
// TODO: drive from column once width calculation is performed
|
||||
Width = 300;
|
||||
|
||||
Height = 25;
|
||||
|
||||
// Use event rather than OnLayout as it only seems to produce the desired effect
|
||||
this.Layout += AggTableCell_Layout;
|
||||
}
|
||||
|
||||
// TODO: Investigate. Without this solution, child content is wrapped and clipped, leaving only the last text block visible
|
||||
private void AggTableCell_Layout(object sender, EventArgs e)
|
||||
{
|
||||
Console.WriteLine(Parent?.Name);
|
||||
if (this.Children.Count > 0 && this.Children.First() is FlowLeftRightWithWrapping wrappedChild
|
||||
&& wrappedChild.Height != this.Height)
|
||||
{
|
||||
//using (this.LayoutLock())
|
||||
{
|
||||
//// Set height to ensure bounds grow to content after reflow
|
||||
//this.Height = wrappedChild.Height;
|
||||
|
||||
if (this.Parent is AggTableRow parentRow)
|
||||
{
|
||||
parentRow.CellHeightChanged(wrappedChild.Height);
|
||||
}
|
||||
}
|
||||
|
||||
this.ContentWidth = wrappedChild.ContentWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public double ContentWidth { get; private set; }
|
||||
|
||||
// TODO: Use to align child content when bounds are less than current
|
||||
public HAnchor FlowHAnchor { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Markdig.Extensions.Tables;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTableColumn
|
||||
{
|
||||
private TableColumnDefinition ColumnDefinition;
|
||||
|
||||
public AggTableColumn(TableColumnDefinition definition)
|
||||
{
|
||||
this.ColumnDefinition = definition;
|
||||
}
|
||||
|
||||
public List<AggTableCell> Cells { get; } = new List<AggTableCell>();
|
||||
|
||||
public void SetCellWidths()
|
||||
{
|
||||
double cellPadding = 10;
|
||||
|
||||
if (this.Cells.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Column/cell width theortically is:
|
||||
//
|
||||
// Case A. Expanding to the maximum content width of cells in column to grow each
|
||||
// cell to a minimum value.
|
||||
//
|
||||
// Case B. Contracting when the aggregate column widths exceed the bounds
|
||||
// of the parent container.
|
||||
//
|
||||
// Case C. Distributing percentages across fixed bounds of the parent container
|
||||
//
|
||||
// Other cases...
|
||||
|
||||
// This block attempts to implement Case A by finding the max content width per cells in each column
|
||||
//
|
||||
// Collect max content widths from each cell in this column
|
||||
double maxCellWidth = this.Cells.Select(c => c.ContentWidth).Max() + cellPadding * 2;
|
||||
|
||||
// Apply max width to cells in this column
|
||||
foreach (var cell in this.Cells)
|
||||
{
|
||||
if (cell.Width != maxCellWidth)
|
||||
{
|
||||
cell.Width = maxCellWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) Nicolas Musset. All rights reserved.
|
||||
// Copyright (c) 2022, John Lewin
|
||||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Markdig.Extensions.Tables;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTableRenderer : AggObjectRenderer<Table>
|
||||
{
|
||||
protected override void Write(AggRenderer renderer, Table mdTable)
|
||||
{
|
||||
if (renderer == null) throw new ArgumentNullException(nameof(renderer));
|
||||
if (mdTable == null) throw new ArgumentNullException(nameof(mdTable));
|
||||
|
||||
var aggTable = new AggTable(mdTable)
|
||||
{
|
||||
Margin = new BorderDouble(top: 12),
|
||||
};
|
||||
|
||||
renderer.Push(aggTable);
|
||||
|
||||
foreach (var rowObj in mdTable)
|
||||
{
|
||||
var mdRow = (TableRow)rowObj;
|
||||
|
||||
var aggRow = new AggTableRow()
|
||||
{
|
||||
IsHeadingRow = mdRow.IsHeader,
|
||||
};
|
||||
|
||||
renderer.Push(aggRow);
|
||||
|
||||
if (mdRow.IsHeader)
|
||||
{
|
||||
// Update to desired header row styling and/or move into AggTableRow for consistency
|
||||
aggRow.BackgroundColor = MatterHackers.MatterControl.AppContext.Theme.TabBarBackground;
|
||||
}
|
||||
|
||||
for (var i = 0; i < mdRow.Count; i++)
|
||||
{
|
||||
var mdCell = (TableCell)mdRow[i];
|
||||
|
||||
var aggCell = new AggTableCell();
|
||||
aggRow.Cells.Add(aggCell);
|
||||
|
||||
if (mdTable.ColumnDefinitions.Count > 0)
|
||||
{
|
||||
// Grab the column definition, or fall back to a default
|
||||
var columnIndex = mdCell.ColumnIndex < 0 || mdCell.ColumnIndex >= mdTable.ColumnDefinitions.Count
|
||||
? i
|
||||
: mdCell.ColumnIndex;
|
||||
columnIndex = columnIndex >= mdTable.ColumnDefinitions.Count ? mdTable.ColumnDefinitions.Count - 1 : columnIndex;
|
||||
|
||||
aggTable.Columns[columnIndex].Cells.Add(aggCell);
|
||||
|
||||
if (mdTable.ColumnDefinitions[columnIndex].Alignment.HasValue)
|
||||
{
|
||||
switch (mdTable.ColumnDefinitions[columnIndex].Alignment)
|
||||
{
|
||||
case TableColumnAlign.Center:
|
||||
aggCell.FlowHAnchor |= HAnchor.Center;
|
||||
break;
|
||||
case TableColumnAlign.Right:
|
||||
aggCell.FlowHAnchor |= HAnchor.Right;
|
||||
break;
|
||||
case TableColumnAlign.Left:
|
||||
aggCell.FlowHAnchor |= HAnchor.Left;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderer.Push(aggCell);
|
||||
renderer.Write(mdCell);
|
||||
renderer.Pop();
|
||||
}
|
||||
|
||||
// Pop row
|
||||
renderer.Pop();
|
||||
}
|
||||
|
||||
// Pop table
|
||||
renderer.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
// This file is licensed under the MIT license.
|
||||
// See the LICENSE.md file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Markdig.Renderers.Agg.Inlines;
|
||||
using MatterHackers.Agg;
|
||||
|
|
@ -10,19 +12,19 @@ using MatterHackers.Agg.UI;
|
|||
|
||||
namespace Markdig.Renderers.Agg
|
||||
{
|
||||
public class AggTableRow: FlowLayoutWidget
|
||||
public class AggTableRow : FlowLayoutWidget
|
||||
{
|
||||
public AggTableRow()
|
||||
{
|
||||
this.VAnchor = VAnchor.Fit;
|
||||
this.Margin = new BorderDouble(3, 4, 0, 12);
|
||||
|
||||
// Hack to force content on-screen (seemingly not working when set late/after constructor)
|
||||
VAnchor = VAnchor.Absolute;
|
||||
Height = 25;
|
||||
this.Margin = new BorderDouble(10, 4);
|
||||
this.VAnchor = VAnchor.Absolute;
|
||||
this.Height = 25;
|
||||
}
|
||||
|
||||
public bool IsHeadingRow { get; set; }
|
||||
public bool IsHeadingRow { get; set; }
|
||||
|
||||
public List<AggTableCell> Cells { get; } = new List<AggTableCell>();
|
||||
public double RowHeight { get; private set; }
|
||||
|
||||
// Override AddChild to push styles to child elements when table rows are resolved to the tree
|
||||
public override GuiWidget AddChild(GuiWidget childToAdd, int indexInChildrenList = -1)
|
||||
|
|
@ -48,5 +50,29 @@ namespace Markdig.Renderers.Agg
|
|||
|
||||
return base.AddChild(childToAdd, indexInChildrenList);
|
||||
}
|
||||
|
||||
internal void CellHeightChanged(double newHeight)
|
||||
{
|
||||
double cellPadding = 2;
|
||||
double height = newHeight + 2 * cellPadding;
|
||||
|
||||
//double maxChildHeight = this.Cells.Select(c => c.Height).Max();
|
||||
|
||||
if (this.RowHeight != height)
|
||||
{
|
||||
foreach (var cell in this.Cells)
|
||||
{
|
||||
using (cell.LayoutLock())
|
||||
{
|
||||
cell.Height = height;
|
||||
}
|
||||
}
|
||||
|
||||
using (this.LayoutLock())
|
||||
{
|
||||
this.Height = this.RowHeight = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue