diff options
| author | MichaelTheShifter <[email protected]> | 2016-07-20 09:40:36 -0400 |
|---|---|---|
| committer | MichaelTheShifter <[email protected]> | 2016-07-20 09:40:36 -0400 |
| commit | d40fed5ce2bc806a91245adb18039634eac13ed0 (patch) | |
| tree | f1d7168aee6db109ac2c738ad18c9db667a6ba69 /source/ShiftUI/Widgets/TableLayoutPanel.cs | |
| parent | f1856e8ed30ed882229fd3fa2a4038122a5fb441 (diff) | |
| download | shiftos-c-_theultimatehacker-d40fed5ce2bc806a91245adb18039634eac13ed0.tar.gz shiftos-c-_theultimatehacker-d40fed5ce2bc806a91245adb18039634eac13ed0.tar.bz2 shiftos-c-_theultimatehacker-d40fed5ce2bc806a91245adb18039634eac13ed0.zip | |
Move ShiftUI source code to ShiftOS
This'll be a lot easier to work on.
Diffstat (limited to 'source/ShiftUI/Widgets/TableLayoutPanel.cs')
| -rw-r--r-- | source/ShiftUI/Widgets/TableLayoutPanel.cs | 788 |
1 files changed, 788 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/TableLayoutPanel.cs b/source/ShiftUI/Widgets/TableLayoutPanel.cs new file mode 100644 index 0000000..e327795 --- /dev/null +++ b/source/ShiftUI/Widgets/TableLayoutPanel.cs @@ -0,0 +1,788 @@ +// +// TableLayoutPanel.cs +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2006 Jonathan Pobst +// +// Authors: +// Jonathan Pobst ([email protected]) +// + +using System; +using System.Drawing; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; +using ShiftUI.Layout; +using System.ComponentModel.Design.Serialization; + +namespace ShiftUI +{ + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + [ProvideProperty ("CellPosition", typeof (Widget))] + [ProvideProperty ("Column", typeof (Widget))] + [ProvideProperty ("ColumnSpan", typeof (Widget))] + [ProvideProperty ("Row", typeof (Widget))] + [ProvideProperty ("RowSpan", typeof (Widget))] + [DefaultProperty ("ColumnCount")] + [Docking (DockingBehavior.Never)] + //[Designer ("ShiftUI.Design.TableLayoutPanelDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + //[DesignerSerializer ("ShiftUI.Design.TableLayoutPanelCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] + [ToolboxWidget] + public class TableLayoutPanel : Panel, IExtenderProvider + { + private TableLayoutSettings settings; + private static TableLayout layout_engine = new TableLayout (); + private TableLayoutPanelCellBorderStyle cell_border_style; + + // This is the row/column the Widget actually got placed + internal Widget[,] actual_positions; + + // Widths and heights of each column/row + internal int[] column_widths; + internal int[] row_heights; + + #region Public Constructor + public TableLayoutPanel () + { + settings = new TableLayoutSettings(this); + cell_border_style = TableLayoutPanelCellBorderStyle.None; + column_widths = new int[0]; + row_heights = new int[0]; + CreateDockPadding (); + } + #endregion + + #region Public Properties + [Localizable (true)] + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + new public BorderStyle BorderStyle { + get { return base.BorderStyle; } + set { base.BorderStyle = value; } + } + + [Localizable (true)] + [DefaultValue (TableLayoutPanelCellBorderStyle.None)] + public TableLayoutPanelCellBorderStyle CellBorderStyle { + get { return this.cell_border_style; } + set { + if (this.cell_border_style != value) { + this.cell_border_style = value; + this.PerformLayout (this, "CellBorderStyle"); + this.Invalidate (); + } + } + } + + [Localizable (true)] + [DefaultValue (0)] + public int ColumnCount { + get { return settings.ColumnCount; } + set { settings.ColumnCount = value; } + } + + [Browsable (false)] + [DisplayName ("Columns")] + [MergableProperty (false)] + //[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public TableLayoutColumnStyleCollection ColumnStyles { + get { return settings.ColumnStyles; } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + new public TableLayoutControlCollection Widgets { + get { return (TableLayoutControlCollection) base.Widgets; } + } + + [DefaultValue (TableLayoutPanelGrowStyle.AddRows)] + public TableLayoutPanelGrowStyle GrowStyle { + get { return settings.GrowStyle; } + set { settings.GrowStyle = value; } + } + + public override ShiftUI.Layout.LayoutEngine LayoutEngine { + get { return TableLayoutPanel.layout_engine; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public TableLayoutSettings LayoutSettings { + get { return this.settings; } + set { + if (value.isSerialized) { + // Serialized version doesn't calculate these. + value.ColumnCount = value.ColumnStyles.Count; + value.RowCount = value.RowStyles.Count; + value.panel = this; + + this.settings = value; + } else + throw new NotSupportedException ("LayoutSettings value cannot be set directly."); + } + } + + [Localizable (true)] + [DefaultValue (0)] + public int RowCount { + get { return settings.RowCount; } + set { settings.RowCount = value; } + } + + [Browsable (false)] + [DisplayName ("Rows")] + [MergableProperty (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] + public TableLayoutRowStyleCollection RowStyles { + get { return settings.RowStyles; } + } + #endregion + + #region Public Methods + [DefaultValue (-1)] + [DisplayName ("Cell")] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public TableLayoutPanelCellPosition GetCellPosition (Widget control) + { + return settings.GetCellPosition (control); + } + + [DisplayName ("Column")] + [DefaultValue (-1)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int GetColumn (Widget control) + { + return settings.GetColumn (control); + } + + [DisplayName ("ColumnSpan")] + [DefaultValue (1)] + public int GetColumnSpan (Widget control) + { + return settings.GetColumnSpan (control); + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public int[] GetColumnWidths () + { + return this.column_widths; + } + + public Widget GetControlFromPosition (int column, int row) + { + if (column < 0 || row < 0) + throw new ArgumentException (); + + TableLayoutPanelCellPosition pos = new TableLayoutPanelCellPosition (column, row); + + foreach (Widget c in this.Widgets) + if (settings.GetCellPosition (c) == pos) + return c; + + return null; + } + + public TableLayoutPanelCellPosition GetPositionFromControl (Widget control) + { + for (int x = 0; x < this.actual_positions.GetLength (0); x++) + for (int y = 0; y < this.actual_positions.GetLength (1); y++) + if (this.actual_positions[x, y] == control) + return new TableLayoutPanelCellPosition (x, y); + + return new TableLayoutPanelCellPosition (-1, -1); + } + + [DisplayName ("Row")] + [DefaultValue ("-1")] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int GetRow (Widget control) + { + return settings.GetRow (control); + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public int[] GetRowHeights () + { + return this.row_heights; + } + + [DisplayName ("RowSpan")] + [DefaultValue (1)] + public int GetRowSpan (Widget control) + { + return settings.GetRowSpan (control); + } + + public void SetCellPosition (Widget control, TableLayoutPanelCellPosition position) + { + settings.SetCellPosition (control, position); + } + + public void SetColumn (Widget control, int column) + { + settings.SetColumn (control, column); + } + + public void SetColumnSpan (Widget control, int value) + { + settings.SetColumnSpan (control, value); + } + + public void SetRow (Widget control, int row) + { + settings.SetRow (control, row); + } + + public void SetRowSpan (Widget control, int value) + { + settings.SetRowSpan (control, value); + } + #endregion + + #region Protected Methods + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override WidgetCollection CreateWidgetsInstance () + { + return new TableLayoutControlCollection (this); + } + + protected virtual void OnCellPaint (TableLayoutCellPaintEventArgs e) + { + TableLayoutCellPaintEventHandler eh = (TableLayoutCellPaintEventHandler)(Events [CellPaintEvent]); + if (eh != null) + eh (this, e); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnLayout (LayoutEventArgs levent) + { + base.OnLayout (levent); + Invalidate (); + } + + protected override void OnPaintBackground (PaintEventArgs e) + { + base.OnPaintBackground (e); + + DrawCellBorders (e); + + int border_width = GetCellBorderWidth (CellBorderStyle); + + int x = border_width; + int y = border_width; + + for (int i = 0; i < column_widths.Length; i++) { + for (int j = 0; j < row_heights.Length; j++) { + this.OnCellPaint (new TableLayoutCellPaintEventArgs (e.Graphics, e.ClipRectangle, new Rectangle (x, y, column_widths[i] + border_width, row_heights[j] + border_width), i, j)); + y += row_heights[j] + border_width; + } + + x += column_widths[i] + border_width; + y = border_width; + } + } + + protected override void ScaleWidget (SizeF factor, BoundsSpecified specified) + { + base.ScaleWidget (factor, specified); + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override void ScaleCore (float dx, float dy) + { + base.ScaleCore (dx, dy); + } + #endregion + + #region Internal Methods + internal static int GetCellBorderWidth (TableLayoutPanelCellBorderStyle style) + { + switch (style) { + case TableLayoutPanelCellBorderStyle.Single: + return 1; + case TableLayoutPanelCellBorderStyle.Inset: + case TableLayoutPanelCellBorderStyle.Outset: + return 2; + case TableLayoutPanelCellBorderStyle.InsetDouble: + case TableLayoutPanelCellBorderStyle.OutsetPartial: + case TableLayoutPanelCellBorderStyle.OutsetDouble: + return 3; + } + + return 0; + } + + private void DrawCellBorders (PaintEventArgs e) + { + Rectangle paint_here = new Rectangle (Point.Empty, this.Size); + + switch (CellBorderStyle) { + case TableLayoutPanelCellBorderStyle.Single: + DrawSingleBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.Inset: + DrawInsetBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.InsetDouble: + DrawInsetDoubleBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.Outset: + DrawOutsetBorder (e.Graphics, paint_here); + break; + case TableLayoutPanelCellBorderStyle.OutsetDouble: + case TableLayoutPanelCellBorderStyle.OutsetPartial: + DrawOutsetDoubleBorder (e.Graphics, paint_here); + break; + } + } + + private void DrawSingleBorder (Graphics g, Rectangle rect) + { + WidgetPaint.DrawBorder (g, rect, SystemColors.ControlDark, ButtonBorderStyle.Solid); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 1; + + g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 2)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 1; + + g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 2, y)); + } + } + + private void DrawInsetBorder (Graphics g, Rectangle rect) + { + WidgetPaint.DrawBorder3D (g, rect, Border3DStyle.Etched); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 2; + + g.DrawLine (SystemPens.ControlDark, new Point (x, 1), new Point (x, Bottom - 3)); + g.DrawLine (Pens.White, new Point (x + 1, 1), new Point (x + 1, Bottom - 3)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 2; + + g.DrawLine (SystemPens.ControlDark, new Point (1, y), new Point (Right - 3, y)); + g.DrawLine (Pens.White, new Point (1, y + 1), new Point (Right - 3, y + 1)); + } + } + + private void DrawOutsetBorder (Graphics g, Rectangle rect) + { + g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 1, rect.Top + 1, rect.Width - 2, rect.Height - 2)); + g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2)); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 2; + + g.DrawLine (Pens.White, new Point (x, 1), new Point (x, Bottom - 3)); + g.DrawLine (SystemPens.ControlDark, new Point (x + 1, 1), new Point (x + 1, Bottom - 3)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 2; + + g.DrawLine (Pens.White, new Point (1, y), new Point (Right - 3, y)); + g.DrawLine (SystemPens.ControlDark, new Point (1, y + 1), new Point (Right - 3, y + 1)); + } + } + + private void DrawOutsetDoubleBorder (Graphics g, Rectangle rect) + { + rect.Width -= 1; + rect.Height -= 1; + + g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2)); + g.DrawRectangle (Pens.White, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2)); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (Pens.White, new Point (x, 3), new Point (x, Bottom - 5)); + g.DrawLine (SystemPens.ControlDark, new Point (x + 2, 3), new Point (x + 2, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (Pens.White, new Point (3, y), new Point (Right - 4, y)); + g.DrawLine (SystemPens.ControlDark, new Point (3, y + 2), new Point (Right - 4, y + 2)); + } + + x = DisplayRectangle.X; + y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1)); + } + } + + private void DrawInsetDoubleBorder (Graphics g, Rectangle rect) + { + rect.Width -= 1; + rect.Height -= 1; + + g.DrawRectangle (Pens.White, new Rectangle (rect.Left + 2, rect.Top + 2, rect.Width - 2, rect.Height - 2)); + g.DrawRectangle (SystemPens.ControlDark, new Rectangle (rect.Left, rect.Top, rect.Width - 2, rect.Height - 2)); + + int x = DisplayRectangle.X; + int y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (SystemPens.ControlDark, new Point (x, 3), new Point (x, Bottom - 5)); + g.DrawLine (Pens.White, new Point (x + 2, 3), new Point (x + 2, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (SystemPens.ControlDark, new Point (3, y), new Point (Right - 4, y)); + g.DrawLine (Pens.White, new Point (3, y + 2), new Point (Right - 4, y + 2)); + } + + x = DisplayRectangle.X; + y = DisplayRectangle.Y; + + for (int i = 0; i < column_widths.Length - 1; i++) { + x += column_widths[i] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (x + 1, 3), new Point (x + 1, Bottom - 5)); + } + + for (int j = 0; j < row_heights.Length - 1; j++) { + y += row_heights[j] + 3; + + g.DrawLine (ThemeEngine.Current.ResPool.GetPen (BackColor), new Point (3, y + 1), new Point (Right - 4, y + 1)); + } + } + + internal override Size GetPreferredSizeCore (Size proposedSize) + { + // If the tablelayoutowner is autosize, we have to make sure it is big enough + // to hold every non-autosize control + actual_positions = (LayoutEngine as TableLayout).CalculateWidgetPositions (this, Math.Max (ColumnCount, 1), Math.Max (RowCount, 1)); + + // Use actual row/column counts, not user set ones + int actual_cols = actual_positions.GetLength (0); + int actual_rows = actual_positions.GetLength (1); + + // Find the largest column-span/row-span values. A table entry that spans more than one + // column (row) should not be treated as though it's width (height) all belongs to the + // first column (row), but should be spread out across all the columns (rows) that are + // spanned. So we need to keep track of the widths (heights) of spans as well as + // individual columns (rows). + int max_colspan = 1, max_rowspan = 1; + foreach (Widget c in Widgets) + { + max_colspan = Math.Max(max_colspan, GetColumnSpan(c)); + max_rowspan = Math.Max(max_rowspan, GetRowSpan(c)); + } + + // Figure out how wide the owner needs to be + int[] column_widths = new int[actual_cols]; + // Keep track of widths for spans as well as columns. column_span_widths[i,j] stores + // the maximum width for items column i than have a span of j+1 (ie, covers columns + // i through i+j). + int[,] column_span_widths = new int[actual_cols, max_colspan]; + int[] biggest = new int[max_colspan]; + float total_column_percentage = 0f; + + // Figure out how wide each column wants to be + for (int i = 0; i < actual_cols; i++) { + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent) + total_column_percentage += ColumnStyles[i].Width; + int absolute_width = -1; + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Absolute) + absolute_width = (int)ColumnStyles[i].Width; // use the absolute width if it's absolute! + + for (int s = 0; s < max_colspan; ++s) + biggest[s] = 0; + + for (int j = 0; j < actual_rows; j++) { + Widget c = actual_positions[i, j]; + + if (c != null) { + int colspan = GetColumnSpan (c); + if (colspan == 0) + continue; + if (colspan == 1 && absolute_width > -1) + biggest[0] = absolute_width; // use the absolute width if the column has absolute width assigned! + else if (!c.AutoSize) + biggest[colspan-1] = Math.Max (biggest[colspan-1], c.ExplicitBounds.Width + c.Margin.Horizontal + Padding.Horizontal); + else + biggest[colspan-1] = Math.Max (biggest[colspan-1], c.PreferredSize.Width + c.Margin.Horizontal + Padding.Horizontal); + } + else if (absolute_width > -1) { + biggest[0] = absolute_width; + } + } + + for (int s = 0; s < max_colspan; ++s) + column_span_widths[i,s] = biggest[s]; + } + + for (int i = 0; i < actual_cols; ++i) { + for (int s = 1; s < max_colspan; ++s) { + if (column_span_widths[i,s] > 0) + AdjustWidthsForSpans (column_span_widths, i, s); + } + column_widths[i] = column_span_widths[i,0]; + } + + // Because percentage based rows divy up the remaining space, + // we have to make the owner big enough so that all the rows + // get bigger, even if we only need one to be bigger. + int non_percent_total_width = 0; + int percent_total_width = 0; + + for (int i = 0; i < actual_cols; i++) { + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType == SizeType.Percent) + percent_total_width = Math.Max (percent_total_width, (int)(column_widths[i] / ((ColumnStyles[i].Width) / total_column_percentage))); + else + non_percent_total_width += column_widths[i]; + } + + int border_width = GetCellBorderWidth (CellBorderStyle); + int needed_width = non_percent_total_width + percent_total_width + (border_width * (actual_cols + 1)); + + // Figure out how tall the owner needs to be + int[] row_heights = new int[actual_rows]; + int[,] row_span_heights = new int[actual_rows, max_rowspan]; + biggest = new int[max_rowspan]; + float total_row_percentage = 0f; + + // Figure out how tall each row wants to be + for (int j = 0; j < actual_rows; j++) { + if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent) + total_row_percentage += RowStyles[j].Height; + int absolute_height = -1; + if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Absolute) + absolute_height = (int)RowStyles[j].Height; // use the absolute height if it's absolute! + + for (int s = 0; s < max_rowspan; ++s) + biggest[s] = 0; + + for (int i = 0; i < actual_cols; i++) { + Widget c = actual_positions[i, j]; + + if (c != null) { + int rowspan = GetRowSpan (c); + if (rowspan == 0) + continue; + if (rowspan == 1 && absolute_height > -1) + biggest[0] = absolute_height; // use the absolute height if the row has absolute height assigned! + else if (!c.AutoSize) + biggest[rowspan-1] = Math.Max (biggest[rowspan-1], c.ExplicitBounds.Height + c.Margin.Vertical + Padding.Vertical); + else + biggest[rowspan-1] = Math.Max (biggest[rowspan-1], c.PreferredSize.Height + c.Margin.Vertical + Padding.Vertical); + } + else if (absolute_height > -1) { + biggest[0] = absolute_height; + } + } + + for (int s = 0; s < max_rowspan; ++s) + row_span_heights[j,s] = biggest[s]; + } + + for (int j = 0; j < actual_rows; ++j) { + for (int s = 1; s < max_rowspan; ++s) { + if (row_span_heights[j,s] > 0) + AdjustHeightsForSpans (row_span_heights, j, s); + } + row_heights[j] = row_span_heights[j,0]; + } + + // Because percentage based rows divy up the remaining space, + // we have to make the owner big enough so that all the rows + // get bigger, even if we only need one to be bigger. + int non_percent_total_height = 0; + int percent_total_height = 0; + + for (int j = 0; j < actual_rows; j++) { + if (j < RowStyles.Count && RowStyles[j].SizeType == SizeType.Percent) + percent_total_height = Math.Max (percent_total_height, (int)(row_heights[j] / ((RowStyles[j].Height) / total_row_percentage))); + else + non_percent_total_height += row_heights[j]; + } + + int needed_height = non_percent_total_height + percent_total_height + (border_width * (actual_rows + 1)); + + return new Size (needed_width, needed_height); + } + + /// <summary> + /// Adjust the widths of the columns underlying a span if necessary. + /// </summary> + private void AdjustWidthsForSpans (int[,] widths, int col, int span) + { + // Get the combined width of the columns underlying the span. + int existing_width = 0; + for (int i = col; i <= col+span; ++i) + existing_width += widths[i,0]; + if (widths[col,span] > existing_width) + { + // We need to expand one or more of the underlying columns to fit the span, + // preferably ones that are not Absolute style. + int excess = widths[col,span] - existing_width; + int remaining = excess; + List<int> adjusting = new List<int>(); + List<float> adjusting_widths = new List<float>(); + for (int i = col; i <= col+span; ++i) { + if (i < ColumnStyles.Count && ColumnStyles[i].SizeType != SizeType.Absolute) { + adjusting.Add(i); + adjusting_widths.Add((float)widths[i,0]); + } + } + if (adjusting.Count == 0) { + // if every column is Absolute, spread the gain across every column + for (int i = col; i <= col+span; ++i) { + adjusting.Add(i); + adjusting_widths.Add((float)widths[i,0]); + } + } + float original_total = 0f; + foreach (var w in adjusting_widths) + original_total += w; + // Divide up the needed additional width proportionally. + for (int i = 0; i < adjusting.Count; ++i) { + var idx = adjusting[i]; + var percent = adjusting_widths[i] / original_total; + var adjust = (int)(percent * excess); + widths[idx,0] += adjust; + remaining -= adjust; + } + // Any remaining fragment (1 or 2 pixels?) is divided evenly. + while (remaining > 0) { + for (int i = 0; i < adjusting.Count && remaining > 0; ++i) { + ++widths[adjusting[i],0]; + --remaining; + } + } + } + } + + /// <summary> + /// Adjust the heights of the rows underlying a span if necessary. + /// </summary> + private void AdjustHeightsForSpans (int[,] heights, int row, int span) + { + // Get the combined height of the rows underlying the span. + int existing_height = 0; + for (int i = row; i <= row+span; ++i) + existing_height += heights[i,0]; + if (heights[row,span] > existing_height) + { + // We need to expand one or more of the underlying rows to fit the span, + // preferably ones that are not Absolute style. + int excess = heights[row,span] - existing_height; + int remaining = excess; + List<int> adjusting = new List<int>(); + List<float> adjusting_heights = new List<float>(); + for (int i = row; i <= row+span; ++i) { + if (i < RowStyles.Count && RowStyles[i].SizeType != SizeType.Absolute) { + adjusting.Add(i); + adjusting_heights.Add((float)heights[i,0]); + } + } + if (adjusting.Count == 0) { + // if every row is Absolute, spread the gain across every row + for (int i = row; i <= row+span; ++i) { + adjusting.Add(i); + adjusting_heights.Add((float)heights[i,0]); + } + } + float original_total = 0f; + foreach (var w in adjusting_heights) + original_total += w; + // Divide up the needed additional height proportionally. + for (int i = 0; i < adjusting.Count; ++i) { + var idx = adjusting[i]; + var percent = adjusting_heights[i] / original_total; + var adjust = (int)(percent * excess); + heights[idx,0] += adjust; + remaining -= adjust; + } + // Any remaining fragment (1 or 2 pixels?) is divided evenly. + while (remaining > 0) { + for (int i = 0; i < adjusting.Count && remaining > 0; ++i) { + ++heights[adjusting[i],0]; + --remaining; + } + } + } + } + #endregion + + #region Public Events + static object CellPaintEvent = new object (); + + public event TableLayoutCellPaintEventHandler CellPaint { + add { Events.AddHandler (CellPaintEvent, value); } + remove { Events.RemoveHandler (CellPaintEvent, value); } + } + #endregion + + #region IExtenderProvider + bool IExtenderProvider.CanExtend (object obj) + { + if (obj is Widget) + if ((obj as Widget).Parent == this) + return true; + + return false; + } + #endregion + + } +} |
