Пример #1
0
        void ArrangeLines(MathNode node)
        {
            //Get spacings and line styles; expand to cover the table fully
            List<double> spacings = node.GetListProperty("rowspacing").Select(x=> node.ParseLength(x)).ToList();
            List<string> lines = node.GetListProperty("rowlines");

            for (int i=0; i < node.Rows.Count -1; i++) //Todo: Verify
            {
                node.Rows[i].SpaceAfter = (double)Measurer.GetByIndexOrLast(spacings, i);
                string line = GetByIndexOrLast(lines, i);
                if (line != "none")
                {
                    node.Rows[i].LineAfter = line;
                    node.Rows[i].SpaceAfter += node.LineWidth;
                }
            }

            spacings = node.GetListProperty("columnspacing").Select(x => node.ParseLength(x)).ToList();
            lines = node.GetListProperty("columnlines");

            for (int i=0; i < node.Columns.Count -1; i++) //Todo: Verify
            {
                node.Columns[i].SpaceAfter = GetByIndexOrLast(spacings, i);
                string line = GetByIndexOrLast(lines, i);
                if (line != "none")
                {
                    node.Columns[i].LineAfter = line;
                    node.Columns[i].SpaceAfter += node.LineWidth;
                }
            }

            node.FrameSpacings = new List<double>(){0, 0};
            node.FrameLines = new List<string>(){null, null};

            spacings = node.GetListProperty("framespacing").Select(x => node.ParseSpace(x)).ToList();
            lines = node.GetListProperty("frame");
            for (int i = 0; i < 2; i++) //Todo: Verify
            {
                string line = GetByIndexOrLast(lines, i);
                if (line != "none")
                {
                    node.FrameSpacings[i] = GetByIndexOrLast(spacings, i);
                    node.FrameLines[i] = line;
                }
            }
        }
Пример #2
0
        void CalculateColumnWidths(MathNode node)
        {
            // Get total width
            string fullwidthattr = "auto";
            if (node.Attributes.ContainsKey("width"))
                fullwidthattr = node.Attributes["width"];

            double? fullwidth;
            if (fullwidthattr == "auto")
            {
                fullwidth = null;
            }
            else
            {
                fullwidth = node.ParseLength(fullwidthattr);
                if (fullwidth <= 0)
                    fullwidth = null;
            }

            // Fill fixed column widths
            List<string> columnwidths = node.GetListProperty("columnwidth");
            foreach (var item in node.Columns.Select((value,i) => new {i, value}))
            {
                ColumnDescriptor column = item.value;
                string attr = GetByIndexOrLast(columnwidths, item.i);
                if (attr == "auto" || attr == "fit")
                {
                    column.Fit = (attr == "fit");
                }
                else if (attr.EndsWith("%"))
                {
                    if (fullwidth == null)
                    {
                        //ToDo: node.error("Percents in column widths supported only in tables with explicit width; width of column %d treated as 'auto'" % (i+1))
                    }
                    else
                    {
                        double value = 0.0;
                        bool result = double.TryParse(attr.Substring(0, attr.Length - 1), out value);
                        if (result && value > 0)
                        {
                            column.Width = (double)fullwidth * value / 100;
                            column.Auto = false;
                        }
                    }
                }
                else
                {
                    column.Width = node.ParseSpace(attr);
                    column.Auto = true;
                }
            }

            // Set  initial auto widths for cells with colspan == 1
            foreach (RowDescriptor r in node.Rows)
            {
                foreach (var item in r.Cells.Select((value, i)=> new {i, value}))
                {
                    CellDescriptor c = item.value;
                    if (c == null || c.Content == null || c.ColSpan > 1)
                        continue;
                    ColumnDescriptor column = node.Columns[item.i];
                    if (column.Auto)
                        column.Width = Math.Max(column.Width, c.Content.Width);
                }
            }

            // Calculate auto widths for cells with colspan > 1
            while (true)
            {
                List<ColumnDescriptor> adjustedColumns = new List<ColumnDescriptor>();
                double adjustedWidth = 0;

                foreach (RowDescriptor r in node.Rows)
                {
                    foreach (var item in r.Cells.Select((value,i) => new {i, value}))
                    {
                        CellDescriptor c = item.value;
                        if (c == null || c.Content == null || c.ColSpan == 1)
                            continue;

                        List<ColumnDescriptor> columns = node.Columns.Skip(item.i).Take(item.i + c.ColSpan).ToList(); //ToDo: Verify
                        List<ColumnDescriptor> autoColumns = columns.Where(x => x.Auto == true).ToList();
                        if (autoColumns.Count == 0)
                            continue;
                        List<ColumnDescriptor> fixedColumns = columns.Where(x=> x.Auto == false).ToList();

                        double fixedWidth = columns.TakeWhile((value, i) => i != columns.Count-1).Select(x=> x.SpaceAfter).Sum();
                        if (fixedColumns.Count > 0)
                            fixedWidth += fixedColumns.Select(x => x.Width).Sum(); //ToDo: Verify
                        double autoWidth = autoColumns.Select(x => x.Width).Sum(); //ToDo: Verify
                        if (c.Content.Width <= fixedWidth + autoWidth)
                            continue; // already fits

                        double requiredWidth = c.Content.Width - fixedWidth;
                        double unitWidth = requiredWidth / autoColumns.Count;

                        while (true)
                        {
                            List<ColumnDescriptor> oversizedColumns = autoColumns.Where(x=> x.Width >= unitWidth).ToList();
                            if (oversizedColumns.Count == 0)
                                break;

                            autoColumns = autoColumns.Where(x => x.Width < unitWidth).ToList();
                            if (autoColumns.Count == 0)
                                break; //weird rounding effects

                            requiredWidth -= oversizedColumns.Select(x => x.Width).Sum();
                            unitWidth = requiredWidth / autoColumns.Count;

                            if (autoColumns.Count == 0)
                                continue; //protection against arithmetic overflow

                            //Store the maximum unit width
                            if (unitWidth > adjustedWidth)
                            {
                                adjustedWidth = unitWidth;
                                adjustedColumns = autoColumns;
                            }
                        }
                    }
                }

                if (adjustedColumns.Count == 0)
                    break;
                foreach (ColumnDescriptor col in adjustedColumns)
                    col.Width = adjustedWidth;
            }

            if (node.GetProperty("equalcolumns") == "true")
            {
                double globalWidth = node.Columns.Where(x => x.Auto = true).Select(x => x.Width).Max();
                foreach (ColumnDescriptor col in node.Columns)
                {
                    if (col.Auto == true)
                        col.Width = globalWidth;
                }
            }
            if (fullwidth != null)
            {
                double delta = (double)fullwidth;
                delta -= node.Columns.Select(x => x.Width).Sum();
                delta -= node.Columns.TakeWhile((x, i) => i < node.Columns.Count - 1).Select(x => x.SpaceAfter).Sum(); //ToDo: verify
                delta -= 2 * node.FrameSpacings[0];
                if (delta != 0)
                {
                    List<ColumnDescriptor> sizableColumns = node.Columns.Where(x => x.Fit == true).ToList();
                    if (sizableColumns.Count == 0)
                        sizableColumns = node.Columns.Where(x => x.Auto == true).ToList();

                    if (sizableColumns.Count == 0)
                    {
                        //ToDo: Implement
                        //node.error("Overconstrained table layout: explicit table width specified, but no column has automatic width; table width attribute ignored")
                    }
                    else
                    {
                        delta /= sizableColumns.Count;
                        foreach (ColumnDescriptor col in sizableColumns)
                            col.Width += delta;
                    }
                }
            }
        }
