]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetTabular.cpp
Fix assertion when checking if change in selection
[lyx.git] / src / insets / InsetTabular.cpp
index a25f4d6356a54012b9e14c2c6953cbfb18cfc73b..ed2824149479fe2337ff05b94a3063b0e20ffe06 100644 (file)
@@ -199,6 +199,7 @@ TabularFeature tabularFeature[] =
        { Tabular::LONGTABULAR_ALIGN_RIGHT, "longtabular-align-right", false },
        { Tabular::SET_DECIMAL_POINT, "set-decimal-point", true },
        { Tabular::SET_TABULAR_WIDTH, "set-tabular-width", true },
+       { Tabular::SET_INNER_LINES, "set-inner-lines", false },
        { Tabular::LAST_ACTION, "", false }
 };
 
@@ -1029,15 +1030,60 @@ int Tabular::cellHeight(idx_type cell) const
 }
 
 
-bool Tabular::updateColumnWidths()
+bool Tabular::updateColumnWidths(MetricsInfo & mi)
 {
        vector<int> max_dwidth(ncols(), 0);
+       // collect max. fixed width of column
+       map<col_type, int> max_pwidth;
+       // collect max. variable width of column
+       map<col_type, int> max_width;
+
        for(col_type c = 0; c < ncols(); ++c)
                for(row_type r = 0; r < nrows(); ++r) {
                        idx_type const i = cellIndex(r, c);
                        if (getAlignment(i) == LYX_ALIGN_DECIMAL)
                                max_dwidth[c] = max(max_dwidth[c], cell_info[r][c].decimal_width);
+                       if (!getPWidth(i).zero())
+                               max_pwidth[c] = max(max_pwidth[c], cell_info[r][c].width);
+                       else if (!column_info[c].varwidth)
+                               max_width[c] = max(max_width[c], cell_info[r][c].width);
+               }
+
+       // If we have a fixed tabular width, we take this into account
+       Length tab_width = tabular_width;
+       bool const tabularx = hasVarwidthColumn();
+       if (tabularx && tab_width.zero())
+               // If no tabular width is specified with X columns,
+               // we use 100% colwidth
+               tab_width = Length(100, Length::PCW);
+       int restwidth = -1;
+       if (!tab_width.zero()) {
+               restwidth = mi.base.inPixels(tab_width);
+               // Substract the fixed widths from the table width
+               for (auto const w : max_pwidth)
+                       restwidth -= w.second;
+       }
+
+       // If we have a fixed width, distribute the available table width
+       // (minus the fixed widths) to the variable-width columns
+       int vcolwidth = -1;
+       int restcols = ncols() - max_pwidth.size();
+       if (restwidth > 0)
+               vcolwidth = restwidth / restcols;
+
+       // Now consider that some variable width columns exceed the vcolwidth
+       if (vcolwidth > 0) {
+               bool changed = false;
+               for (auto const w : max_width) {
+                       if (tabularx || w.second > vcolwidth) {
+                               --restcols;
+                               restwidth -= w.second;
+                               changed = true;
+                       }
                }
+               if (changed && restwidth > 0)
+                       vcolwidth = restwidth / restcols;
+       }
 
        bool update = false;
        // for each col get max of single col cells
@@ -1050,14 +1096,23 @@ bool Tabular::updateColumnWidths()
                                        && cell_info[r][c].decimal_width != 0)
                                        new_width = max(new_width, cellInfo(i).width
                                                + max_dwidth[c] - cellInfo(i).decimal_width);
-                               else
+                               else if (getPWidth(i).zero() && vcolwidth > 0) {
+                                       if (tabularx && !column_info[c].varwidth)
+                                               new_width = max(new_width, cellInfo(i).width);
+                                       else if (tabularx)
+                                               new_width = vcolwidth;
+                                       else
+                                               new_width = max(vcolwidth, max(new_width, cellInfo(i).width));
+                               } else
                                        new_width = max(new_width, cellInfo(i).width);
                        }
                }
 
                if (column_info[c].width != new_width) {
                        column_info[c].width = new_width;
-                       update = true;
+                       // Do not trigger update when no space is left for variable
+                       // columns, as this will loop
+                       update = tab_width.zero() || restwidth > 0;
                }
        }
        // update col widths to fit merged cells
