]> git.lyx.org Git - features.git/commitdiff
Format incremented to 605: Extended variable table cell support
authorJuergen Spitzmueller <spitz@lyx.org>
Fri, 22 Jan 2021 18:16:43 +0000 (19:16 +0100)
committerJuergen Spitzmueller <spitz@lyx.org>
Fri, 22 Jan 2021 18:16:43 +0000 (19:16 +0100)
- Multicolumn now supports multiple paragraphs in non-fixed-width context.
- Multicolumn now supports valign in non-fixed-width context.
- varwidth columns now properly align horizontally and vertically.

development/FORMAT
lib/lyx2lyx/lyx_2_4.py
src/LaTeXFeatures.cpp
src/insets/InsetTabular.cpp
src/version.h

index 2fff88521905f38f5901fc060d07abaa94874dea..d0e9cb5ae5fedce50504fbeea86e3bacf2c645a7 100644 (file)
@@ -7,6 +7,12 @@ changes happened in particular if possible. A good example would be
 
 -----------------------
 
+2021-01-22 Jürgen Spitzmüller <spitz@lyx.org>
+       * Format incremented to 605: Extended variable table cell support.
+         - Multicolumn now supports multiple paragraphs in non-fixed-width context.
+         - Multicolumn now supports valign in non-fixed-width context.
+         - varwidth columns now properly align horizontally and vertically.
+
 2021-01-19 Jürgen Spitzmüller <spitz@lyx.org>
        * Format incremented to 604: Branch colors now take two values:
          \color lightmode darkmode
index d3177f9787734fc71a365eb0f8cca60b7e4fa73c..93500d0f75994a3b10b9f14abf29005055a3465e 100644 (file)
@@ -4106,6 +4106,125 @@ def revert_branch_darkcols(document):
         i += 1
 
 
