A game framework written with osu! in mind.
at master 141 lines 4.8 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Collections.Generic; 6using System.Linq; 7using Markdig.Extensions.Tables; 8using osu.Framework.Allocation; 9using osu.Framework.Layout; 10 11namespace osu.Framework.Graphics.Containers.Markdown 12{ 13 /// <summary> 14 /// Visualises a table. 15 /// </summary> 16 /// <code> 17 /// | heading 1 | heading 2 | 18 /// | --------- | --------- | 19 /// | cell 1 | cell 2 | 20 /// </code> 21 public class MarkdownTable : CompositeDrawable 22 { 23 private GridContainer tableContainer; 24 25 private readonly Table table; 26 27 private readonly LayoutValue columnDefinitionCache = new LayoutValue(Invalidation.DrawSize, conditions: (s, _) => s.Parent != null); 28 private readonly LayoutValue rowDefinitionCache = new LayoutValue(Invalidation.DrawSize, conditions: (s, _) => s.Parent != null); 29 30 public MarkdownTable(Table table) 31 { 32 this.table = table; 33 34 AutoSizeAxes = Axes.Y; 35 RelativeSizeAxes = Axes.X; 36 37 table.NormalizeUsingHeaderRow(); 38 39 AddLayout(columnDefinitionCache); 40 AddLayout(rowDefinitionCache); 41 } 42 43 [BackgroundDependencyLoader] 44 private void load() 45 { 46 List<List<Drawable>> rows = new List<List<Drawable>>(); 47 48 foreach (var tableRow in table.OfType<TableRow>()) 49 { 50 var row = new List<Drawable>(); 51 52 for (int c = 0; c < tableRow.Count; c++) 53 { 54 var columnDimensions = table.ColumnDefinitions[c]; 55 row.Add(CreateTableCell((TableCell)tableRow[c], columnDimensions, rows.Count == 0)); 56 } 57 58 rows.Add(row); 59 } 60 61 InternalChild = tableContainer = new GridContainer 62 { 63 AutoSizeAxes = Axes.Y, 64 RelativeSizeAxes = Axes.X, 65 Content = rows.Select(x => x.ToArray()).ToArray() 66 }; 67 } 68 69 protected override void Update() 70 { 71 base.Update(); 72 73 if (!columnDefinitionCache.IsValid) 74 { 75 computeColumnDefinitions(); 76 columnDefinitionCache.Validate(); 77 } 78 } 79 80 protected override void UpdateAfterChildren() 81 { 82 base.UpdateAfterChildren(); 83 84 if (!rowDefinitionCache.IsValid) 85 { 86 computeRowDefinitions(); 87 rowDefinitionCache.Validate(); 88 } 89 } 90 91 private void computeColumnDefinitions() 92 { 93 if (table.Count == 0) 94 return; 95 96 Span<float> columnWidths = stackalloc float[tableContainer.Content[0].Count]; 97 98 // Compute the maximum width of each column 99 for (int r = 0; r < tableContainer.Content.Count; r++) 100 { 101 for (int c = 0; c < tableContainer.Content[r].Count; c++) 102 columnWidths[c] = Math.Max(columnWidths[c], ((MarkdownTableCell)tableContainer.Content[r][c]).ContentWidth); 103 } 104 105 float totalWidth = 0; 106 for (int i = 0; i < columnWidths.Length; i++) 107 totalWidth += columnWidths[i]; 108 109 var columnDimensions = new Dimension[columnWidths.Length]; 110 111 if (totalWidth < DrawWidth) 112 { 113 // The columns will fit within the table, use absolute column widths 114 for (int i = 0; i < columnWidths.Length; i++) 115 columnDimensions[i] = new Dimension(GridSizeMode.Absolute, columnWidths[i]); 116 } 117 else 118 { 119 // The columns will overflow the table, must convert them to a relative size 120 for (int i = 0; i < columnWidths.Length; i++) 121 columnDimensions[i] = new Dimension(GridSizeMode.Relative, columnWidths[i] / totalWidth); 122 } 123 124 tableContainer.ColumnDimensions = columnDimensions; 125 } 126 127 private void computeRowDefinitions() 128 { 129 if (table.Count == 0) 130 return; 131 132 var rowDefinitions = new Dimension[tableContainer.Content.Count]; 133 for (int r = 0; r < tableContainer.Content.Count; r++) 134 rowDefinitions[r] = new Dimension(GridSizeMode.Absolute, tableContainer.Content[r].Max(c => ((MarkdownTableCell)c).ContentHeight)); 135 136 tableContainer.RowDimensions = rowDefinitions; 137 } 138 139 protected virtual MarkdownTableCell CreateTableCell(TableCell cell, TableColumnDefinition definition, bool isHeading) => new MarkdownTableCell(cell, definition); 140 } 141}