private static void StackColumns(int width, ColumnSizingParameters parameters)
        {
            //the columns do not fit, so start stacking until they do.
            parameters.StackSizer = new PropertyStackColumnSizer();

            ColumnWidthNegotiator.ColumnSizerInfo lastColumn;
            while ((lastColumn = parameters.Sizers.LastOrDefault()) != null)
            {
                parameters.StackSizer.AddColumn(lastColumn.PropertyColumnFormat, lastColumn.Sizer.Values);
                parameters.Sizers.Remove(lastColumn);
                parameters.Columns.Remove(lastColumn.PropertyColumnFormat);

                var seperatorOverhead = parameters.Sizers.Count * parameters.SeperatorLength; //all columns in sizer list need seperator.
                if (MinPossibleWidth(seperatorOverhead, parameters) <= width)
                    break;
            }

            if (parameters.Sizers.Any())
            {
                FitColumns(width, parameters.Sizers.Count * parameters.SeperatorLength, parameters);
                parameters.StackedColumnWidth = parameters.StackSizer.GetMinWidth(parameters.TabLength);
            }
            else
                parameters.StackedColumnWidth = width;
        }
        public static void Size(int width, int seperatorOverhead, ColumnSizingParameters parameters)
        {
            var nonProportionalColumnTotalWidth = parameters.Sizers.Where(s => !s.WidthIsProportional()).Sum(s => s.PropertyColumnFormat.Format.ActualWidth);
            var proportionalColumns = parameters.Sizers.Where(s => s.WidthIsProportional()).ToList();

            var availableWidth = width - seperatorOverhead - nonProportionalColumnTotalWidth - parameters.StackedColumnWidth;

            var totalProportions = proportionalColumns.Sum(s => s.PropertyColumnFormat.Format.ProportionalWidth);
            var proportions = proportionalColumns
                .Select(s => new { ProportionalWidthCalc = MakeProportionalWidth(availableWidth, totalProportions, s.PropertyColumnFormat.Format), s.PropertyColumnFormat.Format})
                .Select(s => new { ProportionalWidth = s.ProportionalWidthCalc.Item1, s.Format, ExcessWidth = s.ProportionalWidthCalc.Item2 })
                .OrderByDescending(s => s.Format.ProportionalWidth)
                .ToList();

            var availableCharacters = availableWidth - proportions.Sum(p => p.ProportionalWidth);

            var adjuster = availableCharacters < 0 ? -1 : 1;
            while (availableCharacters != 0)
            {
                var current = proportions.First(c => c.ProportionalWidth + adjuster > 1);
                proportions.Remove(current);
                if (current.ExcessWidth > 0 && adjuster > 0)
                    proportions.Add(new { current.ProportionalWidth, current.Format, ExcessWidth = current.ExcessWidth - adjuster});
                else if (current.ExcessWidth == 0 && (current.Format.MaxWidth == 0 || current.ProportionalWidth + adjuster <= current.Format.MaxWidth))
                {
                    proportions.Add(new { ProportionalWidth = current.ProportionalWidth + adjuster, current.Format, current.ExcessWidth});
                    availableCharacters -= adjuster;
                }
                else
                    proportions.Add(current);
            }

            foreach(var col in proportions)
                col.Format.SetActualWidth(col.ProportionalWidth);
        }
 public static void ShrinkColumns(int width, int seperatorOverhead, ColumnSizingParameters parameters)
 {
     var minPossibleWidth = MinPossibleWidth(seperatorOverhead, parameters);
     if (minPossibleWidth > width)
         StackColumns(width, parameters);
     else
     {
         FitColumns(width, seperatorOverhead, parameters);
     }
 }
 /// <summary>
 /// Perform the stretch operation. This method takes any stacked columns into account.
 /// </summary>
 /// <param name="width">The available width.</param>
 /// <param name="seperatorOverhead">The amount of space occupied by column seperators.</param>
 /// <param name="parameters">The column sizing parameters for this operation.</param>
 /// <param name="maximiseWidth">True to systematically use all of the available width when sizing the columns.</param>
 public static void FillAvailableSpace(int width, int seperatorOverhead, ColumnSizingParameters parameters, bool maximiseWidth)
 {
     var columnPriorityList = parameters.Sizers.Where(s => s.PropertyColumnFormat.Format.DetermineWidthFromData()).ToList();
     while (CurrentWidth(seperatorOverhead, parameters.Sizers, parameters.StackedColumnWidth) < width)
     {
         if (!WidenBasedOnLineBreaks(columnPriorityList)
             && !WidenBasedOnMaximumWidth(columnPriorityList, maximiseWidth)
             && (!maximiseWidth || !WidenUnrestrictedColumns(columnPriorityList)))
             break;
     }
 }
        private static void FitColumns(int width, int seperatorOverhead, ColumnSizingParameters parameters)
        {
            if (!parameters.Sizers.Any()) return;

            var minStackWidth = (parameters.StackSizer == null ? 0 : parameters.StackSizer.GetMinWidth(parameters.TabLength));
            var linebreaks = 0;
            do
            {
                var widths = parameters.Sizers
                    .Select(s => new { Sizer = s, Width = Math.Max(s.Sizer.MinWidth(linebreaks), s.Sizer.GetIdealMinimumWidth()) })
                    .ToList();
                var totalWidth = widths.Sum(w => w.Width);
                if (totalWidth <= width - seperatorOverhead - minStackWidth)
                {
                    foreach (var propWidth in widths)
                    {
                        propWidth.Sizer.PropertyColumnFormat.Format.SetActualWidth(propWidth.Width);
                    }
                    break;
                }

                linebreaks++;
            } while (true);
        }
 public void SetUp()
 {
     _parameters = new ColumnSizingParameters();
     _parameters.TabLength = 4;
     _parameters.SeperatorLength = 1;
 }
        public void SetUp()
        {
            _data = Enumerable.Range(0, 5)
                .Select(i => new TestType("AAAA" + i, "AAAAAAA AAAAAAAA AAAAAAAA"))
                .ToList();

            _parameters = new ColumnSizingParameters();
            _parameters.Columns = FormatAnalyser.Analyse(typeof(TestType), null, true);
            _parameters.Sizers = _parameters.Columns.Select(f => new ColumnWidthNegotiator.ColumnSizerInfo(f, 4)).ToList();
            _parameters.TabLength = 4;
            _parameters.SeperatorLength = 1;

            ImportSizeData();

            _seperatorOverhead = 3;
            const int defaultWidth = 26;
            ColumnShrinker.ShrinkColumns(defaultWidth, _seperatorOverhead, _parameters);

            CreateInitialReport(defaultWidth);
        }
 private static int MinPossibleWidth(int seperatorOverhead, ColumnSizingParameters parameters)
 {
     var minStackWidth = parameters.StackSizer != null ? parameters.StackSizer.GetMinWidth(parameters.TabLength) : 0;
     var minPossibleWidth = parameters.Sizers.Sum(s => s.Sizer.GetIdealMinimumWidth()) + seperatorOverhead + minStackWidth;
     return minPossibleWidth;
 }