+def revert_vcolumns2(document):
+    """Revert varwidth columns with line breaks etc."""
+    i = 0
+    needvarwidth = False
+    needarray = False
+    needcellvarwidth = False
+    try:
+        while True:
+            i = find_token(document.body, "\\begin_inset Tabular", i+1)
+            if i == -1:
+                return
+            j = find_end_of_inset(document.body, i)
+            if j == -1:
+                document.warning("Malformed LyX document: Could not find end of tabular.")
+                continue
+
+            # Collect necessary column information
+            m = i + 1
+            nrows = int(document.body[i+1].split('"')[3])
+            ncols = int(document.body[i+1].split('"')[5])
+            col_info = []
+            for k in range(ncols):
+                m = find_token(document.body, "<column", m)
+                width = get_option_value(document.body[m], 'width')
+                varwidth = get_option_value(document.body[m], 'varwidth')
+                alignment = get_option_value(document.body[m], 'alignment')
+                valignment = get_option_value(document.body[m], 'valignment')
+                special = get_option_value(document.body[m], 'special')
+                col_info.append([width, varwidth, alignment, valignment, special, m])
+                m += 1
+
+            # Now parse cells
+            m = i + 1
+            lines = []
+            for row in range(nrows):
+                for col in range(ncols):
+                    m = find_token(document.body, "<cell", m)
+                    multicolumn = get_option_value(document.body[m], 'multicolumn') != ""
+                    multirow = get_option_value(document.body[m], 'multirow') != ""
+                    fixedwidth = get_option_value(document.body[m], 'width') != ""
+                    rotate = get_option_value(document.body[m], 'rotate')
+                    cellalign = get_option_value(document.body[m], 'alignment')
+                    cellvalign = get_option_value(document.body[m], 'valignment')
+                    # Check for: linebreaks, multipars, non-standard environments
+                    begcell = m
+                    endcell = find_token(document.body, "</cell>", begcell)
+                    vcand = False
+                    if find_token(document.body, "\\begin_inset Newline", begcell, endcell) != -1:
+                        vcand = not fixedwidth and not multirow
+                    elif count_pars_in_inset(document.body, begcell + 2) > 1:
+                        vcand = not fixedwidth and not multirow
+                    elif get_value(document.body, "\\begin_layout", begcell) != "Plain Layout":
+                        vcand = not fixedwidth and not multirow
+                    colalignment = col_info[col][2]
+                    colvalignment = col_info[col][3]
+                    if vcand:
+                        if rotate == "" and ((colalignment == "left" and colvalignment == "top") or (multicolumn == True and cellalign == "left" and cellvalign == "top")):
+                            if col_info[col][0] == "" and col_info[col][1] == "" and col_info[col][4] == "":
+                                needvarwidth = True
+                                col_line = col_info[col][5]
+                                needarray = True
+                                vval = "V{\\linewidth}"
+                                if multicolumn:
+                                    document.body[m] = document.body[m][:-1] + " special=\"" + vval + "\">"
+                                else:
+                                    document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">"
+                        else:
+                            alarg = ""
+                            if multicolumn:
+                                if cellvalign == "middle":
+                                    alarg = "[m]"
+                                elif cellvalign == "bottom":
+                                    alarg = "[b]"
+                            else:
+                                document.warning("col: %i, alignment: %s" % (col, colvalignment))
+                                if colvalignment == "middle":
+                                    alarg = "[m]"
+                                elif colvalignment == "bottom":
+                                    alarg = "[b]"
+                            flt = find_token(document.body, "\\begin_layout", begcell, endcell)
+                            elt = find_token_backwards(document.body, "\\end_layout", endcell)
+                            if flt != -1 and elt != -1:
+                                document.body[elt:elt+1] = put_cmd_in_ert("\\end{cellvarwidth}")
+                                document.body[flt+1:flt+1] = put_cmd_in_ert("\\begin{cellvarwidth}" + alarg)
+                                needcellvarwidth = True
+                                needvarwidth = True
+                        # ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes
+                        # with newlines, and we do not want that)
+                        while True:
+                            endcell = find_token(document.body, "</cell>", begcell)
+                            linebreak = False
+                            nl = find_token(document.body, "\\begin_inset Newline newline", begcell, endcell)
+                            if nl == -1:
+                                nl = find_token(document.body, "\\begin_inset Newline linebreak", begcell, endcell)
+                                if nl == -1:
+                                     break
+                                linebreak = True
+                            nle = find_end_of_inset(document.body, nl)
+                            del(document.body[nle:nle+1])
+                            if linebreak:
+                                document.body[nl:nl+1] = put_cmd_in_ert("\\linebreak{}")
+                            else:
+                                document.body[nl:nl+1] = put_cmd_in_ert("\\\\")
+                    m += 1
+
+            i = j
+
+    finally:
+        if needarray == True:
+            add_to_preamble(document, ["\\usepackage{array}"])
+        if needcellvarwidth == True:
+            add_to_preamble(document, ["%% Variable width box for table cells",
+                                       "\\newenvironment{cellvarwidth}[1][t]",
+                                       "    {\\begin{varwidth}[#1]{\\linewidth}}",
+                                       "    {\\@finalstrut\\@arstrutbox\\end{varwidth}}"])
+        if needvarwidth == True:
+            add_to_preamble(document, ["\\usepackage{varwidth}"])
+
+
 ##
 # Conversion hub
 #
@@ -4171,10 +4290,12 @@ convert = [
            [601, [convert_math_refs]],
            [602, [convert_branch_colors]],
            [603, []],
-           [604, []]
+           [604, []],
+           [605, []]
           ]
 
