diff --git a/ImGuiWidgets/Grid.cs b/ImGuiWidgets/Grid.cs index f01343b..9d7ae2c 100644 --- a/ImGuiWidgets/Grid.cs +++ b/ImGuiWidgets/Grid.cs @@ -1,5 +1,6 @@ namespace ktsu.ImGuiWidgets; +using System.Drawing; using System.Numerics; using ImGuiNET; @@ -36,21 +37,35 @@ public enum GridOrder /// /// Items are displayed top to bottom before moving to the next column. /// Recommended when displaying tables of data. - /// Note: This will never display uneven rows that have more than 1 item - /// missing relative to them. /// Example: - /// [ [1] [3] [5] ] - /// [ [2] [4] [6] ] + /// [ [1] [4] ] + /// [ [2] [5] ] + /// [ [3] [6] ] /// OR - /// [ [1] [3] [5] ] - /// [ [2] [4] ] - /// NEVER - /// [ [1] [3] [5] ] - /// [ [2] ] + /// [ [1] [5] ] + /// [ [2] [6] ] + /// [ [3] ] + /// [ [4] ] /// ColumnMajor, } + /// + /// Options for changing how the grid is laid out. + /// + public class GridOptions + { + /// + /// Size of the grid. Setting any axis to 0 will use the available space. + /// + public Vector2 GridSize { get; set; } = new(0, 0); + + /// + /// Size the content region to cover all the items. + /// + public bool FitToContents { get; init; } + } + /// /// Delegate to measure the size of a grid cell. /// @@ -72,17 +87,72 @@ public enum GridOrder /// Renders a grid with the specified items and delegates. /// /// The type of the items. + /// Id for the grid. /// The items to be displayed in the grid. /// The delegate to measure the size of each item. /// The delegate to draw each item. - /// What ordering should grid items use - public static void Grid(IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate, GridOrder gridOrder) + public static void RowMajorGrid(string id, IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate) { ArgumentNullException.ThrowIfNull(items); ArgumentNullException.ThrowIfNull(measureDelegate); ArgumentNullException.ThrowIfNull(drawDelegate); - GridImpl.Show(items, measureDelegate, drawDelegate, gridOrder); + GridImpl.ShowRowMajor(id, items, measureDelegate, drawDelegate, new()); + } + + /// + /// Renders a grid with the specified items and delegates. + /// + /// The type of the items. + /// Id for the grid. + /// The items to be displayed in the grid. + /// The delegate to measure the size of each item. + /// The delegate to draw each item. + /// Additional options to modify the grid behaviour + public static void RowMajorGrid(string id, IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate, GridOptions gridOptions) + { + ArgumentNullException.ThrowIfNull(items); + ArgumentNullException.ThrowIfNull(measureDelegate); + ArgumentNullException.ThrowIfNull(drawDelegate); + ArgumentNullException.ThrowIfNull(gridOptions); + + GridImpl.ShowRowMajor(id, items, measureDelegate, drawDelegate, gridOptions); + } + + /// + /// Renders a grid with the specified items and delegates. + /// + /// The type of the items. + /// Id for the grid. + /// The items to be displayed in the grid. + /// The delegate to measure the size of each item. + /// The delegate to draw each item. + public static void ColumnMajorGrid(string id, IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate) + { + ArgumentNullException.ThrowIfNull(items); + ArgumentNullException.ThrowIfNull(measureDelegate); + ArgumentNullException.ThrowIfNull(drawDelegate); + + GridImpl.ShowColumnMajor(id, items, measureDelegate, drawDelegate, new()); + } + + /// + /// Renders a grid with the specified items and delegates. + /// + /// The type of the items. + /// Id for the grid. + /// The items to be displayed in the grid. + /// The delegate to measure the size of each item. + /// The delegate to draw each item. + /// Additional options to modify the grid behaviour + public static void ColumnMajorGrid(string id, IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate, GridOptions gridOptions) + { + ArgumentNullException.ThrowIfNull(items); + ArgumentNullException.ThrowIfNull(measureDelegate); + ArgumentNullException.ThrowIfNull(drawDelegate); + ArgumentNullException.ThrowIfNull(gridOptions); + + GridImpl.ShowColumnMajor(id, items, measureDelegate, drawDelegate, gridOptions); } /// @@ -90,191 +160,275 @@ public static void Grid(IEnumerable items, MeasureGridCell measureDeleg /// internal static class GridImpl { - /// - /// Shows the grid with the specified items and delegates. - /// - /// The type of the items. - /// The items to be displayed in the grid. - /// The delegate to measure the size of each item. - /// The delegate to draw each item. - /// What ordering should grid items use - public static void Show(IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate, GridOrder gridOrder) + internal class GridLayout() { - var itemSpacing = ImGui.GetStyle().ItemSpacing; - var itemList = items.ToArray(); - var itemDimensions = itemList.Select(i => measureDelegate(i) + itemSpacing).ToArray(); - var contentRegionAvailable = ImGui.GetContentRegionAvail(); - int numColumns = 1; + internal Point Dimensions { private get; init; } + internal float[] ColumnWidths { get; init; } = []; + internal float[] RowHeights { get; init; } = []; + internal int ColumnCount => Dimensions.X; + internal int RowCount => Dimensions.Y; + } - while (numColumns <= itemList.Length) - { - int numRowsForColumns = (int)Math.Ceiling((float)itemList.Length / numColumns); + #region RowMajor + private static Point CalculateRowMajorCellLocation(int itemIndex, int columnCount) + { + int columnIndex = itemIndex % columnCount; + int rowIndex = itemIndex / columnCount; + return new(columnIndex, rowIndex); + } - float maxRowWidth = 0f; + private static GridLayout CalculateRowMajorGridLayout(Vector2[] itemSizes, float containerWidth) + { + float widestElementHeight = itemSizes.Max(itemSize => itemSize.X); + GridLayout currentGridLayout = new() + { + Dimensions = new(1, itemSizes.Length), + ColumnWidths = [widestElementHeight], + RowHeights = itemSizes.Select(itemSize => itemSize.Y).ToArray() + }; - switch (gridOrder) + var previousGridLayout = currentGridLayout; + while (currentGridLayout.ColumnCount < itemSizes.Length) + { + int newColumnCount = currentGridLayout.ColumnCount + 1; + int newRowCount = (int)MathF.Ceiling(itemSizes.Length / (float)newColumnCount); + currentGridLayout = new() { - case GridOrder.RowMajor: - float rowWidth = 0f; - - for (int i = 0; i < itemList.Length; i++) - { - if (i % numColumns == 0) - { - rowWidth = 0f; - } + Dimensions = new(newColumnCount, newRowCount), + ColumnWidths = new float[newColumnCount], + RowHeights = new float[newRowCount], + }; - rowWidth += itemDimensions[i].X + itemSpacing.X; - maxRowWidth = Math.Max(maxRowWidth, rowWidth); - } - break; + for (int i = 0; i < itemSizes.Length; i++) + { + var itemSize = itemSizes[i]; + var cellLocation = CalculateRowMajorCellLocation(i, newColumnCount); - case GridOrder.ColumnMajor: - for (int i = 0; i < numColumns; i++) - { - int colOffset = i * numRowsForColumns; - var colItems = itemDimensions.Skip(colOffset).Take(numRowsForColumns).ToArray(); - if (colItems.Length != 0) - { - maxRowWidth += colItems.Max(item => item.X) + itemSpacing.X; - } - } - break; + float maxColumnWidth = currentGridLayout.ColumnWidths[cellLocation.X]; + maxColumnWidth = Math.Max(maxColumnWidth, itemSize.X); + currentGridLayout.ColumnWidths[cellLocation.X] = maxColumnWidth; - default: - throw new NotImplementedException($"GridOrder '{gridOrder}' not implemented in ImGuiWidgets.Grid.Show"); + float maxRowHeight = currentGridLayout.RowHeights[cellLocation.Y]; + maxRowHeight = Math.Max(maxRowHeight, itemSize.Y); + currentGridLayout.RowHeights[cellLocation.Y] = maxRowHeight; } - if (maxRowWidth > contentRegionAvailable.X) + if (currentGridLayout.ColumnWidths.Sum() > containerWidth) { - numColumns--; + currentGridLayout = previousGridLayout; break; } - // Once we have iterated all items without exceeding the contentRegionAvailable.X we - // want to break without incrementing the number of columns because the content will fit - else if (numColumns == itemList.Length) + previousGridLayout = currentGridLayout; + } + + return currentGridLayout; + } + + internal static void ShowRowMajor(string id, IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate, GridOptions gridOptions) + { + if (gridOptions.GridSize.X <= 0) + { + gridOptions.GridSize = new(ImGui.GetContentRegionAvail().X, gridOptions.GridSize.Y); + } + if (gridOptions.GridSize.Y <= 0) + { + gridOptions.GridSize = new(gridOptions.GridSize.X, ImGui.GetContentRegionAvail().Y); + } + + var itemSpacing = ImGui.GetStyle().ItemSpacing; + var itemList = items.ToArray(); + int itemListCount = itemList.Length; + var itemDimensions = itemList.Select(i => measureDelegate(i)).ToArray(); + var itemDimensionsWithSpacing = itemDimensions.Select(d => d + itemSpacing).ToArray(); + var gridLayout = CalculateRowMajorGridLayout(itemDimensionsWithSpacing, gridOptions.GridSize.X); + + if (gridOptions.FitToContents) + { + float width = gridLayout.ColumnWidths.Sum(); + float height = gridLayout.RowHeights.Sum(); + gridOptions.GridSize = new(width, height); + } + + var drawList = ImGui.GetWindowDrawList(); + uint borderColor = ImGui.GetColorU32(ImGui.GetStyle().Colors[(int)ImGuiCol.Border]); + if (ImGui.BeginChild($"rowMajorGrid_{id}", gridOptions.GridSize, ImGuiChildFlags.None)) + { + var gridTopLeft = ImGui.GetCursorScreenPos(); + if (EnableGridDebugDraw) { - break; + drawList.AddRect(gridTopLeft, gridTopLeft + gridOptions.GridSize, borderColor); } - // ColumnMajor grids are not allowed to have any rows with 2 or more unused cells. If we tried - // to draw such a case we would end up displaying items that were meant for the end cells on a - // different row which would then cause the grid to be misaligned. - // [1] [2] [3] => [1] [3] [X] - // [4] [2] [4] - // Don't check for uneven columns if there is only 1 column as it isn't possible for them - // to be uneven (an simplifies the checking logic) - else if (gridOrder == GridOrder.ColumnMajor && numColumns != 1) - { - int maxItemsPerRow = numColumns; - int minItemsPerRow = numColumns - 1; - List itemsPerRow = []; - int itemCount = 0; - for (int i = 0; i < itemList.Length; i++) + var rowTopleft = gridTopLeft; + for (int rowIndex = 0; rowIndex < gridLayout.RowCount; rowIndex++) + { + bool isFirstRow = rowIndex == 0; + float previousRowHeight = isFirstRow ? 0f : gridLayout.RowHeights[rowIndex - 1]; + + float columnCursorX = rowTopleft.X; + float columnCursorY = rowTopleft.Y + previousRowHeight; + rowTopleft = new(columnCursorX, columnCursorY); + ImGui.SetCursorScreenPos(rowTopleft); + + var cellTopLeft = ImGui.GetCursorScreenPos(); + int itemBeginIndex = rowIndex * gridLayout.ColumnCount; + int itemEndIndex = Math.Min(itemBeginIndex + gridLayout.ColumnCount, itemListCount); + for (int itemIndex = itemBeginIndex; itemIndex < itemEndIndex; itemIndex++) { - itemCount++; - // The first item will trigger the end of row log (0 % 1 == 0) and we only get in here - // if numColumns > 1 so we can safely ignore the end of row check in that situation - bool endOfRow = (i != 0) && (i % numColumns == 0); - if (endOfRow) + int columnIndex = itemIndex - itemBeginIndex; + bool isFirstColumn = itemIndex == itemBeginIndex; + float previousCellWidth = isFirstColumn ? 0f : gridLayout.ColumnWidths[columnIndex - 1]; + + float cellCursorX = cellTopLeft.X + previousCellWidth; + float cellCursorY = cellTopLeft.Y; + cellTopLeft = new(cellCursorX, cellCursorY); + ImGui.SetCursorScreenPos(cellTopLeft); + + float cellWidth = gridLayout.ColumnWidths[columnIndex]; + float cellHeight = gridLayout.RowHeights[rowIndex]; + Vector2 cellSize = new(cellWidth, cellHeight); + + if (EnableGridDebugDraw) { - itemsPerRow.Add(itemCount); - itemCount = 0; + drawList.AddRect(cellTopLeft, cellTopLeft + cellSize, borderColor); } - } - - if (itemsPerRow.Any(c => c < minItemsPerRow)) - { - numColumns--; - break; + drawDelegate(itemList[itemIndex], cellSize, itemDimensions[itemIndex]); } } - numColumns++; - } - - if (numColumns < 1) - { - numColumns = 1; } + ImGui.EndChild(); + } + #endregion - int numRows = (int)Math.Ceiling((float)itemList.Length / numColumns); - - // calculate column widths and row heights - float[] columnWidths = new float[numColumns]; - float[] rowHeights = new float[numRows]; + #region ColumnMajor + private static Point CalculateColumnMajorCellLocation(int itemIndex, int rowCount) + { + int columnIndex = itemIndex / rowCount; + int rowIndex = itemIndex % rowCount; + return new(columnIndex, rowIndex); + } - for (int i = 0; i < numColumns * numRows; i++) + private static GridLayout CalculateColumnMajorGridLayout(Vector2[] itemSizes, float containerHeight) + { + float tallestElementHeight = itemSizes.Max(itemSize => itemSize.Y); + GridLayout currentGridLayout = new() { - int column = i % numColumns; - int row = i / numColumns; + Dimensions = new(itemSizes.Length, 1), + ColumnWidths = itemSizes.Select(itemSize => itemSize.X).ToArray(), + RowHeights = [tallestElementHeight], + }; - int itemIndex = gridOrder switch + var previousGridLayout = currentGridLayout; + while (currentGridLayout.RowCount < itemSizes.Length) + { + int newRowCount = currentGridLayout.RowCount + 1; + int newColumnCount = (int)MathF.Ceiling(itemSizes.Length / (float)newRowCount); + currentGridLayout = new() { - GridOrder.RowMajor => i, - GridOrder.ColumnMajor => (column * numRows) + row, - _ => throw new NotImplementedException() + Dimensions = new(newColumnCount, newRowCount), + ColumnWidths = new float[newColumnCount], + RowHeights = new float[newRowCount], }; - if (itemIndex < itemList.Length) + for (int i = 0; i < itemSizes.Length; i++) { - var thisItemSize = itemDimensions[itemIndex]; + var itemSize = itemSizes[i]; + var cellLocation = CalculateColumnMajorCellLocation(i, newRowCount); - columnWidths[column] = Math.Max(columnWidths[column], thisItemSize.X); - rowHeights[row] = Math.Max(rowHeights[row], thisItemSize.Y); + float maxColumnWidth = currentGridLayout.ColumnWidths[cellLocation.X]; + maxColumnWidth = Math.Max(maxColumnWidth, itemSize.X); + currentGridLayout.ColumnWidths[cellLocation.X] = maxColumnWidth; + + float maxRowHeight = currentGridLayout.RowHeights[cellLocation.Y]; + maxRowHeight = Math.Max(maxRowHeight, itemSize.Y); + currentGridLayout.RowHeights[cellLocation.Y] = maxRowHeight; + } + + if (currentGridLayout.RowHeights.Sum() > containerHeight) + { + currentGridLayout = previousGridLayout; + break; } + previousGridLayout = currentGridLayout; } - float totalContentWidth = columnWidths.Sum(); - float extraSpace = contentRegionAvailable.X - totalContentWidth; - float extraSpacePerColumn = extraSpace / numColumns; + return currentGridLayout; + } - for (int i = 0; i < numColumns; i++) + internal static void ShowColumnMajor(string id, IEnumerable items, MeasureGridCell measureDelegate, DrawGridCell drawDelegate, GridOptions gridOptions) + { + if (gridOptions.GridSize.X <= 0) + { + gridOptions.GridSize = new(ImGui.GetContentRegionAvail().X, gridOptions.GridSize.Y); + } + if (gridOptions.GridSize.Y <= 0) { - columnWidths[i] += extraSpacePerColumn; + gridOptions.GridSize = new(gridOptions.GridSize.X, ImGui.GetContentRegionAvail().Y); } - var marginTopLeftCursor = ImGui.GetCursorScreenPos(); - float gridWidth = contentRegionAvailable.X; - float gridHeight = rowHeights.Sum(h => h); + var itemSpacing = ImGui.GetStyle().ItemSpacing; + var itemList = items.ToArray(); + int itemListCount = itemList.Length; + var itemDimensions = itemList.Select(i => measureDelegate(i)).ToArray(); + var itemDimensionsWithSpacing = itemDimensions.Select(d => d + itemSpacing).ToArray(); + var gridLayout = CalculateColumnMajorGridLayout(itemDimensionsWithSpacing, gridOptions.GridSize.Y); - int numCells = numColumns * numRows; - for (int i = 0; i < numCells; i++) + if (gridOptions.FitToContents) { - var itemStartCursor = ImGui.GetCursorScreenPos(); - int column = i % numColumns; - int row = i / numColumns; + float width = gridLayout.ColumnWidths.Sum(); + float height = gridLayout.RowHeights.Sum(); + gridOptions.GridSize = new(width, height); + } - int itemIndex = gridOrder switch + var drawList = ImGui.GetWindowDrawList(); + uint borderColor = ImGui.GetColorU32(ImGui.GetStyle().Colors[(int)ImGuiCol.Border]); + if (ImGui.BeginChild($"columnMajorGrid_{id}", gridOptions.GridSize, ImGuiChildFlags.None, ImGuiWindowFlags.HorizontalScrollbar)) + { + var gridTopLeft = ImGui.GetCursorScreenPos(); + if (EnableGridDebugDraw) { - GridOrder.RowMajor => i, - GridOrder.ColumnMajor => (column * numRows) + row, - _ => throw new NotImplementedException() - }; - - var cellSize = new Vector2(columnWidths[column], rowHeights[row]); + drawList.AddRect(gridTopLeft, gridTopLeft + gridOptions.GridSize, borderColor); + } - if (itemIndex < itemList.Length) + var columnTopLeft = gridTopLeft; + for (int columnIndex = 0; columnIndex < gridLayout.ColumnCount; columnIndex++) { - if (EnableGridDebugDraw) + bool isFirstColumn = columnIndex == 0; + float previousColumnWidth = isFirstColumn ? 0f : gridLayout.ColumnWidths[columnIndex - 1]; + + float columnCursorX = columnTopLeft.X + previousColumnWidth; + float columnCursorY = columnTopLeft.Y; + columnTopLeft = new(columnCursorX, columnCursorY); + ImGui.SetCursorScreenPos(columnTopLeft); + + var cellTopLeft = ImGui.GetCursorScreenPos(); + int itemBeginIndex = columnIndex * gridLayout.RowCount; + int itemEndIndex = Math.Min(itemBeginIndex + gridLayout.RowCount, itemListCount); + for (int itemIndex = itemBeginIndex; itemIndex < itemEndIndex; itemIndex++) { - uint borderColor = ImGui.GetColorU32(ImGui.GetStyle().Colors[(int)ImGuiCol.Border]); - var drawList = ImGui.GetWindowDrawList(); - drawList.AddRect(itemStartCursor, itemStartCursor + cellSize, ImGui.GetColorU32(borderColor)); - } + int rowIndex = itemIndex - itemBeginIndex; + bool isFirstRow = itemIndex == itemBeginIndex; + float previousCellHeight = isFirstRow ? 0f : itemDimensionsWithSpacing[rowIndex - 1].Y; - drawDelegate(itemList[itemIndex], cellSize, itemDimensions[itemIndex]); - } + float cellCursorX = cellTopLeft.X; + float cellCursorY = cellTopLeft.Y + previousCellHeight; + cellTopLeft = new(cellCursorX, cellCursorY); + ImGui.SetCursorScreenPos(cellTopLeft); - var advance = new Vector2(marginTopLeftCursor.X, itemStartCursor.Y + cellSize.Y); - if (column < numColumns - 1) - { - advance = new Vector2(itemStartCursor.X + cellSize.X, itemStartCursor.Y); + float cellWidth = gridLayout.ColumnWidths[columnIndex]; + float cellHeight = gridLayout.RowHeights[rowIndex]; + Vector2 cellSize = new(cellWidth, cellHeight); + + if (EnableGridDebugDraw) + { + drawList.AddRect(cellTopLeft, cellTopLeft + cellSize, borderColor); + } + drawDelegate(itemList[itemIndex], cellSize, itemDimensions[itemIndex]); + } } - ImGui.SetCursorScreenPos(advance); } - - ImGui.SetCursorScreenPos(marginTopLeftCursor + new Vector2(gridWidth, 0f)); - ImGui.Dummy(new Vector2(0, gridHeight)); + ImGui.EndChild(); } + #endregion } } diff --git a/ImGuiWidgets/ImGuiWidgets.csproj b/ImGuiWidgets/ImGuiWidgets.csproj index 7b6348b..1b304f5 100644 --- a/ImGuiWidgets/ImGuiWidgets.csproj +++ b/ImGuiWidgets/ImGuiWidgets.csproj @@ -9,7 +9,7 @@ - + diff --git a/ImGuiWidgetsDemo/ImGuiWidgetsDemo.cs b/ImGuiWidgetsDemo/ImGuiWidgetsDemo.cs index b05815f..0d0c286 100644 --- a/ImGuiWidgetsDemo/ImGuiWidgetsDemo.cs +++ b/ImGuiWidgetsDemo/ImGuiWidgetsDemo.cs @@ -46,8 +46,14 @@ private static void Main() private ImGuiPopups.MessageOK MessageOK { get; } = new(); private List GridStrings { get; } = []; - private static int InitialGridSize { get; } = 32; - private int gridItemsToShow = InitialGridSize; + private static int InitialGridItemCount { get; } = 32; + private int GridItemsToShow { get; set; } = InitialGridItemCount; + private float GridHeight { get; set; } = 500f; + private ImGuiWidgets.GridOrder GridOrder { get; set; } = ImGuiWidgets.GridOrder.RowMajor; + private ImGuiWidgets.IconAlignment GridIconAlignment { get; set; } = ImGuiWidgets.IconAlignment.Vertical; + private bool GridIconSizeBig { get; set; } = true; + private bool GridIconCenterWithinCell { get; set; } = true; + private bool GridFitToContents { get; set; } private EnumValues selectedEnumValue = EnumValues.Value1; private string selectedStringValue = "Hello"; private readonly Collection possibleStringValues = ["Hello", "World", "Goodbye"]; @@ -61,7 +67,7 @@ private void OnStart() DividerContainer.Add(new("Left", 0.25f, ShowLeftPanel)); DividerContainer.Add(new("Right", 0.75f, ShowRightPanel)); - for (int i = 0; i < InitialGridSize; i++) + for (int i = 0; i < InitialGridItemCount; i++) { string randomString = $"{i}:"; int randomAmount = new Random().Next(2, 32); @@ -149,11 +155,11 @@ private void ShowLeftPanel(float size) private void ShowRightPanel(float size) { - ImGui.Text("Right Divider Zone"); - var ktsuIconPath = (AbsoluteDirectoryPath)Environment.CurrentDirectory / (FileName)"ktsu.png"; var ktsuTexture = ImGuiApp.GetOrLoadTexture(ktsuIconPath); + ImGui.Text("Right Divider Zone"); + if (ImGuiWidgets.Image(ktsuTexture.TextureId, new(128, 128))) { MessageOK.Open("Click", "You chose the image"); @@ -196,37 +202,104 @@ private void ShowRightPanel(float size) Tooltip = "You hovered over me" }); - float iconSizePx = ImGuiApp.EmsToPx(2.5f); ImGui.NewLine(); - bool showGridDebug = ImGuiWidgets.EnableGridDebugDraw; - if (ImGui.Checkbox("Show Grid Debug", ref showGridDebug)) + if (ImGui.CollapsingHeader("Grid Settings")) { - ImGuiWidgets.EnableGridDebugDraw = showGridDebug; - } - bool showIconDebug = ImGuiWidgets.EnableIconDebugDraw; - if (ImGui.Checkbox("Show Icon Debug", ref showIconDebug)) - { - ImGuiWidgets.EnableIconDebugDraw = showIconDebug; + bool showGridDebug = ImGuiWidgets.EnableGridDebugDraw; + if (ImGui.Checkbox("Show Grid Debug", ref showGridDebug)) + { + ImGuiWidgets.EnableGridDebugDraw = showGridDebug; + } + bool showIconDebug = ImGuiWidgets.EnableIconDebugDraw; + if (ImGui.Checkbox("Show Icon Debug", ref showIconDebug)) + { + ImGuiWidgets.EnableIconDebugDraw = showIconDebug; + } + + { + bool gridIconCenterWithinCell = GridIconCenterWithinCell; + bool gridIconSizeBig = GridIconSizeBig; + bool gridFitToContents = GridFitToContents; + int gridItemsToShow = GridItemsToShow; + var gridOrder = GridOrder; + var gridIconAlignment = GridIconAlignment; + float gridHeight = GridHeight; + + if (ImGui.Checkbox("Use Big Grid Icons", ref gridIconSizeBig)) + { + GridIconSizeBig = gridIconSizeBig; + } + if (ImGui.Checkbox("Center within cell", ref gridIconCenterWithinCell)) + { + GridIconCenterWithinCell = gridIconCenterWithinCell; + } + if (ImGui.Checkbox("Fit to contents", ref gridFitToContents)) + { + GridFitToContents = gridFitToContents; + } + if (ImGui.SliderInt("Items to show", ref gridItemsToShow, 1, GridStrings.Count)) + { + GridItemsToShow = gridItemsToShow; + } + if (ImGuiWidgets.Combo("Order", ref gridOrder)) + { + GridOrder = gridOrder; + } + if (ImGuiWidgets.Combo("Icon Alignment", ref gridIconAlignment)) + { + GridIconAlignment = gridIconAlignment; + } + if (ImGui.SliderFloat("Grid Height", ref gridHeight, 1f, 1000f)) + { + GridHeight = gridHeight; + } + } } - ImGui.SliderInt("Grid items to show", ref gridItemsToShow, 1, GridStrings.Count); - ImGui.SeparatorText("Grid (Column Major) Icon Alignment Horizontal"); - ImGuiWidgets.Grid(GridStrings.Take(gridItemsToShow), i => ImGuiWidgets.CalcIconSize(i, iconSizePx, ImGuiWidgets.IconAlignment.Horizontal), (item, cellSize, itemSize) => - { - ImGuiWidgets.Icon(item, ktsuTexture.TextureId, iconSizePx, ImGuiWidgets.IconAlignment.Horizontal); - }, ImGuiWidgets.GridOrder.ColumnMajor); + float iconSizePx = ImGuiApp.EmsToPx(2.5f); + float bigIconSizePx = iconSizePx * 2; + float gridIconSize = GridIconSizeBig ? bigIconSizePx : iconSizePx; + var gridSize = new Vector2(ImGui.GetContentRegionAvail().X, GridHeight); - ImGui.NewLine(); - ImGui.SeparatorText("Grid (Row Major) Icon Alignment Vertical"); - float bigIconSize = iconSizePx * 2; - ImGuiWidgets.Grid(GridStrings.Take(gridItemsToShow), i => ImGuiWidgets.CalcIconSize(i, bigIconSize, ImGuiWidgets.IconAlignment.Vertical), (item, cellSize, itemSize) => + ImGui.Separator(); + + Vector2 MeasureGridSize(string item) => ImGuiWidgets.CalcIconSize(item, gridIconSize, GridIconAlignment); + void DrawGridCell(string item, Vector2 cellSize, Vector2 itemSize) { - using (new Alignment.CenterWithin(itemSize, cellSize)) + if (GridIconCenterWithinCell) + { + using (new Alignment.CenterWithin(itemSize, cellSize)) + { + ImGuiWidgets.Icon(item, ktsuTexture.TextureId, gridIconSize, GridIconAlignment); + } + } + else { - ImGuiWidgets.Icon(item, ktsuTexture.TextureId, bigIconSize, ImGuiWidgets.IconAlignment.Vertical); + ImGuiWidgets.Icon(item, ktsuTexture.TextureId, gridIconSize, GridIconAlignment); } - }, ImGuiWidgets.GridOrder.RowMajor); + } + + ImGuiWidgets.GridOptions gridOptions = new() + { + GridSize = new(ImGui.GetContentRegionAvail().X, GridHeight), + FitToContents = GridFitToContents, + }; + switch (GridOrder) + { + case ImGuiWidgets.GridOrder.RowMajor: + ImGuiWidgets.RowMajorGrid("demoRowMajorGrid", GridStrings.Take(GridItemsToShow), MeasureGridSize, DrawGridCell, gridOptions); + break; + + case ImGuiWidgets.GridOrder.ColumnMajor: + ImGuiWidgets.ColumnMajorGrid("demoColumnMajorGrid", GridStrings.Take(GridItemsToShow), MeasureGridSize, DrawGridCell, gridOptions); + break; + + default: + throw new NotImplementedException(); + } + + ImGui.Separator(); MessageOK.ShowIfOpen(); }