Merge pull request #1442 from ermshiperete/TextOverlapsImage
[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                                 } else
140                                         throw new NotSupportedException ("LayoutSettings value cannot be set directly.");
141                         }
142                 }
143
144                 [Localizable (true)]
145                 [DefaultValue (0)]
146                 public int RowCount {
147                         get { return settings.RowCount; }
148                         set { settings.RowCount = value; }
149                 }
150
151                 [Browsable (false)]
152                 [DisplayName ("Rows")]
153                 [MergableProperty (false)]
154                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
155                 public TableLayoutRowStyleCollection RowStyles {
156                         get { return settings.RowStyles; }
157                 }
158                 #endregion
159
160                 #region Public Methods
161                 [DefaultValue (-1)]
162                 [DisplayName ("Cell")]
163                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
164                 public TableLayoutPanelCellPosition GetCellPosition (Control control)
165                 {
166                         return settings.GetCellPosition (control);
167                 }
168
169                 [DisplayName ("Column")]
170                 [DefaultValue (-1)]
171                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
172                 public int GetColumn (Control control)
173                 {
174                         return settings.GetColumn (control);
175                 }
176
177                 [DisplayName ("ColumnSpan")]
178                 [DefaultValue (1)]
179                 public int GetColumnSpan (Control control)
180                 {
181                         return settings.GetColumnSpan (control);
182                 }
183
184                 [Browsable (false)]
185                 [EditorBrowsable (EditorBrowsableState.Never)]
186                 public int[] GetColumnWidths ()
187                 {
188                         return this.column_widths;
189                 }
190
191                 public Control GetControlFromPosition (int column, int row)
192                 {
193                         if (column < 0 || row < 0)
194                                 throw new ArgumentException ();
195
196                         TableLayoutPanelCellPosition pos = new TableLayoutPanelCellPosition (column, row);
197
198                         foreach (Control c in this.Controls)
199                                 if (settings.GetCellPosition (c) == pos)
200                                         return c;
201
202                         return null;
203                 }
204
205                 public TableLayoutPanelCellPosition GetPositionFromControl (Control control)
206                 {
207                         for (int x = 0; x < this.actual_positions.GetLength (0); x++)
208                                 for (int y = 0; y < this.actual_positions.GetLength (1); y++)
209                                         if (this.actual_positions[x, y] == control)
210                                                 return new TableLayoutPanelCellPosition (x, y);
211
212                         return new TableLayoutPanelCellPosition (-1, -1);
213                 }
214
215                 [DisplayName ("Row")]
216                 [DefaultValue ("-1")]
217                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
218                 public int GetRow (Control control)
219                 {
220                         return settings.GetRow (control);
221                 }
222
223                 [Browsable (false)]
224                 [EditorBrowsable (EditorBrowsableState.Never)]
225                 public int[] GetRowHeights ()
226                 {
227                         return this.row_heights;
228                 }
229
230                 [DisplayName ("RowSpan")]
231                 [DefaultValue (1)]
232                 public int GetRowSpan (Control control)
233                 {
234                         return settings.GetRowSpan (control);
235                 }
236
237                 public void SetCellPosition (Control control, TableLayoutPanelCellPosition position)
238                 {
239                         settings.SetCellPosition (control, position);
240                 }
241
242                 public void SetColumn (Control control, int column)
243                 {
244                         settings.SetColumn (control, column);
245                 }
246
247                 public void SetColumnSpan (Control control, int value)
248                 {
249                         settings.SetColumnSpan (control, value);
250                 }
251
252                 public void SetRow (Control control, int row)
253                 {
254                         settings.SetRow (control, row);
255                 }
256
257                 public void SetRowSpan (Control control, int value)
258                 {
259                         settings.SetRowSpan (control, value);
260                 }
261                 #endregion
262
263                 #region Protected Methods
264                 [EditorBrowsable (EditorBrowsableState.Advanced)]
265                 protected override ControlCollection CreateControlsInstance ()
266                 {
267                         return new TableLayoutControlCollection (this);
268                 }
269
270                 protected virtual void OnCellPaint (TableLayoutCellPaintEventArgs e)
271                 {
272                         TableLayoutCellPaintEventHandler eh = (TableLayoutCellPaintEventHandler)(Events [CellPaintEvent]);
273                         if (eh != null)
274                                 eh (this, e);
275                 }
276
277                 [EditorBrowsable (EditorBrowsableState.Advanced)]
278                 protected override void OnLayout (LayoutEventArgs levent)
279                 {
280                         base.OnLayout (levent);
281                         Invalidate ();
282                 }
283
284                 protected override void OnPaintBackground (PaintEventArgs e)
285                 {
286                         base.OnPaintBackground (e);
287
288                         DrawCellBorders (e);
289                         
290                         int border_width = GetCellBorderWidth (CellBorderStyle);
291
292                         int x = border_width;
293                         int y = border_width;
294                         
295                         for (int i = 0; i < column_widths.Length; i++) {
296                                 for (int j = 0; j < row_heights.Length; j++) {
297                                         this.OnCellPaint (new TableLayoutCellPaintEventArgs (e.Graphics, e.ClipRectangle, new Rectangle (x, y, column_widths[i] + border_width, row_heights[j] + border_width), i, j));
298                                         y += row_heights[j] + border_width;
299                                 }
300
301                                 x += column_widths[i] + border_width;
302                                 y = border_width;
303                         }
304                 }
305
306                 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
307                 {
308                         base.ScaleControl (factor, specified);
309                 }
310                 
311                 [EditorBrowsable (EditorBrowsableState.Never)]
312                 protected override void ScaleCore (float dx, float dy)
313                 {
314                         base.ScaleCore (dx, dy);
315                 }
316                 #endregion
317
318                 #region Internal Methods
319                 internal static int GetCellBorderWidth (TableLayoutPanelCellBorderStyle style)
320                 {
321                         switch (style) {
322                                 case TableLayoutPanelCellBorderStyle.Single:
323                                         return 1;
324                                 case TableLayoutPanelCellBorderStyle.Inset:
325                                 case TableLayoutPanelCellBorderStyle.Outset:
326                                         return 2;
327                                 case TableLayoutPanelCellBorderStyle.InsetDouble:
328                                 case TableLayoutPanelCellBorderStyle.OutsetPartial:
329                                 case TableLayoutPanelCellBorderStyle.OutsetDouble:
330                                         return 3;
331                         }
332                         
333                         return 0;
334                 }
335                 
336                 private void DrawCellBorders (PaintEventArgs e)
337                 {
338                         Rectangle paint_here = new Rectangle (Point.Empty, this.Size);
339
340                         switch (CellBorderStyle) {
341                                 case TableLayoutPanelCellBorderStyle.Single:
342                                         DrawSingleBorder (e.Graphics, paint_here);
343                                         break;
344                                 case TableLayoutPanelCellBorderStyle.Inset:
345                                         DrawInsetBorder (e.Graphics, paint_here);
346                                         break;
347                                 case TableLayoutPanelCellBorderStyle.InsetDouble:
348                                         DrawInsetDoubleBorder (e.Graphics, paint_here);
349                                         break;
350                                 case TableLayoutPanelCellBorderStyle.Outset:
351                                         DrawOutsetBorder (e.Graphics, paint_here);
352                                         break;
353                                 case TableLayoutPanelCellBorderStyle.OutsetDouble:
354                                 case TableLayoutPanelCellBorderStyle.OutsetPartial:
355                                         DrawOutsetDoubleBorder (e.Graphics, paint_here);
356                                         break;
357                         }
358                 }
359
360                 private void DrawSingleBorder (Graphics g, Rectangle rect)
361                 {
362                         ControlPaint.DrawBorder (g, rect, SystemColors.ControlDark, ButtonBorderStyle.Solid);
363
364                         int x = DisplayRectangle.X;
365                         int y = DisplayRectangle.Y;
366
367                         for (int i = 0; i < column_widths.Length - 1; i++) {
368                                 x += column_widths[i] + 1;
369
370                                 g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 2));
371                         }
372
373                         for (int j = 0; j < row_heights.Length - 1; j++) {
374                                 y += row_heights[j] + 1;
375
376                                 g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 2, y));
377                         }
378                 }
379
380                 private void DrawInsetBorder (Graphics g, Rectangle rect)
381                 {
382                         ControlPaint.DrawBorder3D (g, rect, Border3DStyle.Etched);
383                         
384                         int x = DisplayRectangle.X;
385                         int y = DisplayRectangle.Y;
386
387                         for (int i = 0; i < column_widths.Length - 1; i++) {
388                                 x += column_widths[i] + 2;
389
390                                 g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 3));
391                                 g.DrawLine (Pens.White, new Point (x + 1, 1), new Point (x + 1, Bottom - 3));
392                         }
393
394                         for (int j = 0; j < row_heights.Length - 1; j++) {
395                                 y += row_heights[j] + 2;
396
397                                 g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 3, y));
398                                 g.DrawLine (Pens.White, new Point (1, y + 1), new Point (Right - 3, y + 1));
399                         }
400                 }
401
402                 private void DrawOutsetBorder (Graphics g, Rectangle rect)
403                 {
404                         g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 1, rect.Top + 1, rect.Width - 2, rect.Height - 2));
405                         g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2));
406
407                         int x = DisplayRectangle.X;
408                         int y = DisplayRectangle.Y;
409
410                         for (int i = 0; i < column_widths.Length - 1; i++) {
411                                 x += column_widths[i] + 2;
412
413                                 g.DrawLine (Pens.White, new Point (x, 1), new Point (x, Bottom - 3));
414                                 g.DrawLine (SystemPens.ControlDark, new Point (x + 1, 1), new Point (x + 1, Bottom - 3));
415                         }
416
417                         for (int j = 0; j < row_heights.Length - 1; j++) {
418                                 y += row_heights[j] + 2;
419
420                                 g.DrawLine (Pens.White, new Point (1, y), new Point (Right - 3, y));
421                                 g.DrawLine (SystemPens.ControlDark, new Point (1, y + 1), new Point (Right - 3, y + 1));
422                         }
423                 }
424
425                 private void DrawOutsetDoubleBorder (Graphics g, Rectangle rect)
426                 {
427                         rect.Width -= 1;
428                         rect.Height -= 1;
429                         
430                         g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2));
431                         g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2));
432
433                         int x = DisplayRectangle.X;
434                         int y = DisplayRectangle.Y;
435
436                         for (int i = 0; i < column_widths.Length - 1; i++) {
437                                 x += column_widths[i] + 3;
438
439                                 g.DrawLine (Pens.White, new Point (x, 3), new Point (x, Bottom - 5));
440                                 g.DrawLine (SystemPens.ControlDark, new Point (x + 2, 3), new Point (x + 2, Bottom - 5));
441                         }
442
443                         for (int j = 0; j < row_heights.Length - 1; j++) {
444                                 y += row_heights[j] + 3;
445
446                                 g.DrawLine (Pens.White, new Point (3, y), new Point (Right - 4, y));
447                                 g.DrawLine (SystemPens.ControlDark, new Point (3, y + 2), new Point (Right - 4, y + 2));
448                         }
449
450                         x = DisplayRectangle.X;
451                         y = DisplayRectangle.Y;
452
453                         for (int i = 0; i < column_widths.Length - 1; i++) {
454                                 x += column_widths[i] + 3;
455
456                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5));
457                         }
458
459                         for (int j = 0; j < row_heights.Length - 1; j++) {
460                                 y += row_heights[j] + 3;
461
462                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1));
463                         }
464                 }
465         
466                 private void DrawInsetDoubleBorder (Graphics g, Rectangle rect)
467                 {
468                         rect.Width -= 1;
469                         rect.Height -= 1;
470                         
471                         g.DrawRectangle (Pens.White, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2));
472                         g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2));
473
474                         int x = DisplayRectangle.X;
475                         int y = DisplayRectangle.Y;
476
477                         for (int i = 0; i < column_widths.Length - 1; i++) {
478                                 x += column_widths[i] + 3;
479
480                                 g.DrawLine (SystemPens.ControlDark, new Point (x, 3), new Point (x, Bottom - 5));
481                                 g.DrawLine (Pens.White, new Point (x + 2, 3), new Point (x + 2, Bottom - 5));
482                         }
483
484                         for (int j = 0; j < row_heights.Length - 1; j++) {
485                                 y += row_heights[j] + 3;
486
487                                 g.DrawLine (SystemPens.ControlDark, new Point (3, y), new Point (Right - 4, y));
488                                 g.DrawLine (Pens.White, new Point (3, y + 2), new Point (Right - 4, y + 2));
489                         }
490
491                         x = DisplayRectangle.X;
492                         y = DisplayRectangle.Y;
493                         
494                         for (int i = 0; i < column_widths.Length - 1; i++) {
495                                 x += column_widths[i] + 3;
496
497                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5));
498                         }
499
500                         for (int j = 0; j < row_heights.Length - 1; j++) {
501                                 y += row_heights[j] + 3;
502
503                                 g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1));
504                         }
505                 }
506
507                 internal override Size GetPreferredSizeCore (Size proposedSize)
508                 {
509                         // If the tablelayoutowner is autosize, we have to make sure it is big enough
510                         // to hold every non-autosize control
511                         actual_positions = (LayoutEngine as TableLayout).CalculateControlPositions (this, Math.Max (ColumnCount, 1), Math.Max (RowCount, 1));
512                         
513                         // Use actual row/column counts, not user set ones
514                         int actual_cols = actual_positions.GetLength (0);
515                         int actual_rows = actual_positions.GetLength (1);
516                         
517                         // Figure out how wide the owner needs to be
518                         int[] column_widths = new int[actual_cols];
519                         float total_column_percentage = 0f;
520                         
521                         // Figure out how tall each column wants to be
522                         for (int i = 0; i < actual_cols; i++) {
523                                 if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent)
524                                         total_column_percentage += ColumnStyles[i].Width;
525                                         
526                                 int biggest = 0;
527
528                                 for (int j = 0; j < actual_rows; j++) {
529                                         Control c = actual_positions[i, j];
530
531                                         if (c != null) {
532                                                 if (!c.AutoSize)
533                                                         biggest = Math.Max (biggest, c.ExplicitBounds.Width + c.Margin.Horizontal + Padding.Horizontal);
534                                                 else
535                                                         biggest = Math.Max (biggest, c.PreferredSize.Width + c.Margin.Horizontal + Padding.Horizontal);
536                                         }
537                                 }
538
539                                 column_widths[i] = biggest;
540                         }
541
542                         // Because percentage based rows divy up the remaining space,
543                         // we have to make the owner big enough so that all the rows
544                         // get bigger, even if we only need one to be bigger.
545                         int non_percent_total_width = 0;
546                         int percent_total_width = 0;
547
548                         for (int i = 0; i < actual_cols; i++) {
549                                 if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent)
550                                         percent_total_width = Math.Max (percent_total_width, (int)(column_widths[i] / ((ColumnStyles[i].Width) / total_column_percentage)));
551                                 else
552                                         non_percent_total_width += column_widths[i];
553                         }
554
555
556                         // Figure out how tall the owner needs to be
557                         int[] row_heights = new int[actual_rows];
558                         float total_row_percentage = 0f;
559                 
560                         // Figure out how tall each row wants to be
561                         for (int j = 0; j < actual_rows; j++) {
562                                 if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent)
563                                         total_row_percentage += RowStyles[j].Height;
564                                         
565                                 int biggest = 0;
566                                 
567                                 for (int i = 0; i < actual_cols; i++) {
568                                         Control c = actual_positions[i, j];
569
570                                         if (c != null) {
571                                                 if (!c.AutoSize)
572                                                         biggest = Math.Max (biggest, c.ExplicitBounds.Height + c.Margin.Vertical + Padding.Vertical);
573                                                 else
574                                                         biggest = Math.Max (biggest, c.PreferredSize.Height + c.Margin.Vertical + Padding.Vertical);
575                                         }
576                                 }
577
578                                 row_heights[j] = biggest;
579                         }
580                         
581                         // Because percentage based rows divy up the remaining space,
582                         // we have to make the owner big enough so that all the rows
583                         // get bigger, even if we only need one to be bigger.
584                         int non_percent_total_height = 0;
585                         int percent_total_height = 0;
586
587                         for (int j = 0; j < actual_rows; j++) {
588                                 if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent)
589                                         percent_total_height = Math.Max (percent_total_height, (int)(row_heights[j] / ((RowStyles[j].Height) / total_row_percentage)));
590                                 else
591                                         non_percent_total_height += row_heights[j];
592                         }
593
594                         int border_width = GetCellBorderWidth (CellBorderStyle);
595                         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)));
596                 }
597                 #endregion
598                 
599                 #region Public Events
600                 static object CellPaintEvent = new object ();
601
602                 public event TableLayoutCellPaintEventHandler CellPaint {
603                         add { Events.AddHandler (CellPaintEvent, value); }
604                         remove { Events.RemoveHandler (CellPaintEvent, value); }
605                 }
606                 #endregion
607                 
608                 #region IExtenderProvider
609                 bool IExtenderProvider.CanExtend (object obj)
610                 {
611                         if (obj is Control)
612                                 if ((obj as Control).Parent == this)
613                                         return true;
614
615                         return false;
616                 }
617                 #endregion
618                 
619         }
620 }