Пример #3
0
        void ArrangeCells(MathNode node)
        {
            node.Rows = new List<RowDescriptor>();
            node.Columns = new List<ColumnDescriptor>();
            List<int> busycells = new List<int>();

            // Read table-level alignment properties
            List<string> table_rowaligns = node.GetListProperty("rowalign");
            List<string> table_columnaligns = node.GetListProperty("columnalign");

            foreach (MathNode ch in node.Children)
            {
                string rowalign = GetByIndexOrLast(table_rowaligns, node.Rows.Count);
                List<string> row_columnaligns = table_columnaligns;
                List<MathNode> cells = new List<MathNode>();

                if (ch.ElementName == "mtr" || ch.ElementName == "mlabeledtr")
                {
                    cells = ch.Children;
                    if (ch.Attributes.ContainsKey("rowalign"))
                        rowalign = ch.Attributes["rowalign"];
                    if (ch.Attributes.ContainsKey("columnalign"))
                    {
                        List<string> columnaligns = node.GetListProperty("columnalign", ch.Attributes["columnalign"]);
                    }
                        
                }
                else
                {
                    cells.Add(ch);
                }

                RowDescriptor row = new RowDescriptor(node, cells, rowalign, row_columnaligns, busycells);
                node.Rows.Add(row);
                // busycells passes information about cells spanning multiple rows
                busycells = busycells.Select(n => Math.Max(0, n - 1)).ToList();
                while (busycells.Count < row.Cells.Count)
                    busycells.Add(0);

                for(int i =0; i < row.Cells.Count; i++)
                {
                    CellDescriptor cell = row.Cells[i];
                    if (cell == null)
                        continue;
                    if (cell.RowSpan > 1)
                    {
                        for (int j = i; j <= i + cell.ColSpan; i++)
                        {
                            busycells[j] = cell.RowSpan - 1;
                        }
                    }
                }
            }

            //Pad the table with empty rows until no spanning cell protrudes
            while (busycells.Max() > 0)
            {
                string rowalign = Measurer.GetByIndexOrLast(table_rowaligns, node.Rows.Count);
                node.Rows.Add(new RowDescriptor(node, new List<MathNode>(), rowalign, table_columnaligns, busycells));
                busycells = busycells.Select(x => Math.Max(0, x - 1)).ToList();
            }

        }