From 8085fc21f8875921adad8970f3f02d484b148789 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Wed, 3 Apr 2019 07:59:52 +0200 Subject: [PATCH] booktabs: support for \cmidrule trimming This has probably still some rough edges, so please test thoroughly. Fixes: #3072 --- development/FORMAT | 5 + lib/lyx2lyx/lyx_2_4.py | 24 ++- src/LyXAction.cpp | 3 + src/frontends/qt4/GuiSetBorder.cpp | 304 +++++++++++++++++++++++--- src/frontends/qt4/GuiSetBorder.h | 51 ++++- src/frontends/qt4/GuiTabular.cpp | 103 +++++++-- src/frontends/qt4/GuiTabular.h | 2 + src/insets/InsetTabular.cpp | 332 +++++++++++++++++++++++++---- src/insets/InsetTabular.h | 40 ++++ src/tex2lyx/TODO.txt | 2 + src/version.h | 4 +- 11 files changed, 780 insertions(+), 90 deletions(-) diff --git a/development/FORMAT b/development/FORMAT index 3ec34e61f7..d38e809f17 100644 --- a/development/FORMAT +++ b/development/FORMAT @@ -7,6 +7,11 @@ changes happened in particular if possible. A good example would be ----------------------- +2019-04-03 Jürgen Spitzmüller + * format incremented to 571: Add \cmidrule trimming support + \cmidrule(lr){n-n} + + 2019-03-29 Jürgen Spitzmüller * format incremented to 570: Add individual bib encodings for biblatex \begin_inset CommandInset bibtex diff --git a/lib/lyx2lyx/lyx_2_4.py b/lib/lyx2lyx/lyx_2_4.py index 33b2a3984f..3bf7a6b2d1 100644 --- a/lib/lyx2lyx/lyx_2_4.py +++ b/lib/lyx2lyx/lyx_2_4.py @@ -1555,6 +1555,26 @@ def revert_bibfileencodings(document): i = j + 1 +def revert_cmidruletrimming(document): + " Remove \\cmidrule trimming " + + # FIXME: Revert to TeX code? + i = 0 + while True: + # first, let's find out if we need to do anything + i = find_token(document.body, ': append-row|append-column|delete-row|delete-column|copy-row|\n copy-column|move-column-right|move-column-left|move-row-down|move-row-up|\n + set-line-top|set-line-bottom|set-line-left|set-line-right|\n toggle-line-top|toggle-line-bottom|toggle-line-left|toggle-line-right|\n + set-ltrim-top|set-rtrim-top|set-ltrim-bottom|set-rtrim-bottom\n + toggle-ltrim-top|toggle-rtrim-top|toggle-ltrim-bottom|toggle-rtrim-bottom\n align-left|align-right|align-center|align-block|align-decimal|set-decimal-point|\n valign-top|valign-bottom|valign-middle|longtabular-align-left|\n longtabular-align-center|longtabular-align-right|m-align-left|m-align-right|\n diff --git a/src/frontends/qt4/GuiSetBorder.cpp b/src/frontends/qt4/GuiSetBorder.cpp index f35a17df2b..30e25743fb 100644 --- a/src/frontends/qt4/GuiSetBorder.cpp +++ b/src/frontends/qt4/GuiSetBorder.cpp @@ -5,6 +5,7 @@ * * \author Edwin Leuven * \author John Levon + * \author Jürgen Spitzmüller * * Full author contact details are available in file CREDITS. */ @@ -13,26 +14,29 @@ #include "GuiSetBorder.h" +#include "support/debug.h" + #include #include #include GuiSetBorder::GuiSetBorder(QWidget * parent, Qt::WindowFlags fl) - : QWidget(parent, fl), buffer(75, 75) + : QWidget(parent, fl), buffer(75, 75), bottom_drawn_wide_(false), + top_drawn_wide_(false) { /* length of corner line */ - l = buffer.width() / 10; + corner_length = buffer.width() / 10; /* margin */ - m = buffer.height() / 10; + margin = buffer.height() / 10; - w = buffer.width(); - h = buffer.height(); + bwidth = buffer.width(); + bheight = buffer.height(); init(); - setMinimumSize(w,h); - setMaximumSize(w,h); + setMinimumSize(bwidth, bheight); + setMaximumSize(bwidth, bheight); } @@ -51,19 +55,26 @@ void GuiSetBorder::init() paint.setPen(Qt::black); - // FIXME: wow, readable !! :) + // Draw the corner marks + paint.drawLine(margin + corner_length, margin, + margin + corner_length, margin + corner_length); + paint.drawLine(bwidth - (margin + corner_length), margin, + bwidth - (margin + corner_length), margin + corner_length); - paint.drawLine(m + l , m, m + l, m + l); - paint.drawLine(w - (m + l), m, w - (m + l), m + l); + paint.drawLine(margin, margin + corner_length, + margin + corner_length, margin + corner_length); + paint.drawLine(margin, bheight - (margin + corner_length), + margin + corner_length, bheight - (margin + corner_length)); - paint.drawLine(m, m + l , m + l, m + l); - paint.drawLine(m, h - (m + l), m + l, h - (m + l)); + paint.drawLine(margin + corner_length ,bheight - margin, + margin + corner_length ,bheight - (margin + corner_length)); + paint.drawLine(bwidth - (margin + corner_length), bheight - margin, + bwidth - (margin + corner_length), bheight - (margin + corner_length)); - paint.drawLine(m + l ,h - m, m + l ,h - (m + l)); - paint.drawLine(w - (m + l), h - m, w - (m + l), h - (m + l)); - - paint.drawLine(h - m, m+l, h - (m + l), m + l); - paint.drawLine(h - m, h - (m + l), h - (m + l),h - (m + l)); + paint.drawLine(bheight - margin, margin+corner_length, + bheight - (margin + corner_length), margin + corner_length); + paint.drawLine(bheight - margin, bheight - (margin + corner_length), + bheight - (margin + corner_length),bheight - (margin + corner_length)); } @@ -77,7 +88,15 @@ void GuiSetBorder::mousePressEvent(QMouseEvent * e) leftSet(); } } else { - if (bottom_.enabled) { + if (bottom_trim_left_.enabled && e->x() < margin + 4 + 2 * corner_length) { + setBottomLeftTrim(bottom_trim_left_.set == LINE_SET ? LINE_UNSET : LINE_SET); + // emit signal + bottomLTSet(); + } else if (bottom_trim_right_.enabled && e->x() > bwidth - margin - 2 * corner_length - 4) { + setBottomRightTrim(bottom_trim_right_.set == LINE_SET ? LINE_UNSET : LINE_SET); + // emit signal + bottomRTSet(); + } else if (bottom_.enabled) { setBottom(bottom_.set == LINE_SET ? LINE_UNSET : LINE_SET); // emit signal bottomSet(); @@ -85,7 +104,15 @@ void GuiSetBorder::mousePressEvent(QMouseEvent * e) } } else { if (e->y() < height() - e->x()) { - if (top_.enabled) { + if (top_trim_left_.enabled && e->x() < margin + 4 + 2 * corner_length) { + setTopLeftTrim(top_trim_left_.set == LINE_SET ? LINE_UNSET : LINE_SET); + // emit signal + topLTSet(); + } else if (top_trim_right_.enabled && e->x() > bwidth - margin - 2 * corner_length - 4) { + setTopRightTrim(top_trim_right_.set == LINE_SET ? LINE_UNSET : LINE_SET); + // emit signal + topRTSet(); + } else if (top_.enabled) { setTop(top_.set == LINE_SET ? LINE_UNSET : LINE_SET); // emit signal topSet(); @@ -132,7 +159,8 @@ void GuiSetBorder::drawLeft(BorderState draw) } if (!left_.enabled) col = QColor(Qt::lightGray); - drawLine(col, m + l, m + l + 2, m + l, h - m - l - 1); + drawLine(col, margin + corner_length, margin + corner_length + 2, + margin + corner_length, bheight - margin - corner_length - 1); } @@ -153,7 +181,8 @@ void GuiSetBorder::drawRight(BorderState draw) } if (!right_.enabled) col = QColor(Qt::lightGray); - drawLine(col, h - m - l + 1, m + l + 2, h - m - l + 1, h - m - l - 1); + drawLine(col, bheight - margin - corner_length + 1, margin + corner_length + 2, + bheight - margin - corner_length + 1, bheight - margin - corner_length - 1); } @@ -163,22 +192,40 @@ void GuiSetBorder::drawTop(BorderState draw) switch (draw) { case LINE_SET: col = Qt::black; + top_drawn_wide_ = true; break; case LINE_UNSET: col = Qt::white; + top_drawn_wide_ = false; break; case LINE_UNDECIDED: case LINE_UNDEF: col = Qt::lightGray; + top_drawn_wide_ = true; break; } if (!top_.enabled) col = QColor(Qt::lightGray); - drawLine(col, m + l + 2, m + l, w - m - l - 1, m + l); + int const lt = (top_trim_left_.enabled) ? corner_length + 4 : 0; + int const rt = (top_trim_right_.enabled) ? corner_length + 4 : 0; + drawLine(col, margin + corner_length + 2 + lt, margin + corner_length, + bwidth - margin - corner_length - 1 - rt, margin + corner_length); } -void GuiSetBorder::drawBottom(BorderState draw) +void GuiSetBorder::undrawWideTopLine() +{ + if (!top_drawn_wide_) + return; + + // Overpaint previous lines white + drawLine(Qt::white, margin + corner_length + 2, margin + corner_length, + bwidth - margin - corner_length - 1, margin + corner_length); + top_drawn_wide_ = false; +} + + +void GuiSetBorder::drawTopLeftTrim(BorderState draw) { QColor col; switch (draw) { @@ -193,9 +240,123 @@ void GuiSetBorder::drawBottom(BorderState draw) col = Qt::lightGray; break; } + if (!top_trim_left_.enabled) + col = QColor(Qt::white); + int const lt = corner_length; + if (top_trim_left_.enabled) + drawLine(col, margin + corner_length + 2, margin + corner_length, + margin + corner_length + 2 + lt, margin + corner_length); +} + + +void GuiSetBorder::drawTopRightTrim(BorderState draw) +{ + QColor col; + switch (draw) { + case LINE_SET: + col = Qt::black; + break; + case LINE_UNSET: + col = Qt::white; + break; + case LINE_UNDECIDED: + case LINE_UNDEF: + col = Qt::lightGray; + break; + } + if (!top_trim_right_.enabled) + col = QColor(Qt::white); + int const rt = corner_length; + if (top_trim_right_.enabled) + drawLine(col, bwidth - margin - corner_length - 1 - rt, margin + corner_length, + bwidth - margin - corner_length - 1, margin + corner_length); +} + + +void GuiSetBorder::drawBottom(BorderState draw) +{ + QColor col; + switch (draw) { + case LINE_SET: + col = Qt::black; + bottom_drawn_wide_ = true; + break; + case LINE_UNSET: + col = Qt::white; + bottom_drawn_wide_ = false; + break; + case LINE_UNDECIDED: + case LINE_UNDEF: + col = Qt::lightGray; + bottom_drawn_wide_ = true; + break; + } if (!bottom_.enabled) col = QColor(Qt::lightGray); - drawLine(col, m + l + 2, w - m - l + 1, w - m - l - 1, w - m - l + 1); + int const lt = (bottom_trim_left_.enabled) ? corner_length + 4 : 0; + int const rt = (bottom_trim_right_.enabled) ? corner_length + 4 : 0; + drawLine(col, margin + corner_length + 2 + lt, bwidth - margin - corner_length + 1, + bwidth - margin - corner_length - 1 - rt, bwidth - margin - corner_length + 1); +} + + +void GuiSetBorder::undrawWideBottomLine() +{ + if (!bottom_drawn_wide_) + return; + + //Overpaint previous lines white + drawLine(Qt::white, margin + corner_length + 2, bwidth - margin - corner_length + 1, + bwidth - margin - corner_length - 1, bwidth - margin - corner_length + 1); + bottom_drawn_wide_ = false; +} + + +void GuiSetBorder::drawBottomLeftTrim(BorderState draw) +{ + QColor col; + switch (draw) { + case LINE_SET: + col = Qt::black; + break; + case LINE_UNSET: + col = Qt::white; + break; + case LINE_UNDECIDED: + case LINE_UNDEF: + col = Qt::lightGray; + break; + } + if (!bottom_trim_left_.enabled) + col = QColor(Qt::white); + int const lt = corner_length; + if (bottom_trim_left_.enabled) + drawLine(col, margin + corner_length + 2, bwidth - margin - corner_length + 1, + margin + corner_length + 2 + lt, bwidth - margin - corner_length + 1); +} + + +void GuiSetBorder::drawBottomRightTrim(BorderState draw) +{ + QColor col; + switch (draw) { + case LINE_SET: + col = Qt::black; + break; + case LINE_UNSET: + col = Qt::white; + break; + case LINE_UNDECIDED: + case LINE_UNDEF: + col = Qt::lightGray; + break; + } + if (!bottom_trim_right_.enabled) + col = QColor(Qt::white); + int const rt = corner_length; + if (bottom_trim_right_.enabled) + drawLine(col, bwidth - margin - corner_length - 1 - rt, bwidth - margin - corner_length + 1, + bwidth - margin - corner_length - 1, bwidth - margin - corner_length + 1); } @@ -227,6 +388,46 @@ void GuiSetBorder::setBottomEnabled(bool enabled) } +void GuiSetBorder::setTopLeftTrimEnabled(bool enabled) +{ + top_trim_left_.enabled = enabled; + undrawWideTopLine(); + drawTopLeftTrim(top_trim_left_.set); + drawTop(top_.set); + top_drawn_wide_ = !enabled; +} + + +void GuiSetBorder::setTopRightTrimEnabled(bool enabled) +{ + top_trim_right_.enabled = enabled; + undrawWideTopLine(); + drawTopRightTrim(top_trim_right_.set); + drawTop(top_.set); + top_drawn_wide_ = !enabled;; +} + + +void GuiSetBorder::setBottomLeftTrimEnabled(bool enabled) +{ + bottom_trim_left_.enabled = enabled; + undrawWideBottomLine(); + drawBottomLeftTrim(bottom_trim_left_.set); + drawBottom(bottom_.set); + bottom_drawn_wide_ = !enabled;; +} + + +void GuiSetBorder::setBottomRightTrimEnabled(bool enabled) +{ + bottom_trim_right_.enabled = enabled; + undrawWideBottomLine(); + drawBottomRightTrim(bottom_trim_right_.set); + drawBottom(bottom_.set); + bottom_drawn_wide_ = !enabled;; +} + + void GuiSetBorder::setLeft(BorderState border) { left_.set = border; @@ -255,12 +456,43 @@ void GuiSetBorder::setBottom(BorderState border) } +void GuiSetBorder::setTopLeftTrim(BorderState border) +{ + top_trim_left_.set = border; + drawTopLeftTrim(border); +} + + +void GuiSetBorder::setTopRightTrim(BorderState border) +{ + top_trim_right_.set = border; + drawTopRightTrim(border); +} + + +void GuiSetBorder::setBottomLeftTrim(BorderState border) +{ + bottom_trim_left_.set = border; + drawBottomLeftTrim(border); +} + +void GuiSetBorder::setBottomRightTrim(BorderState border) +{ + bottom_trim_right_.set = border; + drawBottomRightTrim(border); +} + + void GuiSetBorder::setAll(BorderState border) { setLeft(border); setRight(border); setTop(border); setBottom(border); + setTopLeftTrim(border); + setTopRightTrim(border); + setBottomLeftTrim(border); + setBottomRightTrim(border); } @@ -287,4 +519,28 @@ GuiSetBorder::BorderState GuiSetBorder::getBottom() return bottom_.set; } + +GuiSetBorder::BorderState GuiSetBorder::getTopLeftTrim() +{ + return top_trim_left_.set; +} + + +GuiSetBorder::BorderState GuiSetBorder::getTopRightTrim() +{ + return top_trim_right_.set; +} + + +GuiSetBorder::BorderState GuiSetBorder::getBottomLeftTrim() +{ + return bottom_trim_left_.set; +} + + +GuiSetBorder::BorderState GuiSetBorder::getBottomRightTrim() +{ + return bottom_trim_right_.set; +} + #include "moc_GuiSetBorder.cpp" diff --git a/src/frontends/qt4/GuiSetBorder.h b/src/frontends/qt4/GuiSetBorder.h index 7230e4d11b..1abfa9608e 100644 --- a/src/frontends/qt4/GuiSetBorder.h +++ b/src/frontends/qt4/GuiSetBorder.h @@ -6,6 +6,7 @@ * * \author Edwin Leuven * \author John Levon + * \author Jürgen Spitzmüller * * Full author contact details are available in file CREDITS. */ @@ -26,7 +27,7 @@ class GuiSetBorder : public QWidget { Q_OBJECT public: - GuiSetBorder(QWidget * parent = 0, Qt::WindowFlags fl = 0); + GuiSetBorder(QWidget * parent = nullptr, Qt::WindowFlags fl = nullptr); // We need tristate for multi-cell selection enum BorderState { @@ -40,6 +41,10 @@ public: BorderState getRight(); BorderState getTop(); BorderState getBottom(); + BorderState getTopLeftTrim(); + BorderState getTopRightTrim(); + BorderState getBottomLeftTrim(); + BorderState getBottomRightTrim(); bool leftLineSet() { return getLeft() == LINE_SET; } bool rightLineSet() { return getRight() == LINE_SET; } @@ -51,11 +56,25 @@ public: bool topLineUnset() { return getTop() == LINE_UNSET; } bool bottomLineUnset() { return getBottom() == LINE_UNSET; } + bool topLineLTSet() { return getTopLeftTrim() == LINE_SET; } + bool bottomLineLTSet() { return getBottomLeftTrim() == LINE_SET; } + bool topLineRTSet() { return getTopRightTrim() == LINE_SET; } + bool bottomLineRTSet() { return getBottomRightTrim() == LINE_SET; } + + bool topLineLTUnset() { return getTopLeftTrim() == LINE_UNSET; } + bool bottomLineLTUnset() { return getBottomLeftTrim() == LINE_UNSET; } + bool topLineRTUnset() { return getTopRightTrim() == LINE_UNSET; } + bool bottomLineRTUnset() { return getBottomRightTrim() == LINE_UNSET; } + Q_SIGNALS: void rightSet(); void leftSet(); void topSet(); void bottomSet(); + void topLTSet(); + void bottomLTSet(); + void topRTSet(); + void bottomRTSet(); void clicked(); public Q_SLOTS: @@ -63,10 +82,18 @@ public Q_SLOTS: void setRightEnabled(bool); void setTopEnabled(bool); void setBottomEnabled(bool); + void setTopLeftTrimEnabled(bool); + void setTopRightTrimEnabled(bool); + void setBottomLeftTrimEnabled(bool); + void setBottomRightTrimEnabled(bool); void setLeft(BorderState); void setRight(BorderState); void setTop(BorderState); void setBottom(BorderState); + void setTopLeftTrim(BorderState); + void setTopRightTrim(BorderState); + void setBottomLeftTrim(BorderState); + void setBottomRightTrim(BorderState); void setAll(BorderState); protected: @@ -81,7 +108,13 @@ private: void drawLeft(BorderState); void drawRight(BorderState); void drawTop(BorderState); + void undrawWideTopLine(); void drawBottom(BorderState); + void undrawWideBottomLine(); + void drawTopLeftTrim(BorderState); + void drawTopRightTrim(BorderState); + void drawBottomLeftTrim(BorderState); + void drawBottomRightTrim(BorderState); class Border { public: @@ -94,13 +127,21 @@ private: Border right_; Border top_; Border bottom_; + /// trim areas + Border top_trim_left_; + Border top_trim_right_; + Border bottom_trim_left_; + Border bottom_trim_right_; - int m; - int l; - int w; - int h; + int margin; + int corner_length; + int bwidth; + int bheight; QPixmap buffer; + + bool bottom_drawn_wide_; + bool top_drawn_wide_; }; diff --git a/src/frontends/qt4/GuiTabular.cpp b/src/frontends/qt4/GuiTabular.cpp index b162458b3e..633982c86f 100644 --- a/src/frontends/qt4/GuiTabular.cpp +++ b/src/frontends/qt4/GuiTabular.cpp @@ -48,7 +48,7 @@ namespace frontend { GuiTabular::GuiTabular(QWidget * parent) : InsetParamsWidget(parent), firstheader_suppressable_(false), lastfooter_suppressable_(false), orig_leftborder_(GuiSetBorder::LINE_UNDEF), - orig_rightborder_(GuiSetBorder::LINE_UNDEF) + orig_rightborder_(GuiSetBorder::LINE_UNDEF), lastrow_(0) { setupUi(this); @@ -147,6 +147,14 @@ GuiTabular::GuiTabular(QWidget * parent) this, SLOT(checkEnabled())); connect(borders, SIGNAL(leftSet()), this, SLOT(checkEnabled())); + connect(borders, SIGNAL(topLTSet()), + this, SLOT(checkEnabled())); + connect(borders, SIGNAL(topRTSet()), + this, SLOT(checkEnabled())); + connect(borders, SIGNAL(bottomLTSet()), + this, SLOT(checkEnabled())); + connect(borders, SIGNAL(bottomRTSet()), + this, SLOT(checkEnabled())); connect(rotateTabularCB, SIGNAL(clicked()), this, SLOT(checkEnabled())); connect(rotateTabularAngleSB, SIGNAL(valueChanged(int)), @@ -344,6 +352,20 @@ void GuiTabular::enableWidgets() const // Vertical lines cannot be set in formal tables borders->setLeftEnabled(!booktabsRB->isChecked()); borders->setRightEnabled(!booktabsRB->isChecked()); + // Trimming is only allowed in booktabs and if the line is set + int const row = tabularRowED->text().toInt(); + borders->setTopLeftTrimEnabled(booktabsRB->isChecked() + && borders->topLineSet() + && row > 1); + borders->setTopRightTrimEnabled(booktabsRB->isChecked() + && borders->topLineSet() + && row > 1); + borders->setBottomLeftTrimEnabled(booktabsRB->isChecked() + && borders->bottomLineSet() + && row < lastrow_); + borders->setBottomRightTrimEnabled(booktabsRB->isChecked() + && borders->bottomLineSet() + && row < lastrow_); } @@ -360,6 +382,10 @@ void GuiTabular::borderSet_clicked() borders->setBottom(GuiSetBorder::LINE_SET); borders->setLeft(GuiSetBorder::LINE_SET); borders->setRight(GuiSetBorder::LINE_SET); + borders->setTopLeftTrim(GuiSetBorder::LINE_SET); + borders->setBottomLeftTrim(GuiSetBorder::LINE_SET); + borders->setTopRightTrim(GuiSetBorder::LINE_SET); + borders->setBottomRightTrim(GuiSetBorder::LINE_SET); // repaint the setborder widget borders->update(); checkEnabled(); @@ -372,6 +398,10 @@ void GuiTabular::borderUnset_clicked() borders->setBottom(GuiSetBorder::LINE_UNSET); borders->setLeft(GuiSetBorder::LINE_UNSET); borders->setRight(GuiSetBorder::LINE_UNSET); + borders->setTopLeftTrim(GuiSetBorder::LINE_UNSET); + borders->setBottomLeftTrim(GuiSetBorder::LINE_UNSET); + borders->setTopRightTrim(GuiSetBorder::LINE_UNSET); + borders->setBottomRightTrim(GuiSetBorder::LINE_UNSET); // repaint the setborder widget borders->update(); checkEnabled(); @@ -603,6 +633,22 @@ docstring GuiTabular::dialogToParams() const setParam(param_str, Tabular::SET_LINE_BOTTOM, borders->bottomLineSet() ? "true" : "false"); } + if (borders->topLineLTSet()) + setParam(param_str, Tabular::SET_LTRIM_TOP, "false"); + else if (borders->topLineLTUnset()) + setParam(param_str, Tabular::SET_LTRIM_TOP, "true"); + if (borders->topLineRTSet()) + setParam(param_str, Tabular::SET_RTRIM_TOP, "false"); + else if (borders->topLineRTUnset()) + setParam(param_str, Tabular::SET_RTRIM_TOP, "true"); + if (borders->bottomLineLTSet()) + setParam(param_str, Tabular::SET_LTRIM_BOTTOM, "false"); + else if (borders->bottomLineRTUnset()) + setParam(param_str, Tabular::SET_LTRIM_BOTTOM, "true"); + if (borders->bottomLineRTSet()) + setParam(param_str, Tabular::SET_RTRIM_BOTTOM, "false"); + else if (borders->bottomLineRTUnset()) + setParam(param_str, Tabular::SET_RTRIM_BOTTOM, "true"); // apply the special alignment string special = fromqstr(specialAlignmentED->text()); @@ -784,6 +830,7 @@ void GuiTabular::paramsToDialog(Inset const * inset) tabularRowED->setText(QString::number(row + 1)); tabularColumnED->setText(QString::number(col + 1)); + lastrow_ = int(tabular.nrows()); bool const multicol = tabular.isMultiColumn(cell); multicolumnCB->setChecked(multicol); @@ -810,12 +857,16 @@ void GuiTabular::paramsToDialog(Inset const * inset) } // In what follows, we check the borders of all selected cells, - // and if there are diverging settings, we use the LINE_UNDEF + // and if there are diverging settings, we use the LINE_UNDECIDED // border status. - GuiSetBorder::BorderState lt = GuiSetBorder::LINE_UNDEF; - GuiSetBorder::BorderState lb = GuiSetBorder::LINE_UNDEF; - GuiSetBorder::BorderState ll = GuiSetBorder::LINE_UNDEF; - GuiSetBorder::BorderState lr = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState ltop = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState lbottom = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState lleft = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState lright = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState ltop_ltrim = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState ltop_rtrim = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState lbottom_ltrim = GuiSetBorder::LINE_UNDEF; + GuiSetBorder::BorderState lbottom_rtrim = GuiSetBorder::LINE_UNDEF; CursorSlice const & beg = bv->cursor().selBegin(); CursorSlice const & end = bv->cursor().selEnd(); if (beg != end) { @@ -830,27 +881,39 @@ void GuiTabular::paramsToDialog(Inset const * inset) for (Tabular::row_type r = rs; r <= re; ++r) for (Tabular::col_type c = cs; c <= ce; ++c) { idx_type const cc = tabular.cellIndex(r, c); - lt = borderState(lt, tabular.topLine(cc)); - lb = borderState(lb, tabular.bottomLine(cc)); - ll = borderState(ll, tabular.leftLine(cc)); - lr = borderState(lr, tabular.rightLine(cc)); + ltop = borderState(ltop, tabular.topLine(cc)); + lbottom = borderState(lbottom, tabular.bottomLine(cc)); + lleft = borderState(lleft, tabular.leftLine(cc)); + lright = borderState(lright, tabular.rightLine(cc)); + ltop_ltrim = borderState(ltop_ltrim, !tabular.topLineTrim(cc).first); + ltop_rtrim = borderState(ltop_rtrim, !tabular.topLineTrim(cc).second); + lbottom_ltrim = borderState(lbottom_ltrim, !tabular.bottomLineTrim(cc).first); + lbottom_rtrim = borderState(lbottom_rtrim, !tabular.bottomLineTrim(cc).second); // store left/right borders for the case of formal/nonformal switch - orig_leftborder_ = borderState(ll, tabular.leftLine(cc, true)); - orig_rightborder_ = borderState(lr, tabular.rightLine(cc, true)); + orig_leftborder_ = borderState(lleft, tabular.leftLine(cc, true)); + orig_rightborder_ = borderState(lright, tabular.rightLine(cc, true)); } } else { - lt = tabular.topLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; - lb = tabular.bottomLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; - ll = tabular.leftLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; - lr = tabular.rightLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; + ltop = tabular.topLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; + lbottom = tabular.bottomLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; + lleft = tabular.leftLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; + lright = tabular.rightLine(cell) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; + ltop_ltrim = tabular.topLineTrim(cell).first ? GuiSetBorder::LINE_UNSET : GuiSetBorder::LINE_SET; + ltop_rtrim = tabular.topLineTrim(cell).second ? GuiSetBorder::LINE_UNSET : GuiSetBorder::LINE_SET; + lbottom_ltrim = tabular.bottomLineTrim(cell).first ? GuiSetBorder::LINE_UNSET : GuiSetBorder::LINE_SET; + lbottom_rtrim = tabular.bottomLineTrim(cell).second ? GuiSetBorder::LINE_UNSET : GuiSetBorder::LINE_SET; // store left/right borders for the case of formal/nonformal switch orig_leftborder_ = tabular.leftLine(cell, true) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; orig_rightborder_ = tabular.rightLine(cell, true) ? GuiSetBorder::LINE_SET : GuiSetBorder::LINE_UNSET; } - borders->setTop(lt); - borders->setBottom(lb); - borders->setLeft(ll); - borders->setRight(lr); + borders->setTop(ltop); + borders->setBottom(lbottom); + borders->setLeft(lleft); + borders->setRight(lright); + borders->setTopLeftTrim(ltop_ltrim); + borders->setTopRightTrim(ltop_rtrim); + borders->setBottomLeftTrim(lbottom_ltrim); + borders->setBottomRightTrim(lbottom_rtrim); // repaint the setborder widget borders->update(); diff --git a/src/frontends/qt4/GuiTabular.h b/src/frontends/qt4/GuiTabular.h index 692e331d28..5890c52066 100644 --- a/src/frontends/qt4/GuiTabular.h +++ b/src/frontends/qt4/GuiTabular.h @@ -74,6 +74,8 @@ private: GuiSetBorder::BorderState orig_leftborder_; /// GuiSetBorder::BorderState orig_rightborder_; + /// + int lastrow_; }; } // namespace frontend diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 007f0910a8..43795e7d40 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", true }, + { Tabular::TOGGLE_LTRIM_BOTTOM, "toggle-ltrim-bottom", true }, + { Tabular::TOGGLE_RTRIM_TOP, "toggle-rtrim-top", true }, + { Tabular::TOGGLE_RTRIM_BOTTOM, "toggle-rtrim-bottom", true }, { Tabular::ALIGN_LEFT, "align-left", false }, { Tabular::ALIGN_RIGHT, "align-right", false }, { Tabular::ALIGN_CENTER, "align-center", false }, @@ -585,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)) @@ -608,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), @@ -634,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; @@ -981,6 +1001,24 @@ bool Tabular::rightLine(idx_type cell, bool const ignore_bt) const } +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()) @@ -1321,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; @@ -1615,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) @@ -1729,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); @@ -2305,18 +2387,27 @@ 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; + } 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 @@ -2324,36 +2415,57 @@ 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 << '-'; - + 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 (c > cstart && topltrims.find(c) != topltrims.end() + && topltrims.find(c)->second) { + --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; } } } @@ -2369,11 +2481,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) @@ -2382,29 +2499,42 @@ 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; + } 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; @@ -2412,22 +2542,46 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang, 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 << '-'; - + 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 (c > cstart && bottomltrims.find(c) != bottomltrims.end() + && bottomltrims.find(c)->second) { + --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; } } } @@ -4215,13 +4369,21 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const namespace { -void tabline(PainterInfo const & pi, int x1, int y1, int x2, int y2, +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; - pi.pain.line(x1, y1, x2, y2, pi.textColor(col), + 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); } } @@ -4233,6 +4395,8 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, y -= tabular.rowAscent(row); int const w = tabular.cellWidth(cell); int const h = tabular.cellHeight(cell); + int lt = 0; + int rt = 0; col_type const col = tabular.cellColumn(cell); @@ -4240,9 +4404,16 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, bool drawline = tabular.topLine(cell) || (row > 0 && tabular.bottomLine(tabular.cellAbove(cell))); bool heavy = tabular.use_booktabs && row == 0 && tabular.rowTopLine(row); - tabline(pi, x, y, x + w, y, drawline, heavy); + 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); row_type const lastrow = tabular.nrows() - 1; // Consider multi-rows @@ -4253,12 +4424,16 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, heavy = tabular.use_booktabs && ((row == lastrow && tabular.rowBottomLine(row)) || (r == lastrow && tabular.rowBottomLine(r))); - tabline(pi, x, y + h, x + w, y + h, drawline, heavy); + 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 drawline = tabular.leftLine(cell) || (col > 0 && tabular.rightLine(tabular.cellIndex(row, col - 1))); - tabline(pi, x, y, x, y + h, drawline); + tabline(pi, x, y, x, y + h, 0, 0, drawline); // Right x -= tabular.interColumnSpace(cell); @@ -4269,7 +4444,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))); - tabline(pi, x + w, y, x + w, y + h, drawline); + tabline(pi, x + w, y, x + w, y + h, 0, 0, drawline); } @@ -4999,6 +5174,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())); @@ -5021,6 +5210,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 @@ -5901,9 +6114,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) @@ -5988,6 +6204,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) diff --git a/src/insets/InsetTabular.h b/src/insets/InsetTabular.h index 182b419bdd..fac2660fe6 100644 --- a/src/insets/InsetTabular.h +++ b/src/insets/InsetTabular.h @@ -179,6 +179,22 @@ public: ///FIXME: remove TOGGLE_LINE_RIGHT, /// + SET_LTRIM_TOP, + /// + SET_RTRIM_TOP, + /// + SET_LTRIM_BOTTOM, + /// + SET_RTRIM_BOTTOM, + /// + TOGGLE_LTRIM_TOP, + /// + TOGGLE_RTRIM_TOP, + /// + TOGGLE_LTRIM_BOTTOM, + /// + TOGGLE_RTRIM_BOTTOM, + /// ALIGN_LEFT, /// ALIGN_RIGHT, @@ -420,6 +436,10 @@ public: /// If \p ignore_bt is true, we return the state as if booktabs was /// not used bool rightLine(idx_type cell, bool const ignore_bt = false) const; + /// Returns whether the top line is trimmed left and/or right + std::pair topLineTrim(idx_type const cell) const; + /// Returns whether the bottom line is trimmed left and/or right + std::pair bottomLineTrim(idx_type const cell) const; /// return space occupied by the second horizontal line and /// interline space above row \p row in pixels @@ -453,6 +473,18 @@ public: /// void setBottomLine(idx_type cell, bool line); /// + void setTopLineLTrim(idx_type cell, bool val); + /// + void setBottomLineLTrim(idx_type cell, bool val); + /// + void setTopLineRTrim(idx_type cell, bool val); + /// + void setBottomLineRTrim(idx_type cell, bool val); + /// + void setTopLineTrim(idx_type cell, std::pair); + /// + void setBottomLineTrim(idx_type cell, std::pair); + /// void setLeftLine(idx_type cell, bool line); /// void setRightLine(idx_type cell, bool line); @@ -692,6 +724,14 @@ public: /// bool right_line; /// + bool top_line_rtrimmed; + /// + bool top_line_ltrimmed; + /// + bool bottom_line_rtrimmed; + /// + bool bottom_line_ltrimmed; + /// BoxType usebox; /// int rotate; diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index 1706ef4f54..b360bc0e41 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -34,6 +34,8 @@ Format LaTeX feature LyX feature 443 unicode-math.sty InsetMath* 453 automatic stmaryrd loading \use_package stmaryrd 457 automatic stackrel loading \use_package stackrel +571 cmirule trimming (booktabs) + \cmidrule(lr){n-n} diff --git a/src/version.h b/src/version.h index 7783fd75e7..2b900966ca 100644 --- a/src/version.h +++ b/src/version.h @@ -32,8 +32,8 @@ extern char const * const lyx_version_info; // Do not remove the comment below, so we get merge conflict in // independent branches. Instead add your own. -#define LYX_FORMAT_LYX 570 // spitz: biblatex bibencodings -#define LYX_FORMAT_TEX2LYX 570 +#define LYX_FORMAT_LYX 571 // spitz: cmidrule trimming +#define LYX_FORMAT_TEX2LYX 571 #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX #ifndef _MSC_VER