Exemple #1
0
 /// <summary>
 /// Retrieves the size of a rectangular area into which a control can be fitted.
 /// </summary>
 /// <param name="container">The container.</param>
 /// <param name="proposedSize">The custom-sized area for a control.</param>
 /// <returns>An ordered pair of type <see cref="Size"/> representing the width and height of a rectangle.</returns>
 public Size GetPreferredSize(ControlListBase container, Size proposedSize)
 {
     if (lastLayout != proposedSize)
     {
         Layout(container, new LayoutEventArgs(container, null), proposedSize);
     }
     return(idealSize);
 }
Exemple #2
0
        private bool Layout(ControlListBase parent, LayoutEventArgs layoutEventArgs, Size proposedSize)
        {
            if (parent == null)
            {
                throw new InvalidCastException(nameof(ColumnLayoutEngine) + " can only be used to layout controls derived from " + nameof(ControlListBase));
            }

            if (proposedSize == Size.Empty)
            {
                proposedSize = parent.ClientSize;
            }

            if (parent.BaseItems != null && parent.BaseItems.Count > 0)
            {
                System.Diagnostics.Debug.WriteLine(parent.Name + ": Layout:");
                System.Diagnostics.Debug.WriteLine($"  ClientSize:{proposedSize}, Margin:{parent.Margin}, Padding:{parent.Padding}, Cols:{parent.RepeatColumns}, Spacing:{parent.ItemSpacing}, Items:{parent.BaseItems.Count}, Dir:{parent.RepeatDirection}, Even:{parent.SpaceEvenly}");
                ItemBounds.Clear();
                using (var g = parent.CreateGraphics())
                {
                    // Determine the start coordinate of each column
                    var colWidth = (parent.ClientSize.Width - parent.Padding.Horizontal - ((parent.RepeatColumns - 1) * parent.ItemSpacing.Width)) / parent.RepeatColumns;
                    var colPos   = new Point[parent.RepeatColumns];
                    for (var x = 0; x < parent.RepeatColumns; x++)
                    {
                        colPos[x] = new Point(parent.Padding.Left + (x * (colWidth + parent.ItemSpacing.Width)), parent.Padding.Top);
                    }

                    // Get the base height of all items and the max height
                    var maxItemHeight = 0;
                    idealSize.Height = 0;
                    var maxSize = new Size(colWidth, 0);
                    for (var i = 0; i < parent.BaseItems.Count; i++)
                    {
                        var sz = parent.MeasureItem(g, i, maxSize);
                        ItemBounds[i] = new Rectangle(Point.Empty, sz);

                        // Calculate maximum item height
                        maxItemHeight = Math.Max(maxItemHeight, sz.Height);
                    }

                    // Calculate the positions of each item
                    var curCol = 0;
                    for (var i = 0; i < parent.BaseItems.Count; i++)
                    {
                        // Set bounds of the item
                        ItemBounds[i] = new Rectangle(colPos[curCol], ItemBounds[i].Size);
                        // Set top position of next item
                        colPos[curCol].Y += (parent.SpaceEvenly ? maxItemHeight : ItemBounds[i].Height) + parent.ItemSpacing.Height;
                        if (parent.RepeatDirection == RepeatDirection.Horizontal)
                        {
                            if (++curCol == parent.RepeatColumns)
                            {
                                curCol = 0;
                            }
                        }
                        // If parent.ItemSpacing evenly we can determine all locations now by changing column count at pure divisions

                        /*if (parent.SpaceEvenly && parent.RepeatDirection == GroupControls.RepeatDirection.Vertical && i > 0)
                         * {
                         *      if (i % (parent.BaseItems.Count / parent.RepeatColumns) == 0 && curCol <= (parent.BaseItems.Count % parent.RepeatColumns))
                         *              curCol++;
                         * }*/
                    }

                    // Split vertical parent.RepeatColumns and reset positions of items
                    if (parent.RepeatDirection == RepeatDirection.Vertical && parent.RepeatColumns > 1)
                    {
                        var idealColHeight = colPos[0].Y / parent.RepeatColumns;
                        var thisColBottom  = idealColHeight;
                        var y = parent.Padding.Top + parent.Margin.Top;
                        for (var i = 0; i < parent.BaseItems.Count; i++)
                        {
                            var iBounds = ItemBounds[i];
                            var nBounds = Rectangle.Empty;
                            if ((i + 1) < parent.BaseItems.Count)
                            {
                                nBounds = ItemBounds[i + 1];
                            }

                            if (curCol > 0)
                            {
                                ItemBounds[i] = new Rectangle(new Point(colPos[curCol].X, y), ItemBounds[i].Size);
                            }
                            colPos[curCol].Y = ItemBounds[i].Bottom + parent.ItemSpacing.Height;

                            if ((iBounds.Bottom > thisColBottom || nBounds.Bottom > thisColBottom) && (curCol + 1 < parent.RepeatColumns))
                            {
                                if (Math.Abs(iBounds.Bottom - idealColHeight) < Math.Abs(nBounds.Bottom - idealColHeight))
                                {
                                    y = parent.Padding.Top;
                                    curCol++;
                                    thisColBottom = iBounds.Bottom + parent.ItemSpacing.Height + idealColHeight;
                                }
                            }
                            else
                            {
                                y += (parent.SpaceEvenly ? maxItemHeight : ItemBounds[i].Height) + parent.ItemSpacing.Height;
                            }
                        }
                    }

                    // Set ideal height
                    idealSize.Height = 0;
                    for (var c = 0; c < parent.RepeatColumns; c++)
                    {
                        if (idealSize.Height < colPos[c].Y)
                        {
                            idealSize.Height = colPos[c].Y;
                        }
                    }
                    idealSize.Height = idealSize.Height - parent.ItemSpacing.Height + parent.Padding.Bottom;
                }

                // Set scroll height and autosize to ideal height
                parent.AutoScrollMinSize = new Size(parent.ClientRectangle.Width, idealSize.Height);
                if (parent.AutoSize)
                {
                    parent.Height = idealSize.Height;
                }

                System.Diagnostics.Debug.WriteLine("  " + string.Join(" ", Array.ConvertAll(ItemBounds.ToArray(), r => $"({r})")));
            }

            return(parent.AutoSize);
        }