-revert =  [[603, [revert_branch_darkcols]],
+revert =  [[604, [revert_vcolumns2]],
+           [603, [revert_branch_darkcols]],
            [602, [revert_darkmode_graphics]],
            [601, [revert_branch_colors]],
            [600, []],
index b55b0be3073b4d1c32c59c8c61b6ea02afb337df..cec1078a5658da44322eebdb2782f33f963fa962 100644 (file)
@@ -193,6 +193,12 @@ static docstring const tabularnewline_def = from_ascii(
        "%% Because html converters don't know tabularnewline\n"
        "\\providecommand{\\tabularnewline}{\\\\}\n");
 
+static docstring const cellvarwidth_def = from_ascii(
+       "%% Variable width box for table cells\n"
+       "\\newenvironment{cellvarwidth}[1][t]\n"
+       "    {\\begin{varwidth}[#1]{\\linewidth}}\n"
+       "    {\\@finalstrut\\@arstrutbox\\end{varwidth}}\n");
+
 // We want to omit the file extension for includegraphics, but this does not
 // work when the filename contains other dots.
 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
@@ -1695,6 +1701,9 @@ TexString LaTeXFeatures::getMacros() const
        if (mustProvide("NeedTabularnewline"))
                macros << tabularnewline_def;
 
+       if (mustProvide("cellvarwidth"))
+               macros << cellvarwidth_def;
+
        // greyed-out environment (note inset)
        // the color is specified in the routine
        // getColorOptions() to avoid LaTeX-package clashes
index 3cd8212441583ae494cc2008e790fb02814fef6f..961a5c8743e0367c106393a9154198a9ead72248 100644 (file)
@@ -1310,16 +1310,15 @@ void Tabular::setVAlignment(idx_type cell, VAlignment align,
 namespace {
 
 /**
- * Allow line and paragraph breaks for fixed width multicol/multirow cells
+ * Allow line and paragraph breaks for fixed width multirow cells
  * or disallow them, merge cell paragraphs and reset layout to standard
  * for variable width multicol cells.
  */
 void toggleFixedWidth(Cursor & cur, InsetTableCell * inset,
-                     bool const fixedWidth, bool const multicol,
-                     bool const multirow)
+                     bool const fixedWidth, bool const multirow)
 {
        inset->toggleFixedWidth(fixedWidth);
-       if (!multirow && (fixedWidth || !multicol))
+       if (!multirow)
                return;
 
        // merge all paragraphs to one
@@ -1366,8 +1365,7 @@ void Tabular::setColumnPWidth(Cursor & cur, idx_type cell,
                idx_type const cidx = cellIndex(r, c);
                // because of multicolumns
                toggleFixedWidth(cur, cellInset(cidx).get(),
-                                !getPWidth(cidx).zero(), isMultiColumn(cidx),
-                                isMultiRow(cidx));
+                                !getPWidth(cidx).zero(), isMultiRow(cidx));
                if (isMultiRow(cidx))
                        setAlignment(cidx, LYX_ALIGN_LEFT, false);
        }
@@ -1394,7 +1392,7 @@ bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell,
 
        cellInfo(cell).p_width = width;
        toggleFixedWidth(cur, cellInset(cell).get(), !width.zero(),
-                        isMultiColumn(cell), isMultiRow(cell));
+                       isMultiRow(cell));
        // cur can become invalid after paragraphs were merged
        cur.fixIfBroken();
        return true;
@@ -1984,7 +1982,9 @@ bool Tabular::isVTypeColumn(col_type c) const
 {
        for (row_type r = 0; r < nrows(); ++r) {
                idx_type idx = cellIndex(r, c);
-               if (getRotateCell(idx) == 0 && useBox(idx) == BOX_VARWIDTH)
+               if (getRotateCell(idx) == 0 && useBox(idx) == BOX_VARWIDTH
+                   && getAlignment(idx) == LYX_ALIGN_LEFT
+                   && getVAlignment(idx) == LYX_VALIGN_TOP)
                        return true;
        }
        return false;
@@ -2021,8 +2021,7 @@ idx_type Tabular::setMultiColumn(Cursor & cur, idx_type cell, idx_type number,
        // non-fixed width multicolumns cannot have multiple paragraphs
        if (getPWidth(cell).zero()) {
                toggleFixedWidth(cur, cellInset(cell).get(),
-                                !getPWidth(cell).zero(), isMultiColumn(cell),
-                                isMultiRow(cell));
+                                !getPWidth(cell).zero(), isMultiRow(cell));
                // cur can become invalid after paragraphs were merged
                cur.fixIfBroken();
        }
@@ -2081,7 +2080,7 @@ idx_type Tabular::setMultiRow(Cursor & cur, idx_type cell, idx_type number,
        if (getPWidth(cell).zero()) {
                toggleFixedWidth(cur, cellInset(cell).get(),
                                 !getPWidth(cell).zero(),
-                                isMultiColumn(cell), isMultiRow(cell));
+                                isMultiRow(cell));
                // cur can become invalid after paragraphs were merged
                cur.fixIfBroken();
        }
@@ -2825,16 +2824,21 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
                                   << from_ascii(getPWidth(cell).asLatexString())
                                   << '}';
                        } else {
-                               switch (align) {
-                               case LYX_ALIGN_LEFT:
-                                       os << 'l';
-                                       break;
-                               case LYX_ALIGN_RIGHT:
-                                       os << 'r';
-                                       break;
-                               default:
-                                       os << 'c';
-                                       break;
+                               if ((getRotateCell(cell) == 0 && useBox(cell) == BOX_VARWIDTH
+                                    && align == LYX_ALIGN_LEFT))
+                                       os << "V{\\linewidth}";
+                               else {
+                                       switch (align) {
+                                       case LYX_ALIGN_LEFT:
+                                               os << 'l';
+                                               break;
+                                       case LYX_ALIGN_RIGHT:
+                                               os << 'r';
+                                               break;
+                                       default:
+                                               os << 'c';
+                                               break;
+                                       }
                                }
                        } // end if else !getPWidth
                } // end if else !cellinfo_of_cell
@@ -2894,8 +2898,10 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
                }
                os << "]{" << from_ascii(getPWidth(cell).asLatexString())
                   << "}\n";
-       } else if (getRotateCell(cell) != 0 && getUsebox(cell) == BOX_VARWIDTH) {
-               os << "\\begin{varwidth}[";
+       } else if (getUsebox(cell) == BOX_VARWIDTH
+                  && (getRotateCell(cell) != 0 || align != LYX_ALIGN_LEFT
+                      || valign != LYX_VALIGN_TOP)) {
+               os << "\\begin{cellvarwidth}[";
                switch (valign) {
                case LYX_VALIGN_TOP:
                        os << 't';
@@ -2906,9 +2912,26 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
                case LYX_VALIGN_BOTTOM:
                        os << 'b';
                        break;
+               }
+               os << "]\n";
+               switch (align) {
+               case LYX_ALIGN_RIGHT:
+                       os << "\\raggedleft\n";
+                       break;
+               case LYX_ALIGN_CENTER:
+                       os << "\\centering\n";
+                       break;
+               case LYX_ALIGN_LEFT:
+                       //os << "\\narrowragged\n";
+                       break;
+               case LYX_ALIGN_BLOCK:
+               case LYX_ALIGN_DECIMAL:
+               case LYX_ALIGN_NONE:
+               case LYX_ALIGN_LAYOUT:
+               case LYX_ALIGN_SPECIAL:
+                       break;
+               }
        }
