Merge pull request #268 from pcc/menudeactivate
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TableLayoutPanel.cs
1 //
2 // TableLayoutPanel.cs
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Copyright (c) 2006 Jonathan Pobst
24 //
25 // Authors:
26 //      Jonathan Pobst (monkey@jpobst.com)
27 //
28
29 using System;
30 using System.Drawing;
31 using System.ComponentModel;
32 using System.Runtime.InteropServices;
33 using System.Windows.Forms.Layout;
34 using System.ComponentModel.Design.Serialization;
35
36 namespace System.Windows.Forms
37 {
38         [ComVisible (true)]
39         [ClassInterface (ClassInterfaceType.AutoDispatch)]
40         [ProvideProperty ("CellPosition", typeof (Control))]
41         [ProvideProperty ("Column", typeof (Control))]
42         [ProvideProperty ("ColumnSpan", typeof (Control))]
43         [ProvideProperty ("Row", typeof (Control))]
44         [ProvideProperty ("RowSpan", typeof (Control))]
45         [DefaultProperty ("ColumnCount")]
46         [Docking (DockingBehavior.Never)]
47         [Designer ("System.Windows.Forms.Design.TableLayoutPanelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
48         [DesignerSerializer ("System.Windows.Forms.Design.TableLayoutPanelCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
49         public class TableLayoutPanel : Panel, IExtenderProvider
50         {
51                 private TableLayoutSettings settings;
52                 private static TableLayout layout_engine = new TableLayout ();
53                 private TableLayoutPanelCellBorderStyle cell_border_style;
54
55                 // This is the row/column the Control actually got placed
56                 internal Control[,] actual_positions;
57                 
58                 // Widths and heights of each column/row
59                 internal int[] column_widths;
60                 internal int[] row_heights;
61
62                 #region Public Constructor
63                 public TableLayoutPanel ()
64                 {
65                         settings = new TableLayoutSettings(this);
66                         cell_border_style = TableLayoutPanelCellBorderStyle.None;
67                         column_widths = new int[0];
68                         row_heights = new int[0];
69                         CreateDockPadding ();
70                 }
71                 #endregion
72
73                 #region Public Properties
74                 [Localizable (true)]
75                 [Browsable (false)]
76                 [EditorBrowsable (EditorBrowsableState.Never)]
77                 new public BorderStyle BorderStyle {
78                         get { return base.BorderStyle; }
79                         set { base.BorderStyle = value; }
80                 }
81
82                 [Localizable (true)]
83                 [DefaultValue (TableLayoutPanelCellBorderStyle.None)]
84                 public TableLayoutPanelCellBorderStyle CellBorderStyle {
85                         get { return this.cell_border_style; }
86                         set { 
87                                 if (this.cell_border_style != value) {
88                                         this.cell_border_style = value;
89                                         this.PerformLayout (this, "CellBorderStyle");
90                                         this.Invalidate ();
91                                 }
92                         }
93                 }
94
95                 [Localizable (true)]
96                 [DefaultValue (0)]
97                 public int ColumnCount {
98                         get { return settings.ColumnCount; }
99                         set { settings.ColumnCount = value; }
100                 }
101
102                 [Browsable (false)]
103                 [DisplayName ("Columns")]
104                 [MergableProperty (false)]
105                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
106                 public TableLayoutColumnStyleCollection ColumnStyles {
107                         get { return settings.ColumnStyles; }
108                 }
109
110                 [Browsable (false)]
111                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
112                 new public TableLayoutControlCollection Controls {
113                         get { return (TableLayoutControlCollection) base.Controls; }
114                 }
115
116                 [DefaultValue (TableLayoutPanelGrowStyle.AddRows)]
117                 public TableLayoutPanelGrowStyle GrowStyle {
118                         get { return settings.GrowStyle; }
119                         set { settings.GrowStyle = value; }
120                 }
121
122                 public override System.Windows.Forms.Layout.LayoutEngine LayoutEngine {
123                         get { return TableLayoutPanel.layout_engine; }
124                 }
125
126                 [Browsable (false)]
127                 [EditorBrowsable (EditorBrowsableState.Never)]
128                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
129                 public TableLayoutSettings LayoutSettings {
130                         get { return this.settings; }
131                         set {
132                                 if (value.isSerialized) {
133                                         // Serialized version doesn't calculate these.
134                                         value.ColumnCount = value.ColumnStyles.Count;
135                                         value.RowCount = value.RowStyles.Count;
136                                         value.panel = this;
137                                         
138                                         this.settings = value;
139                                         value.isSerialized = false;
140                                 } else
141                                         throw new NotSupportedException ("LayoutSettings value cannot be set directly.");
142                         }
143                 }
144
145                 [Localizable (true)]
146                 [DefaultValue (0)]
147                 public int RowCount {
148                         get { return settings.RowCount; }
149                         set { settings.RowCount = value; }
150                 }
151
152                 [Browsable (false)]
153                 [DisplayName ("Rows")]
154                 [MergableProperty (false)]
155                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
156                 public TableLayoutRowStyleCollection RowStyles {
157                         get { return settings.RowStyles; }
158                 }
159                 #endregion
160
161                 #region Public Methods
162                 [DefaultValue (-1)]
163                 [DisplayName ("Cell")]
164                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
165                 public TableLayoutPanelCellPosition GetCellPosition (Control control)
166                 {
167                         return settings.GetCellPosition (control);
168                 }
169
170                 [DisplayName ("Column")]
171                 [DefaultValue (-1)]
172                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
173                 public int GetColumn (Control control)
174                 {
175                         return settings.GetColumn (control);
176                 }
177
178                 [DisplayName ("ColumnSpan")]
179                 [DefaultValue (1)]
180                 public int GetColumnSpan (Control control)
181                 {
182                         return settings.GetColumnSpan (control);
183                 }
184
185                 [Browsable (false)]
186                 [EditorBrowsable (EditorBrowsableState.Never)]
187                 public int[] GetColumnWidths ()
188                 {
189                         return this.column_widths;
190                 }
191
192                 public Control GetControlFromPosition (int column, int row)
193                 {
194                         if (column < 0 || row < 0)
195                                 throw new ArgumentException ();
196
197                         TableLayoutPanelCellPosition pos = new TableLayoutPanelCellPosition (column, row);
198
199                         foreach (Control c in this.Controls)
200                                 if (settings.GetCellPosition (c) == pos)
201                                         return c;
202
203                         return null;
204                 }
205
206                 public TableLayoutPanelCellPosition GetPositionFromControl (Control control)
207                 {
208                         for (int x = 0; x < this.actual_positions.GetLength (0); x++)
209                                 for (int y = 0; y < this.actual_positions.GetLength (1); y++)
210                                         if (this.actual_positions[x, y] == control)
211                                                 return new TableLayoutPanelCellPosition (x, y);
212
213                         return new TableLayoutPanelCellPosition (-1, -1);
214                 }
215
216                 [DisplayName ("Row")]
217                 [DefaultValue ("-1")]
218                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
219                 public int GetRow (Control control)
220                 {
221                         return settings.GetRow (control);
222                 }
223
224                 [Browsable (false)]
225                 [EditorBrowsable (EditorBrowsableState.Never)]
226                 public int[] GetRowHeights ()
227                 {
228                         return this.row_heights;
229                 }
230
231                 [DisplayName ("RowSpan")]
232                 [DefaultValue (1)]
233                 public int GetRowSpan (Control control)
234                 {
235                         return settings.GetRowSpan (control);
236                 }
237
238                 public void SetCellPosition (Control control, TableLayoutPanelCellPosition position)
239                 {
240                         settings.SetCellPosition (control, position);
241                 }
242
243                 public void SetColumn (Control control, int column)
244                 {
245                         settings.SetColumn (control, column);
246                 }
247
248                 public void SetColumnSpan (Control control, int value)
249                 {
250                         settings.SetColumnSpan (control, value);
251                 }
252
253                 public void SetRow (Control control, int row)
254                 {
255                         settings.SetRow (control, row);
256                 }
257
258                 public void SetRowSpan (Control control, int value)
259                 {
260                         settings.SetRowSpan (control, value);
261                 }
262                 #endregion
263
264                 #region Protected Methods
265                 [EditorBrowsable (EditorBrowsableState.Advanced)]
266                 protected override ControlCollection CreateControlsInstance ()
267                 {
268                         return new TableLayoutControlCollection (this);
269                 }
270
271                 protected virtual void OnCellPaint (TableLayoutCellPaintEventArgs e)
272                 {
273                         TableLayoutCellPaintEventHandler eh = (TableLayoutCellPaintEventHandler)(Events [CellPaintEvent]);
274                         if (eh != null)
275                                 eh (this, e);
276                 }
277
278                 [EditorBrowsable (EditorBrowsableState.Advanced)]
279                 protected override void OnLayout (LayoutEventArgs levent)
280                 {
281                         base.OnLayout (levent);
282                         Invalidate ();
283                 }
284
285                 protected override void OnPaintBackground (PaintEventArgs e)
286                 {
287                         base.OnPaintBackground (e);
288
289                         DrawCellBorders (e);
290                         
291                         int border_width = GetCellBorderWidth (CellBorderStyle);
292
293                         int x = border_width;
294                         int y = border_width;
295                         
296                         for (int i = 0; i < column_widths.Length; i++) {
297                                 for (int j = 0; j < row_heights.Length; j++) {
298                                         this.OnCellPaint (new TableLayoutCellPaintEventArgs (e.Graphics, e.ClipRectangle, new Rectangle (x, y, column_widths[i] + border_width, row_heights[j] + border_width), i, j));
299                                         y += row_heights[j] + border_width;
300                                 }
301
302                                 x += column_widths[i] + border_width;
303                                 y = border_width;
304                         }
305                 }
306
307                 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
308                 {
309                         base.ScaleControl (factor, specified);
310                 }
311                 
312                 [EditorBrowsable (EditorBrowsableState.Never)]
313                 protected override void ScaleCore (float dx, float dy)
314                 {
315                         base.ScaleCore (dx, dy);
316                 }
317                 #endregion
318
319                 #region Internal Methods
320                 internal static int GetCellBorderWidth (TableLayoutPanelCellBorderStyle style)
321                 {
322                         switch (style) {
323                                 case TableLayoutPanelCellBorderStyle.Single:
324                                         return 1;
325                                 case TableLayoutPanelCellBorderStyle.Inset:
326                                 case TableLayoutPanelCellBorderStyle.Outset:
327                                         return 2;
328                                 case TableLayoutPanelCellBorderStyle.InsetDouble:
329                                 case TableLayoutPanelCellBorderStyle.OutsetPartial:
330                                 case TableLayoutPanelCellBorderStyle.OutsetDouble:
331                                         return 3;
332                         }
333                         
334                         return 0;
335                 }
336                 
337                 private void DrawCellBorders (PaintEventArgs e)
338                 {
339                         Rectangle paint_here = new Rectangle (Point.Empty, this.Size);
340
341                         switch (CellBorderStyle) {
342                                 case TableLayoutPanelCellBorderStyle.Single:
343                                         DrawSingleBorder (e.Graphics, paint_here);
344                                         break;
345                                 case TableLayoutPanelCellBorderStyle.Inset:
346                                         DrawInsetBorder (e.Graphics, paint_here);
347                                         break;
348                                 case TableLayoutPanelCellBorderStyle.InsetDouble:
349                                         DrawInsetDoubleBorder (e.Graphics, paint_here);
350                                         break;
351                                 case TableLayoutPanelCellBorderStyle.Outset:
352                                         DrawOutsetBorder (e.Graphics, paint_here);
353                                         break;
354                                 case TableLayoutPanelCellBorderStyle.OutsetDouble:
355                                 case TableLayoutPanelCellBorderStyle.OutsetPartial:
356                                         DrawOutsetDoubleBorder (e.Graphics, paint_here);
357                                         break;
358                         }
359                 }
360
361                 private void DrawSingleBorder (Graphics g, Rectangle rect)
362                 {
363                         ControlPaint.DrawBorder (g, rect, SystemColors.ControlDark, ButtonBorderStyle.Solid);
364
365                         int x = DisplayRectangle.X;
366                         int y = DisplayRectangle.Y;
367
368                         for (int i = 0; i < column_widths.Length - 1; i++) {
369                                 x += column_widths[i] + 1;
370
371                                 g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 2));
372                         }
373
374                         for (int j = 0; j < row_heights.Length - 1; j++) {
375                                 y += row_heights[j] + 1;
376
377                                 g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 2, y));
378                         }
379                 }
380
381                 private void DrawInsetBorder (Graphics g, Rectangle rect)
382                 {
383                         ControlPaint.DrawBorder3D (g, rect, Border3DStyle.Etched);
384                         
385                         int x = DisplayRectangle.X;
386                         int y = DisplayRectangle.Y;
387
388                         for (int i = 0; i < column_widths.Length - 1; i++) {
389                                 x += column_widths[i] + 2;
390
391                                 g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 3));
392                                 g.DrawLine (Pens.White, new Point (x + 1, 1), new Point (x + 1, Bottom - 3));
393                         }
394
395                         for (int j = 0; j < row_heights.Length - 1; j++) {
396                                 y += row_heights[j] + 2;
397
398                                 g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 3, y));
399                                 g.DrawLine (Pens.White, new Point (1, y + 1), new Point (Right - 3, y + 1));
400                         }
401                 }
402
403                 private void DrawOutsetBorder (Graphics g, Rectangle rect)
404                 {
405                         g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 1, rect.Top + 1, rect.Width - 2, rect.Height - 2));
406                         g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2));
407
408                         int x = DisplayRectangle.X;
409                         int y = DisplayRectangle.Y;
410
411                         for (int i = 0; i < column_widths.Length - 1; i++) {
412                                 x += column_widths[i] + 2;
413
414                                 g.DrawLine (Pens.White, new Point (x, 1), new Point (x, Bottom - 3));
415                                 g.DrawLine (SystemPens.ControlDark, new Point (x + 1, 1), new Point (x + 1, Bottom - 3));
416                         }
417
418                         for (int j = 0; j < row_heights.Length - 1; j++) {
419                                 y += row_heights[j] + 2;
420
421                                 g.DrawLine (Pens.White, new Point (1, y), new Point (Right - 3, y));
422                                 g.DrawLine (SystemPens.ControlDark, new Point (1, y + 1), new Point (Right - 3, y + 1));
423                         }
424                 }
425
426                 private void DrawOutsetDoubleBorder (Graphics g, Rectangle rect)
427                 {
428                         rect.Width -= 1;
429                         rect.Height -= 1;
430                         
431                         g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2));
432                         g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2));
433
434                         int x = DisplayRectangle.X;
435                         int y = DisplayRectangle.Y;
436
437                         for (int i = 0; i < column_widths.Length - 1; i++) {
438                                 x += column_widths[i] + 3;
439
440                                 g.DrawLine (Pens.White, new Point (x, 3), new Point (x, Bottom - 5));
441                                 g.DrawLine (SystemPens.ControlDark, new Point (x + 2, 3), new Point (x + 2, Bottom - 5));
442                         }
443
444                         for (int j = 0; j < row_heights.Length - 1; j++) {
445                                 y += row_heights[j] + 3;
446
447                                 g.DrawLine (Pens.White, new Point (3, y), new Point (Right - 4, y));
448                                 g.DrawLine (SystemPens.ControlDark, new Point (3, y + 2), new Point (Right - 4, y + 2));
449                         }
450
451                         x = DisplayRectangle.X;
452                         y = DisplayRectangle.Y;
453
454                         for (int i = 0; i < column_widths.Length - 1; i++) {
455                                 x += column_widths[i] + 3;
456
457                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5));
458                         }
459
460                         for (int j = 0; j < row_heights.Length - 1; j++) {
461                                 y += row_heights[j] + 3;
462
463                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1));
464                         }
465                 }
466         
467                 private void DrawInsetDoubleBorder (Graphics g, Rectangle rect)
468                 {
469                         rect.Width -= 1;
470                         rect.Height -= 1;
471                         
472                         g.DrawRectangle (Pens.White, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2));
473                         g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2));
474
475                         int x = DisplayRectangle.X;
476                         int y = DisplayRectangle.Y;
477
478                         for (int i = 0; i < column_widths.Length - 1; i++) {
479                                 x += column_widths[i] + 3;
480
481                                 g.DrawLine (SystemPens.ControlDark, new Point (x, 3), new Point (x, Bottom - 5));
482                                 g.DrawLine (Pens.White, new Point (x + 2, 3), new Point (x + 2, Bottom - 5));
483                         }
484
485                         for (int j = 0; j < row_heights.Length - 1; j++) {
486                                 y += row_heights[j] + 3;
487
488                                 g.DrawLine (SystemPens.ControlDark, new Point (3, y), new Point (Right - 4, y));
489                                 g.DrawLine (Pens.White, new Point (3, y + 2), new Point (Right - 4, y + 2));
490                         }
491
492                         x = DisplayRectangle.X;
493                         y = DisplayRectangle.Y;
494                         
495                         for (int i = 0; i < column_widths.Length - 1; i++) {
496                                 x += column_widths[i] + 3;
497
498                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5));
499                         }
500
501                         for (int j = 0; j < row_heights.Length - 1; j++) {
502                                 y += row_heights[j] + 3;
503
504                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1));
505                         }
506                 }
507
508                 internal override Size GetPreferredSizeCore (Size proposedSize)
509                 {
510                         // If the tablelayoutowner is autosize, we have to make sure it is big enough
511                         // to hold every non-autosize control
512                         actual_positions = (LayoutEngine as TableLayout).CalculateControlPositions (this, Math.Max (ColumnCount, 1), Math.Max (RowCount, 1));
513                         
514                         // Use actual row/column counts, not user set ones
515                         int actual_cols = actual_positions.GetLength (0);
516                         int actual_rows = actual_positions.GetLength (1);
517                         
518                         // Figure out how wide the owner needs to be
519                         int[] column_widths = new int[actual_cols];
520                         float total_column_percentage = 0f;
521                         
522                         // Figure out how tall each column wants to be
523                         for (int i = 0; i < actual_cols; i++) {
524                                 if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent)
525                                         total_column_percentage += ColumnStyles[i].Width;
526                                         
527                                 int biggest = 0;
528
529                                 for (int j = 0; j < actual_rows; j++) {
530                                         Control c = actual_positions[i, j];
531
532                                         if (c != null) {
533                                                 if (!c.AutoSize)
534                                                         biggest = Math.Max (biggest, c.ExplicitBounds.Width + c.Margin.Horizontal + Padding.Horizontal);
535                                                 else
536                                                         biggest = Math.Max (biggest, c.PreferredSize.Width + c.Margin.Horizontal + Padding.Horizontal);
537                                         }
538                                 }
539
540                                 column_widths[i] = biggest;
541                         }
542
543                         // Because percentage based rows divy up the remaining space,
544                         // we have to make the owner big enough so that all the rows
545                         // get bigger, even if we only need one to be bigger.
546                         int non_percent_total_width = 0;
547                         int percent_total_width = 0;
548
549                         for (int i = 0; i < actual_cols; i++) {
550                                 if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent)
551                                         percent_total_width = Math.Max (percent_total_width, (int)(column_widths[i] / ((ColumnStyles[i].Width) / total_column_percentage)));
552                                 else
553                                         non_percent_total_width += column_widths[i];
554                         }
555
556
557                         // Figure out how tall the owner needs to be
558                         int[] row_heights = new int[actual_rows];
559                         float total_row_percentage = 0f;
560                 
561                         // Figure out how tall each row wants to be
562                         for (int j = 0; j < actual_rows; j++) {
563                                 if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent)
564                                         total_row_percentage += RowStyles[j].Height;
565                                         
566                                 int biggest = 0;
567                                 
568                                 for (int i = 0; i < actual_cols; i++) {
569                                         Control c = actual_positions[i, j];
570
571                                         if (c != null) {
572                                                 if (!c.AutoSize)
573                                                         biggest = Math.Max (biggest, c.ExplicitBounds.Height + c.Margin.Vertical + Padding.Vertical);
574                                                 else
575                                                         biggest = Math.Max (biggest, c.PreferredSize.Height + c.Margin.Vertical + Padding.Vertical);
576                                         }
577                                 }
578
579                                 row_heights[j] = biggest;
580                         }
581                         
582                         // Because percentage based rows divy up the remaining space,
583                         // we have to make the owner big enough so that all the rows
584                         // get bigger, even if we only need one to be bigger.
585                         int non_percent_total_height = 0;
586                         int percent_total_height = 0;
587
588                         for (int j = 0; j < actual_rows; j++) {
589                                 if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent)
590                                         percent_total_height = Math.Max (percent_total_height, (int)(row_heights[j] / ((RowStyles[j].Height) / total_row_percentage)));
591                                 else
592                                         non_percent_total_height += row_heights[j];
593                         }
594
595                         int border_width = GetCellBorderWidth (CellBorderStyle);
596                         return new Size (non_percent_total_width + percent_total_width + (border_width * (actual_cols + 1)), non_percent_total_height + percent_total_height + (border_width * (actual_rows + 1)));
597                 }
598                 #endregion
599                 
600                 #region Public Events
601                 static object CellPaintEvent = new object ();
602
603                 public event TableLayoutCellPaintEventHandler CellPaint {
604                         add { Events.AddHandler (CellPaintEvent, value); }
605                         remove { Events.RemoveHandler (CellPaintEvent, value); }
606                 }
607                 #endregion
608                 
609                 #region IExtenderProvider
610                 bool IExtenderProvider.CanExtend (object obj)
611                 {
612                         if (obj is Control)
613                                 if ((obj as Control).Parent == this)
614                                         return true;
615
616                         return false;
617                 }
618                 #endregion
619                 
620         }
621 }