From 9b0945a47fd0876d01a84e83443364acc4dae656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20P=C3=B6nitz?= Date: Wed, 28 Nov 2001 13:09:40 +0000 Subject: [PATCH] re-enable the mathcursor->normalize() safety belt. This trades Asserts() against a console warning git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@3103 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/mathed/formulabase.C | 2 + src/mathed/math_arrayinset.C | 11 +- src/mathed/math_arrayinset.h | 2 + src/mathed/math_cursor.C | 3 + src/mathed/math_gridinset.C | 248 ++++++++++++++++++++++++++--------- src/mathed/math_gridinset.h | 36 +++-- src/mathed/math_hullinset.C | 2 +- src/mathed/math_parser.C | 77 ++++++++--- 8 files changed, 279 insertions(+), 102 deletions(-) diff --git a/src/mathed/formulabase.C b/src/mathed/formulabase.C index 9331006c24..7e9d1b8844 100644 --- a/src/mathed/formulabase.C +++ b/src/mathed/formulabase.C @@ -647,6 +647,8 @@ InsetFormulaBase::localDispatch(BufferView * bv, kb_action action, result = UNDISPATCHED; } + mathcursor->normalize(); + lyx::Assert(mathcursor); if (mathcursor->selection() || was_selection) diff --git a/src/mathed/math_arrayinset.C b/src/mathed/math_arrayinset.C index 4c0490af7f..c0ed8a273f 100644 --- a/src/mathed/math_arrayinset.C +++ b/src/mathed/math_arrayinset.C @@ -24,6 +24,11 @@ MathArrayInset::MathArrayInset(int m, int n, char valign, string const & halign) {} +MathArrayInset::MathArrayInset(char valign, string const & halign) + : MathGridInset(valign, halign) +{} + + MathArrayInset::MathArrayInset(string const & str) : MathGridInset(1, 1) { @@ -72,11 +77,7 @@ void MathArrayInset::write(WriteStream & os) const if (v_align_ == 't' || v_align_ == 'b') os << '[' << char(v_align_) << ']'; - - os << '{'; - for (col_type col = 0; col < ncols(); ++col) - os << colinfo_[col].align_; - os << "}\n"; + os << '{' << halign().c_str() << "}\n"; MathGridInset::write(os); diff --git a/src/mathed/math_arrayinset.h b/src/mathed/math_arrayinset.h index 89f34545c3..d09dae7e8a 100644 --- a/src/mathed/math_arrayinset.h +++ b/src/mathed/math_arrayinset.h @@ -15,6 +15,8 @@ public: MathArrayInset(int m, int n); /// MathArrayInset(int m, int n, char valign, string const & halign); + /// + MathArrayInset(char valign, string const & halign); /// convienience constructor from whitespace/newline seperated data MathArrayInset(string const & str); /// diff --git a/src/mathed/math_cursor.C b/src/mathed/math_cursor.C index 6d4a1970fc..588a2ce25f 100644 --- a/src/mathed/math_cursor.C +++ b/src/mathed/math_cursor.C @@ -572,6 +572,9 @@ void MathCursor::delLine() if (par()->nrows() > 1) par()->delRow(row()); + if (idx() > par()->nargs()) + idx() = par()->nargs(); + if (pos() > size()) pos() = size(); } diff --git a/src/mathed/math_gridinset.C b/src/mathed/math_gridinset.C index 600b7140cc..8ca134842e 100644 --- a/src/mathed/math_gridinset.C +++ b/src/mathed/math_gridinset.C @@ -5,17 +5,31 @@ #include "math_gridinset.h" #include "math_mathmlstream.h" #include "lyxfont.h" +#include "Painter.h" #include "debug.h" namespace { /// -int const MATH_COLSEP = 10; +int const COLSEP = 6; /// -int const MATH_ROWSEP = 10; +int const ROWSEP = 6; /// -int const MATH_BORDER = 2; +int const HLINESEP = 3; +/// +int const VLINESEP = 3; +/// +int const BORDER = 2; + + +string verboseHLine(int n) +{ + string res; + for (int i = 0; i < n; ++i) + res += "\\hline"; + return res + ' '; +} } @@ -24,7 +38,7 @@ int const MATH_BORDER = 2; MathGridInset::RowInfo::RowInfo() - : upperline_(false), lowerline_(false) + : skip_(0), lines_(0) {} @@ -34,7 +48,7 @@ int MathGridInset::RowInfo::skipPixels() const #ifdef WITH_WARNINGS #warning fix this once the interface to LyXLength has improved #endif - return int(skip_.value()); + return int(crskip_.value()); } @@ -43,22 +57,31 @@ int MathGridInset::RowInfo::skipPixels() const MathGridInset::ColInfo::ColInfo() - : align_('c'), leftline_(false), rightline_(false), skip_(MATH_COLSEP) + : align_('c'), leftline_(false), rightline_(false), lines_(0) {} ////////////////////////////////////////////////////////////// +MathGridInset::MathGridInset(char v, string const & h) + : MathNestInset(guessColumns(h)), rowinfo_(2), colinfo_(guessColumns(h) + 1) +{ + setDefaults(); + valign(v); + halign(h); +} + + MathGridInset::MathGridInset(col_type m, row_type n) - : MathNestInset(m * n), rowinfo_(n), colinfo_(m), v_align_('c') + : MathNestInset(m * n), rowinfo_(n + 1), colinfo_(m + 1), v_align_('c') { setDefaults(); } MathGridInset::MathGridInset(col_type m, row_type n, char v, string const & h) - : MathNestInset(m * n), rowinfo_(n), colinfo_(m), v_align_(v) + : MathNestInset(m * n), rowinfo_(n + 1), colinfo_(m + 1), v_align_(v) { setDefaults(); valign(v); @@ -75,9 +98,9 @@ MathInset::idx_type MathGridInset::index(row_type row, col_type col) const void MathGridInset::setDefaults() { if (ncols() <= 0) - lyxerr << "positve number of columns expected\n"; + lyxerr << "positive number of columns expected\n"; if (nrows() <= 0) - lyxerr << "positve number of rows expected\n"; + lyxerr << "positive number of rows expected\n"; for (col_type col = 0; col < ncols(); ++col) { colinfo_[col].align_ = defaultColAlign(col); colinfo_[col].skip_ = defaultColSpace(col); @@ -87,11 +110,37 @@ void MathGridInset::setDefaults() void MathGridInset::halign(string const & hh) { + col_type col = 0; + for (string::const_iterator it = hh.begin(); it != hh.end(); ++it) { + char c = *it; + if (c == '|') { + colinfo_[col].lines_++; + } else if (c == 'c' || c == 'l' || c == 'r') { + colinfo_[col].align_ = c; + ++col; + colinfo_[col].lines_ = 0; + } else { + lyxerr << "unkown column separator: '" << c << "'\n"; + } + } + +/* col_type n = hh.size(); if (n > ncols()) n = ncols(); for (col_type col = 0; col < n; ++col) colinfo_[col].align_ = hh[col]; +*/ +} + + +MathGridInset::col_type MathGridInset::guessColumns(string const & hh) const +{ + col_type col = 0; + for (string::const_iterator it = hh.begin(); it != hh.end(); ++it) + if (*it == 'c' || *it == 'l' || *it == 'r') + ++col; + return col; } @@ -107,6 +156,16 @@ char MathGridInset::halign(col_type col) const } +string MathGridInset::halign() const +{ + string res; + for (col_type col = 0; col < ncols(); ++col) { + res += string(colinfo_[col].lines_, '|'); + res += colinfo_[col].align_; + } + return res + string(colinfo_[ncols()].lines_, '|'); +} + void MathGridInset::valign(char c) { @@ -120,16 +179,39 @@ char MathGridInset::valign() const } - -void MathGridInset::vskip(LyXLength const & skip, row_type row) +MathGridInset::col_type MathGridInset::ncols() const { - rowinfo_[row].skip_ = skip; + return colinfo_.size() - 1; } -LyXLength MathGridInset::vskip(row_type row) const +MathGridInset::row_type MathGridInset::nrows() const { - return rowinfo_[row].skip_; + return rowinfo_.size() - 1; +} + + +MathGridInset::col_type MathGridInset::col(idx_type idx) const +{ + return idx % ncols(); +} + + +MathGridInset::row_type MathGridInset::row(idx_type idx) const +{ + return idx / ncols(); +} + + +void MathGridInset::vcrskip(LyXLength const & crskip, row_type row) +{ + rowinfo_[row].crskip_ = crskip; +} + + +LyXLength MathGridInset::vcrskip(row_type row) const +{ + return rowinfo_[row].crskip_; } @@ -139,6 +221,7 @@ void MathGridInset::metrics(MathMetricsInfo const & mi) const MathNestInset::metrics(mi); // adjust vertical structure + rowinfo_[0].offset_ = 0; for (row_type row = 0; row < nrows(); ++row) { int asc = 0; int desc = 0; @@ -149,59 +232,70 @@ void MathGridInset::metrics(MathMetricsInfo const & mi) const } rowinfo_[row].ascent_ = asc; rowinfo_[row].descent_ = desc; + rowinfo_[row].offset_ += asc + HLINESEP * rowinfo_[row].lines_; - if (row) - rowinfo_[row].offset_ = - rowinfo_[row - 1].offset_ + - rowinfo_[row - 1].descent_ + - rowinfo_[row - 1].skipPixels() + - MATH_ROWSEP + - rowinfo_[row].ascent_; - else - rowinfo_[row].offset_ = 0; + rowinfo_[row + 1].offset_ = + rowinfo_[row].offset_ + + rowinfo_[row].descent_ + + rowinfo_[row].skipPixels() + + ROWSEP; } + rowinfo_[nrows()].ascent_ = 0; + rowinfo_[nrows()].descent_ = 0; + rowinfo_[nrows()].offset_ += HLINESEP * rowinfo_[nrows()].lines_; // adjust vertical offset int h = 0; switch (v_align_) { - case 't': - h = 0; - break; - case 'b': - h = rowinfo_.back().offset_; - break; - default: - h = rowinfo_.back().offset_ / 2; + case 't': + h = 0; + break; + case 'b': + h = rowinfo_[nrows()].offset_; + break; + default: + h = rowinfo_[nrows()].offset_ / 2; + //lyxerr << "\nnrows: " << nrows() << ' ' << ncols() << '\n'; } - - for (row_type row = 0; row < nrows(); ++row) { + for (row_type row = 0; row <= nrows(); ++row) rowinfo_[row].offset_ -= h; - rowinfo_[row].offset_ += MATH_BORDER; - } + // adjust horizontal structure + colinfo_[0].offset_ = BORDER; for (col_type col = 0; col < ncols(); ++col) { - int wid = 0; + int wid = 0; for (row_type row = 0; row < nrows(); ++row) wid = std::max(wid, xcell(index(row, col)).width()); colinfo_[col].width_ = wid; - colinfo_[col].offset_ = colinfo_[col].width_; + colinfo_[col].offset_ += VLINESEP * colinfo_[col].lines_; - if (col) - colinfo_[col].offset_ = - colinfo_[col - 1].offset_ + - colinfo_[col - 1].width_ + - colinfo_[col - 1].skip_; - else - colinfo_[col].offset_ = 0; - - colinfo_[col].offset_ += MATH_BORDER; + colinfo_[col + 1].offset_ = + colinfo_[col].offset_ + + colinfo_[col].width_ + + colinfo_[col].skip_ + + COLSEP; } + colinfo_[ncols()].width_ = 0; + colinfo_[ncols()].offset_ += VLINESEP * colinfo_[ncols()].lines_; + + + width_ = colinfo_[ncols() - 1].offset_ + + colinfo_[ncols() - 1].width_ + + VLINESEP * colinfo_[ncols()].lines_ + + BORDER; + + ascent_ = - rowinfo_[0].offset_ + + rowinfo_[0].ascent_ + + HLINESEP * rowinfo_[0].lines_ + + BORDER; + + descent_ = rowinfo_[nrows() - 1].offset_ + + rowinfo_[nrows() - 1].descent_ + + HLINESEP * rowinfo_[nrows()].lines_ + + BORDER; + - width_ = colinfo_.back().offset_ + colinfo_.back().width_; - ascent_ = - rowinfo_.front().offset_ + rowinfo_.front().ascent_; - descent_ = rowinfo_.back().offset_ + rowinfo_.back().descent_; - /* // Increase ws_[i] for 'R' columns (except the first one) for (int i = 1; i < nc_; ++i) @@ -213,9 +307,9 @@ void MathGridInset::metrics(MathMetricsInfo const & mi) const ws_[0] = 7 * workwidth / 8; // Adjust local tabs - width = MATH_COLSEP; + width = COLSEP; for (cxrow = row_.begin(); cxrow; ++cxrow) { - int rg = MATH_COLSEP; + int rg = COLSEP; int lf = 0; for (int i = 0; i < nc_; ++i) { bool isvoid = false; @@ -245,9 +339,9 @@ void MathGridInset::metrics(MathMetricsInfo const & mi) const } int const ww = (isvoid) ? lf : lf + cxrow->getTab(i); cxrow->setTab(i, lf + rg); - rg = ws_[i] - ww + MATH_COLSEP; + rg = ws_[i] - ww + COLSEP; if (cxrow == row_.begin()) - width += ws_[i] + MATH_COLSEP; + width += ws_[i] + COLSEP; } cxrow->setBaseline(cxrow->getBaseline() - ascent); } @@ -259,30 +353,51 @@ void MathGridInset::draw(Painter & pain, int x, int y) const { for (idx_type idx = 0; idx < nargs(); ++idx) xcell(idx).draw(pain, x + cellXOffset(idx), y + cellYOffset(idx)); + + for (row_type row = 0; row <= nrows(); ++row) + for (int i = 0; i < rowinfo_[row].lines_; ++i) { + int yy = y + rowinfo_[row].offset_ - rowinfo_[row].ascent_ + - i * HLINESEP - HLINESEP/2 - ROWSEP/2; + //lyxerr << "i: " << i << " yy: " << yy << '\n'; + pain.line(x + 1, yy, x + width_ - 1, yy); + } + + for (col_type col = 0; col <= ncols(); ++col) + for (int i = 0; i < colinfo_[col].lines_; ++i) { + int xx = x + colinfo_[col].offset_ + - i * VLINESEP - VLINESEP/2 - COLSEP/2; + //lyxerr << "i: " << i << " xx: " << xx << '\n'; + pain.line(xx, y - ascent_ + 1, xx, y + descent_ - 1); + } } string MathGridInset::eolString(row_type row) const { - if (row + 1 == nrows()) - return ""; + string eol; - if (rowinfo_[row].skip_.value() != 0) - return "\\\\[" + rowinfo_[row].skip_.asLatexString() + "]\n"; + if (rowinfo_[row].crskip_.value() != 0) + eol += "[" + rowinfo_[row].crskip_.asLatexString() + "]"; // make sure an upcoming '[' does not break anything - MathArray const & c = cell(index(row + 1, 0)); - if (c.size() && (*c.begin())->getChar() == '[') - return "\\\\[0pt]\n"; + if (row + 1 < nrows()) { + MathArray const & c = cell(index(row + 1, 0)); + if (c.size() && c.front()->getChar() == '[') + eol += "[0pt]"; + } - return "\\\\\n"; + // only add \\ if necessary + if (eol.empty() && row + 1 == nrows()) + return string(); + + return "\\\\" + eol + '\n'; } string MathGridInset::eocString(col_type col) const { if (col + 1 == ncols()) - return ""; + return string(); return " & "; } @@ -297,6 +412,7 @@ void MathGridInset::addRow(row_type row) void MathGridInset::appendRow() { rowinfo_.push_back(RowInfo()); + //cells_.insert(cells_.end(), ncols(), MathXArray()); for (col_type col = 0; col < ncols(); ++col) cells_.push_back(cells_type::value_type()); } @@ -587,10 +703,14 @@ void MathGridInset::mathmlize(MathMLStream & os) const void MathGridInset::write(WriteStream & os) const { for (row_type row = 0; row < nrows(); ++row) { + os << verboseHLine(rowinfo_[row].lines_).c_str(); for (col_type col = 0; col < ncols(); ++col) os << cell(index(row, col)) << eocString(col).c_str(); os << eolString(row).c_str(); } + string s = verboseHLine(rowinfo_[nrows()].lines_); + if (s.size()) + os << "\\\\" << s.c_str(); } diff --git a/src/mathed/math_gridinset.h b/src/mathed/math_gridinset.h index 968ed13254..8a6e8a14a8 100644 --- a/src/mathed/math_gridinset.h +++ b/src/mathed/math_gridinset.h @@ -30,12 +30,12 @@ class MathGridInset : public MathNestInset { mutable int ascent_; /// cached offset mutable int offset_; - /// hline abow this row? - bool upperline_; - /// hline below this row? - bool lowerline_; - /// distance - LyXLength skip_; + /// how many hlines above this row? + int lines_; + /// parameter to the line break + LyXLength crskip_; + /// extra distance between lines + int skip_; }; // additional per-row information @@ -54,11 +54,15 @@ class MathGridInset : public MathNestInset { bool leftline_; /// do we need a line to the right? bool rightline_; + /// how many lines to the left of this column? + int lines_; /// additional amount to be skipped when drawing int skip_; }; public: + /// constructor from columns description, creates one row + MathGridInset(char valign, string const & halign); /// Note: columns first! MathGridInset(col_type m, row_type n); /// @@ -74,30 +78,32 @@ public: /// char halign(col_type col) const; /// + string halign() const; + /// void valign(char c); /// char valign() const; /// - void vskip(LyXLength const &, row_type row); + void vcrskip(LyXLength const &, row_type row); /// - LyXLength vskip(row_type row) const; + LyXLength vcrskip(row_type row) const; /// void resize(short int type, col_type cols); /// const RowInfo & rowinfo(row_type row) const; - /// + /// returns topmost row if passed (-1) RowInfo & rowinfo(row_type row); /// identifies GridInset virtual MathGridInset * asGridInset() { return this; } /// - col_type ncols() const { return colinfo_.size(); } + col_type ncols() const; /// - row_type nrows() const { return rowinfo_.size(); } + row_type nrows() const; /// - col_type col(idx_type idx) const { return idx % ncols(); } + col_type col(idx_type idx) const; /// - row_type row(idx_type idx) const { return idx / ncols(); } + row_type row(idx_type idx) const; /// int cellXOffset(idx_type idx) const; /// @@ -139,7 +145,7 @@ public: /// std::vector idxBetween(idx_type from, idx_type to) const; /// - virtual int defaultColSpace(col_type) { return 10; } + virtual int defaultColSpace(col_type) { return 0; } /// virtual char defaultColAlign(col_type) { return 'c'; } /// @@ -161,6 +167,8 @@ protected: string eolString(row_type row) const; /// returns proper 'end of column' code for LaTeX string eocString(col_type col) const; + /// extract number of columns from alignment string + col_type guessColumns(string const & halign) const; /// row info std::vector rowinfo_; diff --git a/src/mathed/math_hullinset.C b/src/mathed/math_hullinset.C index c84ad3f83d..535a7c44c3 100644 --- a/src/mathed/math_hullinset.C +++ b/src/mathed/math_hullinset.C @@ -136,7 +136,7 @@ int MathHullInset::defaultColSpace(col_type col) return (col & 1) ? 40 : 0; default:; } - return 10; + return 0; } diff --git a/src/mathed/math_parser.C b/src/mathed/math_parser.C index 55bda8fe2b..f0b6e4fa99 100644 --- a/src/mathed/math_parser.C +++ b/src/mathed/math_parser.C @@ -275,6 +275,10 @@ private: Token const & nextToken() const; /// Token const & getToken(); + /// skips spaces if any + void skipSpaces(); + /// counts a sequence of hlines + int readHLines(); /// void lex(string const & s); /// @@ -339,10 +343,31 @@ Token const & Parser::nextToken() const Token const & Parser::getToken() { static const Token dummy; + //lyxerr << "looking at token " << tokens_[pos_] << '\n'; return good() ? tokens_[pos_++] : dummy; } +void Parser::skipSpaces() +{ + while (nextToken().cat() == catSpace) + getToken(); +} + + +int Parser::readHLines() +{ + int num = 0; + skipSpaces(); + while (nextToken().cs() == "hline") { + getToken(); + ++num; + skipSpaces(); + } + return num; +} + + void Parser::putback() { --pos_; @@ -481,6 +506,9 @@ bool Parser::parse_lines(MathAtom & t, bool numbered, bool outmost) bool const saved_num = curr_num_; string const saved_label = curr_label_; + // read initial hlines + p->rowinfo(0).lines_ = readHLines(); + for (int row = 0; true; ++row) { // reset global variables curr_num_ = numbered; @@ -491,12 +519,15 @@ bool Parser::parse_lines(MathAtom & t, bool numbered, bool outmost) //lyxerr << "reading cell " << row << " " << col << "\n"; parse_into(p->cell(col + row * cols), FLAG_BLOCK); - // no ampersand - if (prevToken().cat() != catAlign) { + // break if cell is not followed by an ampersand + if (nextToken().cat() != catAlign) { //lyxerr << "less cells read than normal in row/col: " // << row << " " << col << "\n"; break; } + + // skip the ampersand + getToken(); } if (outmost) { @@ -508,17 +539,34 @@ bool Parser::parse_lines(MathAtom & t, bool numbered, bool outmost) m->numbered(row, curr_num_); m->label(row, curr_label_); if (curr_skip_.size()) { - m->vskip(LyXLength(curr_skip_), row); + m->vcrskip(LyXLength(curr_skip_), row); curr_skip_.erase(); } } - // no newline? - if (!prevToken().isCR()) { - //lyxerr << "no newline here\n"; + // is a \\ coming? + if (nextToken().isCR()) { + // skip the cr-token + getToken(); + + // try to read a length + //get + + // read hlines for next row + p->rowinfo(row + 1).lines_ = readHLines(); + } + + // we are finished if the next token is an 'end' + if (nextToken().cs() == "end") { + // skip the end-token + getToken(); + getArg('{','}'); + + // leave the 'read a line'-loop break; } + // otherwise, we have to start a new row p->appendRow(); } @@ -533,9 +581,7 @@ bool Parser::parse_lines(MathAtom & t, bool numbered, bool outmost) string Parser::parse_macro() { string name = "{error}"; - - while (nextToken().cat() == catSpace) - getToken(); + skipSpaces(); if (getToken().cs() != "newcommand") { lyxerr << "\\newcommand expected\n"; @@ -571,9 +617,7 @@ string Parser::parse_macro() bool Parser::parse_normal(MathAtom & matrix) { - while (nextToken().cat() == catSpace) - getToken(); - + skipSpaces(); Token const & t = getToken(); if (t.cs() == "(") { @@ -706,10 +750,8 @@ void Parser::parse_into(MathArray & array, unsigned flags, MathTextCodes code) } if (flags & FLAG_BLOCK) { - if (t.cat() == catAlign || t.isCR()) - return; - if (t.cs() == "end") { - getArg('{', '}'); + if (t.cat() == catAlign || t.isCR() || t.cs() == "end") { + putback(); return; } } @@ -865,8 +907,7 @@ void Parser::parse_into(MathArray & array, unsigned flags, MathTextCodes code) if (name == "array") { string const valign = getArg('[', ']') + 'c'; string const halign = getArg('{', '}'); - array.push_back( - MathAtom(new MathArrayInset(halign.size(), 1, valign[0], halign))); + array.push_back(MathAtom(new MathArrayInset(valign[0], halign))); parse_lines(array.back(), false, false); } else if (name == "split") { array.push_back(MathAtom(new MathSplitInset(1)));