protected override void OnMouseClick(GLMouseEventArgs e) { base.OnMouseClick(e); GLDataGridView dgv = Parent as GLDataGridView; var g = contentpanel.GridRowCol(e.Location); if (e.Button == GLMouseEventArgs.MouseButtons.Left) { if (dragging == -1 && lastselectionstart == lastselectionend) // if not dragging sizing or area { if (g != null) { //System.Diagnostics.Debug.WriteLine($"Click valid {g.Row}"); MouseClickRowHeader(g.Row, e); } } } else if (e.Button == GLMouseEventArgs.MouseButtons.Right) { if (g != null && dgv.ContextMenuRowHeaders != null) { g.Column = -1; dgv.ContextMenuRowHeaders.Show(FindDisplay(), e.ScreenCoord, opentag: g); } } }
public Action <int, GLMouseEventArgs> MouseClickRowHeader; // -1 for top left cell public GLDataGridViewRowHeaderPanel(string name, Rectangle location) : base(name, location) { BorderColorNI = DefaultVerticalScrollPanelBorderColor; BackColorGradientAltNI = BackColorNI = DefaultVerticalScrollPanelBackColor; autoscroll.Tick += (t, tick) => { GLDataGridView dgv = Parent as GLDataGridView; if (lastmousemove.Y > 0) { if (dgv.LastCompleteLine() < dgv.Rows.Count - 1) // and scroll to the end, until all lines are on screen { dgv.FirstDisplayIndex++; } } else { if (dgv.FirstDisplayIndex > 0) { dgv.FirstDisplayIndex--; } } UpdateSelection(lastmousemove); }; }
protected override void OnMouseMove(GLMouseEventArgs e) { base.OnMouseMove(e); GLDataGridView dgv = Parent as GLDataGridView; if (selectionstart != null) { if (!dgv.AllowUserToDragSelectCells) // disable drag { return; } if (e.Location.Y >= 0 && e.Location.Y <= ClientHeight) // if within window, no scroll { autoscroll.Stop(); } else if (!autoscroll.Running) { autoscroll.Start(50, 200); // else autoscroll } lastmousemove = e.Location; // record this for autoscroll purposes UpdateSelection(e.Location); } else { MoveToCell(e); } }
private void MoveTo(int fdl) { GLDataGridView dgv = Parent as GLDataGridView; firstdisplayindex = dgv.Rows.Count > 0 ? Math.Max(0, Math.Min(fdl, dgv.Rows.Count)) : 0; // if FDL is within the drawn range of the bitmap if (firstdisplayindex >= gridfirstline && firstdisplayindex <= gridlastcompleteline) { // offset of lines in the draw int lineoffset = firstdisplayindex - gridfirstline; // this will be our new scroll position.. int ystart = gridrowoffsets[lineoffset]; // what we have left in the bitmap int depthleft = girddrawndepth - ystart; // System.Diagnostics.Debug.WriteLine($"Move to {firstdisplayindex} lo {lineoffset} ys {ystart} {depthleft} >= {ClientHeight}"); // if enough bitmap left.. OR we drew complete the last line, nothing to redraw. Move to pos if (depthleft >= ClientHeight || gridlastcompleteline == dgv.Rows.Count - 1) { ScrollOffset = new Point(ScrollOffset.X, ystart); // move the image down to this position Invalidate(); // invalidate only, no need to redraw return; } } Redraw(); }
public GLDataGridViewContentPanel(string name, GLDataGridViewRowHeaderPanel rowheaderpanel, Rectangle location) : base(name, location) { this.rowheaderpanel = rowheaderpanel; BorderColorNI = DefaultVerticalScrollPanelBorderColor; BackColorGradientAltNI = BackColorNI = Color.Red;// DefaultVerticalScrollPanelBackColor; autoscroll.Tick += (t, tick) => { GLDataGridView dgv = Parent as GLDataGridView; if (lastmousemove.Y > 0) { //System.Diagnostics.Debug.WriteLine($"First line {dgv.FirstDisplayIndex} last complete {dgv.LastCompleteLine()}"); if (LastCompleteLine() < dgv.Rows.Count - 1) // and scroll to the end, until all lines are on screen { dgv.FirstDisplayIndex++; } } else { if (FirstDisplayIndex > 0) { FirstDisplayIndex--; } } UpdateSelection(lastmousemove); }; }
protected override void Paint(Graphics gr) { GLDataGridView dgv = Parent as GLDataGridView; if (dgv.UpperLeftBackColor != Color.Transparent) { using (Brush b = new SolidBrush(dgv.UpperLeftBackColor)) { gr.FillRectangle(b, new Rectangle(0, 0, ClientWidth, ClientHeight)); } } if (dgv.CellBorderWidth > 0) { using (Brush b = new SolidBrush(dgv.CellBorderColor)) { using (Pen p = new Pen(b, dgv.CellBorderWidth)) { gr.DrawLine(p, 0, 0, ClientWidth - 1, 0); // draw a line across the top gr.DrawLine(p, 0, 0, 0, ClientHeight - 1); } } } if (dgv.UserPaintTopLeftHeader != null) { Rectangle area = new Rectangle(dgv.CellBorderWidth, dgv.CellBorderWidth, ClientWidth - 2 * dgv.CellBorderWidth, ClientHeight - 2 * dgv.CellBorderWidth); dgv.UserPaintTopLeftHeader(gr, area); } }
protected override void OnMouseWheel(GLMouseEventArgs e) { base.OnMouseWheel(e); GLDataGridView dgv = Parent as GLDataGridView; dgv.Scroll(e.Delta); }
protected override void OnMouseMove(GLMouseEventArgs e) { base.OnMouseMove(e); GLDataGridView dgv = Parent as GLDataGridView; int xoff = e.Location.X + HorzScroll; if (dragging == 0) { dgv.RowHeaderWidth = xoff + initialrowheaderwidth; } else if (dragging == -2) { dgv.ColumnHeaderHeight = e.Location.Y; } else if (dragging > 0) { int colx = xoff - dgv.ColumnPixelLeft(dragging - 1); dgv.SetColumnWidth(dragging - 1, colx); } else { var over = Over(e.Location); Cursor = (over != null && over.Item1 == ClickOn.Divider) ? GLWindowControl.GLCursorType.EW : (over != null && over.Item1 == ClickOn.Height) ? GLWindowControl.GLCursorType.NS : GLWindowControl.GLCursorType.Normal; } return; }
public void MoveToCell(GLMouseEventArgs e) { GLDataGridView dgv = Parent as GLDataGridView; var g = GridRowCol(e.Location); // find row/col if (g != null) { if (g.Column < dgv.Rows[g.Row].CellCount) // if within the range of cells of the current row { var newcell = CellPara(g, e); // get cell and set up mouse event args if (newcell == currentcell) { currentcell.OnMouseCellMove(e); // same cell, its a move } else { if (currentcell != null) // different cell, its a leave on last { currentcell.OnMouseCellLeave(e); } currentcell = newcell; currentcell?.OnMouseCellEnter(e); // if we have a new cell, enter. } return; // stop } } if (currentcell != null) // did not get a cell, but if we have a current cell, we need to leave { currentcell.OnMouseCellLeave(e); currentcell = null; } }
private void UpdateSelection(Point loc) { var g = GridRowCol(loc); if (g != null) { GLDataGridView dgv = Parent as GLDataGridView; // get the min/max ranges of selection, which can be the minimum/max of start/end and current loc int minrow = ObjectExtensionsNumbersBool.Min(lastselectionstart.Row, lastselectionend.Row, g.Row); int maxrow = ObjectExtensionsNumbersBool.Max(lastselectionstart.Row, lastselectionend.Row, g.Row); int mincol = ObjectExtensionsNumbersBool.Min(lastselectionstart.Column, lastselectionend.Column, g.Column); int maxcol = ObjectExtensionsNumbersBool.Max(lastselectionstart.Column, lastselectionend.Column, g.Column); //System.Diagnostics.Debug.WriteLine($"Cursor {loc} at {g.Row} {g.Column} minr {minrow} maxr {maxrow}"); for (int row = minrow; row <= maxrow; row++) { for (int col = mincol; col <= maxcol && col < dgv.Rows[row].CellCount; col++) { bool selrow = g.Row < selectionstart.Row ? row >= g.Row && row <= selectionstart.Row : row >= selectionstart.Row && row <= g.Row; bool selcol = g.Column < selectionstart.Column ? col >= g.Column && col <= selectionstart.Column : col >= selectionstart.Column && col <= g.Column; // System.Diagnostics.Debug.WriteLine($"{col} {row} = {selrow} {selcol}"); dgv.Rows[row].Cells[col].Selected = selrow && selcol; } } lastselectionstart = selectionstart; lastselectionend = g; } }
protected override void OnMouseClick(GLMouseEventArgs e) { base.OnMouseClick(e); if (e.Button == GLMouseEventArgs.MouseButtons.Left) { if (dragging == -1) { var over = Over(e.Location); if (over != null && over.Item1 != ClickOn.Divider) { MouseClickColumnHeader(over.Item2, e); } } } else if (e.Button == GLMouseEventArgs.MouseButtons.Right) { GLDataGridView dgv = Parent as GLDataGridView; if (dgv.ContextMenuColumnHeaders != null) { var over = Over(e.Location); if (over != null && over.Item1 == ClickOn.Header) { dgv.ContextMenuColumnHeaders.Show(FindDisplay(), e.ScreenCoord, opentag: new GLDataGridView.RowColPos() { Column = over.Item2, Row = -1, Location = over.Item3 }); } } } }
// returns real row number public GLDataGridView.RowColPos GridRowCol(Point p) { if (gridrowoffsets.Count > 0) { int y = ScrollOffset.Y + Math.Max(0, Math.Min(p.Y, ClientHeight)); // if mouse if captured, y may be well beyond grid, clip to it int gridrow = gridrowoffsets.FindLastIndex(a => a < y); if (gridrow >= 0 && gridrow < gridrowoffsets.Count - 1) // last entry is end of grid, either reject or accept { GLDataGridView dgv = Parent as GLDataGridView; int xoffset = ScrollOffset.X + Math.Max(0, Math.Min(p.X, ClientWidth)); // clip X for (int i = 0; i < dgv.Columns.Count; i++) { int left = dgv.ColumnPixelLeft(i); if (xoffset >= left && xoffset < left + dgv.Columns[i].Width) { Point off = new Point(xoffset - left, y - gridrowoffsets[gridrow]); Point cellloc = new Point(left, gridrowoffsets[gridrow] + dgv.CellBorderWidth); gridrow += gridfirstline; return(new GLDataGridView.RowColPos() { Row = gridrow, Column = i, Location = off, CellLocation = cellloc }); } } } } return(null); }
protected override void OnMouseClick(GLMouseEventArgs e) { base.OnMouseClick(e); GLDataGridView dgv = Parent as GLDataGridView; var g = GridRowCol(e.Location); if (e.Button == GLMouseEventArgs.MouseButtons.Left) { if (lastselectionstart == lastselectionend) { if (g != null) { var orgbounds = e.Bounds; var orgbloc = e.BoundsLocation; var orgloc = e.Location; var newcell = CellPara(g, e); // may return null if cell not there newcell?.OnMouseCellClick(e); if (e.Handled == false) // and if it did not, call global click { e.Bounds = orgbounds; e.BoundsLocation = orgbloc; e.Location = orgloc; MouseClickOnGrid(g.Row, g.Column, e); } } else { MouseClickOnGrid(-1, -1, e); } } } else if (e.Button == GLMouseEventArgs.MouseButtons.Right) { if (dgv.ContextMenuGrid != null) { if (g == null) // out of cell, return pos of click { g = new GLDataGridView.RowColPos() { Column = -1, Row = -1, Location = e.Location } } ; else { if (dgv.SelectRowOnRightClick) { dgv.Rows[g.Row].Selected = true; } } dgv.ContextMenuGrid.Show(FindDisplay(), e.ScreenCoord, opentag: g); } } }
public void DrawHeaders(int firstline, int lastline, int drawndepth, int ystart) { yoffset = ystart; GLDataGridView dgv = Parent as GLDataGridView; if (!dgv.RowHeaderEnable || dgv.Rows.Count == 0 || dgv.Columns.Count == 0) // sanity check { return; } int headerwidth = dgv.RowHeaderWidth + dgv.CellBorderWidth; if (gridbitmap == null || gridbitmap.Height < drawndepth || gridbitmap.Width < headerwidth) { gridbitmap?.Dispose(); gridbitmap = new Bitmap(dgv.RowHeaderWidth + dgv.CellBorderWidth, drawndepth); } using (Graphics gr = Graphics.FromImage(gridbitmap)) { gr.Clear(Color.Transparent); using (Brush b = new SolidBrush(dgv.CellBorderColor)) { using (Pen p = new Pen(b, dgv.CellBorderWidth)) { int vpos = 0; for (var rowno = firstline; rowno < dgv.Rows.Count && vpos < gridbitmap.Height; rowno++) { var row = dgv.Rows[rowno]; if (dgv.CellBorderWidth > 0) { gr.DrawLine(p, 0, vpos, headerwidth, vpos); // draw a line across the top vpos += dgv.CellBorderWidth; } Rectangle area = new Rectangle(dgv.CellBorderWidth, vpos, dgv.RowHeaderWidth, row.Height); row.Paint(gr, area); dgv.UserPaintRowHeaders?.Invoke(row, gr, area); vpos += row.Height; } if (dgv.CellBorderWidth > 0) { gr.DrawLine(p, 0, vpos, headerwidth, vpos); // draw a line across the bottom gr.DrawLine(p, 0, 0, 0, vpos); // and one on the left } } } } Invalidate(); }
protected override void Paint(Graphics gr) { GLDataGridView dgv = Parent as GLDataGridView; if (gridbitmap != null) { //using (Brush b = new SolidBrush(Color.Red)) gr.FillRectangle(b, ClientRectangle); Rectangle drawarea = new Rectangle(0, 0, gridbitmap.Width, gridbitmap.Height - yoffset); gr.DrawImage(gridbitmap, drawarea, 0, yoffset, drawarea.Width, drawarea.Height, GraphicsUnit.Pixel); } }
protected override void OnMouseMove(GLMouseEventArgs e) { base.OnMouseMove(e); GLDataGridView dgv = Parent as GLDataGridView; if (dragging >= 0) // row height { dgv.Rows[dragging].Height = e.Location.Y - draggingstart; } else if (dragging == -2) // header width { dgv.RowHeaderWidth = e.Location.X; } else if (selectionstart != -1) // multi selection of line { if (!dgv.AllowUserToSelectMultipleRows) // disable drag { return; } if (e.Location.Y >= 0 && e.Location.Y <= ClientHeight) // if within window, no scroll { autoscroll.Stop(); } else if (!autoscroll.Running) { autoscroll.Start(50, 200); // else autoscroll } UpdateSelection(e.Location); lastmousemove = e.Location; } else { if (dgv.AllowUserToResizeColumns && e.Location.X >= Width + leftmargin) { Cursor = GLWindowControl.GLCursorType.EW; return; } GLDataGridView.RowColPos g; if (dgv.AllowUserToResizeRows && (g = contentpanel.GridRowCol(e.Location)) != null && g.Location.Y >= dgv.Rows[g.Row].Height - bottommargin) { Cursor = dgv.Rows[g.Row].AutoSize == false ? GLWindowControl.GLCursorType.NS : GLWindowControl.GLCursorType.Normal; return; } Cursor = GLWindowControl.GLCursorType.Normal; } }
private Tuple <ClickOn, int, Point> Over(Point p) { GLDataGridView dgv = Parent as GLDataGridView; int xoff = p.X + HorzScroll; if (dgv.AllowUserToResizeColumns) { foreach (var c in dgv.Columns) // horz part, col headers { int hoff = xoff - dgv.ColumnPixelLeft(c.Index); // System.Diagnostics.Debug.WriteLine($"loc {p} col {c.Index} {c.HeaderBounds} {hoff}"); if (hoff >= leftmargin && hoff <= rightmargin) { // System.Diagnostics.Debug.WriteLine($"Header mouse over divider {c.Index} {p}"); return(new Tuple <ClickOn, int, Point>(ClickOn.Divider, c.Index, Point.Empty)); } } if (dgv.Columns.Count > 0 && dgv.ColumnFillMode != GLDataGridView.ColFillMode.FillWidth) { int hoff = xoff - dgv.ColumnPixelRight(dgv.Columns.Count - 1); if (hoff >= leftmargin && hoff <= rightmargin) { return(new Tuple <ClickOn, int, Point>(ClickOn.Divider, dgv.Columns.Count, new Point(hoff, p.Y))); } } } if (p.Y >= Height - bottommargin && dgv.AllowUserToResizeColumnHeight) { return(new Tuple <ClickOn, int, Point>(ClickOn.Height, -1, Point.Empty)); } foreach (var c in dgv.Columns) // horz part, col headers { int left = dgv.ColumnPixelLeft(c.Index); if (xoff > left && xoff < left + c.Width) { // System.Diagnostics.Debug.WriteLine($"Header mouse over {c.Index} {p}"); return(new Tuple <ClickOn, int, Point>(ClickOn.Header, c.Index, new Point(xoff - left, p.Y))); } } return(null); }
// Get the cell from the rowcolpos, and set event args private GLDataGridViewCell CellPara(GLDataGridView.RowColPos g, GLMouseEventArgs e) { GLDataGridView dgv = Parent as GLDataGridView; if (g.Column < dgv.Rows[g.Row].CellCount) { var newcell = dgv.Rows[g.Row].Cells[g.Column]; e.Bounds = new Rectangle(g.CellLocation.X, g.CellLocation.Y, dgv.Columns[g.Column].Width, dgv.Rows[g.Row].Height); e.BoundsLocation = g.Location; e.Location = new Point(g.Location.X - newcell.Style.Padding.Left, g.Location.Y - newcell.Style.Padding.Top); return(newcell); } else { return(null); } }
protected override void OnMouseDown(GLMouseEventArgs e) { base.OnMouseDown(e); if (e.Button == GLMouseEventArgs.MouseButtons.Left) { GLDataGridView dgv = Parent as GLDataGridView; if (e.Location.X >= Width + leftmargin && dgv.AllowUserToResizeColumns) { dragging = 0; } else if (e.Location.Y >= Height - bottommargin && dgv.AllowUserToResizeColumnHeight) { dragging = 1; } } }
protected override void OnMouseUp(GLMouseEventArgs e) { base.OnMouseUp(e); autoscroll.Stop(); lastselectionstart = lastselectionend = selectionstart = null; if (e.Button == GLMouseEventArgs.MouseButtons.Left) { GLDataGridView dgv = Parent as GLDataGridView; var g = GridRowCol(e.Location); if (g != null) { var newcell = CellPara(g, e); // may return null if cell not there newcell?.OnMouseCellUp(e); } } }
protected override void Paint(Graphics gr) { GLDataGridView dgv = Parent as GLDataGridView; if (gridredraw) // do we need to redisplay { DrawTable(); gridredraw = false; } // the drawn rectangle is whats left of the bitmap after ScrollOffset.. Rectangle drawarea = new Rectangle(0, 0, LevelBitmap.Width - ScrollOffset.X, LevelBitmap.Height - ScrollOffset.Y); gr.DrawImage(LevelBitmap, drawarea, ScrollOffset.X, ScrollOffset.Y, drawarea.Width, drawarea.Height, GraphicsUnit.Pixel); if (rowheaderpanel.Visible) { rowheaderpanel.Redraw(ScrollOffset.Y); } }
protected override void OnMouseDown(GLMouseEventArgs e) { base.OnMouseDown(e); if (e.Button == GLMouseEventArgs.MouseButtons.Left) { GLDataGridView dgv = Parent as GLDataGridView; if (dgv.AllowUserToResizeColumns && e.Location.X >= Width + leftmargin) { dragging = -2; return; } var g = contentpanel.GridRowCol(e.Location); if (g != null) { //System.Diagnostics.Debug.WriteLine($"Grid {g.Row} {g.Column} {g.Location}"); if (dgv.AllowUserToResizeRows && g.Location.Y >= dgv.Rows[g.Row].Height - bottommargin) { dragging = g.Row; draggingstart = e.Location.Y - g.Location.Y; // compute where top line, based on location, would be } else if (dgv.AllowUserToSelectRows) { //System.Diagnostics.Debug.WriteLine($"Selection start on {g.Row}"); bool itwason = dgv.Rows[g.Row].Selected; dgv.ClearSelection(); if (!itwason) { lastselectionstart = lastselectionend = selectionstart = g.Row; dgv.Rows[selectionstart].Selected = true; } } } } }
protected override void Paint(Graphics gr) { GLDataGridView dgv = Parent as GLDataGridView; if (!dgv.ColumnHeaderEnable || dgv.Columns.Count == 0) { return; } int vpos = 0; using (Brush b = new SolidBrush(dgv.CellBorderColor)) { using (Pen p = new Pen(b, dgv.CellBorderWidth)) { int colright = dgv.ColumnPixelWidth - 1; gr.DrawLine(p, 0, vpos, colright, vpos); // draw across horz top vpos += dgv.ColumnHeaderHeight + dgv.CellBorderWidth; int hpos = -horzscroll; foreach (var c in dgv.Columns) // horz part, col headers { //System.Diagnostics.Debug.WriteLine($"Paint | {hpos}"); gr.DrawLine(p, hpos, 0, hpos, vpos); // draw verticle hpos += dgv.CellBorderWidth; Rectangle area = new Rectangle(hpos, dgv.CellBorderWidth, c.Width, dgv.ColumnHeaderHeight); c.Paint(gr, area); dgv.UserPaintColumnHeaders?.Invoke(c, gr, area); hpos += c.Width; } gr.DrawLine(p, hpos, 0, hpos, vpos); // last verticle } } }
protected override void OnMouseMove(GLMouseEventArgs e) { base.OnMouseMove(e); GLDataGridView dgv = Parent as GLDataGridView; if (dragging == 0) { dgv.RowHeaderWidth = e.Location.X; } else if (dragging == 1) { dgv.ColumnHeaderHeight = e.Location.Y; } else { Cursor = (e.Location.X >= Width + leftmargin && dgv.AllowUserToResizeColumns) ? GLWindowControl.GLCursorType.EW : (e.Location.Y >= Height - bottommargin && dgv.AllowUserToResizeColumnHeight) ? GLWindowControl.GLCursorType.NS : GLWindowControl.GLCursorType.Normal; } return; }
private void UpdateSelection(Point p) { var g = contentpanel.GridRowCol(p); if (g != null) { GLDataGridView dgv = Parent as GLDataGridView; int minrow = ObjectExtensionsNumbersBool.Min(lastselectionstart, lastselectionend, g.Row); int maxrow = ObjectExtensionsNumbersBool.Max(lastselectionstart, lastselectionend, g.Row); for (int i = minrow; i <= maxrow; i++) { dgv.Rows[i].Selected = g.Row < selectionstart ? i >= g.Row && i <= selectionstart : i >= selectionstart && i <= g.Row; } lastselectionstart = selectionstart; lastselectionend = g.Row; // System.Diagnostics.Debug.WriteLine($"Selection {lastselectionstart}..{selectionstart}..{lastselectionend}"); } }
protected override void OnMouseDown(GLMouseEventArgs e) { base.OnMouseDown(e); if (e.Button == GLMouseEventArgs.MouseButtons.Left) { var over = Over(e.Location); if (over != null) { GLDataGridView dgv = Parent as GLDataGridView; if (over.Item1 == ClickOn.Divider && dgv.AllowUserToResizeColumns) { dragging = over.Item2; initialrowheaderwidth = dgv.RowHeaderWidth; } else if (over.Item1 == ClickOn.Height && dgv.AllowUserToResizeColumnHeight) { dragging = -2; } } } }
protected override void OnMouseDown(GLMouseEventArgs e) { base.OnMouseDown(e); if (e.Button == GLMouseEventArgs.MouseButtons.Left) { GLDataGridView dgv = Parent as GLDataGridView; var g = GridRowCol(e.Location); if (g != null) { var newcell = CellPara(g, e); // may return null if cell not there newcell?.OnMouseCellDown(e); if (!e.Handled && dgv.AllowUserToSelectCells && g.Column < dgv.Rows[g.Row].CellCount) { lastselectionstart = lastselectionend = selectionstart = g; dgv.ClearSelection(); dgv.Rows[g.Row].Cells[g.Column].Selected = true; } } } }
private void DrawTable() { GLDataGridView dgv = Parent as GLDataGridView; //System.Diagnostics.Debug.WriteLine($"Redraw Table"); int backup = 10; while (true) { using (Graphics gr = Graphics.FromImage(LevelBitmap)) { gr.Clear(Color.Transparent); gridrowoffsets.Clear(); if (dgv.Columns.Count == 0 || dgv.Rows.Count == 0) { ScrollOffset = Point.Empty; rowheaderpanel.DrawEmpty(); return; } gridfirstline = Math.Max(0, firstdisplayindex - backup); // back up a little using (Brush b = new SolidBrush(dgv.CellBorderColor)) { using (Pen p = new Pen(b, dgv.CellBorderWidth)) { int gridwidth = dgv.ColumnPixelWidth - 1; // width of grid incl cell borders int vpos = 0; for (var rowno = gridfirstline; rowno < dgv.Rows.Count && vpos < LevelBitmap.Height; rowno++) { var row = dgv.Rows[rowno]; if (row.AutoSize) { dgv.PerformAutoSize(row); } gridrowoffsets.Add(vpos); // this row at this border line offset if (dgv.CellBorderWidth > 0) { gr.DrawLine(p, 0, vpos, gridwidth, vpos); // draw a line across the top vpos += dgv.CellBorderWidth; } int hpos = dgv.CellBorderWidth; for (int i = 0; i < dgv.Columns.Count; i++) { var col = dgv.Columns[i]; if (i < row.CellCount) { var cell = row.Cells[i]; Rectangle area = new Rectangle(hpos, vpos, col.Width, row.Height); cell.Paint(gr, area); } else { break; } hpos += col.Width + dgv.CellBorderWidth; } vpos += row.Height; // System.Diagnostics.Debug.WriteLine($"Row {rowno} Start {gridrowoffsets.Last()}..{vpos} bitmap H {LevelBitmap.Height}"); if (vpos < LevelBitmap.Height) { gridlastcompleteline = rowno; } } int endpos = Math.Min(vpos + 1, LevelBitmap.Height); // maximum height (not line) we drew to is vpos or the end of the bitmap gridrowoffsets.Add(endpos); // add final row vpos for searching purposes girddrawndepth = endpos; if (dgv.CellBorderWidth > 0) { gr.DrawLine(p, 0, vpos, gridwidth, vpos); // final bottom line int hpos = 0; for (int i = 0; i < dgv.Columns.Count; i++) { // System.Diagnostics.Debug.WriteLine($"Cell boundary {hpos}"); gr.DrawLine(p, hpos, 0, hpos, vpos); // each column one hpos += dgv.CellBorderWidth + dgv.Columns[i].Width; } gr.DrawLine(p, hpos, 0, hpos, vpos); // final one } } } if (firstdisplayindex > gridlastcompleteline) // if not got to first display index, backup too much, decrease { if (backup > 0) { backup /= 2; } else { System.Diagnostics.Debug.WriteLine($"DGV **** Error in drawing {firstdisplayindex} {gridfirstline} {gridlastcompleteline}"); return; } } else { int ystart = gridrowoffsets[firstdisplayindex - gridfirstline]; //System.Diagnostics.Debug.WriteLine($"Draw grid backed {backup} {LevelBitmapfirstline}..{firstdisplayindex}..{LevelBitmaplastcompleteline} {LevelBitmapdrawndepth}"); // if we backed up, and the backup is very large, we may not have enough bitmap to draw into to fill up the client area // this does not apply if we drew to the end // and stop it continuing forever just in case with backup>0 if (backup > 0 && gridlastcompleteline != dgv.Rows.Count - 1 && girddrawndepth < ystart + Height) // what we have drawn is less than ystart (y=0 on client) + client height { backup /= 2; } else { ScrollOffset = new Point(ScrollOffset.X, ystart); if (rowheaderpanel.Visible) { rowheaderpanel.DrawHeaders(gridfirstline, gridlastcompleteline + 1, girddrawndepth, ystart); } break; } } } } }
// we have just been layedout by parent, we know our size // set up columns protected override void PerformRecursiveLayout() { base.PerformRecursiveLayout(); GLDataGridView dgv = Parent as GLDataGridView; if (dgv.ColumnFillMode == GLDataGridView.ColFillMode.FillWidth) { int pixelsforborder = (dgv.Columns.Count + 1) * dgv.CellBorderWidth; int cellpixels = Width - pixelsforborder; float filltotalallcolumns = dgv.Columns.Select(x => x.FillWidth).Sum(); bool[] minwidths = new bool[dgv.Columns.Count]; float hfillfinaltotal = 0; foreach (var col in dgv.Columns) { int width = (int)(cellpixels * col.FillWidth / filltotalallcolumns); // candidate width for all columns if (width < col.MinimumWidth) // if less than min width, set it to that, take this column out of the fill equation { col.WidthNI = col.MinimumWidth; cellpixels -= col.Width; minwidths[col.Index] = true; //System.Diagnostics.Debug.WriteLine($"{col.Index} less than min width"); } else { hfillfinaltotal += col.FillWidth; } } //System.Diagnostics.Debug.WriteLine($"{hfillfinaltotal} cell pixels {cellpixels}"); int pixels = 0; foreach (var col in dgv.Columns) { if (!minwidths[col.Index]) // if not min width it, set it to the width, to the column minimum width { col.WidthNI = Math.Max(col.MinimumWidth, (int)(cellpixels * col.FillWidth / hfillfinaltotal)); // System.Diagnostics.Debug.WriteLine($"{col.Index} auto size to {col.Width}"); pixels += col.Width; } } // System.Diagnostics.Debug.WriteLine($"Cell pixels {cellpixels} total {pixels}"); int colno = 0; while (pixels < cellpixels && dgv.Columns.Count > 0) // add 1 pixel to each column in turn until back to count { dgv.Columns[colno].WidthNI += 1; // System.Diagnostics.Debug.WriteLine($"Distribute pixel to {colno}"); pixels++; colno = (colno + 1) % dgv.Columns.Count; } } else { // normal width fill ,just make sure not below min width foreach (var col in dgv.Columns) { if (col.Width < col.MinimumWidth) { col.WidthNI = col.MinimumWidth; } } } //int hpos = dgv.CellBorderWidth; foreach (var col in dgv.Columns) { System.Diagnostics.Debug.WriteLine($"Col {col.Index} {hpos} {col.Width}"); hpos += dgv.CellBorderWidth + col.Width; } int gridwidth = Math.Max(1, dgv.ColumnPixelWidth); // width of grid if (LevelBitmap == null || LevelBitmap.Width < gridwidth || LevelBitmap.Height < ClientHeight * 2) // if bitmap not there, or different width needed { MakeLevelBitmap(Math.Max(gridwidth, 10), Math.Max(Height * DepthMult, 10)); // System.Diagnostics.Debug.WriteLine($"Make Grid bitmap {LevelBitmap.Width} {LevelBitmap.Height}"); gridredraw = true; } }