Пример #1
0
        public TextileTable(
            string[] header,
            string[] styles,
            IList <string[]> details)
        {
            Header = header.Select(txt =>
            {
                var cell = new TextileTableCell(txt);
                // Ignore Header Row-span
                cell.RowSpan = 1;
                return(cell);
            }).ToList <ITableCell>();

            Details = details.Select(row =>
                                     row.Select(txt => new TextileTableCell(txt)).ToList <ITableCell>()
                                     ).ToList();

            // column-idx vs text-alignment
            Dictionary <int, TextAlignment> styleMt = styles
                                                      .Select((txt, idx) =>
            {
                var firstChar = txt[0];
                var lastChar  = txt[txt.Length - 1];

                return
                ((firstChar == ':' && lastChar == ':') ?
                 Tuple.Create(idx, (TextAlignment?)TextAlignment.Center) :

                 (lastChar == ':') ?
                 Tuple.Create(idx, (TextAlignment?)TextAlignment.Right) :

                 (firstChar == ':') ?
                 Tuple.Create(idx, (TextAlignment?)TextAlignment.Left) :

                 Tuple.Create(idx, (TextAlignment?)null));
            })
                                                      .Where(tpl => tpl.Item2.HasValue)
                                                      .ToDictionary(tpl => tpl.Item1, tpl => tpl.Item2.Value);

            var styleColumnCount = styleMt.Count;

            // apply cell style to header
            var headerColumnCount = 0;
            {
                var colOffset = 0;
                foreach (TextileTableCell cell in Header)
                {
                    cell.ColumnIndex = colOffset;

                    // apply text align
                    if (styleMt.TryGetValue(colOffset, out var style))
                    {
                        cell.Horizontal = style;
                    }

                    colOffset += cell.ColSpan;
                }

                headerColumnCount = colOffset;
            }

            // apply cell style to header
            var colCntAtDetail     = new List <int>();
            var maxColCntInDetails = 1;

            {
                var multiRowsAtColIdx = new Dictionary <int, MdSpan>();
                for (var rowIdx = 0; rowIdx < Details.Count; ++rowIdx)
                {
                    List <ITableCell> row = Details[rowIdx];

                    var hasAnyCell = false;
                    var colOffset  = 0;

                    var rowspansColOffset = multiRowsAtColIdx
                                            .Select(ent => ent.Value.ColSpan)
                                            .Sum();

                    /*
                     * In this row, is space exists to insert cell?
                     *
                     * eg. has space
                     *    __________________________________
                     *    | 2x1 cell | 1x1 cell | 1x1 cell |
                     * -> |          |‾‾‾‾‾‾‾‾‾‾|‾‾‾‾‾‾‾‾‾‾|
                     *    ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
                     *
                     * eg. has no space: multi-rows occupy all space in this row.
                     *    __________________________________
                     *    | 2x1 cell |      2x2 cell        |
                     * -> |          |                      |
                     *    ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
                     *
                     */
                    if (rowspansColOffset < maxColCntInDetails)
                    {
                        int colIdx;
                        for (colIdx = 0; colIdx < row.Count;)
                        {
                            int colSpan;
                            if (multiRowsAtColIdx.TryGetValue(colOffset, out var span))
                            {
                                colSpan = span.ColSpan;
                            }
                            else
                            {
                                hasAnyCell = true;

                                var cell = (TextileTableCell)row[colIdx];
                                cell.ColumnIndex = colOffset;

                                // apply text align
                                if (!cell.Horizontal.HasValue &&
                                    styleMt.TryGetValue(colOffset, out var style))
                                {
                                    cell.Horizontal = style;
                                }

                                colSpan = cell.ColSpan;

                                if (cell.RowSpan > 1)
                                {
                                    multiRowsAtColIdx[colOffset] =
                                        new MdSpan(cell.RowSpan, cell.ColSpan);
                                }

                                ++colIdx;
                            }

                            colOffset += colSpan;
                        }

                        foreach (var left in multiRowsAtColIdx.Where(tpl => tpl.Key >= colOffset)
                                 .OrderBy(tpl => tpl.Key))
                        {
                            while (colOffset < left.Key)
                            {
                                var cell = new TextileTableCell(null);
                                cell.ColumnIndex = colOffset++;
                                row.Add(cell);
                            }
                            colOffset += left.Value.ColSpan;
                        }
                    }

                    colOffset += multiRowsAtColIdx
                                 .Where(ent => ent.Key >= colOffset)
                                 .Select(ent => ent.Value.ColSpan)
                                 .Sum();

                    foreach (var spanEntry in multiRowsAtColIdx.ToArray())
                    {
                        if (--spanEntry.Value.Life == 0)
                        {
                            multiRowsAtColIdx.Remove(spanEntry.Key);
                        }
                    }

                    colCntAtDetail.Add(colOffset);
                    maxColCntInDetails = Math.Max(maxColCntInDetails, colOffset);

                    if (!hasAnyCell)
                    {
                        Details.Insert(rowIdx, new List <ITableCell>());
                    }
                }

                // if any multirow is left, insert an empty row.
                while (multiRowsAtColIdx.Count > 0)
                {
                    var row = new List <ITableCell>();
                    Details.Add(row);

                    var colOffset = 0;

                    foreach (var spanEntry in multiRowsAtColIdx.OrderBy(tpl => tpl.Key))
                    {
                        while (colOffset < spanEntry.Key)
                        {
                            var cell = new TextileTableCell(null);
                            cell.ColumnIndex = colOffset++;
                            row.Add(cell);
                        }

                        colOffset += spanEntry.Value.ColSpan;

                        if (--spanEntry.Value.Life == 0)
                        {
                            multiRowsAtColIdx.Remove(spanEntry.Key);
                        }
                    }

                    colCntAtDetail.Add(colOffset);
                }
            }

            ColCount = Math.Max(Math.Max(headerColumnCount, styleColumnCount), maxColCntInDetails);
            RowCount = Details.Count;

            // insert cell for the shortfall

            for (var retry = Header.Sum(cell => cell.ColSpan); retry < ColCount; ++retry)
            {
                var cell = new TextileTableCell(null);
                cell.ColumnIndex = retry;
                Header.Add(cell);
            }

            for (var rowIdx = 0; rowIdx < Details.Count; ++rowIdx)
            {
                for (var retry = colCntAtDetail[rowIdx]; retry < ColCount; ++retry)
                {
                    var cell = new TextileTableCell(null);
                    cell.ColumnIndex = retry;
                    Details[rowIdx].Add(cell);
                }
            }
        }