@@ -1074,7 +1129,9 @@ bool Tabular::updateColumnWidths()
 
                        if (cellInfo(i).width > old_width) {
                                column_info[c + span - 1].width += cellInfo(i).width - old_width;
-                               update = true;
+                               // Do not trigger update when no space is left for variable
+                               // columns, as this will loop
+                               update = tab_width.zero() || restwidth > 0;
                        }
                }
 
@@ -3781,7 +3838,6 @@ void InsetTableCell::metrics(MetricsInfo & mi, Dimension & dim) const
 
        // We tell metrics here not to expand on multiple pars
        // This is the difference to InsetText::Metrics
-       // FIXME: pars with newlines are still too wide!
        if (hasFixedWidth())
                tm.metrics(mi, dim, mi.base.textwidth, false);
        else
@@ -3938,8 +3994,10 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                        Length const p_width = tabular.getPWidth(cell);
                        if (!p_width.zero())
                                m.base.textwidth = mi.base.inPixels(p_width);
+                       else if (tabular.column_info[c].varwidth)
+                               m.base.textwidth = tabular.column_info[c].width;
                        tabular.cellInset(cell)->metrics(m, dim0);
-                       if (!p_width.zero())
+                       if (!p_width.zero() || tabular.column_info[c].varwidth)
                                dim0.wid = m.base.textwidth;
                        tabular.cellInfo(cell).width = dim0.wid + 2 * WIDTH_OF_LINE
                                + tabular.interColumnSpace(cell);
@@ -4006,7 +4064,10 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space);
        }
 
-       tabular.updateColumnWidths();
+       // We need to recalculate the metrics after column width calculation
+       // with xtabular (possibly multiple times, so the call is recursive).
+       if (tabular.updateColumnWidths(mi) && tabular.hasVarwidthColumn())
+               metrics(mi, dim);
        dim.asc = tabular.rowAscent(0) - tabular.offsetVAlignment();
        dim.des = tabular.height() - dim.asc;
        dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH;
@@ -4151,35 +4212,44 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
 }
 
 
+namespace {
+
+void tabline(PainterInfo const & pi, int x1, int y1, int x2, int y2,
+             bool drawline, bool heavy = false)
+{
+       ColorCode const col = drawline ? Color_tabularline : Color_tabularonoffline;
+       pi.pain.line(x1, y1, x2, y2, pi.textColor(col),
+                                drawline ? Painter::line_solid : Painter::line_onoffdash,
+                                (heavy ? 2 : 1) * Painter::thin_line);
+}
+
+}
+
+
 void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y,
                                 row_type row, idx_type cell) const
 {
        y -= tabular.rowAscent(row);
        int const w = tabular.cellWidth(cell);
        int const h = tabular.cellHeight(cell);
-       Color const linecolor = pi.textColor(Color_tabularline);
-       Color const gridcolor = pi.textColor(Color_tabularonoffline);
 
        // Top
        bool drawline = tabular.topLine(cell)
                || (row > 0 && tabular.bottomLine(tabular.cellAbove(cell)));
-       pi.pain.line(x, y, x + w, y,
-               drawline ? linecolor : gridcolor,
-               drawline ? Painter::line_solid : Painter::line_onoffdash);
+       bool heavy = tabular.use_booktabs && row == 0 && tabular.rowTopLine(row);
+       tabline(pi, x, y, x + w, y, drawline, heavy);
 
        // Bottom
        drawline = tabular.bottomLine(cell);
-       pi.pain.line(x, y + h, x + w, y + h,
-               drawline ? linecolor : gridcolor,
-               drawline ? Painter::line_solid : Painter::line_onoffdash);
+       heavy = tabular.use_booktabs && row == tabular.nrows() - 1
+               && tabular.rowBottomLine(row);
+       tabline(pi, x, y + h, x + w, y + h, drawline, heavy);
 
        // Left
        col_type const col = tabular.cellColumn(cell);
        drawline = tabular.leftLine(cell)
                || (col > 0 && tabular.rightLine(tabular.cellIndex(row, col - 1)));
-       pi.pain.line(x, y, x, y + h,
-               drawline ? linecolor : gridcolor,
-               drawline ? Painter::line_solid : Painter::line_onoffdash);
+       tabline(pi, x, y, x, y + h, drawline);
 
        // Right
        x -= tabular.interColumnSpace(cell);
@@ -4190,9 +4260,7 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y,
        drawline = tabular.rightLine(cell)
                   || (next_cell_col < tabular.ncols()
                       && tabular.leftLine(tabular.cellIndex(row, next_cell_col)));
-       pi.pain.line(x + w, y, x + w, y + h,
-               drawline ? linecolor : gridcolor,
-               drawline ? Painter::line_solid : Painter::line_onoffdash);
+       tabline(pi, x + w, y, x + w, y + h, drawline);
 }
 
 