-       os << "]{\\linewidth}\n";
-}
 }
 
 
@@ -2924,8 +2947,10 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell,
                os << '}';
        else if (getUsebox(cell) == BOX_MINIPAGE)
                os << breakln << "\\end{minipage}";
-       else if (getRotateCell(cell) != 0 && getUsebox(cell) == BOX_VARWIDTH)
-               os << breakln << "\\end{varwidth}";
+       else if (getUsebox(cell) == BOX_VARWIDTH
+                && (getRotateCell(cell) != 0 || getAlignment(cell) != LYX_ALIGN_LEFT
+                    || getVAlignment(cell) != LYX_VALIGN_TOP))
+               os << breakln << "\\end{cellvarwidth}";
        if (getRotateCell(cell) != 0)
                os << breakln << "\\end{turn}";
        if (ismultirow)
@@ -3404,26 +3429,9 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const
                                        break;
                                }
                                os << 'X';
-                       } else if (isVTypeColumn(c)) {
-                               switch (column_info[c].alignment) {
-                               case LYX_ALIGN_LEFT:
-                                       os << ">{\\raggedright}";
-                                       break;
-                               case LYX_ALIGN_RIGHT:
-                                       os << ">{\\raggedleft}";
-                                       break;
-                               case LYX_ALIGN_CENTER:
-                                       os << ">{\\centering}";
-                                       break;
-                               case LYX_ALIGN_NONE:
-                               case LYX_ALIGN_BLOCK:
-                               case LYX_ALIGN_LAYOUT:
-                               case LYX_ALIGN_SPECIAL:
-                               case LYX_ALIGN_DECIMAL:
-                                       break;
-                               }
+                       } else if (isVTypeColumn(c))
                                os << "V{\\linewidth}";
