[LyX/master] Format incremented to 605: Extended variable table cell support

Juergen Spitzmueller spitz at lyx.org
Fri Jan 22 18:15:37 UTC 2021


commit 0b0757916e90bcea1bcfa250e8ccb239642cc8df
Author: Juergen Spitzmueller <spitz at lyx.org>
Date:   Fri Jan 22 19:16:43 2021 +0100

    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.
---
 development/FORMAT          |    6 ++
 lib/lyx2lyx/lyx_2_4.py      |  125 ++++++++++++++++++++++++++++++++++++++++++-
 src/LaTeXFeatures.cpp       |    9 +++
 src/insets/InsetTabular.cpp |  116 +++++++++++++++++++++------------------
 src/version.h               |    4 +-
 5 files changed, 202 insertions(+), 58 deletions(-)

diff --git a/development/FORMAT b/development/FORMAT
index 2fff885..d0e9cb5 100644
--- a/development/FORMAT
+++ b/development/FORMAT
@@ -7,6 +7,12 @@ changes happened in particular if possible. A good example would be
 
 -----------------------
 
+2021-01-22 Jürgen Spitzmüller <spitz at 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 at lyx.org>
  	* Format incremented to 604: Branch colors now take two values:
  	  \color lightmode darkmode
diff --git a/lib/lyx2lyx/lyx_2_4.py b/lib/lyx2lyx/lyx_2_4.py
index d3177f9..93500d0 100644
--- a/lib/lyx2lyx/lyx_2_4.py
+++ b/lib/lyx2lyx/lyx_2_4.py
@@ -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, []],
diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp
index b55b0be..cec1078 100644
--- a/src/LaTeXFeatures.cpp
+++ b/src/LaTeXFeatures.cpp
@@ -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
diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp
index 3cd8212..961a5c8 100644
--- a/src/insets/InsetTabular.cpp
+++ b/src/insets/InsetTabular.cpp
@@ -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);
 }
 
 
diff --git a/src/version.h b/src/version.h
index 1b15e8d..8fe59c1 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 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


More information about the lyx-cvs mailing list