@@ -4902,6 +4970,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s,
 
                case Tabular::SET_ALL_LINES:
                case Tabular::UNSET_ALL_LINES:
+               case Tabular::SET_INNER_LINES:
                case Tabular::SET_BORDER_LINES:
                        status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
                        break;
@@ -5712,6 +5781,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        row_type sel_row_start;
        row_type sel_row_end;
        bool setLines = false;
+       bool setLinesInnerOnly = false;
        LyXAlignment setAlign = LYX_ALIGN_LEFT;
        Tabular::VAlignment setVAlign = Tabular::LYX_VALIGN_TOP;
 
@@ -5773,10 +5843,12 @@ void InsetTabular::tabularFeatures(Cursor & cur,
 
        case Tabular::SET_PWIDTH: {
                Length const len(value);
-               tabular.setColumnPWidth(cur, cur.idx(), len);
-               if (len.zero()
-                   && tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_BLOCK)
-                       tabularFeatures(cur, Tabular::ALIGN_CENTER, string());
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+                       tabular.setColumnPWidth(cur, tabular.cellIndex(row, c), len);
+                       if (len.zero()
+                           && tabular.getAlignment(tabular.cellIndex(row, c), true) == LYX_ALIGN_BLOCK)
+                               tabularFeatures(cur, Tabular::ALIGN_CENTER, string());
+               }
                break;
        }
 
@@ -5786,7 +5858,8 @@ void InsetTabular::tabularFeatures(Cursor & cur,
 
        case Tabular::TOGGLE_VARWIDTH_COLUMN: {
                bool const varwidth = value == "on";
-               tabular.toggleVarwidth(cur.idx(), varwidth);
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c)
+                       tabular.toggleVarwidth(tabular.cellIndex(row, c), varwidth);
                break;
        }
 
@@ -6061,6 +6134,9 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                break;
        }
 
+       case Tabular::SET_INNER_LINES:
+               setLinesInnerOnly = true;
+               // fall through
        case Tabular::SET_ALL_LINES:
                setLines = true;
                // fall through
@@ -6068,10 +6144,16 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                for (row_type r = sel_row_start; r <= sel_row_end; ++r)
                        for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
                                idx_type const cell = tabular.cellIndex(r, c);
-                               tabular.setTopLine(cell, setLines);
-                               tabular.setBottomLine(cell, setLines);
-                               tabular.setRightLine(cell, setLines);
-                               tabular.setLeftLine(cell, setLines);
+                               if (!setLinesInnerOnly || r != sel_row_start)
+                                       tabular.setTopLine(cell, setLines);
+                               if ((!setLinesInnerOnly || r != sel_row_end)
+                                   && (!setLines || r == sel_row_end))
+                                       tabular.setBottomLine(cell, setLines);
+                               if ((!setLinesInnerOnly || c != sel_col_end)
+                                   && (!setLines || c == sel_col_end))
+                                       tabular.setRightLine(cell, setLines);
+                               if ((!setLinesInnerOnly || c != sel_col_start))
+                                       tabular.setLeftLine(cell, setLines);
                        }
                break;
 
@@ -6146,8 +6228,6 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                tabular.longtabular_alignment = Tabular::LYX_LONGTABULAR_ALIGN_RIGHT;
                break;
 
-
-
        case Tabular::SET_ROTATE_CELL:
                for (row_type r = sel_row_start; r <= sel_row_end; ++r)
                        for (col_type c = sel_col_start; c <= sel_col_end; ++c)