X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FInsetMathGrid.cpp;h=67300403907d947f43f1ca71e2b75323bf2192e6;hb=cdc847fd304019a19425a0d5d9d42a556a937097;hp=ed77f71f851be12a46fa959b5b0f9c7e81d0defc;hpb=6d75800f5d23f5b051302cb5ff49940748fed4c1;p=lyx.git diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp index ed77f71f85..6730040390 100644 --- a/src/mathed/InsetMathGrid.cpp +++ b/src/mathed/InsetMathGrid.cpp @@ -20,21 +20,22 @@ #include "MetricsInfo.h" #include "Buffer.h" +#include "BufferParams.h" #include "BufferView.h" -#include "CutAndPaste.h" -#include "FuncStatus.h" #include "Cursor.h" +#include "CutAndPaste.h" #include "FuncRequest.h" +#include "FuncStatus.h" +#include "LaTeXFeatures.h" +#include "TexRow.h" #include "frontends/Clipboard.h" -#include "frontends/FontMetrics.h" #include "frontends/Painter.h" #include "support/debug.h" #include "support/docstream.h" #include "support/gettext.h" #include "support/lstrings.h" - #include "support/lassert.h" #include @@ -81,7 +82,7 @@ static void resetGrid(InsetMathGrid & grid) InsetMathGrid::CellInfo::CellInfo() - : dummy_(false) + : multi_(CELL_NORMAL) {} @@ -90,16 +91,15 @@ InsetMathGrid::CellInfo::CellInfo() InsetMathGrid::RowInfo::RowInfo() - : lines_(0), skip_(0), allow_newpage_(true) + : descent_(0), ascent_(0), offset_(0), lines_(0), skip_(0), + allow_newpage_(true) {} int InsetMathGrid::RowInfo::skipPixels(MetricsInfo const & mi) const { - frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); - return crskip_.inPixels(mi.base.textwidth, - fm.width(char_type('M'))); + return crskip_.inPixels(mi.base); } @@ -108,7 +108,7 @@ int InsetMathGrid::RowInfo::skipPixels(MetricsInfo const & mi) const InsetMathGrid::ColInfo::ColInfo() - : align_('c'), lines_(0) + : align_('c'), width_(0), offset_(0), lines_(0), skip_(0) {} @@ -174,13 +174,15 @@ void InsetMathGrid::setDefaults() colinfo_[col].skip_ = defaultColSpace(col); colinfo_[col].special_.clear(); } + for (idx_type idx = 0; idx < nargs(); ++idx) + cellinfo_[idx].multi_ = CELL_NORMAL; } bool InsetMathGrid::interpretString(Cursor & cur, docstring const & str) { if (str == "\\hline") { - FuncRequest fr = FuncRequest(LFUN_INSET_MODIFY, "tabular add-hline-above"); + FuncRequest fr = FuncRequest(LFUN_TABULAR_FEATURE, "add-hline-above"); FuncStatus status; if (getStatus(cur, fr, status)) { if (status.enabled()) { @@ -360,6 +362,23 @@ InsetMathGrid::row_type InsetMathGrid::row(idx_type idx) const } +InsetMathGrid::col_type InsetMathGrid::ncellcols(idx_type idx) const +{ + col_type cols = 1; + if (cellinfo_[idx].multi_ == CELL_NORMAL) + return cols; + // If the cell at idx is already CELL_PART_OF_MULTICOLUMN we return + // the number of remaining columns, not the ones of the complete + // multicolumn cell. This makes it possible to always go to the next + // cell with idx + ncellcols(idx) - 1. + row_type const r = row(idx); + while (idx+cols < nargs() && row(idx+cols) == r && + cellinfo_[idx+cols].multi_ == CELL_PART_OF_MULTICOLUMN) + cols++; + return cols; +} + + void InsetMathGrid::vcrskip(Length const & crskip, row_type row) { rowinfo_[row].crskip_ = crskip; @@ -375,7 +394,12 @@ Length InsetMathGrid::vcrskip(row_type row) const void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const { // let the cells adjust themselves - InsetMathNest::metrics(mi); + for (idx_type i = 0; i < nargs(); ++i) { + if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) { + Dimension dimc; + cell(i).metrics(mi, dimc); + } + } BufferView & bv = *mi.base.bv; @@ -384,14 +408,16 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const int asc = 0; int desc = 0; for (col_type col = 0; col < ncols(); ++col) { - Dimension const & dimc = cell(index(row, col)).dimension(bv); - asc = max(asc, dimc.asc); - desc = max(desc, dimc.des); + idx_type const i = index(row, col); + if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) { + Dimension const & dimc = cell(i).dimension(bv); + asc = max(asc, dimc.asc); + desc = max(desc, dimc.des); + } } rowinfo_[row].ascent_ = asc; rowinfo_[row].descent_ = desc; } - rowinfo_[0].ascent_ += hlinesep() * rowinfo_[0].lines_; rowinfo_[nrows()].ascent_ = 0; rowinfo_[nrows()].descent_ = 0; @@ -423,26 +449,77 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const rowinfo_[row].offset_ -= h; + // multicolumn cell widths, as a map from first column to width in a + // vector of last columns. + // This is only used if the grid has more than one row, since for + // one-row grids multicolumn cells do not need special handling + vector > mcolwidths(ncols()); + // compute absolute sizes of horizontal structure for (col_type col = 0; col < ncols(); ++col) { int wid = 0; - for (row_type row = 0; row < nrows(); ++row) - wid = max(wid, cell(index(row, col)).dimension(bv).wid); + for (row_type row = 0; row < nrows(); ++row) { + idx_type const i = index(row, col); + if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) { + int const w = cell(i).dimension(bv).wid; + col_type const cols = ncellcols(i); + if (cols > 1 && nrows() > 1) { + col_type last = col+cols-1; + LASSERT(last < ncols(), last = ncols()-1); + map::iterator it = + mcolwidths[last].find(col); + if (it == mcolwidths[last].end()) + mcolwidths[last][col] = w; + else + it->second = max(it->second, w); + } else + wid = max(wid, w); + } + } colinfo_[col].width_ = wid; } colinfo_[ncols()].width_ = 0; // compute horizontal offsets - colinfo_[0].offset_ = border(); + colinfo_[0].offset_ = border() + colinfo_[0].lines_ * vlinesep();; for (col_type col = 1; col <= ncols(); ++col) { colinfo_[col].offset_ = colinfo_[col - 1].offset_ + colinfo_[col - 1].width_ + - colinfo_[col - 1].skip_ + + displayColSpace(col - 1) + colsep() + colinfo_[col].lines_ * vlinesep(); } + // increase column widths for multicolumn cells if needed + // FIXME: multicolumn lines are not yet considered + for (col_type last = 0; last < ncols(); ++last) { + map const & widths = mcolwidths[last]; + // We increase the width of the last column of the multicol + // cell (some sort of left alignment). Since we iterate through + // the last and the first columns from left to right, we ensure + // that increased widths of previous columns are correctly + // taken into account for later columns, thus preventing + // unneeded width increasing. + for (map::const_iterator it = widths.begin(); + it != widths.end(); ++it) { + int const wid = it->second; + col_type const first = it->first; + int const nextoffset = + colinfo_[first].offset_ + + wid + + displayColSpace(last) + + colsep() + + colinfo_[last+1].lines_ * vlinesep(); + int const dx = nextoffset - colinfo_[last+1].offset_; + if (dx > 0) { + colinfo_[last].width_ += dx; + for (col_type col = last + 1; col <= ncols(); ++col) + colinfo_[col].offset_ += dx; + } + } + } + dim.wid = colinfo_[ncols() - 1].offset_ + colinfo_[ncols() - 1].width_ @@ -457,7 +534,7 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const dim.des = rowinfo_[nrows() - 1].offset_ + rowinfo_[nrows() - 1].descent_ + hlinesep() * rowinfo_[nrows()].lines_ - + border(); + + border() + 1; /* @@ -510,71 +587,98 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const cxrow->setBaseline(cxrow->getBaseline() - ascent); } */ - metricsMarkers2(dim); - // Cache the inset dimension. - setDimCache(mi, dim); + dim.wid += leftMargin() + rightMargin(); } -void InsetMathGrid::draw(PainterInfo & pi, int x, int y) const +int InsetMathGrid::vLineHOffset(col_type col, unsigned int line) const { - drawWithMargin(pi, x, y, 1, 1); + if (col < ncols()) + return leftMargin() + colinfo_[col].offset_ + - (colinfo_[col].lines_ - line - 1) * vlinesep() + - vlinesep()/2 - colsep()/2; + else { + LASSERT(col == ncols(), return 0); + return leftMargin() + colinfo_[col-1].offset_ + colinfo_[col-1].width_ + + line * vlinesep() + + vlinesep()/2 + colsep()/2; + } } -void InsetMathGrid::drawWithMargin(PainterInfo & pi, int x, int y, - int lmargin, int rmargin) const +int InsetMathGrid::hLineVOffset(row_type row, unsigned int line) const { - Dimension const dim = dimension(*pi.base.bv); - BufferView const & bv = *pi.base.bv; + return rowinfo_[row].offset_ + - rowinfo_[row].ascent_ + - line * hlinesep() + - hlinesep()/2 - rowsep()/2; +} - for (idx_type idx = 0; idx < nargs(); ++idx) - cell(idx).draw(pi, x + lmargin + cellXOffset(bv, idx), - y + cellYOffset(idx)); - for (row_type row = 0; row <= nrows(); ++row) - for (unsigned int i = 0; i < rowinfo_[row].lines_; ++i) { - int yy = y + rowinfo_[row].offset_ - rowinfo_[row].ascent_ - - i * hlinesep() - hlinesep()/2 - rowsep()/2; - pi.pain.line(x + lmargin + 1, yy, - x + dim.width() - rmargin - 1, yy, - Color_foreground); +void InsetMathGrid::draw(PainterInfo & pi, int x, int y) const +{ + BufferView const & bv = *pi.base.bv; + + for (idx_type idx = 0; idx < nargs(); ++idx) { + if (cellinfo_[idx].multi_ != CELL_PART_OF_MULTICOLUMN) { + cell(idx).draw(pi, + x + leftMargin() + cellXOffset(bv, idx), + y + cellYOffset(idx)); + + row_type r = row(idx); + int const yy1 = y + hLineVOffset(r, 0); + int const yy2 = y + hLineVOffset(r + 1, rowinfo_[r + 1].lines_ - 1); + auto draw_left_borders = [&](col_type c) { + for (unsigned int i = 0; i < colinfo_[c].lines_; ++i) { + int const xx = x + vLineHOffset(c, i); + pi.pain.line(xx, yy1, xx, yy2, Color_foreground); + } + }; + col_type c = col(idx); + // Draw inner left borders cell-by-cell because of multicolumns + draw_left_borders(c); + // Draw the right border (only once) + if (c == 0) + draw_left_borders(ncols()); } + } - for (col_type col = 0; col <= ncols(); ++col) - for (unsigned int i = 0; i < colinfo_[col].lines_; ++i) { - int xx = x + lmargin + colinfo_[col].offset_ - - i * vlinesep() - vlinesep()/2 - colsep()/2; - pi.pain.line(xx, y - dim.ascent() + 1, - xx, y + dim.descent() - 1, - Color_foreground); + // Draw horizontal borders + for (row_type r = 0; r <= nrows(); ++r) { + int const xx1 = x + vLineHOffset(0, 0); + int const xx2 = x + vLineHOffset(ncols(), colinfo_[ncols()].lines_ - 1); + for (unsigned int i = 0; i < rowinfo_[r].lines_; ++i) { + int const yy = y + hLineVOffset(r, i); + pi.pain.line(xx1, yy, xx2, yy, Color_foreground); } - drawMarkers2(pi, x, y); + } } void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const { // let the cells adjust themselves - //InsetMathNest::metrics(mi); for (idx_type i = 0; i < nargs(); ++i) - cell(i).metricsT(mi, dim); + if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) + cell(i).metricsT(mi, dim); // compute absolute sizes of vertical structure for (row_type row = 0; row < nrows(); ++row) { int asc = 0; int desc = 0; for (col_type col = 0; col < ncols(); ++col) { - //MathData const & c = cell(index(row, col)); - // FIXME: BROKEN! - Dimension dimc; - asc = max(asc, dimc.ascent()); - desc = max(desc, dimc.descent()); + idx_type const i = index(row, col); + if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) { + //MathData const & c = cell(i); + // FIXME: BROKEN! + Dimension dimc; + asc = max(asc, dimc.ascent()); + desc = max(desc, dimc.descent()); + } } rowinfo_[row].ascent_ = asc; rowinfo_[row].descent_ = desc; } - //rowinfo_[0].ascent_ += hlinesep() * rowinfo_[0].lines_; rowinfo_[nrows()].ascent_ = 0; rowinfo_[nrows()].descent_ = 0; @@ -611,7 +715,9 @@ void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const int wid = 0; for (row_type row = 0; row < nrows(); ++row) { // FIXME: BROKEN! - //wid = max(wid, cell(index(row, col)).width()); + //idx_type const i = index(row, col); + //if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) + // wid = max(wid, cell(i).width()); } colinfo_[col].width_ = wid; } @@ -623,7 +729,7 @@ void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const colinfo_[col].offset_ = colinfo_[col - 1].offset_ + colinfo_[col - 1].width_ + - colinfo_[col - 1].skip_ + + displayColSpace(col - 1) + 1 ; //colsep() + //colinfo_[col].lines_ * vlinesep(); } @@ -649,7 +755,8 @@ void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const void InsetMathGrid::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const { // for (idx_type idx = 0; idx < nargs(); ++idx) -// cell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx)); +// if (cellinfo_[idx].multi_ != CELL_PART_OF_MULTICOLUMN) +// cell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx)); } @@ -657,7 +764,8 @@ void InsetMathGrid::updateBuffer(ParIterator const & it, UpdateType utype) { // pass down for (idx_type idx = 0; idx < nargs(); ++idx) - cell(idx).updateBuffer(it, utype); + if (cellinfo_[idx].multi_ != CELL_PART_OF_MULTICOLUMN) + cell(idx).updateBuffer(it, utype); } @@ -674,7 +782,7 @@ docstring InsetMathGrid::eolString(row_type row, bool fragile, // make sure an upcoming '[' does not break anything if (row + 1 < nrows()) { MathData const & c = cell(index(row + 1, 0)); - if (c.size() && c.front()->getChar() == '[') + if (!c.empty() && c.front()->getChar() == '[') //eol += "[0pt]"; eol += "{}"; } @@ -803,14 +911,16 @@ void InsetMathGrid::swapCol(col_type col) int InsetMathGrid::cellXOffset(BufferView const & bv, idx_type idx) const { + if (cellinfo_[idx].multi_ == CELL_PART_OF_MULTICOLUMN) + return 0; col_type c = col(idx); int x = colinfo_[c].offset_; - char align = displayColAlign(c, row(idx)); + char align = displayColAlign(idx); Dimension const & celldim = cell(idx).dimension(bv); if (align == 'r' || align == 'R') - x += colinfo_[c].width_ - celldim.wid; + x += cellWidth(idx) - celldim.wid; if (align == 'c' || align == 'C') - x += (colinfo_[c].width_ - celldim.wid) / 2; + x += (cellWidth(idx) - celldim.wid) / 2; return x; } @@ -821,6 +931,27 @@ int InsetMathGrid::cellYOffset(idx_type idx) const } +int InsetMathGrid::cellWidth(idx_type idx) const +{ + switch (cellinfo_[idx].multi_) { + case CELL_NORMAL: + return colinfo_[col(idx)].width_; + case CELL_BEGIN_OF_MULTICOLUMN: { + col_type c1 = col(idx); + col_type c2 = c1 + ncellcols(idx); + return colinfo_[c2].offset_ + - colinfo_[c1].offset_ + - displayColSpace(c2) + - colsep() + - colinfo_[c2].lines_ * vlinesep(); + } + case CELL_PART_OF_MULTICOLUMN: + return 0; + } + return 0; +} + + bool InsetMathGrid::idxUpDown(Cursor & cur, bool up) const { if (up) { @@ -832,6 +963,11 @@ bool InsetMathGrid::idxUpDown(Cursor & cur, bool up) const return false; cur.idx() += ncols(); } + // If we are in a multicolumn cell, move to the "real" cell + while (cellinfo_[cur.idx()].multi_ == CELL_PART_OF_MULTICOLUMN) { + LASSERT(cur.idx() > 0, return false); + --cur.idx(); + } cur.pos() = cur.cell().x2pos(&cur.bv(), cur.x_target() - cur.cell().xo(cur.bv())); return true; } @@ -843,6 +979,11 @@ bool InsetMathGrid::idxBackward(Cursor & cur) const if (cur.col() == 0) return false; --cur.idx(); + // If we are in a multicolumn cell, move to the "real" cell + while (cellinfo_[cur.idx()].multi_ == CELL_PART_OF_MULTICOLUMN) { + LASSERT(cur.idx() > 0, return false); + --cur.idx(); + } cur.pos() = cur.lastpos(); return true; } @@ -854,6 +995,13 @@ bool InsetMathGrid::idxForward(Cursor & cur) const if (cur.col() + 1 == ncols()) return false; ++cur.idx(); + // If we are in a multicolumn cell, move to the next cell + while (cellinfo_[cur.idx()].multi_ == CELL_PART_OF_MULTICOLUMN) { + // leave matrix if at the back edge + if (cur.col() + 1 == ncols()) + return false; + ++cur.idx(); + } cur.pos() = 0; return true; } @@ -871,6 +1019,11 @@ bool InsetMathGrid::idxFirst(Cursor & cur) const default: cur.idx() = ((nrows() - 1) / 2) * ncols(); } + // If we are in a multicolumn cell, move to the "real" cell + while (cellinfo_[cur.idx()].multi_ == CELL_PART_OF_MULTICOLUMN) { + LASSERT(cur.idx() > 0, return false); + --cur.idx(); + } cur.pos() = 0; return true; } @@ -888,6 +1041,11 @@ bool InsetMathGrid::idxLast(Cursor & cur) const default: cur.idx() = ((nrows() - 1) / 2 + 1) * ncols() - 1; } + // If we are in a multicolumn cell, move to the "real" cell + while (cellinfo_[cur.idx()].multi_ == CELL_PART_OF_MULTICOLUMN) { + LASSERT(cur.idx() > 0, return false); + --cur.idx(); + } cur.pos() = cur.lastpos(); return true; } @@ -905,7 +1063,7 @@ bool InsetMathGrid::idxDelete(idx_type & idx) // try to delete entire sequence of ncols() empty cells if possible for (idx_type i = idx; i < idx + ncols(); ++i) - if (cell(i).size()) + if (!cell(i).empty()) return false; // move cells if necessary @@ -938,9 +1096,15 @@ void InsetMathGrid::idxGlue(idx_type idx) delRow(row(idx) + 1); } } else { - cell(idx).append(cell(idx + 1)); + idx_type idx_next = idx + 1; + while (idx_next < nargs() && + cellinfo_[idx_next].multi_ == CELL_PART_OF_MULTICOLUMN) + ++idx_next; + if (idx_next < nargs()) + cell(idx).append(cell(idx_next)); + col_type oldcol = c + 1; for (col_type cc = c + 2; cc < ncols(); ++cc) - cell(idx - c + cc - 1) = cell(idx - c + cc); + cell(idx - oldcol + cc) = cell(idx - oldcol + 1 + cc); cell(idx - c + ncols() - 1).clear(); } } @@ -970,14 +1134,26 @@ bool InsetMathGrid::idxBetween(idx_type idx, idx_type from, idx_type to) const } - void InsetMathGrid::normalize(NormalStream & os) const { os << "[grid "; for (row_type row = 0; row < nrows(); ++row) { os << "[row "; - for (col_type col = 0; col < ncols(); ++col) - os << "[cell " << cell(index(row, col)) << ']'; + for (col_type col = 0; col < ncols(); ++col) { + idx_type const i = index(row, col); + switch (cellinfo_[i].multi_) { + case CELL_NORMAL: + os << "[cell " << cell(i) << ']'; + break; + case CELL_BEGIN_OF_MULTICOLUMN: + os << "[cell colspan=" + << static_cast(ncellcols(i)) << ' ' + << cell(i) << ']'; + break; + case CELL_PART_OF_MULTICOLUMN: + break; + } + } os << ']'; } os << ']'; @@ -994,9 +1170,16 @@ void InsetMathGrid::mathmlize(MathStream & os) const if (havetable) os << MTag("mtr"); for (col_type col = 0; col < ncols(); ++col) { - os << MTag(celltag); - os << cell(index(row, col)); - os << ETag(celltag); + idx_type const i = index(row, col); + if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) { + col_type const cellcols = ncellcols(i); + ostringstream attr; + if (havetable && cellcols > 1) + attr << "colspan='" << cellcols << '\''; + os << MTag(celltag, attr.str()); + os << cell(index(row, col)); + os << ETag(celltag); + } } if (havetable) os << ETag("mtr"); @@ -1019,9 +1202,16 @@ void InsetMathGrid::htmlize(HtmlStream & os, string attrib) const for (row_type row = 0; row < nrows(); ++row) { os << MTag("tr"); for (col_type col = 0; col < ncols(); ++col) { - os << MTag("td"); - os << cell(index(row, col)); - os << ETag("td"); + idx_type const i = index(row, col); + if (cellinfo_[i].multi_ != CELL_PART_OF_MULTICOLUMN) { + col_type const cellcols = ncellcols(i); + ostringstream attr; + if (cellcols > 1) + attr << "colspan='" << cellcols << '\''; + os << MTag("td", attr.str()); + os << cell(index(row, col)); + os << ETag("td"); + } } os << ETag("tr"); } @@ -1035,6 +1225,20 @@ void InsetMathGrid::htmlize(HtmlStream & os) const } +void InsetMathGrid::validate(LaTeXFeatures & features) const +{ + if (features.runparams().math_flavor == OutputParams::MathAsHTML + && (nrows() > 1 || ncols() > 1)) { + // CSS taken from InsetMathCases + features.addCSSSnippet( + "table.mathtable{display: inline-block; text-align: center; border: none;" + "border-left: thin solid black; vertical-align: middle; padding-left: 0.5ex;}\n" + "table.mathtable td {text-align: left; border: none;}"); + } + InsetMathNest::validate(features); +} + + void InsetMathGrid::write(WriteStream & os) const { write(os, 0, 0, nrows(), ncols()); @@ -1054,19 +1258,43 @@ void InsetMathGrid::write(WriteStream & os, bool emptyline = true; bool last_eoln = true; for (col_type col = beg_col; col < end_col; ++col) { - bool const empty_cell = cell(index(row, col)).empty(); - if (!empty_cell) + idx_type const idx = index(row, col); + bool const empty_cell = cell(idx).empty(); + if (!empty_cell || cellinfo_[idx].multi_ != CELL_NORMAL) last_eoln = false; - if (!empty_cell || colinfo_[col + 1].lines_) { + if (!empty_cell || cellinfo_[idx].multi_ != CELL_NORMAL || + colinfo_[col + 1].lines_) { lastcol = col + 1; emptyline = false; } } - for (col_type col = beg_col; col < lastcol; ++col) { - os << cell(index(row, col)); + for (col_type col = beg_col; col < end_col;) { + int nccols = 1; + idx_type const idx = index(row, col); + TexRow::RowEntry entry = TexRow::mathEntry(id(),idx); + os.texrow().start(entry); + if (col >= lastcol) { + ++col; + continue; + } + Changer dummy = os.changeRowEntry(entry); + if (cellinfo_[idx].multi_ == CELL_BEGIN_OF_MULTICOLUMN) { + size_t s = col + 1; + while (s < ncols() && + cellinfo_[index(row, s)].multi_ == CELL_PART_OF_MULTICOLUMN) + s++; + nccols = s - col; + os << "\\multicolumn{" << nccols + << "}{" << cellinfo_[idx].align_ + << "}{"; + } + os << cell(idx); if (os.pendingBrace()) ModeSpecifier specifier(os, TEXT_MODE); - os << eocString(col, lastcol); + if (cellinfo_[idx].multi_ == CELL_BEGIN_OF_MULTICOLUMN) + os << '}'; + os << eocString(col + nccols - 1, lastcol); + col += nccols; } eol = eolString(row, os.fragile(), os.latex(), last_eoln); os << eol; @@ -1127,11 +1355,35 @@ void InsetMathGrid::splitCell(Cursor & cur) ar.erase(0, cur.pos()); cur.cell().erase(cur.pos(), cur.lastpos()); ++cur.idx(); + while (cur.idx() << nargs() && + cellinfo_[cur.idx()].multi_ == CELL_BEGIN_OF_MULTICOLUMN) + ++cur.idx(); cur.pos() = 0; cur.cell().insert(0, ar); } +char InsetMathGrid::displayColAlign(idx_type idx) const +{ + if (cellinfo_[idx].multi_ == CELL_BEGIN_OF_MULTICOLUMN) { + // align_ may also contain lines like "||r|", so this is + // not complete, but we catch at least the simple cases. + if (cellinfo_[idx].align_ == "c") + return 'c'; + if (cellinfo_[idx].align_ == "l") + return 'l'; + if (cellinfo_[idx].align_ == "r") + return 'r'; + } + return colinfo_[col(idx)].align_; +} + + +int InsetMathGrid::displayColSpace(col_type col) const +{ + return colinfo_[col].skip_; +} + void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) { //lyxerr << "*** InsetMathGrid: request: " << cmd << endl; @@ -1142,7 +1394,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) switch (act) { // insert file functions - case LFUN_LINE_DELETE: + case LFUN_LINE_DELETE_FORWARD: cur.recordUndoInset(); //autocorrect_ = false; //macroModeClose(); @@ -1165,7 +1417,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CELL_BACKWARD: // See below. - cur.setSelection(false); + cur.selection(false); if (!idxPrev(cur)) { cmd = FuncRequest(LFUN_FINISHED_BACKWARD); cur.undispatched(); @@ -1175,7 +1427,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CELL_FORWARD: // Can't handle selection by additional 'shift' as this is // hard bound to LFUN_CELL_BACKWARD - cur.setSelection(false); + cur.selection(false); if (!idxNext(cur)) { cmd = FuncRequest(LFUN_FINISHED_FORWARD); cur.undispatched(); @@ -1193,7 +1445,8 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) // split cell splitCell(cur); - swap(cell(cur.idx()), cell(cur.idx() + ncols() - 1)); + if (ncols() > 1) + swap(cell(cur.idx()), cell(cur.idx() + ncols() - 1)); if (cur.idx() > 0) --cur.idx(); cur.pos() = cur.lastpos(); @@ -1203,17 +1456,12 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) break; } - case LFUN_INSET_MODIFY: { + case LFUN_TABULAR_FEATURE: { cur.recordUndoInset(); //lyxerr << "handling tabular-feature " << to_utf8(cmd.argument()) << endl; istringstream is(to_utf8(cmd.argument())); string s; is >> s; - if (s != "tabular") { - InsetMathNest::doDispatch(cur, cmd); - return; - } - is >> s; if (s == "valign-top") setVerticalAlignment('t'); else if (s == "valign-middle") @@ -1302,7 +1550,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) docstring & special = colinfo_[cur.col()].special_; if (!special.empty()) { docstring::size_type i = special.rfind('|'); - LASSERT(i != docstring::npos, /**/); + LASSERT(i != docstring::npos, break); special.erase(i, 1); } } @@ -1311,7 +1559,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) docstring & special = colinfo_[cur.col()+1].special_; if (!special.empty()) { docstring::size_type i = special.find('|'); - LASSERT(i != docstring::npos, /**/); + LASSERT(i != docstring::npos, break); special.erase(i, 1); } } @@ -1328,35 +1576,35 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) parseflg |= Parse::VERBATIM; // fall through case LFUN_PASTE: { - if (cur.currentMode() <= TEXT_MODE) + if (cur.currentMode() != MATH_MODE) parseflg |= Parse::TEXTMODE; cur.message(_("Paste")); cap::replaceSelection(cur); docstring topaste; if (cmd.argument().empty() && !theClipboard().isInternal()) - topaste = theClipboard().getAsText(); + topaste = theClipboard().getAsText(frontend::Clipboard::PlainTextType); else { idocstringstream is(cmd.argument()); int n = 0; is >> n; - topaste = cap::selection(n); + topaste = cap::selection(n, buffer().params().documentClassPtr()); } InsetMathGrid grid(buffer_, 1, 1); if (!topaste.empty()) - if ((topaste.size() == 1 && topaste.at(0) < 0x80) + if ((topaste.size() == 1 && isAscii(topaste)) || !mathed_parse_normal(grid, topaste, parseflg)) { resetGrid(grid); mathed_parse_normal(grid, topaste, parseflg | Parse::VERBATIM); } bool hline_enabled = false; - FuncRequest fr = FuncRequest(LFUN_INSET_MODIFY, "tabular add-hline-above"); + FuncRequest fr = FuncRequest(LFUN_TABULAR_FEATURE, "add-hline-above"); FuncStatus status; if (getStatus(cur, fr, status)) hline_enabled = status.enabled(); if (grid.nargs() == 1) { // single cell/part of cell - cur.recordUndo(); + cur.recordUndoInset(); cur.cell().insert(cur.pos(), grid.cell(0)); cur.pos() += grid.cell(0).size(); if (hline_enabled) @@ -1417,12 +1665,10 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) break; } - case LFUN_LINE_BEGIN_SELECT: case LFUN_LINE_BEGIN: - case LFUN_WORD_BACKWARD_SELECT: - case LFUN_WORD_BACKWARD: - case LFUN_WORD_LEFT_SELECT: - case LFUN_WORD_LEFT: + cur.screenUpdateFlags(Update::Decoration | Update::FitCursor); + // fall through + case LFUN_LINE_BEGIN_SELECT: cur.selHandle(act == LFUN_WORD_BACKWARD_SELECT || act == LFUN_WORD_LEFT_SELECT || act == LFUN_LINE_BEGIN_SELECT); @@ -1441,12 +1687,10 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) } break; - case LFUN_WORD_FORWARD_SELECT: - case LFUN_WORD_FORWARD: - case LFUN_WORD_RIGHT_SELECT: - case LFUN_WORD_RIGHT: - case LFUN_LINE_END_SELECT: case LFUN_LINE_END: + cur.screenUpdateFlags(Update::Decoration | Update::FitCursor); + // fall through + case LFUN_LINE_END_SELECT: cur.selHandle(act == LFUN_WORD_FORWARD_SELECT || act == LFUN_WORD_RIGHT_SELECT || act == LFUN_LINE_END_SELECT); @@ -1476,14 +1720,8 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { switch (cmd.action()) { - case LFUN_INSET_MODIFY: { - istringstream is(to_utf8(cmd.argument())); - string s; - is >> s; - if (s != "tabular") { - // We only now about table actions here. - break; - } + case LFUN_TABULAR_FEATURE: { + string s = cmd.getArg(0); if (&cur.inset() != this) { // Table actions requires that the cursor is _inside_ the // table. @@ -1491,7 +1729,6 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, status.message(from_utf8(N_("Cursor not in table"))); return true; } - is >> s; if (nrows() <= 1 && (s == "delete-row" || s == "swap-row")) { status.setEnabled(false); status.message(from_utf8(N_("Only one row"))); @@ -1546,7 +1783,8 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, } else { status.setEnabled(false); status.message(bformat( - from_utf8(N_("Unknown tabular feature '%1$s'")), lyx::from_ascii(s))); + from_utf8(N_("Unknown tabular feature '%1$s'")), + from_utf8(s))); } #if 0 @@ -1587,4 +1825,69 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, } +// static +char InsetMathGrid::colAlign(HullType type, col_type col) +{ + switch (type) { + case hullEqnArray: + return "rcl"[col % 3]; + + case hullMultline: + case hullGather: + return 'c'; + + case hullAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullFlAlign: + return "rl"[col & 1]; + + case hullUnknown: + case hullNone: + case hullSimple: + case hullEquation: + case hullRegexp: + return 'c'; + } + // avoid warning + return 'c'; +} + + +//static +int InsetMathGrid::colSpace(HullType type, col_type col) +{ + int alignInterSpace = 0; + switch (type) { + case hullUnknown: + case hullNone: + case hullSimple: + case hullEquation: + case hullMultline: + case hullGather: + case hullRegexp: + return 0; + + case hullEqnArray: + return 5; + + case hullAlign: + alignInterSpace = 20; + break; + case hullAlignAt: + alignInterSpace = 0; + break; + case hullXAlignAt: + alignInterSpace = 40; + break; + case hullXXAlignAt: + case hullFlAlign: + alignInterSpace = 60; + break; + } + return (col % 2) ? alignInterSpace : 0; +} + + } // namespace lyx