Exemple #3
0
        private bool NewLayout(ControlListBase parent, LayoutEventArgs layoutEventArgs, Size proposedSize)
        {
            if (parent == null)
            {
                throw new InvalidCastException(nameof(ColumnLayoutEngine) + " can only be used to layout controls derived from " + nameof(ControlListBase));
            }

            if (proposedSize == Size.Empty)
            {
                proposedSize = parent.ClientSize;
            }

            if (parent.BaseItems != null && parent.BaseItems.Count > 0)
            {
                var parentWidthPinned = parent.Dock != DockStyle.None || (parent.Anchor & (AnchorStyles.Left | AnchorStyles.Right)) != 0;
                System.Diagnostics.Debug.WriteLine(parent.Name + ": Layout: ");
                System.Diagnostics.Debug.WriteLine($"  ClientSize:{proposedSize}, Margin:{parent.Margin}, Padding:{parent.Padding}, Cols:{parent.RepeatColumns}, Spacing:{parent.ItemSpacing}, Items:{parent.BaseItems.Count}, Dir:{parent.RepeatDirection}, Even:{parent.SpaceEvenly}");
                ItemBounds.Clear();
                using (var g = parent.CreateGraphics())
                {
                    idealSize = proposedSize;

                    // Determine starting width of column
                    var colWidth = (proposedSize.Width - parent.Padding.Horizontal - ((parent.RepeatColumns - 1) * parent.ItemSpacing.Width)) / parent.RepeatColumns;

                    // Get the min width of all items
                    var maxMinW = 0;
                    var minSz   = new Size[parent.BaseItems.Count];
                    var wsz     = new Size(1, int.MaxValue);
                    for (var i = 0; i < parent.BaseItems.Count; i++)
                    {
                        minSz[i] = parent.MeasureItem(g, i, wsz);
                        maxMinW  = Math.Max(maxMinW, minSz[i].Width);
                    }

                    // Determine the column for each item
                    var itemCol = new int[parent.BaseItems.Count];
                    for (var i = 0; i < parent.BaseItems.Count; i++)
                    {
                        if (parent.RepeatDirection == RepeatDirection.Horizontal)
                        {
                            itemCol[i] = i % parent.RepeatColumns;
                        }
                        else
                        {
                            itemCol[i] = i / (int)Math.Ceiling(parent.BaseItems.Count / (decimal)parent.RepeatColumns);
                        }
                    }

                    // If not spaced evenly, then balance the columns based on height
                    if (!parent.SpaceEvenly)
                    {
                        // Determine total height of all items
                        // Determine max height of each column
                        // Working backwards, fit each item into columns with spillover on Column 1
                    }

                    // Get the min width of each column
                    var minColWidth = new int[parent.RepeatColumns];
                    var maxColWidth = 0;
                    var totMinW     = 0;
                    if (parent.VariableColumnWidths)
                    {
                        for (var i = 0; i < parent.BaseItems.Count; i++)
                        {
                            var col = itemCol[i];
                            minColWidth[col] = Math.Max(minColWidth[col], minSz[i].Width);
                            maxColWidth      = Math.Max(maxColWidth, minColWidth[col]);
                        }
                        for (var i = 0; i < parent.RepeatColumns; i++)
                        {
                            totMinW += minColWidth[i];
                        }
                    }
                    else
                    {
                        for (var i = 0; i < parent.RepeatColumns; i++)
                        {
                            minColWidth[i] = maxMinW;
                        }
                        maxColWidth = Math.Min(maxMinW, colWidth);
                        totMinW     = parent.RepeatColumns * maxColWidth;
                    }
                    totMinW += ((parent.RepeatColumns - 1) * parent.ItemSpacing.Width) + parent.Padding.Horizontal;

                    // Determine the start coordinate of each column
                    var colPos = new Point[parent.RepeatColumns];
                    var xPos   = 0;
                    for (var x = 0; x < parent.RepeatColumns; x++)
                    {
                        var cWidth = maxColWidth;
                        if (parent.VariableColumnWidths && parent.AutoSize && !parentWidthPinned)
                        {
                            cWidth = minColWidth[x];
                        }
                        else if (!parent.VariableColumnWidths && (parentWidthPinned || parent.AutoSize))
                        {
                            cWidth = maxColWidth;
                        }
                        colPos[x] = new Point(parent.Padding.Left + xPos, parent.Padding.Top);
                        xPos     += cWidth + parent.ItemSpacing.Width;
                    }

                    // Set the width value based on AutoSize, Dock and SpaceEvenly properties
                    for (var i = 0; i < parent.BaseItems.Count; i++)
                    {
                        minSz[i].Width = Math.Min(minSz[i].Width, minColWidth[itemCol[i]]);
                    }

                    /*int totMinW = 0;
                     * if (parent.AutoSize && !parentWidthPinned)
                     * {
                     *      for (int i = 0; i < parent.BaseItems.Count; i++)
                     *      {
                     *              if (!parent.VariableColumnWidths)
                     *                      minSz[i].Width = minColWidth[itemCol[i]];
                     *              totMinW += minSz[i].Width;
                     *      }
                     * }
                     * else
                     * {
                     *      for (int i = 0; i < parent.BaseItems.Count; i++)
                     *      {
                     *              minSz[i].Width = parentWidthPinned ? colWidth : Math.Max(colWidth, maxMinCol);
                     *              totMinW += minSz[i].Width;
                     *      }
                     * }
                     * totMinW += ((parent.RepeatColumns - 1) * parent.ItemSpacing.Width) + parent.Padding.Horizontal;*/

                    /*// Get min width for all parent.RepeatColumns
                     * int maxMinCol = 0;
                     * int totMinW = 0;
                     * for (int i = 0; i < parent.RepeatColumns; i++)
                     * {
                     *      maxMinCol = Math.Max(maxMinCol, minColWidth[i]);
                     *      totMinW += minColWidth[i];
                     * }*/

                    // Reset ideal width if needed
                    if (!parentWidthPinned)
                    {
                        idealSize.Width = totMinW;
                    }

                    // Get the base height of all items and the max height
                    var maxItemHeight = 0;
                    idealSize.Height = 0;
                    for (var i = 0; i < parent.BaseItems.Count; i++)
                    {
                        minSz[i].Height = 0;
                        var sz = parent.MeasureItem(g, i, minSz[i]);
                        ItemBounds[i] = new Rectangle(Point.Empty, sz);
                        maxItemHeight = Math.Max(maxItemHeight, sz.Height);
                    }

                    // Calculate the positions of each item
                    for (var i = 0; i < parent.BaseItems.Count; i++)
                    {
                        var curCol = itemCol[i];
                        // Set bounds of the item
                        ItemBounds[i] = new Rectangle(colPos[curCol], ItemBounds[i].Size);
                        // Set top position of next item
                        colPos[curCol].Y += (parent.SpaceEvenly ? maxItemHeight : ItemBounds[i].Height) + parent.ItemSpacing.Height;
                    }

                    // Split vertical parent.RepeatColumns and reset positions of items

                    /*if (parent.RepeatDirection == GroupControls.RepeatDirection.Vertical && parent.RepeatColumns > 1)
                     * {
                     *      int idealColHeight = colPos[0].Y / parent.RepeatColumns;
                     *      int thisColBottom = idealColHeight;
                     *      int y = parent.Padding.Top + parent.Margin.Top;
                     *      for (int i = 0; i < parent.BaseItems.Count; i++)
                     *      {
                     *              Rectangle iBounds = itemBounds[i];
                     *              Rectangle nBounds = Rectangle.Empty;
                     *              if ((i + 1) < parent.BaseItems.Count)
                     *                      nBounds = itemBounds[i + 1];
                     *
                     *              if (curCol > 0)
                     *                      itemBounds[i] = new Rectangle(new Point(colPos[curCol].X, y), itemBounds[i].Size);
                     *              colPos[curCol].Y = itemBounds[i].Bottom + parent.ItemSpacing.Height;
                     *
                     *              if ((iBounds.Bottom > thisColBottom || nBounds.Bottom > thisColBottom) && (curCol + 1 < parent.RepeatColumns))
                     *              {
                     *                      if (Math.Abs(iBounds.Bottom - idealColHeight) < Math.Abs(nBounds.Bottom - idealColHeight))
                     *                      {
                     *                              y = parent.Padding.Top;
                     *                              curCol++;
                     *                              thisColBottom = iBounds.Bottom + parent.ItemSpacing.Height + idealColHeight;
                     *                      }
                     *              }
                     *              else
                     *              {
                     *                      y += (parent.SpaceEvenly ? maxItemHeight : itemBounds[i].Height) + parent.ItemSpacing.Height;
                     *              }
                     *      }
                     * }*/

                    // Set ideal height
                    idealSize.Height = 0;
                    for (var c = 0; c < parent.RepeatColumns; c++)
                    {
                        idealSize.Height = Math.Max(idealSize.Height, colPos[c].Y);
                    }
                    idealSize.Height = idealSize.Height - parent.ItemSpacing.Height + parent.Padding.Bottom;
                }

                // Set scroll height and autosize to ideal height
                parent.AutoScrollMinSize = new Size(proposedSize.Width, idealSize.Height);
                if (parentWidthPinned && parent.AutoSize)
                {
                    parent.Size = idealSize;
                }

                System.Diagnostics.Debug.WriteLine("  " + string.Join(" ", Array.ConvertAll(ItemBounds.ToArray(), r => $"({r})")));
            }

            return(parent.AutoSize);
        }