/** * \file math_hullinset.C * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author André Pönitz * * Full author contact details are available in file CREDITS. */ #include #include "math_charinset.h" #include "math_data.h" #include "math_extern.h" #include "math_hullinset.h" #include "math_mathmlstream.h" #include "math_streamstr.h" #include "math_support.h" #include "BufferView.h" #include "CutAndPaste.h" #include "FuncStatus.h" #include "LColor.h" #include "LaTeXFeatures.h" #include "cursor.h" #include "debug.h" #include "dispatchresult.h" #include "funcrequest.h" #include "gettext.h" #include "lyx_main.h" #include "lyxrc.h" #include "outputparams.h" #include "sgml.h" #include "textpainter.h" #include "undo.h" #include "insets/render_preview.h" #include "frontends/Alert.h" #include "graphics/PreviewImage.h" #include "graphics/PreviewLoader.h" #include "support/lstrings.h" #include #include using lyx::cap::grabAndEraseSelection; using lyx::support::bformat; using lyx::support::subst; using std::endl; using std::max; using std::string; using std::ostream; using std::auto_ptr; using std::istringstream; using std::ostream; using std::ostringstream; using std::pair; using std::swap; using std::vector; namespace { int getCols(string const & type) { if (type == "eqnarray") return 3; if (type == "align") return 2; if (type == "flalign") return 2; if (type == "alignat") return 2; if (type == "xalignat") return 2; if (type == "xxalignat") return 2; return 1; } // returns position of first relation operator in the array // used for "intelligent splitting" size_t firstRelOp(MathArray const & ar) { for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) if ((*it)->isRelOp()) return it - ar.begin(); return ar.size(); } char const * star(bool numbered) { return numbered ? "" : "*"; } int typecode(string const & s) { if (s == "none") return 0; if (s == "simple") return 1; if (s == "equation") return 2; if (s == "eqnarray") return 3; if (s == "align") return 4; if (s == "alignat") return 5; if (s == "xalignat") return 6; if (s == "xxalignat") return 7; if (s == "multline") return 8; if (s == "gather") return 9; if (s == "flalign") return 10; lyxerr << "unknown hull type '" << s << "'" << endl; return -1; } bool smaller(string const & s, string const & t) { return typecode(s) < typecode(t); } } // end anon namespace MathHullInset::MathHullInset() : MathGridInset(1, 1), type_("none"), nonum_(1), label_(1), preview_(new RenderPreview(this)) { //lyxerr << "sizeof MathInset: " << sizeof(MathInset) << endl; //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl; //lyxerr << "sizeof MathCharInset: " << sizeof(MathCharInset) << endl; //lyxerr << "sizeof LyXFont: " << sizeof(LyXFont) << endl; setDefaults(); } MathHullInset::MathHullInset(string const & type) : MathGridInset(getCols(type), 1), type_(type), nonum_(1), label_(1), preview_(new RenderPreview(this)) { setDefaults(); } MathHullInset::MathHullInset(MathHullInset const & other) : MathGridInset(other), type_(other.type_), nonum_(other.nonum_), label_(other.label_), preview_(new RenderPreview(this)) {} MathHullInset::~MathHullInset() {} auto_ptr MathHullInset::doClone() const { return auto_ptr(new MathHullInset(*this)); } MathHullInset & MathHullInset::operator=(MathHullInset const & other) { if (this == &other) return *this; *static_cast(this) = MathGridInset(other); type_ = other.type_; nonum_ = other.nonum_; label_ = other.label_; preview_.reset(new RenderPreview(*other.preview_, this)); return *this; } MathInset::mode_type MathHullInset::currentMode() const { if (type_ == "none") return UNDECIDED_MODE; // definitely math mode ... return MATH_MODE; } bool MathHullInset::idxFirst(LCursor & cur) const { cur.idx() = 0; cur.pos() = 0; return true; } bool MathHullInset::idxLast(LCursor & cur) const { cur.idx() = nargs() - 1; cur.pos() = cur.lastpos(); return true; } char MathHullInset::defaultColAlign(col_type col) { if (type_ == "eqnarray") return "rcl"[col]; if (typecode(type_) >= typecode("align")) return "rl"[col & 1]; return 'c'; } int MathHullInset::defaultColSpace(col_type col) { if (type_ == "align" || type_ == "alignat") return 0; if (type_ == "xalignat") return (col & 1) ? 20 : 0; if (type_ == "xxalignat" || type_ == "flalign") return (col & 1) ? 40 : 0; return 0; } char const * MathHullInset::standardFont() const { if (type_ == "none") return "lyxnochange"; return "mathnormal"; } void MathHullInset::metrics(MetricsInfo & mi, Dimension & dim) const { BOOST_ASSERT(mi.base.bv && mi.base.bv->buffer()); bool use_preview = false; if (!editing(mi.base.bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) { lyx::graphics::PreviewImage const * pimage = preview_->getPreviewImage(*mi.base.bv->buffer()); use_preview = pimage && pimage->image(); } if (use_preview) { preview_->metrics(mi, dim); // insert a one pixel gap in front of the formula dim.wid += 1; if (display()) dim.des += 12; dim_ = dim; return; } FontSetChanger dummy1(mi.base, standardFont()); StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); // let the cells adjust themselves MathGridInset::metrics(mi, dim); if (display()) { dim.asc += 12; dim.des += 12; } if (numberedType()) { FontSetChanger dummy(mi.base, "mathbf"); int l = 0; for (row_type row = 0; row < nrows(); ++row) l = max(l, mathed_string_width(mi.base.font, nicelabel(row))); if (l) dim.wid += 30 + l; } // make it at least as high as the current font int asc = 0; int des = 0; math_font_max_dim(mi.base.font, asc, des); dim.asc = max(dim.asc, asc); dim.des = max(dim.des, des); dim_ = dim; } void MathHullInset::draw(PainterInfo & pi, int x, int y) const { BOOST_ASSERT(pi.base.bv && pi.base.bv->buffer()); bool use_preview = false; if (!editing(pi.base.bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) { lyx::graphics::PreviewImage const * pimage = preview_->getPreviewImage(*pi.base.bv->buffer()); use_preview = pimage && pimage->image(); } if (use_preview) { // one pixel gap in front preview_->draw(pi, x + 1, y); setPosCache(pi, x, y); return; } FontSetChanger dummy1(pi.base, standardFont()); StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT); MathGridInset::draw(pi, x + 1, y); if (numberedType()) { int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20; for (row_type row = 0; row < nrows(); ++row) { int const yy = y + rowinfo_[row].offset_; FontSetChanger dummy(pi.base, "mathrm"); drawStr(pi, pi.base.font, xx, yy, nicelabel(row)); } } setPosCache(pi, x, y); } void MathHullInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const { if (display()) { MathGridInset::metricsT(mi, dim); } else { ostringstream os; WriteStream wi(os, false, true); write(wi); dim.wid = os.str().size(); dim.asc = 1; dim.des = 0; } } void MathHullInset::drawT(TextPainter & pain, int x, int y) const { if (display()) { MathGridInset::drawT(pain, x, y); } else { ostringstream os; WriteStream wi(os, false, true); write(wi); pain.draw(x, y, os.str().c_str()); } } namespace { string const latex_string(MathHullInset const & inset) { ostringstream ls; WriteStream wi(ls, false, false); inset.write(wi); return ls.str(); } } // namespace anon void MathHullInset::addPreview(lyx::graphics::PreviewLoader & ploader) const { if (RenderPreview::status() == LyXRC::PREVIEW_ON) { string const snippet = latex_string(*this); preview_->addPreview(snippet, ploader); } } void MathHullInset::notifyCursorLeaves(LCursor & cur) { if (RenderPreview::status() == LyXRC::PREVIEW_ON) { Buffer const & buffer = cur.buffer(); string const snippet = latex_string(*this); preview_->addPreview(snippet, buffer); preview_->startLoading(buffer); } } string MathHullInset::label(row_type row) const { row_type n = nrows(); BOOST_ASSERT(row < n); return label_[row]; } void MathHullInset::label(row_type row, string const & label) { //lyxerr << "setting label '" << label << "' for row " << row << endl; label_[row] = label; } void MathHullInset::numbered(row_type row, bool num) { nonum_[row] = !num; } bool MathHullInset::numbered(row_type row) const { return !nonum_[row]; } bool MathHullInset::ams() const { return type_ == "align" || type_ == "flalign" || type_ == "multline" || type_ == "gather" || type_ == "alignat" || type_ == "xalignat" || type_ == "xxalignat"; } bool MathHullInset::display() const { return type_ != "simple" && type_ != "none"; } void MathHullInset::getLabelList(Buffer const &, vector & labels) const { for (row_type row = 0; row < nrows(); ++row) if (!label_[row].empty() && nonum_[row] != 1) labels.push_back(label_[row]); } bool MathHullInset::numberedType() const { if (type_ == "none") return false; if (type_ == "simple") return false; if (type_ == "xxalignat") return false; for (row_type row = 0; row < nrows(); ++row) if (!nonum_[row]) return true; return false; } void MathHullInset::validate(LaTeXFeatures & features) const { if (ams()) features.require("amsmath"); // Validation is necessary only if not using AMS math. // To be safe, we will always run mathedvalidate. //if (features.amsstyle) // return; features.require("boldsymbol"); //features.binom = true; MathGridInset::validate(features); } void MathHullInset::header_write(WriteStream & os) const { bool n = numberedType(); if (type_ == "none") ; else if (type_ == "simple") { os << '$'; if (cell(0).empty()) os << ' '; } else if (type_ == "equation") { if (n) os << "\\begin{equation" << star(n) << "}\n"; else os << "\\[\n"; } else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign" || type_ == "gather" || type_ == "multline") os << "\\begin{" << type_ << star(n) << "}\n"; else if (type_ == "alignat" || type_ == "xalignat") os << "\\begin{" << type_ << star(n) << '}' << '{' << static_cast((ncols() + 1)/2) << "}\n"; else if (type_ == "xxalignat") os << "\\begin{" << type_ << '}' << '{' << static_cast((ncols() + 1)/2) << "}\n"; else os << "\\begin{unknown" << star(n) << '}'; } void MathHullInset::footer_write(WriteStream & os) const { bool n = numberedType(); if (type_ == "none") os << "\n"; else if (type_ == "simple") os << '$'; else if (type_ == "equation") if (n) os << "\\end{equation" << star(n) << "}\n"; else os << "\\]\n"; else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign" || type_ == "alignat" || type_ == "xalignat" || type_ == "gather" || type_ == "multline") os << "\\end{" << type_ << star(n) << "}\n"; else if (type_ == "xxalignat") os << "\\end{" << type_ << "}\n"; else os << "\\end{unknown" << star(n) << '}'; } bool MathHullInset::rowChangeOK() const { return type_ == "eqnarray" || type_ == "align" || type_ == "flalign" || type_ == "alignat" || type_ == "xalignat" || type_ == "xxalignat" || type_ == "gather" || type_ == "multline"; } bool MathHullInset::colChangeOK() const { return type_ == "align" || type_ == "flalign" ||type_ == "alignat" || type_ == "xalignat" || type_ == "xxalignat"; } void MathHullInset::addRow(row_type row) { if (!rowChangeOK()) return; nonum_.insert(nonum_.begin() + row + 1, !numberedType()); label_.insert(label_.begin() + row + 1, string()); MathGridInset::addRow(row); } void MathHullInset::swapRow(row_type row) { if (nrows() <= 1) return; if (row + 1 == nrows()) --row; swap(nonum_[row], nonum_[row + 1]); swap(label_[row], label_[row + 1]); MathGridInset::swapRow(row); } void MathHullInset::delRow(row_type row) { if (nrows() <= 1 || !rowChangeOK()) return; MathGridInset::delRow(row); nonum_.erase(nonum_.begin() + row); label_.erase(label_.begin() + row); } void MathHullInset::addCol(col_type col) { if (!colChangeOK()) return; MathGridInset::addCol(col); } void MathHullInset::delCol(col_type col) { if (ncols() <= 1 || !colChangeOK()) return; MathGridInset::delCol(col); } string MathHullInset::nicelabel(row_type row) const { if (nonum_[row]) return string(); if (label_[row].empty()) return string("(#)"); return '(' + label_[row] + ')'; } void MathHullInset::glueall() { MathArray ar; for (idx_type i = 0; i < nargs(); ++i) ar.append(cell(i)); *this = MathHullInset("simple"); cell(0) = ar; setDefaults(); } void MathHullInset::splitTo2Cols() { BOOST_ASSERT(ncols() == 1); MathGridInset::addCol(1); for (row_type row = 0; row < nrows(); ++row) { idx_type const i = 2 * row; pos_type pos = firstRelOp(cell(i)); cell(i + 1) = MathArray(cell(i).begin() + pos, cell(i).end()); cell(i).erase(pos, cell(i).size()); } } void MathHullInset::splitTo3Cols() { BOOST_ASSERT(ncols() < 3); if (ncols() < 2) splitTo2Cols(); MathGridInset::addCol(1); for (row_type row = 0; row < nrows(); ++row) { idx_type const i = 3 * row + 1; if (cell(i).size()) { cell(i + 1) = MathArray(cell(i).begin() + 1, cell(i).end()); cell(i).erase(1, cell(i).size()); } } } void MathHullInset::changeCols(col_type cols) { if (ncols() == cols) return; else if (ncols() < cols) { // split columns if (cols < 3) splitTo2Cols(); else { splitTo3Cols(); while (ncols() < cols) MathGridInset::addCol(ncols() - 1); } return; } // combine columns for (row_type row = 0; row < nrows(); ++row) { idx_type const i = row * ncols(); for (col_type col = cols; col < ncols(); ++col) { cell(i + cols - 1).append(cell(i + col)); } } // delete columns while (ncols() > cols) { MathGridInset::delCol(ncols() - 1); } } string const & MathHullInset::getType() const { return type_; } void MathHullInset::setType(string const & type) { type_ = type; setDefaults(); } void MathHullInset::mutate(string const & newtype) { lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl; // we try to move along the chain // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+ // ^ | // +-------------------------------------+ // we use eqnarray as intermediate type for mutations that are not // directly supported because it handles labels and numbering for // "down mutation". if (newtype == "dump") { dump(); } else if (newtype == type_) { // done } else if (typecode(newtype) < 0) { // unknown type } else if (type_ == "none") { setType("simple"); numbered(0, false); mutate(newtype); } else if (type_ == "simple") { if (newtype == "none") { setType("none"); numbered(0, false); } else { setType("equation"); numbered(0, false); mutate(newtype); } } else if (type_ == "equation") { if (smaller(newtype, type_)) { setType("simple"); numbered(0, false); mutate(newtype); } else if (newtype == "eqnarray") { // split it "nicely" on the first relop splitTo3Cols(); setType("eqnarray"); } else if (newtype == "multline" || newtype == "gather") { setType(newtype); } else { // split it "nicely" splitTo2Cols(); setType("align"); mutate(newtype); } } else if (type_ == "eqnarray") { if (smaller(newtype, type_)) { // set correct (no)numbering bool allnonum = true; for (row_type row = 0; row < nrows(); ++row) if (!nonum_[row]) allnonum = false; // set first non-empty label string label; for (row_type row = 0; row < nrows(); ++row) { if (!label_[row].empty()) { label = label_[row]; break; } } glueall(); nonum_[0] = allnonum; label_[0] = label; mutate(newtype); } else { // align & Co. changeCols(2); setType("align"); mutate(newtype); } } else if (type_ == "align" || type_ == "alignat" || type_ == "xalignat" || type_ == "flalign") { if (smaller(newtype, "align")) { changeCols(3); setType("eqnarray"); mutate(newtype); } else if (newtype == "gather" || newtype == "multline") { changeCols(1); setType(newtype); } else if (newtype == "xxalignat") { for (row_type row = 0; row < nrows(); ++row) numbered(row, false); setType(newtype); } else { setType(newtype); } } else if (type_ == "xxalignat") { for (row_type row = 0; row < nrows(); ++row) numbered(row, false); if (smaller(newtype, "align")) { changeCols(3); setType("eqnarray"); mutate(newtype); } else if (newtype == "gather" || newtype == "multline") { changeCols(1); setType(newtype); } else { setType(newtype); } } else if (type_ == "multline" || type_ == "gather") { if (newtype == "gather" || newtype == "multline") setType(newtype); else if (newtype == "align" || newtype == "flalign" || newtype == "alignat" || newtype == "xalignat") { splitTo2Cols(); setType(newtype); } else if (newtype == "xxalignat") { splitTo2Cols(); for (row_type row = 0; row < nrows(); ++row) numbered(row, false); setType(newtype); } else { splitTo3Cols(); setType("eqnarray"); mutate(newtype); } } else { lyxerr << "mutation from '" << type_ << "' to '" << newtype << "' not implemented" << endl; } } string MathHullInset::eolString(row_type row, bool fragile) const { string res; if (numberedType()) { if (!label_[row].empty() && !nonum_[row]) res += "\\label{" + label_[row] + '}'; if (nonum_[row] && (type_ != "multline")) res += "\\nonumber "; } return res + MathGridInset::eolString(row, fragile); } void MathHullInset::write(WriteStream & os) const { header_write(os); MathGridInset::write(os); footer_write(os); } void MathHullInset::normalize(NormalStream & os) const { os << "[formula " << type_ << ' '; MathGridInset::normalize(os); os << "] "; } void MathHullInset::mathmlize(MathMLStream & os) const { MathGridInset::mathmlize(os); } void MathHullInset::infoize(ostream & os) const { os << "Type: " << type_; } void MathHullInset::check() const { BOOST_ASSERT(nonum_.size() == nrows()); BOOST_ASSERT(label_.size() == nrows()); } void MathHullInset::doExtern(LCursor & cur, FuncRequest & func) { string lang; string extra; istringstream iss(func.argument); iss >> lang >> extra; if (extra.empty()) extra = "noextra"; #ifdef WITH_WARNINGS #warning temporarily disabled //if (cur.selection()) { // MathArray ar; // selGet(cur.ar); // lyxerr << "use selection: " << ar << endl; // insert(pipeThroughExtern(lang, extra, ar)); // return; //} #endif MathArray eq; eq.push_back(MathAtom(new MathCharInset('='))); // go to first item in line cur.idx() -= cur.idx() % ncols(); cur.pos() = 0; if (getType() == "simple") { size_type pos = cur.cell().find_last(eq); MathArray ar; if (cur.inMathed() && cur.selection()) { asArray(grabAndEraseSelection(cur), ar); } else if (pos == cur.cell().size()) { ar = cur.cell(); lyxerr << "use whole cell: " << ar << endl; } else { ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end()); lyxerr << "use partial cell form pos: " << pos << endl; } cur.cell().append(eq); cur.cell().append(pipeThroughExtern(lang, extra, ar)); cur.pos() = cur.lastpos(); return; } if (getType() == "equation") { lyxerr << "use equation inset" << endl; mutate("eqnarray"); MathArray & ar = cur.cell(); lyxerr << "use cell: " << ar << endl; ++cur.idx(); cur.cell() = eq; ++cur.idx(); cur.cell() = pipeThroughExtern(lang, extra, ar); // move to end of line cur.pos() = cur.lastpos(); return; } { lyxerr << "use eqnarray" << endl; cur.idx() += 2 - cur.idx() % ncols(); cur.pos() = 0; MathArray ar = cur.cell(); lyxerr << "use cell: " << ar << endl; #ifdef WITH_WARNINGS #warning temporarily disabled #endif addRow(cur.row()); ++cur.idx(); ++cur.idx(); cur.cell() = eq; ++cur.idx(); cur.cell() = pipeThroughExtern(lang, extra, ar); cur.pos() = cur.lastpos(); } } void MathHullInset::doDispatch(LCursor & cur, FuncRequest & cmd) { switch (cmd.action) { case LFUN_FINISHED_LEFT: case LFUN_FINISHED_RIGHT: case LFUN_FINISHED_UP: case LFUN_FINISHED_DOWN: MathGridInset::doDispatch(cur, cmd); notifyCursorLeaves(cur); break; case LFUN_BREAKPARAGRAPH: // just swallow this break; case LFUN_BREAKLINE: // some magic for the common case if (type_ == "simple" || type_ == "equation") { recordUndoInset(cur); mutate("eqnarray"); cur.idx() = 0; cur.pos() = cur.lastpos(); } MathGridInset::doDispatch(cur, cmd); break; case LFUN_MATH_NUMBER: //lyxerr << "toggling all numbers" << endl; if (display()) { recordUndoInset(cur); bool old = numberedType(); if (type_ == "multline") numbered(nrows() - 1, !old); else for (row_type row = 0; row < nrows(); ++row) numbered(row, !old); cur.message(old ? _("No number") : _("Number")); } break; case LFUN_MATH_NONUMBER: if (display()) { recordUndoInset(cur); row_type r = (type_ == "multline") ? nrows() - 1 : cur.row(); bool old = numbered(r); cur.message(old ? _("No number") : _("Number")); numbered(r, !old); } break; case LFUN_INSERT_LABEL: { recordUndoInset(cur); row_type r = (type_ == "multline") ? nrows() - 1 : cur.row(); string old_label = label(r); string new_label = cmd.argument; if (new_label.empty()) { string const default_label = (lyxrc.label_init_length >= 0) ? "eq:" : ""; pair const res = old_label.empty() ? Alert::askForText(_("Enter new label to insert:"), default_label) : Alert::askForText(_("Enter label:"), old_label); if (res.first) new_label = lyx::support::trim(res.second); else new_label = old_label; } if (!new_label.empty()) numbered(r, true); label(r, new_label); break; } case LFUN_MATH_EXTERN: recordUndoInset(cur); doExtern(cur, cmd); break; case LFUN_MATH_MUTATE: { recordUndoInset(cur); row_type row = cur.row(); col_type col = cur.col(); mutate(cmd.argument); cur.idx() = row * ncols() + col; if (cur.idx() > cur.lastidx()) { cur.idx() = cur.lastidx(); cur.pos() = cur.lastpos(); } if (cur.pos() > cur.lastpos()) cur.pos() = cur.lastpos(); //cur.dispatched(FINISHED); break; } case LFUN_MATH_DISPLAY: { recordUndoInset(cur); mutate(type_ == "simple" ? "equation" : "simple"); cur.idx() = 0; cur.pos() = cur.lastpos(); //cur.dispatched(FINISHED); break; } default: MathGridInset::doDispatch(cur, cmd); break; } } bool MathHullInset::getStatus(LCursor & cur, FuncRequest const & cmd, FuncStatus & flag) const { switch (cmd.action) { case LFUN_BREAKLINE: case LFUN_MATH_NUMBER: case LFUN_MATH_NONUMBER: case LFUN_INSERT_LABEL: case LFUN_MATH_EXTERN: case LFUN_MATH_MUTATE: case LFUN_MATH_DISPLAY: // we handle these flag.enabled(true); return true; case LFUN_TABULAR_FEATURE: { istringstream is(cmd.argument); string s; is >> s; if (!rowChangeOK() && (s == "append-row" || s == "delete-row" || s == "copy-row")) { flag.message(bformat( N_("Can't change number of rows in '%1$s'"), type_)); flag.enabled(false); return true; } if (!colChangeOK() && (s == "append-column" || s == "delete-column" || s == "copy-column")) { flag.message(bformat( N_("Can't change number of columns in '%1$s'"), type_)); flag.enabled(false); return true; } if ((type_ == "simple" || type_ == "equation" || type_ == "none") && (s == "add-hline-above" || s == "add-hline-below")) { flag.message(bformat( N_("Can't add horizontal grid lines in '%1$s'"), type_)); flag.enabled(false); return true; } if (s == "add-vline-left" || s == "add-vline-right") { flag.message(bformat( N_("Can't add vertical grid lines in '%1$s'"), type_)); flag.enabled(false); return true; } return MathGridInset::getStatus(cur, cmd, flag); } default: return MathGridInset::getStatus(cur, cmd, flag); } } ///////////////////////////////////////////////////////////////////// #include "math_arrayinset.h" #include "math_deliminset.h" #include "math_factory.h" #include "math_parser.h" #include "math_spaceinset.h" #include "ref_inset.h" #include "bufferview_funcs.h" #include "lyxtext.h" #include "frontends/LyXView.h" #include "frontends/Dialogs.h" #include "support/lyxlib.h" // simply scrap this function if you want void MathHullInset::mutateToText() { #if 0 // translate to latex ostringstream os; latex(NULL, os, false, false); string str = os.str(); // insert this text LyXText * lt = view_->getLyXText(); string::const_iterator cit = str.begin(); string::const_iterator end = str.end(); for (; cit != end; ++cit) view_->owner()->getIntl()->getTransManager().TranslateAndInsert(*cit, lt); // remove ourselves //view_->owner()->dispatch(LFUN_ESCAPE); #endif } void MathHullInset::handleFont(LCursor & cur, string const & arg, string const & font) { // this whole function is a hack and won't work for incremental font // changes... recordUndo(cur); if (cur.inset().asMathInset()->name() == font) cur.handleFont(font); else { cur.handleNest(createMathInset(font)); cur.insert(arg); } } void MathHullInset::handleFont2(LCursor & cur, string const & arg) { recordUndo(cur); LyXFont font; bool b; bv_funcs::string2font(arg, font, b); if (font.color() != LColor::inherit) { MathAtom at = createMathInset("color"); asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0)); cur.handleNest(at, 1); } } void MathHullInset::edit(LCursor & cur, bool left) { cur.push(*this); left ? idxFirst(cur) : idxLast(cur); } string const MathHullInset::editMessage() const { return _("Math editor mode"); } void MathHullInset::getCursorDim(int & asc, int & desc) const { asc = 10; desc = 2; //math_font_max_dim(font_, asc, des); } void MathHullInset::revealCodes(LCursor & cur) const { if (!cur.inMathed()) return; ostringstream os; cur.info(os); cur.message(os.str()); /* // write something to the minibuffer // translate to latex cur.markInsert(bv); ostringstream os; write(NULL, os); string str = os.str(); cur.markErase(bv); string::size_type pos = 0; string res; for (string::iterator it = str.begin(); it != str.end(); ++it) { if (*it == '\n') res += ' '; else if (*it == '\0') { res += " -X- "; pos = it - str.begin(); } else res += *it; } if (pos > 30) res = res.substr(pos - 30); if (res.size() > 60) res = res.substr(0, 60); cur.message(res); */ } InsetBase::Code MathHullInset::lyxCode() const { return MATH_CODE; } ///////////////////////////////////////////////////////////////////// #if 0 bool MathHullInset::searchForward(BufferView * bv, string const & str, bool, bool) { #ifdef WITH_WARNINGS #warning completely broken #endif static MathHullInset * lastformula = 0; static CursorBase current = DocIterator(ibegin(nucleus())); static MathArray ar; static string laststr; if (lastformula != this || laststr != str) { //lyxerr << "reset lastformula to " << this << endl; lastformula = this; laststr = str; current = ibegin(nucleus()); ar.clear(); mathed_parse_cell(ar, str); } else { increment(current); } //lyxerr << "searching '" << str << "' in " << this << ar << endl; for (DocIterator it = current; it != iend(nucleus()); increment(it)) { CursorSlice & top = it.back(); MathArray const & a = top.asMathInset()->cell(top.idx_); if (a.matchpart(ar, top.pos_)) { bv->cursor().setSelection(it, ar.size()); current = it; top.pos_ += ar.size(); bv->update(); return true; } } //lyxerr << "not found!" << endl; lastformula = 0; return false; } #endif void MathHullInset::write(Buffer const &, std::ostream & os) const { WriteStream wi(os, false, false); os << "Formula "; write(wi); } void MathHullInset::read(Buffer const &, LyXLex & lex) { MathAtom at; mathed_parse_normal(at, lex); operator=(*at->asHullInset()); } int MathHullInset::plaintext(Buffer const &, ostream & os, OutputParams const &) const { if (0 && display()) { Dimension dim; TextMetricsInfo mi; metricsT(mi, dim); TextPainter tpain(dim.width(), dim.height()); drawT(tpain, 0, dim.ascent()); tpain.show(os, 3); // reset metrics cache to "real" values //metrics(); return tpain.textheight(); } else { WriteStream wi(os, false, true); wi << cell(0); return wi.line(); } } int MathHullInset::linuxdoc(Buffer const & buf, ostream & os, OutputParams const & runparams) const { return docbook(buf, os, runparams); } int MathHullInset::docbook(Buffer const & buf, ostream & os, OutputParams const & runparams) const { MathMLStream ms(os); int res = 0; string name; if (getType() == "simple") name= "inlineequation"; else name = "informalequation"; string bname = name; if (!label(0).empty()) bname += " id=\"" + sgml::cleanID(buf, runparams, label(0)) + "\""; ms << MTag(bname.c_str()); ostringstream ls; if (runparams.flavor == OutputParams::XML) { ms << MTag("alt role=\"tex\" "); // Workaround for db2latex: db2latex always includes equations with // \ensuremath{} or \begin{display}\end{display} // so we strip LyX' math environment WriteStream wi(ls, false, false); MathGridInset::write(wi); ms << subst(subst(ls.str(), "&", "&"), "<", "<"); ms << ETag("alt"); ms << MTag("math"); MathGridInset::mathmlize(ms); ms << ETag("math"); } else { ms << MTag("alt role=\"tex\""); res = latex(buf, ls, runparams); ms << subst(subst(ls.str(), "&", "&"), "<", "<"); ms << ETag("alt"); } ms << ""; else ms << "\">"; ms << ETag(name.c_str()); return ms.line() + res; }