1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
23 // Jordi Mas i Hernandez <jordi@ximian.com>
25 // Datagrid drawing logic
31 using System.Drawing.Drawing2D;
33 namespace System.Windows.Forms
35 internal class DataGridDrawing
37 #region Local Variables
39 private DataGrid grid;
42 internal Rectangle caption_area;
43 internal Rectangle parent_rows;
44 internal Rectangle columnshdrs_area; // Used columns header area
45 internal int columnshdrs_maxwidth; // Total width (max width) for columns headrs
46 internal Rectangle rowshdrs_area; // Used Headers rows area
47 internal int rowshdrs_maxheight; // Total height for rows (max height)
48 internal Rectangle cells_area;
49 internal Font font_newrow = new Font (FontFamily.GenericSansSerif, 16);
50 #endregion // Local Variables
53 public DataGridDrawing (DataGrid datagrid)
58 #region Public Instance Methods
60 // Calc the max with of all columns
61 internal int CalcAllColumnsWidth ()
64 int cnt = grid.CurrentTableStyle.GridColumnStyles.Count;
66 for (int col = 0; col < cnt; col++) {
67 width += grid.CurrentTableStyle.GridColumnStyles[col].Width;
73 // Gets a column from a pixel
74 public int FromPixelToColumn (int pixel)
77 int cnt = grid.CurrentTableStyle.GridColumnStyles.Count;
82 if (grid.CurrentTableStyle.CurrentRowHeadersVisible)
83 width += rowshdrs_area.X + rowshdrs_area.Width;
85 for (int col = 0; col < cnt; col++) {
86 width += grid.CurrentTableStyle.GridColumnStyles[col].Width;
96 public int GetColumnStartingPixel (int my_col)
99 int cnt = grid.CurrentTableStyle.GridColumnStyles.Count;
101 for (int col = 0; col < cnt; col++) {
106 width += grid.CurrentTableStyle.GridColumnStyles[col].Width;
112 // Which column has to be the first visible column to ensure a column visibility
113 public int GetFirstColumnForColumnVisilibility (int current_first_visiblecolumn, int column)
115 int new_col = column;
118 if (column > current_first_visiblecolumn) { // Going forward
119 for (new_col = column; new_col >= 0; new_col--){
120 width += grid.CurrentTableStyle.GridColumnStyles[new_col].Width;
122 if (width >= cells_area.Width)
124 //return new_col < grid.CurrentTableStyle.GridColumnStyles.Count ? new_col + 1 : grid.CurrentTableStyle.GridColumnStyles.Count;
132 public void CalcGridAreas ()
134 if (grid.IsHandleCreated == false) // Delay calculations until the handle is created
137 /* Order is important. E.g. row headers max. height depends on caption */
138 grid.horz_pixeloffset = 0;
142 CalcColumnsHeader ();
145 UpdateVisibleRowCount (); // need it to be able to calcultate the need of horz scrollbar
146 if (SetUpVerticalScrollBar ()) { // We need a Vertical ScrollBar
148 if (grid.ShowParentRowsVisible) {
149 parent_rows.Width -= grid.vert_scrollbar.Width;
152 if (grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0) {
153 if (columnshdrs_area.X + columnshdrs_area.Width > grid.vert_scrollbar.Location.X) {
154 columnshdrs_area.Width -= grid.vert_scrollbar.Width;
158 if (cells_area.X + cells_area.Width >= grid.vert_scrollbar.Location.X) {
159 cells_area.Width -= grid.vert_scrollbar.Width;
163 if (SetUpHorizontalScrollBar ()) { // We need a Horizontal ScrollBar
164 cells_area.Height -= grid.horiz_scrollbar.Height;
166 if (rowshdrs_area.Y + rowshdrs_area.Height > grid.ClientRectangle.Y + grid.ClientRectangle.Height) {
167 rowshdrs_area.Height -= grid.horiz_scrollbar.Height;
168 rowshdrs_maxheight -= grid.horiz_scrollbar.Height;
172 // Reajust scrollbars to avoid overlapping at the corners
173 if (grid.vert_scrollbar.Visible && grid.horiz_scrollbar.Visible) {
174 grid.horiz_scrollbar.Width -= grid.vert_scrollbar.Width;
175 grid.vert_scrollbar.Height -= grid.horiz_scrollbar.Height;
178 UpdateVisibleColumn ();
179 UpdateVisibleRowCount ();
181 //Console.WriteLine ("DataGridDrawing.CalcGridAreas caption_area:{0}", caption_area);
182 //Console.WriteLine ("DataGridDrawing.CalcGridAreas parent_rows:{0}", parent_rows);
183 //Console.WriteLine ("DataGridDrawing.CalcGridAreas rowshdrs_area:{0}", rowshdrs_area);
184 //Console.WriteLine ("DataGridDrawing.CalcGridAreas columnshdrs_area:{0}", columnshdrs_area);
185 //Console.WriteLine ("DataGridDrawing.CalcGridAreas cells:{0}", cells_area);
188 public void CalcCaption ()
190 if (grid.caption_visible == false) {
191 caption_area = Rectangle.Empty;
195 caption_area.X = grid.ClientRectangle.X;
196 caption_area.Y = grid.ClientRectangle.Y;
197 caption_area.Width = grid.ClientRectangle.Width;
198 caption_area.Height = grid.CaptionFont.Height + 6;
200 //Console.WriteLine ("DataGridDrawing.CalcCaption {0}", caption_area);
203 public void CalcCellsArea ()
205 if (grid.caption_visible) {
206 cells_area.Y = caption_area.Y + caption_area.Height;
208 cells_area.Y = grid.ClientRectangle.Y;
211 if (grid.ShowParentRowsVisible) {
212 cells_area.Y += parent_rows.Height;
215 if (!(grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0)) {
216 cells_area.Y += columnshdrs_area.Height;
219 cells_area.X = grid.ClientRectangle.X + rowshdrs_area.Width;
220 cells_area.Width = grid.ClientRectangle.X + grid.ClientRectangle.Width - cells_area.X;
221 cells_area.Height = grid.ClientRectangle.Y + grid.ClientRectangle.Height - cells_area.Y;
223 //Console.WriteLine ("DataGridDrawing.CalcCellsArea {0}", cells_area);
226 public void CalcColumnsHeader ()
228 int width_all_cols, max_width_cols;
230 if (grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0) {
231 columnshdrs_area = Rectangle.Empty;
235 if (grid.caption_visible) {
236 columnshdrs_area.Y = caption_area.Y + caption_area.Height;
238 columnshdrs_area.Y = grid.ClientRectangle.Y;
241 if (grid.ShowParentRowsVisible) {
242 columnshdrs_area.Y += parent_rows.Height;
245 columnshdrs_area.X = grid.ClientRectangle.X;
246 columnshdrs_area.Height = ColumnsHeaderHeight;
247 width_all_cols = CalcAllColumnsWidth ();
249 // TODO: take into account Scrollbars
250 columnshdrs_maxwidth = grid.ClientRectangle.X + grid.ClientRectangle.Width - columnshdrs_area.X;
251 max_width_cols = columnshdrs_maxwidth;
253 if (grid.CurrentTableStyle.CurrentRowHeadersVisible) {
254 max_width_cols -= grid.RowHeaderWidth;
257 if (width_all_cols > max_width_cols) {
258 columnshdrs_area.Width = columnshdrs_maxwidth;
260 columnshdrs_area.Width = width_all_cols;
262 if (grid.CurrentTableStyle.CurrentRowHeadersVisible) {
263 columnshdrs_area.Width += grid.RowHeaderWidth;
267 //Console.WriteLine ("DataGridDrawing.CalcColumnsHeader {0}", columnshdrs_area);
270 public void CalcParentRows ()
272 if (grid.ShowParentRowsVisible == false) {
273 parent_rows = Rectangle.Empty;
277 if (grid.caption_visible) {
278 parent_rows.Y = caption_area.Y + caption_area.Height;
281 parent_rows.Y = grid.ClientRectangle.Y;
284 parent_rows.X = grid.ClientRectangle.X;
285 parent_rows.Width = grid.ClientRectangle.Width;
286 parent_rows.Height = grid.CaptionFont.Height + 3;
288 //Console.WriteLine ("DataGridDrawing.CalcParentRows {0}", parent_rows);
291 public void CalcRowsHeaders ()
293 if (grid.CurrentTableStyle.CurrentRowHeadersVisible == false) {
294 rowshdrs_area = Rectangle.Empty;
298 if (grid.caption_visible) {
299 rowshdrs_area.Y = caption_area.Y + caption_area.Height;
301 rowshdrs_area.Y = grid.ClientRectangle.Y;
304 if (grid.ShowParentRowsVisible) {
305 rowshdrs_area.Y += parent_rows.Height;
308 if (!(grid.columnheaders_visible == false || grid.CurrentTableStyle.GridColumnStyles.Count == 0)) { // first block is painted by ColumnHeader
309 rowshdrs_area.Y += ColumnsHeaderHeight;
312 rowshdrs_area.X = grid.ClientRectangle.X;
313 rowshdrs_area.Width = grid.RowHeaderWidth;
314 rowshdrs_area.Height = grid.visiblerow_count * grid.RowHeight;
315 rowshdrs_maxheight = grid.ClientRectangle.Height + grid.ClientRectangle.Y - rowshdrs_area.Y;
317 //Console.WriteLine ("DataGridDrawing.CalcRowsHeaders {0} {1}", rowshdrs_area,
318 // rowshdrs_maxheight);
321 public void UpdateVisibleColumn ()
323 if (grid.CurrentTableStyle.GridColumnStyles.Count == 0) {
324 grid.visiblecolumn_count = 0;
329 int max_pixel = grid.horz_pixeloffset + cells_area.Width;
330 grid.first_visiblecolumn = FromPixelToColumn (grid.horz_pixeloffset);
332 col = FromPixelToColumn (max_pixel);
334 grid.visiblecolumn_count = 1 + col - grid.first_visiblecolumn;
336 if (grid.first_visiblecolumn + grid.visiblecolumn_count + 1 < grid.CurrentTableStyle.GridColumnStyles.Count) {
337 grid.visiblecolumn_count++; // Partially visible column
341 public void UpdateVisibleRowCount ()
343 int max_height = cells_area.Height;
344 int total_rows = grid.RowsCount;
346 if (grid.ShowEditRow && grid.RowsCount > 0) {
350 int rows_height = (total_rows - grid.first_visiblerow) * grid.RowHeight;
351 int max_rows = max_height / grid.RowHeight;
353 if (max_rows > total_rows) {
354 max_rows = total_rows;
357 if (rows_height > cells_area.Height) {
358 grid.visiblerow_count = max_rows;
360 grid.visiblerow_count = total_rows;
363 CalcRowsHeaders (); // Height depends on num of visible rows
365 if (grid.visiblerow_count + grid.first_visiblerow > total_rows)
366 grid.visiblerow_count = total_rows - grid.first_visiblerow;
368 if (grid.visiblerow_count < max_rows) {
369 grid.visiblerow_count = max_rows;
370 grid.first_visiblerow = total_rows - max_rows;
376 // From Point to Cell
377 public DataGrid.HitTestInfo HitTest (int x, int y)
379 DataGrid.HitTestInfo hit = new DataGrid.HitTestInfo ();
381 // TODO: Add missing ColumnResize and RowResize checks
382 if (columnshdrs_area.Contains (x, y)) {
383 hit.type = DataGrid.HitTestType.ColumnHeader;
384 hit.column = FromPixelToColumn (x + grid.horz_pixeloffset);
388 if (rowshdrs_area.Contains (x, y)) {
389 hit.type = DataGrid.HitTestType.RowHeader;
391 int rcnt = grid.FirstVisibleRow + grid.VisibleRowCount;
392 for (int r = grid.FirstVisibleRow; r < rcnt; r++) {
393 posy = cells_area.Y + ((r - grid.FirstVisibleRow) * grid.RowHeight);
394 if (y <= posy + grid.RowHeight) { // Found row
402 if (caption_area.Contains (x, y)) {
403 hit.type = DataGrid.HitTestType.Caption;
407 if (parent_rows.Contains (x, y)) {
408 hit.type = DataGrid.HitTestType.ParentRows;
412 int pos_y, pos_x, width;
413 int rowcnt = grid.FirstVisibleRow + grid.VisibleRowCount;
414 for (int row = grid.FirstVisibleRow; row < rowcnt; row++) {
415 pos_y = cells_area.Y + ((row - grid.FirstVisibleRow) * grid.RowHeight);
417 if (y <= pos_y + grid.RowHeight) { // Found row
419 hit.type = DataGrid.HitTestType.Cell;
421 int column_cnt = grid.first_visiblecolumn + grid.visiblecolumn_count;
422 for (int column = grid.first_visiblecolumn; column < column_cnt; column++) {
424 col_pixel = GetColumnStartingPixel (column);
425 pos_x = cells_area.X + col_pixel - grid.horz_pixeloffset;
426 width = grid.CurrentTableStyle.GridColumnStyles[column].Width;
428 if (x <= pos_x + width) { // Column found
441 public Rectangle GetCellBounds (int row, int col)
443 Rectangle bounds = new Rectangle ();
446 bounds.Width = grid.CurrentTableStyle.GridColumnStyles[col].Width;
447 bounds.Height = grid.RowHeight;
448 bounds.Y = cells_area.Y + ((row - grid.FirstVisibleRow) * grid.RowHeight);
449 col_pixel = GetColumnStartingPixel (col);
450 bounds.X = cells_area.X + col_pixel - grid.horz_pixeloffset;
454 public void InvalidateCaption ()
456 if (caption_area.IsEmpty)
459 grid.Invalidate (caption_area);
463 public void InvalidateRow (int row)
465 if (row < grid.FirstVisibleRow || row > grid.FirstVisibleRow + grid.VisibleRowCount) {
469 Rectangle rect_row = new Rectangle ();
471 rect_row.X = cells_area.X;
472 rect_row.Width = cells_area.Width;
473 rect_row.Height = grid.RowHeight;
474 rect_row.Y = cells_area.Y + ((row - grid.FirstVisibleRow) * grid.RowHeight);
475 grid.Invalidate (rect_row);
478 public void InvalidateRowHeader (int row)
480 Rectangle rect_rowhdr = new Rectangle ();
481 rect_rowhdr.X = rowshdrs_area.X;
482 rect_rowhdr.Width = rowshdrs_area.Width;
483 rect_rowhdr.Height = grid.RowHeight;
484 rect_rowhdr.Y = rowshdrs_area.Y + ((row - grid.FirstVisibleRow) * grid.RowHeight);
485 grid.Invalidate (rect_rowhdr);
488 public void InvalidateColumn (DataGridColumnStyle column)
490 Rectangle rect_col = new Rectangle ();
494 col = grid.CurrentTableStyle.GridColumnStyles.IndexOf (column);
500 rect_col.Width = column.Width;
501 col_pixel = GetColumnStartingPixel (col);
502 rect_col.X = cells_area.X + col_pixel - grid.horz_pixeloffset;
503 rect_col.Y = cells_area.Y;
504 rect_col.Height = cells_area.Height;
505 grid.Invalidate (rect_col);
508 // Return true if the scrollbar is needed
509 public bool SetUpHorizontalScrollBar ()
511 int width_all = CalcAllColumnsWidth ();
513 if (width_all <= cells_area.Width) {
514 grid.horiz_scrollbar.Visible = false;
515 grid.Controls.Remove (grid.horiz_scrollbar);
519 grid.horiz_scrollbar.Location = new Point (grid.ClientRectangle.X, grid.ClientRectangle.Y +
520 grid.ClientRectangle.Height - grid.horiz_scrollbar.Height);
522 grid.horiz_scrollbar.Size = new Size (grid.ClientRectangle.Width,
523 grid.horiz_scrollbar.Height);
525 grid.horiz_scrollbar.Maximum = width_all;// - cells_area.Width;
526 grid.horiz_scrollbar.LargeChange = cells_area.Width;
527 grid.Controls.Add (grid.horiz_scrollbar);
528 grid.horiz_scrollbar.Visible = true;
532 // Return true if the scrollbar is needed
533 public bool SetUpVerticalScrollBar ()
536 int allrows = grid.RowsCount;
538 if (grid.ShowEditRow && grid.RowsCount > 0) {
542 if (grid.visiblerow_count == allrows) {
543 grid.vert_scrollbar.Visible = false;
544 grid.Controls.Remove (grid.vert_scrollbar);
548 if (grid.caption_visible) {
549 y = grid.ClientRectangle.Y + caption_area.Height;
550 height = grid.ClientRectangle.Height - caption_area.Height;
552 y = grid.ClientRectangle.Y;
553 height = grid.ClientRectangle.Height;
556 grid.vert_scrollbar.Location = new Point (grid.ClientRectangle.X +
557 grid.ClientRectangle.Width - grid.vert_scrollbar.Width, y);
559 grid.vert_scrollbar.Size = new Size (grid.vert_scrollbar.Width,
562 grid.vert_scrollbar.Maximum = grid.RowsCount;
564 if (grid.ShowEditRow && grid.RowsCount > 0) {
565 grid.vert_scrollbar.Maximum++;
568 grid.vert_scrollbar.LargeChange = VLargeChange;
570 grid.Controls.Add (grid.vert_scrollbar);
571 grid.vert_scrollbar.Visible = true;
575 #endregion // Public Instance Methods
577 #region Instance Properties
578 public Rectangle CellsArea {
584 // Returns the ColumnsHeader area excluding the rectangle shared with RowsHeader
585 public Rectangle ColumnsHeadersArea {
587 Rectangle columns_area = columnshdrs_area;
589 if (grid.CurrentTableStyle.CurrentRowHeadersVisible) {
590 columns_area.X += grid.RowHeaderWidth;
591 columns_area.Width -= grid.RowHeaderWidth;
597 public int ColumnsHeaderHeight {
599 return grid.CurrentTableStyle.HeaderFont.Height + 6;
603 public Rectangle RowsHeadersArea {
605 return rowshdrs_area;
609 public int VLargeChange {
611 return cells_area.Height / grid.RowHeight;
615 #endregion Instance Properties