Пример #2
0
 /// <summary>
 /// Initializes a new instance of <see cref="MdAdmonition"/> with the specified type and title but without any content.
 /// </summary>
 ///
 /// <param name="type">
 /// The admonition's type. Any non-empty string is allowed.
 /// Recommended values are <c>attention</c>, <c>caution</c>, <c>danger</c>, <c>error</c>,
 /// <c>hint</c>, <c>important</c>, <c>note</c>, <c>tip</c> and <c>warning</c>
 /// </param>
 ///
 /// <param name="title">
 /// The admonition's title. To create a admonition without title, use a different constructor overload.
 /// </param>
 ///
 /// <exception cref="ArgumentException">Thrown when <paramref name="type"/> is null or whitespace.</exception>
 /// <exception cref="ArgumentNullException">Thrown when <paramref name="title"/> is <c>null</c>.</exception>
 public MdAdmonition(string type, MdSpan title) : this(type, title, Array.Empty <MdBlock>())
 {
 }
Пример #3
0
 /// <summary>
 /// Initializes a new instance of <see cref="MdAdmonition"/>.
 /// </summary>
 ///
 /// <param name="type">
 /// The admonition's type. Any non-empty string is allowed.
 /// Recommended values are <c>attention</c>, <c>caution</c>, <c>danger</c>, <c>error</c>,
 /// <c>hint</c>, <c>important</c>, <c>note</c>, <c>tip</c> and <c>warning</c>
 /// </param>
 ///
 /// <param name="title">
 /// The admonition's title. To create a admonition without title, use a different constructor overload.
 /// </param>
 ///
 /// <param name="content">
 /// The admonition's content.
 /// </param>
 ///
 /// <exception cref="ArgumentException">Thrown when <paramref name="type"/> is null or whitespace.</exception>
 /// <exception cref="ArgumentNullException">Thrown when <paramref name="title"/> is <c>null</c>.</exception>
 public MdAdmonition(string type, MdSpan title, MdList content) : this(type, title, (MdBlock)content)
 {
 }
Пример #4
0
 /// <summary>
 /// Initializes a new instance of <see cref="MdAdmonition"/>.
 /// </summary>
 ///
 /// <param name="type">
 /// The admonition's type. Any non-empty string is allowed.
 /// Recommended values are <c>attention</c>, <c>caution</c>, <c>danger</c>, <c>error</c>,
 /// <c>hint</c>, <c>important</c>, <c>note</c>, <c>tip</c> and <c>warning</c>
 /// </param>
 ///
 /// <param name="title">
 /// The admonition's title. To create a admonition without title, use a different constructor overload.
 /// </param>
 ///
 /// <param name="content">
 /// The admonition's content.
 /// </param>
 ///
 /// <exception cref="ArgumentException">Thrown when <paramref name="type"/> is null or whitespace.</exception>
 /// <exception cref="ArgumentNullException">Thrown when <paramref name="title"/> is <c>null</c>.</exception>
 public MdAdmonition(string type, MdSpan title, params MdBlock[] content) : this(type, title, (IEnumerable <MdBlock>)content)
 {
 }
Пример #5
0
 /// <summary>
 /// Initializes a new instance of <see cref="MdAdmonition"/>.
 /// </summary>
 ///
 /// <param name="type">
 /// The admonition's type. Any non-empty string is allowed.
 /// Recommended values are <c>attention</c>, <c>caution</c>, <c>danger</c>, <c>error</c>,
 /// <c>hint</c>, <c>important</c>, <c>note</c>, <c>tip</c> and <c>warning</c>
 /// </param>
 ///
 /// <param name="title">
 /// The admonition's title. To create a admonition without title, use a different constructor overload.
 /// </param>
 ///
 /// <param name="content">
 /// The admonition's content.
 /// </param>
 ///
 /// <exception cref="ArgumentException">Thrown when <paramref name="type"/> is null or whitespace.</exception>
 /// <exception cref="ArgumentNullException">Thrown when <paramref name="title"/> is <c>null</c>.</exception>
 public MdAdmonition(string type, MdSpan title, MdContainerBlockBase content) : this(type, title, (MdBlock)content)
 {
 }