X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=9df7d463c3832dde51d9d04e4bd87868c4b9a12a;hb=ebc2b1295a0464dde6c20a09ddc249c463a21c79;hp=a25f4d6356a54012b9e14c2c6953cbfb18cfc73b;hpb=9dcb24d578cfc9df5b70bbf3f13a95cd63ac3213;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index a25f4d6356..9df7d463c3 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -127,12 +127,20 @@ TabularFeature tabularFeature[] = { Tabular::MOVE_ROW_UP, "move-row-up", false }, { Tabular::SET_LINE_TOP, "set-line-top", true }, { Tabular::SET_LINE_BOTTOM, "set-line-bottom", true }, + { Tabular::SET_LTRIM_TOP, "set-ltrim-top", true }, + { Tabular::SET_LTRIM_BOTTOM, "set-ltrim-bottom", true }, + { Tabular::SET_RTRIM_TOP, "set-rtrim-top", true }, + { Tabular::SET_RTRIM_BOTTOM, "set-rtrim-bottom", true }, { Tabular::SET_LINE_LEFT, "set-line-left", true }, { Tabular::SET_LINE_RIGHT, "set-line-right", true }, { Tabular::TOGGLE_LINE_TOP, "toggle-line-top", false }, { Tabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom", false }, { Tabular::TOGGLE_LINE_LEFT, "toggle-line-left", false }, { Tabular::TOGGLE_LINE_RIGHT, "toggle-line-right", false }, + { Tabular::TOGGLE_LTRIM_TOP, "toggle-ltrim-top", false }, + { Tabular::TOGGLE_LTRIM_BOTTOM, "toggle-ltrim-bottom", false }, + { Tabular::TOGGLE_RTRIM_TOP, "toggle-rtrim-top", false }, + { Tabular::TOGGLE_RTRIM_BOTTOM, "toggle-rtrim-bottom", false }, { Tabular::ALIGN_LEFT, "align-left", false }, { Tabular::ALIGN_RIGHT, "align-right", false }, { Tabular::ALIGN_CENTER, "align-center", false }, @@ -155,6 +163,7 @@ TabularFeature tabularFeature[] = { Tabular::UNSET_MULTIROW, "unset-multirow", false }, { Tabular::SET_MROFFSET, "set-mroffset", true }, { Tabular::SET_ALL_LINES, "set-all-lines", false }, + { Tabular::RESET_FORMAL_DEFAULT, "reset-formal-default", false }, { Tabular::UNSET_ALL_LINES, "unset-all-lines", false }, { Tabular::TOGGLE_LONGTABULAR, "toggle-longtabular", false }, { Tabular::SET_LONGTABULAR, "set-longtabular", false }, @@ -199,6 +208,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 } }; @@ -583,6 +593,10 @@ Tabular::CellData::CellData(Buffer * buf) bottom_line(false), left_line(false), right_line(false), + top_line_rtrimmed(false), + top_line_ltrimmed(false), + bottom_line_rtrimmed(false), + bottom_line_ltrimmed(false), usebox(BOX_NONE), rotate(0), inset(new InsetTableCell(buf)) @@ -606,6 +620,10 @@ Tabular::CellData::CellData(CellData const & cs) bottom_line(cs.bottom_line), left_line(cs.left_line), right_line(cs.right_line), + top_line_rtrimmed(cs.top_line_rtrimmed), + top_line_ltrimmed(cs.top_line_ltrimmed), + bottom_line_rtrimmed(cs.bottom_line_rtrimmed), + bottom_line_ltrimmed(cs.bottom_line_ltrimmed), usebox(cs.usebox), rotate(cs.rotate), align_special(cs.align_special), @@ -632,6 +650,10 @@ Tabular::CellData & Tabular::CellData::operator=(CellData const & cs) bottom_line = cs.bottom_line; left_line = cs.left_line; right_line = cs.right_line; + top_line_rtrimmed = cs.top_line_rtrimmed; + top_line_ltrimmed = cs.top_line_ltrimmed; + bottom_line_rtrimmed = cs.bottom_line_rtrimmed; + bottom_line_rtrimmed = cs.bottom_line_rtrimmed; usebox = cs.usebox; rotate = cs.rotate; align_special = cs.align_special; @@ -963,22 +985,40 @@ bool Tabular::bottomLine(idx_type const cell) const } -bool Tabular::leftLine(idx_type cell) const +bool Tabular::leftLine(idx_type cell, bool const ignore_bt) const { - if (use_booktabs) + if (use_booktabs && !ignore_bt) return false; return cellInfo(cell).left_line; } -bool Tabular::rightLine(idx_type cell) const +bool Tabular::rightLine(idx_type cell, bool const ignore_bt) const { - if (use_booktabs) + if (use_booktabs && !ignore_bt) return false; return cellInfo(cell).right_line; } +pair Tabular::topLineTrim(idx_type const cell) const +{ + if (!use_booktabs) + return make_pair(false, false); + return make_pair(cellInfo(cell).top_line_ltrimmed, + cellInfo(cell).top_line_rtrimmed); +} + + +pair Tabular::bottomLineTrim(idx_type const cell) const +{ + if (!use_booktabs) + return make_pair(false, false); + return make_pair(cellInfo(cell).bottom_line_ltrimmed, + cellInfo(cell).bottom_line_rtrimmed); +} + + int Tabular::interRowSpace(row_type row) const { if (!row || row >= nrows()) @@ -1029,15 +1069,60 @@ int Tabular::cellHeight(idx_type cell) const } -bool Tabular::updateColumnWidths() +bool Tabular::updateColumnWidths(MetricsInfo & mi) { vector max_dwidth(ncols(), 0); + // collect max. fixed width of column + map max_pwidth; + // collect max. variable width of column + map 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 +1135,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 +1168,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; } } @@ -1263,6 +1359,42 @@ void Tabular::setBottomLine(idx_type i, bool line) } +void Tabular::setTopLineLTrim(idx_type i, bool val) +{ + cellInfo(i).top_line_ltrimmed = val; +} + + +void Tabular::setTopLineRTrim(idx_type i, bool val) +{ + cellInfo(i).top_line_rtrimmed = val; +} + + +void Tabular::setBottomLineLTrim(idx_type i, bool val) +{ + cellInfo(i).bottom_line_ltrimmed = val; +} + + +void Tabular::setBottomLineRTrim(idx_type i, bool val) +{ + cellInfo(i).bottom_line_rtrimmed = val; +} + + +void Tabular::setTopLineTrim(idx_type i, pair trim) +{ + setTopLineLTrim(i, trim.first); + setTopLineRTrim(i, trim.second); +} + +void Tabular::setBottomLineTrim(idx_type i, pair trim) +{ + setBottomLineLTrim(i, trim.first); + setBottomLineRTrim(i, trim.second); +} + void Tabular::setLeftLine(idx_type cell, bool line) { cellInfo(cell).left_line = line; @@ -1557,7 +1689,11 @@ void Tabular::write(ostream & os) const << write_attribute("alignment", cell_info[r][c].alignment) << write_attribute("valignment", cell_info[r][c].valignment) << write_attribute("topline", cell_info[r][c].top_line) + << write_attribute("toplineltrim", cell_info[r][c].top_line_ltrimmed) + << write_attribute("toplinertrim", cell_info[r][c].top_line_rtrimmed) << write_attribute("bottomline", cell_info[r][c].bottom_line) + << write_attribute("bottomlineltrim", cell_info[r][c].bottom_line_ltrimmed) + << write_attribute("bottomlinertrim", cell_info[r][c].bottom_line_rtrimmed) << write_attribute("leftline", cell_info[r][c].left_line) << write_attribute("rightline", cell_info[r][c].right_line) << write_attribute("rotate", cell_info[r][c].rotate) @@ -1671,7 +1807,11 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "alignment", cell_info[i][j].alignment); getTokenValue(line, "valignment", cell_info[i][j].valignment); getTokenValue(line, "topline", cell_info[i][j].top_line); + getTokenValue(line, "toplineltrim", cell_info[i][j].top_line_ltrimmed); + getTokenValue(line, "toplinertrim", cell_info[i][j].top_line_rtrimmed); getTokenValue(line, "bottomline", cell_info[i][j].bottom_line); + getTokenValue(line, "bottomlineltrim", cell_info[i][j].bottom_line_ltrimmed); + getTokenValue(line, "bottomlinertrim", cell_info[i][j].bottom_line_rtrimmed); getTokenValue(line, "leftline", cell_info[i][j].left_line); getTokenValue(line, "rightline", cell_info[i][j].right_line); getTokenValue(line, "rotate", cell_info[i][j].rotate); @@ -2247,18 +2387,32 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang, // is done in Tabular::TeXBottomHLine(...) // get for each column the topline (if any) - map topline; + map topline, topltrims, toprtrims; col_type nset = 0; + bool have_trims = false; for (auto const & c : columns) { topline[c] = topLine(cellIndex(row, c)); + topltrims[c] = topLineTrim(cellIndex(row, c)).first; + toprtrims[c] = topLineTrim(cellIndex(row, c)).second; // If cell is part of a multirow and not the first cell of the // multirow, no line must be drawn. if (row != 0) if (isMultiRow(cellIndex(row, c)) - && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW) + && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW) { topline[c] = false; + topltrims[c] = false; + toprtrims[c] = false; + } + // copy trimming to multicolumn parts + if (isPartOfMultiColumn(row, c)) { + topltrims[c] = topltrims[c-1]; + toprtrims[c] = toprtrims[c-1]; + } if (topline.find(c) != topline.end() && topline.find(c)->second) ++nset; + if ((topltrims.find(c) != topltrims.end() && topltrims.find(c)->second) + || (toprtrims.find(c) != toprtrims.end() && toprtrims.find(c)->second)) + have_trims = true; } // do nothing if empty first row, or incomplete row line after @@ -2266,36 +2420,66 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang, return; // only output complete row lines and the 1st row's clines - if (nset == ncols()) { + if (nset == ncols() && !have_trims) { if (use_booktabs) { os << (row == 0 ? "\\toprule " : "\\midrule "); } else { os << "\\hline "; } - } else if (row == 0) { + } else if (row == 0 || have_trims) { + string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; for (auto & c : columns) { if (topline.find(c)->second) { col_type offset = 0; for (col_type j = 0 ; j < c; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; - - //babel makes the "-" character an active one, so we have to suppress this here - //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# - if (lang == "slovak" || lang == "czech") - os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") - << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; - else - os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; - + while (isPartOfMultiColumn(row, c)) + ++c; + string trim; + if (topltrims.find(c) != topltrims.end() + && topltrims.find(c)->second) + trim = "l"; + string const firstcol = convert(c + 1 + offset); col_type cstart = c; - for ( ; c < ncols() && topline.find(c)->second; ++c) {} + for ( ; c < ncols() - 1 && topline.find(c)->second ; ++c) { + if (isMultiColumn(cellIndex(row, c)) + && c < ncols() - 1 && isPartOfMultiColumn(row, c + 1)) + continue; + if (c > cstart && topltrims.find(c) != topltrims.end() + && topltrims.find(c)->second) { + if (!isPartOfMultiColumn(row, c)) + --c; + break; + } else if (toprtrims.find(c) != toprtrims.end() + && toprtrims.find(c)->second) + break; + } for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; + col_type const lastcol = c + 1 + offset; + if (toprtrims.find(c) != toprtrims.end() + && toprtrims.find(c)->second) + trim += "r"; - os << c + offset << "} "; + //babel makes the "-" character an active one, so we have to suppress this here + //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# + if (lang == "slovak" || lang == "czech") { + os << "\\expandafter" << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "\\expandafter{\\expandafter" << firstcol << "\\string-"; + } else { + os << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "{" << firstcol << '-'; + } + os << lastcol << "}"; + if (c == ncols() - 1) + break; } } } @@ -2311,11 +2495,16 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, // get the bottomlines of row r, and toplines in next row bool lastrow = row == nrows() - 1; - map bottomline, topline; + map bottomline, topline, topltrims, toprtrims, bottomltrims, bottomrtrims; bool nextrowset = true; for (auto const & c : columns) { + idx_type const idx = cellIndex(row, c); bottomline[c] = bottomLine(cellIndex(row, c)); + bottomltrims[c] = bottomLineTrim(idx).first; + bottomrtrims[c] = bottomLineTrim(idx).second; topline[c] = !lastrow && topLine(cellIndex(row + 1, c)); + topltrims[c] = !lastrow && topLineTrim(cellIndex(row + 1, c)).first; + toprtrims[c] = !lastrow && topLineTrim(cellIndex(row + 1, c)).second; // If cell is part of a multirow and not the last cell of the // multirow, no line must be drawn. if (!lastrow) @@ -2324,52 +2513,103 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, && cell_info[row + 1][c].multirow != CELL_BEGIN_OF_MULTIROW) { bottomline[c] = false; topline[c] = false; - } + bottomltrims[c] = false; + bottomrtrims[c] = false; + topltrims[c] = false; + toprtrims[c] = false; + } + // copy trimming in multicolumn parts + if (isPartOfMultiColumn(row, c)) { + topltrims[c] = topltrims[c-1]; + toprtrims[c] = toprtrims[c-1]; + bottomltrims[c] = bottomltrims[c-1]; + bottomrtrims[c] = bottomrtrims[c-1]; + } + nextrowset &= topline.find(c) != topline.end() && topline.find(c)->second; } // combine this row's bottom lines and next row's toplines if necessary col_type nset = 0; + bool have_trims = false; for (auto const & c : columns) { if (!nextrowset) bottomline[c] = bottomline.find(c)->second || topline.find(c)->second; + bottomltrims[c] = (bottomltrims.find(c) != bottomltrims.end() && bottomltrims.find(c)->second) + || (topltrims.find(c) != topltrims.end() && topltrims.find(c)->second); + bottomrtrims[c] =(bottomrtrims.find(c) != bottomrtrims.end() && bottomrtrims.find(c)->second) + || (toprtrims.find(c) != toprtrims.end() && toprtrims.find(c)->second); if (bottomline.find(c)->second) ++nset; + if ((bottomltrims.find(c) != bottomltrims.end() && bottomltrims.find(c)->second) + || (bottomrtrims.find(c) != bottomrtrims.end() && bottomrtrims.find(c)->second)) + have_trims = true; } // do nothing if empty, OR incomplete row line with a topline in next row if (nset == 0 || (nextrowset && nset != ncols())) return; - if (nset == ncols()) { + if (nset == ncols() && !have_trims) { if (use_booktabs) os << (lastrow ? "\\bottomrule" : "\\midrule"); else os << "\\hline "; } else { + string const cline = use_booktabs ? "\\cmidrule" : "\\cline"; for (auto & c : columns) { if (bottomline.find(c)->second) { col_type offset = 0; for (col_type j = 0 ; j < c; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; - - //babel makes the "-" character an active one, so we have to suppress this here - //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# - if (lang == "slovak" || lang == "czech") - os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") - << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; - else - os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; - + while (isPartOfMultiColumn(row, c)) + ++c; + string trim; + if (bottomltrims.find(c) != bottomltrims.end() + && bottomltrims.find(c)->second) + trim = "l"; + string const firstcol = convert(c + 1 + offset); col_type cstart = c; - for ( ; c < ncols() && bottomline.find(c)->second; ++c) {} + for ( ; c < ncols() - 1 && bottomline.find(c)->second ; ++c) { + if (isMultiColumn(cellIndex(row, c)) + && c < ncols() - 1 + && isPartOfMultiColumn(row, c + 1)) + continue; + if (c > cstart && bottomltrims.find(c) != bottomltrims.end() + && bottomltrims.find(c)->second) { + if (!isPartOfMultiColumn(row, c)) + --c; + break; + } else if (bottomrtrims.find(c) != bottomrtrims.end() + && bottomrtrims.find(c)->second) + break; + } for (col_type j = cstart ; j < c ; ++j) if (column_info[j].alignment == LYX_ALIGN_DECIMAL) ++offset; + col_type const lastcol = c + 1 + offset; + if (bottomrtrims.find(c) != bottomrtrims.end() + && bottomrtrims.find(c)->second) + trim += "r"; - os << c + offset << "} "; + //babel makes the "-" character an active one, so we have to suppress this here + //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# + if (lang == "slovak" || lang == "czech") { + os << "\\expandafter" << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "\\expandafter{\\expandafter" << firstcol << "\\string-"; + } else { + os << cline; + if (!trim.empty()) + os << "(" << trim << ")"; + os << "{" << firstcol << '-'; + } + os << lastcol << "}"; + if (c == ncols() - 1) + break; } } } @@ -3781,7 +4021,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 +4177,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 +4247,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 +4395,73 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const } +namespace { + +void tabline(PainterInfo const & pi, int x1, int y1, int x2, int y2, int lt, int rt, + bool drawline, bool heavy = false) +{ + ColorCode const col = drawline ? Color_tabularline : Color_tabularonoffline; + if (drawline && lt > 0) + pi.pain.line(x1, y1, x1 + lt, y2, pi.textColor(Color_tabularonoffline), + Painter::line_onoffdash, + Painter::thin_line); + pi.pain.line(x1 + lt, y1, x2 - rt, y2, pi.textColor(col), + drawline ? Painter::line_solid : Painter::line_onoffdash, + (heavy ? 2 : 1) * Painter::thin_line); + if (drawline && rt > 0) + pi.pain.line(x2 - rt, y1, x2, y2, pi.textColor(Color_tabularonoffline), + Painter::line_onoffdash, + 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); + int lt = 0; + int rt = 0; + + col_type const col = tabular.cellColumn(cell); // 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); + if (tabular.topLineTrim(cell).first + || (row > 0 && tabular.bottomLineTrim(tabular.cellIndex(row - 1, col)).first)) + lt = 10; + if (tabular.topLineTrim(cell).second + || (row > 0 && tabular.bottomLineTrim(tabular.cellIndex(row - 1, col)).second)) + rt = 10; + tabline(pi, x, y, x + w, y, lt, rt, drawline, heavy); // Bottom + lt = rt = 0; drawline = tabular.bottomLine(cell); - pi.pain.line(x, y + h, x + w, y + h, - drawline ? linecolor : gridcolor, - drawline ? Painter::line_solid : Painter::line_onoffdash); + row_type const lastrow = tabular.nrows() - 1; + // Consider multi-rows + row_type r = row; + while (r < lastrow && tabular.isMultiRow(tabular.cellIndex(r, col)) + && tabular.isPartOfMultiRow(r + 1, col)) + r++; + heavy = tabular.use_booktabs + && ((row == lastrow && tabular.rowBottomLine(row)) + || (r == lastrow && tabular.rowBottomLine(r))); + if (tabular.bottomLineTrim(cell).first) + lt = 10; + if (tabular.bottomLineTrim(cell).second) + rt = 10; + tabline(pi, x, y + h, x + w, y + h, lt, rt, 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, 0, 0, drawline); // Right x -= tabular.interColumnSpace(cell); @@ -4190,9 +4472,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, 0, 0, drawline); } @@ -4702,6 +4982,18 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_PASTE: if (!tabularStackDirty()) { + // Check if we have plain text or HTML with rows/columns. + // and if so, pass over to LFUN_CLIPBOARD_PASTE + if (theClipboard().hasTextContents(Clipboard::AnyTextType) + && !theClipboard().hasTextContents(Clipboard::LyXTextType)) { + docstring const clip = + theClipboard().getAsText(Clipboard::AnyTextType); + if (clip.find_first_of(from_ascii("\t\n")) != docstring::npos) { + FuncRequest ncmd = FuncRequest(LFUN_CLIPBOARD_PASTE, cmd.argument()); + doDispatch(cur, ncmd); + break; + } + } if (!cur.selIsMultiCell()) cell(cur.idx())->dispatch(cur, cmd); break; @@ -4902,10 +5194,15 @@ 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; + case Tabular::RESET_FORMAL_DEFAULT: + status.setEnabled(tabular.use_booktabs); + break; + case Tabular::SET_LINE_TOP: case Tabular::SET_LINE_BOTTOM: status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); @@ -4917,6 +5214,20 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, && !tabular.ltCaption(tabular.cellRow(cur.idx()))); break; + case Tabular::SET_LTRIM_TOP: + case Tabular::SET_RTRIM_TOP: + status.setEnabled(tabular.use_booktabs + && tabular.cellRow(cur.idx()) != 0 + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + break; + + case Tabular::SET_LTRIM_BOTTOM: + case Tabular::SET_RTRIM_BOTTOM: + status.setEnabled(tabular.use_booktabs + && tabular.cellRow(cur.idx()) != tabular.nrows() - 1 + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + break; + case Tabular::TOGGLE_LINE_TOP: status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); status.setOnOff(tabular.topLine(cur.idx())); @@ -4939,6 +5250,30 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, status.setOnOff(tabular.rightLine(cur.idx())); break; + case Tabular::TOGGLE_LTRIM_TOP: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.topLineTrim(cur.idx()).first); + break; + + case Tabular::TOGGLE_RTRIM_TOP: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.topLineTrim(cur.idx()).second); + break; + + case Tabular::TOGGLE_LTRIM_BOTTOM: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.bottomLineTrim(cur.idx()).first); + break; + + case Tabular::TOGGLE_RTRIM_BOTTOM: + status.setEnabled(tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.bottomLineTrim(cur.idx()).second); + break; + // multirow cells only inherit the alignment of the column if the column has // no width, otherwise they are left-aligned // therefore allow always left but right and center only if there is no width @@ -5249,6 +5584,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, // disable these with multiple cells selected case LFUN_INSET_INSERT: case LFUN_TABULAR_INSERT: + case LFUN_TABULAR_STYLE_INSERT: case LFUN_FLEX_INSERT: case LFUN_FLOAT_INSERT: case LFUN_FLOAT_WIDE_INSERT: @@ -5712,6 +6048,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 +6110,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 +6125,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; } @@ -5815,9 +6155,12 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::DELETE_ROW: if (sel_row_end == tabular.nrows() - 1 && sel_row_start != 0) { - for (col_type c = 0; c < tabular.ncols(); c++) + for (col_type c = 0; c < tabular.ncols(); c++) { tabular.setBottomLine(tabular.cellIndex(sel_row_start - 1, c), tabular.bottomLine(tabular.cellIndex(sel_row_end, c))); + tabular.setBottomLineTrim(tabular.cellIndex(sel_row_start - 1, c), + tabular.bottomLineTrim(tabular.cellIndex(sel_row_end, c))); + } } for (row_type r = sel_row_start; r <= sel_row_end; ++r) @@ -5902,6 +6245,46 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } + case Tabular::SET_LTRIM_TOP: + case Tabular::TOGGLE_LTRIM_TOP: { + bool l = (feature == Tabular::SET_LTRIM_TOP) + ? (value == "true") : !tabular.topLineTrim(cur.idx()).first; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setTopLineLTrim(tabular.cellIndex(r, c), l); + break; + } + + case Tabular::SET_RTRIM_TOP: + case Tabular::TOGGLE_RTRIM_TOP: { + bool l = (feature == Tabular::SET_RTRIM_TOP) + ? (value == "true") : !tabular.topLineTrim(cur.idx()).second; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setTopLineRTrim(tabular.cellIndex(r, c), l); + break; + } + + case Tabular::SET_LTRIM_BOTTOM: + case Tabular::TOGGLE_LTRIM_BOTTOM: { + bool l = (feature == Tabular::SET_LTRIM_BOTTOM) + ? (value == "true") : !tabular.bottomLineTrim(cur.idx()).first; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setBottomLineLTrim(tabular.cellIndex(r, c), l); + break; + } + + case Tabular::SET_RTRIM_BOTTOM: + case Tabular::TOGGLE_RTRIM_BOTTOM: { + bool l = (feature == Tabular::SET_RTRIM_BOTTOM) + ? (value == "true") : !tabular.bottomLineTrim(cur.idx()).second; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setBottomLineRTrim(tabular.cellIndex(r, c), l); + break; + } + case Tabular::SET_LINE_LEFT: case Tabular::TOGGLE_LINE_LEFT: { bool lineSet = (feature == Tabular::SET_LINE_LEFT) @@ -6061,6 +6444,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,11 +6454,28 @@ 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; + + case Tabular::RESET_FORMAL_DEFAULT: + for (row_type r = 0; r < tabular.nrows(); ++r) { + bool const head_or_foot = r == 0 || r == tabular.nrows() - 1; + for (col_type c = 0; c < tabular.ncols(); ++c) { + idx_type const cell = tabular.cellIndex(r, c); + tabular.setTopLine(cell, head_or_foot); + tabular.setBottomLine(cell, head_or_foot); } + } break; case Tabular::SET_BORDER_LINES: @@ -6146,8 +6549,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) @@ -6596,20 +6997,26 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, } size_t op = 0; - idx_type const cells = loctab->numberofcells; + idx_type cells = loctab->numberofcells; p = 0; cols = ocol; rows = loctab->nrows(); - col_type const columns = loctab->ncols(); + col_type columns = loctab->ncols(); - while (cell < cells && p < len && row < rows && + while (p < len && (p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos) { if (p >= len) break; switch (buf[p]) { case '\t': - // we can only set this if we are not too far right + // append column if necessary + if (cols == columns) { + loctab->appendColumn(cols - 1); + columns = loctab->ncols(); + cells = loctab->numberofcells; + ++cell; + } if (cols < columns) { shared_ptr inset = loctab->cellInset(cell); Font const font = bv.textMetrics(&inset->text()). @@ -6631,6 +7038,12 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, } cols = ocol; ++row; + // append row if necessary + if (row == rows && p < len - 1) { + loctab->appendRow(row - 1); + rows = loctab->nrows(); + cells = loctab->numberofcells; + } if (row < rows) cell = loctab->cellIndex(row, cols); break;