-                       else {
+                       else {
                                switch (column_info[c].alignment) {
                                case LYX_ALIGN_LEFT:
                                        os << 'l';
@@ -4154,8 +4162,10 @@ void Tabular::validate(LaTeXFeatures & features) const
        for (idx_type cell = 0; cell < numberofcells; ++cell) {
                if (isMultiRow(cell))
                        features.require("multirow");
-               if (getUsebox(cell) == BOX_VARWIDTH)
+               if (getUsebox(cell) == BOX_VARWIDTH) {
                        features.require("varwidth");
+                       features.require("cellvarwidth");
+               }
                if (getVAlignment(cell) != LYX_VALIGN_TOP
                    || !getPWidth(cell).zero()
                    || isVTypeColumn(cellColumn(cell)))
@@ -4205,7 +4215,7 @@ InsetTableCell::InsetTableCell(Buffer * buf)
 
 bool InsetTableCell::forcePlainLayout(idx_type) const
 {
-       return isMultiRow || (isMultiColumn && !isFixedWidth);
+       return isMultiRow;
 }
 
 
@@ -5722,8 +5732,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s,
                        flag = false;
                        // fall through
                case Tabular::VALIGN_BOTTOM:
-                       status.setEnabled(!tabular.getPWidth(cur.idx()).zero()
-                               && !tabular.isMultiRow(cur.idx()));
+                       status.setEnabled(!tabular.isMultiRow(cur.idx()));
                        status.setOnOff(
                                tabular.getVAlignment(cur.idx(), flag) == Tabular::LYX_VALIGN_BOTTOM);
                        break;
@@ -5732,8 +5741,7 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s,
                        flag = false;
                        // fall through
                case Tabular::VALIGN_MIDDLE:
-                       status.setEnabled(!tabular.getPWidth(cur.idx()).zero()
-                               && !tabular.isMultiRow(cur.idx()));
+                       status.setEnabled(!tabular.isMultiRow(cur.idx()));
                        status.setOnOff(
                                tabular.getVAlignment(cur.idx(), flag) == Tabular::LYX_VALIGN_MIDDLE);
                        break;
@@ -6043,7 +6051,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                }
                // fall through
        case LFUN_NEWLINE_INSERT:
-               if ((tabular.isMultiColumn(cur.idx()) || tabular.isMultiRow(cur.idx()))
+               if (tabular.isMultiRow(cur.idx())
                    && tabular.getPWidth(cur.idx()).zero()) {
                        status.setEnabled(false);
                        return true;
@@ -7417,7 +7425,7 @@ bool InsetTabular::allowParagraphCustomization(idx_type cell) const
 
 bool InsetTabular::forcePlainLayout(idx_type cell) const
 {
-       return tabular.isMultiColumn(cell) && !tabular.getPWidth(cell).zero();
+       return tabular.isMultiRow(cell);
 }
 
 
index 1b15e8d6ab0a5298e39b67d3296250ef4339c7e2..8fe59c1c04e4ff2d0c9b048b4ffb84ea8b6deb27 100644 (file)
@@ -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 604 // spitz: separate dark branch color
-#define LYX_FORMAT_TEX2LYX 604
+#define LYX_FORMAT_LYX 605 // spitz: improved varwidth cells
+#define LYX_FORMAT_TEX2LYX 605
 
 #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
 #ifndef _MSC_VER