diff --git a/OpenNest.WinForms.Tests/Controls/GridStyleTests.cs b/OpenNest.WinForms.Tests/Controls/GridStyleTests.cs new file mode 100644 index 00000000..580b5081 --- /dev/null +++ b/OpenNest.WinForms.Tests/Controls/GridStyleTests.cs @@ -0,0 +1,48 @@ +using System.Windows.Forms; +using OpenNest.Controls; + +namespace OpenNest.WinForms.Tests.Controls; + +public class GridStyleTests +{ + [Fact] + public void ColumnsSizeToFirstContentThenKeepTheUsersWidths() => ArchUnitsTests.RunSta(() => + { + using var form = new Form { Width = 1200, Height = 400, ShowInTaskbar = false }; + var grid = GridStyle.Apply(new DataGridView { Dock = DockStyle.Fill, AllowUserToAddRows = false }); + var shortColumn = new DataGridViewTextBoxColumn { HeaderText = "Qty", Width = 300 }; + var longColumn = new DataGridViewTextBoxColumn { HeaderText = "Name", Width = 40 }; + var hugeColumn = new DataGridViewTextBoxColumn { HeaderText = "Notes", Width = 40 }; + grid.Columns.AddRange(shortColumn, longColumn, hugeColumn); + form.Controls.Add(grid); + form.Show(); + Pump(grid); + Assert.Equal(300, shortColumn.Width); // no rows yet: nothing is measured + + grid.Rows.Add("1", "A fairly long drawing name", new string('W', 200)); + Pump(grid); + + Assert.True(shortColumn.Width < 300); + Assert.True(longColumn.Width > 40); + Assert.Equal(400, hugeColumn.Width); + Assert.All(grid.Columns.Cast(), column => + { + Assert.Equal(DataGridViewAutoSizeColumnMode.None, column.InheritedAutoSizeMode); + Assert.True(column.Resizable == DataGridViewTriState.True || column.Resizable == DataGridViewTriState.NotSet); + }); + + longColumn.Width = 77; + grid.Rows.Add("2", new string('X', 80), ""); + Pump(grid); + Assert.Equal(77, longColumn.Width); + }); + + private static void Pump(Control control) + { + for (var i = 0; i < 5; i++) + { + control.Refresh(); + Application.DoEvents(); + } + } +} diff --git a/OpenNest/Controls/DrawingLibraryView.Designer.cs b/OpenNest/Controls/DrawingLibraryView.Designer.cs index edc7bcca..0a76554f 100644 --- a/OpenNest/Controls/DrawingLibraryView.Designer.cs +++ b/OpenNest/Controls/DrawingLibraryView.Designer.cs @@ -199,7 +199,7 @@ namespace OpenNest.Controls // // nestNameColumn // - nestNameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + nestNameColumn.Width = 240; nestNameColumn.HeaderText = "Name"; nestNameColumn.MinimumWidth = 160; nestNameColumn.Name = "nestNameColumn"; @@ -366,7 +366,7 @@ namespace OpenNest.Controls // // nameColumn // - nameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + nameColumn.Width = 240; nameColumn.HeaderText = "Name"; nameColumn.MinimumWidth = 160; nameColumn.Name = "nameColumn"; diff --git a/OpenNest/Controls/GridStyle.cs b/OpenNest/Controls/GridStyle.cs index c52f4e44..38f6c611 100644 --- a/OpenNest/Controls/GridStyle.cs +++ b/OpenNest/Controls/GridStyle.cs @@ -6,11 +6,13 @@ namespace OpenNest.Controls; /// /// The shared look of every in the desktop app, taken from the /// database nest browser: flat light headers, faint grid lines, a soft blue selection and -/// fixed row heights. Behaviour (editing, selection mode, column sizing) stays with each grid. +/// fixed row heights. Columns size once to their first content and are then the user's to +/// resize. Other behaviour (editing, selection mode) stays with each grid. /// public static class GridStyle { public const int RowHeight = 22; + private const int MaxInitialColumnWidth = 400; private static readonly Color HeaderBackColor = Color.FromArgb(245, 245, 245); private static readonly Color HeaderForeColor = Color.FromArgb(90, 90, 90); @@ -42,6 +44,35 @@ public static class GridStyle grid.RowHeadersDefaultCellStyle.SelectionBackColor = SelectionBackColor; grid.RowHeadersDefaultCellStyle.SelectionForeColor = Color.Black; grid.RowHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight; + SizeColumnsOnceToContent(grid); return grid; } + + /// + /// Widens each column to fit its header and the rows first shown, once, then leaves the + /// widths to the user. Columns never stretch to fill the grid. + /// + private static void SizeColumnsOnceToContent(DataGridView grid) + { + // The first paint with rows is the first time they are on screen to be measured. The + // empty new-row placeholder does not count: a grid that starts empty keeps its widths + // until it has content. + void OnPaint(object sender, PaintEventArgs e) + { + var newRowShown = grid.NewRowIndex >= 0 && grid.Rows[grid.NewRowIndex].Displayed; + if (grid.DisplayedRowCount(false) - (newRowShown ? 1 : 0) <= 0) + return; + grid.Paint -= OnPaint; + grid.BeginInvoke(() => + { + if (grid.IsDisposed) + return; + grid.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells); + foreach (DataGridViewColumn column in grid.Columns) + column.Width = System.Math.Min(column.Width, MaxInitialColumnWidth); + }); + } + + grid.Paint += OnPaint; + } } diff --git a/OpenNest/Controls/PostSettingsEditor.cs b/OpenNest/Controls/PostSettingsEditor.cs index 0c220428..b3b062a5 100644 --- a/OpenNest/Controls/PostSettingsEditor.cs +++ b/OpenNest/Controls/PostSettingsEditor.cs @@ -258,14 +258,13 @@ namespace OpenNest.Controls Height = 200, AllowUserToAddRows = true, AllowUserToDeleteRows = true, - AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill, RowHeadersWidth = 28, SelectionMode = DataGridViewSelectionMode.FullRowSelect, MultiSelect = true, Margin = new Padding(0, 4, 0, 0), }); - table.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = field.KeyHeader, FillWeight = 65 }); - table.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = field.ValueHeader, FillWeight = 35 }); + table.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = field.KeyHeader, Width = 260 }); + table.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = field.ValueHeader, Width = 140 }); if (map != null) { diff --git a/OpenNest/Controls/SetReleasesView.Designer.cs b/OpenNest/Controls/SetReleasesView.Designer.cs index ca62f8cc..0b249f98 100644 --- a/OpenNest/Controls/SetReleasesView.Designer.cs +++ b/OpenNest/Controls/SetReleasesView.Designer.cs @@ -176,7 +176,7 @@ namespace OpenNest.Controls releaseNotesColumn.HeaderText = "Notes"; releaseNotesColumn.Name = "releaseNotesColumn"; releaseNotesColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - releaseNotesColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + releaseNotesColumn.Width = 300; // // nestsGroup // diff --git a/OpenNest/Forms/AddReleaseDrawingsForm.Designer.cs b/OpenNest/Forms/AddReleaseDrawingsForm.Designer.cs index 1247027b..6eed9121 100644 --- a/OpenNest/Forms/AddReleaseDrawingsForm.Designer.cs +++ b/OpenNest/Forms/AddReleaseDrawingsForm.Designer.cs @@ -138,7 +138,7 @@ namespace OpenNest.Forms // // libraryCustomerColumn // - libraryCustomerColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + libraryCustomerColumn.Width = 150; libraryCustomerColumn.HeaderText = "Customer"; libraryCustomerColumn.MinimumWidth = 60; libraryCustomerColumn.Name = "libraryCustomerColumn"; diff --git a/OpenNest/Forms/BomImportForm.Designer.cs b/OpenNest/Forms/BomImportForm.Designer.cs index eb7ddcc0..75976651 100644 --- a/OpenNest/Forms/BomImportForm.Designer.cs +++ b/OpenNest/Forms/BomImportForm.Designer.cs @@ -270,7 +270,6 @@ namespace OpenNest.Forms // dgvParts.AllowUserToAddRows = false; dgvParts.AllowUserToDeleteRows = false; - dgvParts.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill; dgvParts.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { colItemNum, colFileName, colDescription, colMaterial, colThickness, colQty, colStatus }); dgvParts.Dock = System.Windows.Forms.DockStyle.Fill; dgvParts.Name = "dgvParts"; @@ -288,7 +287,7 @@ namespace OpenNest.Forms // colItemNum // colItemNum.DataPropertyName = "ItemNum"; - colItemNum.FillWeight = 40F; + colItemNum.Width = 60; colItemNum.HeaderText = "Item #"; colItemNum.Name = "colItemNum"; colItemNum.ReadOnly = true; @@ -297,7 +296,7 @@ namespace OpenNest.Forms // colFileName // colFileName.DataPropertyName = "FileName"; - colFileName.FillWeight = 120F; + colFileName.Width = 180; colFileName.HeaderText = "File Name"; colFileName.Name = "colFileName"; colFileName.ReadOnly = true; @@ -306,7 +305,7 @@ namespace OpenNest.Forms // colDescription // colDescription.DataPropertyName = "Description"; - colDescription.FillWeight = 150F; + colDescription.Width = 220; colDescription.HeaderText = "Description"; colDescription.Name = "colDescription"; colDescription.ReadOnly = true; @@ -315,7 +314,7 @@ namespace OpenNest.Forms // colMaterial // colMaterial.DataPropertyName = "Material"; - colMaterial.FillWeight = 110F; + colMaterial.Width = 140; colMaterial.HeaderText = "Material"; colMaterial.Name = "colMaterial"; colMaterial.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -327,7 +326,7 @@ namespace OpenNest.Forms thicknessCellStyle.Format = "0.####"; colThickness.DataPropertyName = "Thickness"; colThickness.DefaultCellStyle = thicknessCellStyle; - colThickness.FillWeight = 70F; + colThickness.Width = 80; colThickness.HeaderText = "Thickness"; colThickness.Name = "colThickness"; colThickness.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -338,7 +337,7 @@ namespace OpenNest.Forms qtyCellStyle.DataSourceNullValue = null; colQty.DataPropertyName = "Qty"; colQty.DefaultCellStyle = qtyCellStyle; - colQty.FillWeight = 50F; + colQty.Width = 60; colQty.HeaderText = "Qty"; colQty.Name = "colQty"; colQty.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -346,7 +345,7 @@ namespace OpenNest.Forms // colStatus // colStatus.DataPropertyName = "StatusText"; - colStatus.FillWeight = 100F; + colStatus.Width = 140; colStatus.HeaderText = "Status"; colStatus.Name = "colStatus"; colStatus.ReadOnly = true; @@ -363,7 +362,6 @@ namespace OpenNest.Forms // dgvGroups.AllowUserToAddRows = false; dgvGroups.AllowUserToDeleteRows = false; - dgvGroups.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill; dgvGroups.Dock = System.Windows.Forms.DockStyle.Fill; dgvGroups.Name = "dgvGroups"; dgvGroups.RowHeadersVisible = false; diff --git a/OpenNest/Forms/CuttingInspectionPanel.cs b/OpenNest/Forms/CuttingInspectionPanel.cs index 5ee0f705..fb4ff9cf 100644 --- a/OpenNest/Forms/CuttingInspectionPanel.cs +++ b/OpenNest/Forms/CuttingInspectionPanel.cs @@ -212,17 +212,15 @@ internal sealed class CuttingInspectionPanel : UserControl warningGrid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = name, - Width = 48, + Width = name is "Issue" or "Status" ? 260 : 48, SortMode = DataGridViewColumnSortMode.NotSortable, - AutoSizeMode = name == "Issue" ? DataGridViewAutoSizeColumnMode.Fill : DataGridViewAutoSizeColumnMode.None }); foreach (var name in new[] { "Plate", "Part", "Status" }) partsGrid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = name, - Width = 48, + Width = name is "Issue" or "Status" ? 260 : 48, SortMode = DataGridViewColumnSortMode.NotSortable, - AutoSizeMode = name == "Status" ? DataGridViewAutoSizeColumnMode.Fill : DataGridViewAutoSizeColumnMode.None }); Padding = new Padding(10); planButton.Click += (_, _) => StartCurrentMode(); diff --git a/OpenNest/Forms/EditDrawingSetForm.Designer.cs b/OpenNest/Forms/EditDrawingSetForm.Designer.cs index 82b2f8ee..09ebc899 100644 --- a/OpenNest/Forms/EditDrawingSetForm.Designer.cs +++ b/OpenNest/Forms/EditDrawingSetForm.Designer.cs @@ -286,7 +286,7 @@ namespace OpenNest.Forms // // libraryCustomerColumn // - libraryCustomerColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + libraryCustomerColumn.Width = 120; libraryCustomerColumn.HeaderText = "Customer"; libraryCustomerColumn.MinimumWidth = 60; libraryCustomerColumn.Name = "libraryCustomerColumn"; @@ -476,7 +476,7 @@ namespace OpenNest.Forms // // warningColumn // - warningColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + warningColumn.Width = 200; warningColumn.HeaderText = "Note"; warningColumn.MinimumWidth = 60; warningColumn.Name = "warningColumn"; diff --git a/OpenNest/Forms/ImportBomToSetForm.Designer.cs b/OpenNest/Forms/ImportBomToSetForm.Designer.cs index b86ba0a7..4b7370e0 100644 --- a/OpenNest/Forms/ImportBomToSetForm.Designer.cs +++ b/OpenNest/Forms/ImportBomToSetForm.Designer.cs @@ -190,7 +190,6 @@ namespace OpenNest.Forms drawingGrid.AllowUserToAddRows = false; drawingGrid.AllowUserToDeleteRows = false; drawingGrid.AllowUserToResizeRows = false; - drawingGrid.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill; drawingGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; drawingGrid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { drawingColumn, materialColumn, thicknessColumn, quantityColumn, libraryColumn, noteColumn }); drawingGrid.Dock = System.Windows.Forms.DockStyle.Fill; @@ -203,21 +202,21 @@ namespace OpenNest.Forms // // drawingColumn // - drawingColumn.FillWeight = 130F; + drawingColumn.Width = 180; drawingColumn.HeaderText = "Drawing"; drawingColumn.Name = "drawingColumn"; drawingColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // // materialColumn // - materialColumn.FillWeight = 80F; + materialColumn.Width = 120; materialColumn.HeaderText = "Material"; materialColumn.Name = "materialColumn"; materialColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // // thicknessColumn // - thicknessColumn.FillWeight = 50F; + thicknessColumn.Width = 80; thicknessColumn.HeaderText = "Thickness"; thicknessColumn.Name = "thicknessColumn"; thicknessColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -225,7 +224,7 @@ namespace OpenNest.Forms // quantityColumn // quantityColumn.DefaultCellStyle = new System.Windows.Forms.DataGridViewCellStyle { Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight }; - quantityColumn.FillWeight = 40F; + quantityColumn.Width = 60; quantityColumn.HeaderText = "Qty"; quantityColumn.Name = "quantityColumn"; quantityColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; @@ -233,14 +232,14 @@ namespace OpenNest.Forms // // libraryColumn // - libraryColumn.FillWeight = 120F; + libraryColumn.Width = 180; libraryColumn.HeaderText = "Drawing library"; libraryColumn.Name = "libraryColumn"; libraryColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; // // noteColumn // - noteColumn.FillWeight = 120F; + noteColumn.Width = 200; noteColumn.HeaderText = "Note"; noteColumn.Name = "noteColumn"; noteColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; diff --git a/OpenNest/Forms/OptionsForm.cs b/OpenNest/Forms/OptionsForm.cs index e790cbf8..291fb12d 100644 --- a/OpenNest/Forms/OptionsForm.cs +++ b/OpenNest/Forms/OptionsForm.cs @@ -46,7 +46,7 @@ namespace OpenNest.Forms Name = "Name", HeaderText = "Strategy", ReadOnly = true, - AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill, + Width = 220, } ); diff --git a/OpenNest/Forms/ReleaseSetForm.Designer.cs b/OpenNest/Forms/ReleaseSetForm.Designer.cs index 81e11031..7c61ec6e 100644 --- a/OpenNest/Forms/ReleaseSetForm.Designer.cs +++ b/OpenNest/Forms/ReleaseSetForm.Designer.cs @@ -209,7 +209,7 @@ namespace OpenNest.Forms // // setNameColumn // - setNameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + setNameColumn.Width = 260; setNameColumn.HeaderText = "Set or drawing"; setNameColumn.Name = "setNameColumn"; setNameColumn.ReadOnly = true; @@ -434,7 +434,7 @@ namespace OpenNest.Forms // // statusColumn // - statusColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + statusColumn.Width = 200; statusColumn.HeaderText = "Status"; statusColumn.Name = "statusColumn"; statusColumn.ReadOnly = true;