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.
This commit is contained in:
Juergen Spitzmueller 2021-01-22 19:16:43 +01:00
parent 469b43c791
commit 0b0757916e
5 changed files with 202 additions and 58 deletions

View 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

View 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, []],

View 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

View 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);
}

View 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