X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fformula.C;h=a6c0b602018d1942208792fcdc2a17c6e4868572;hb=46880e2b9b49632c56bab2377ce9a3c826cf8d1d;hp=f8916e42d434b3593459fad006fb235824f1c4ff;hpb=bf3d330980f90e0b8400172692a27b9bd067372f;p=lyx.git diff --git a/src/mathed/formula.C b/src/mathed/formula.C index f8916e42d4..a6c0b60201 100644 --- a/src/mathed/formula.C +++ b/src/mathed/formula.C @@ -24,22 +24,30 @@ #include "math_cursor.h" #include "math_parser.h" #include "math_charinset.h" +#include "math_arrayinset.h" +#include "math_deliminset.h" #include "lyx_main.h" #include "BufferView.h" #include "gettext.h" #include "debug.h" -#include "lyx_gui_misc.h" #include "support/LOstream.h" #include "support/LAssert.h" #include "support/lyxlib.h" -#include "support/syscall.h" -#include "support/lstrings.h" -#include "support/filetools.h" // LibFileSearch -#include "LyXView.h" -#include "Painter.h" +#include "support/systemcall.h" +#include "support/filetools.h" +#include "frontends/Alert.h" +#include "frontends/LyXView.h" +#include "frontends/Painter.h" +#include "graphics/GraphicsImage.h" #include "lyxrc.h" -#include "math_matrixinset.h" -#include "mathed/support.h" +#include "math_hullinset.h" +#include "math_support.h" +#include "math_mathmlstream.h" +#include "textpainter.h" + +#include +#include +#include using std::ostream; using std::ifstream; @@ -47,125 +55,95 @@ using std::istream; using std::pair; using std::endl; using std::vector; +using std::getline; -namespace { - - void stripFromLastEqualSign(MathArray & ar) - { - // find position of last '=' in the array - MathArray::size_type pos = ar.size(); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - if ((*it)->getChar() == '=') - pos = it - ar.begin(); - - // delete everything behind this position - ar.erase(pos, ar.size()); - } - - - MathArray pipeThroughExtern(string const & arg, MathArray const & ar) - { - string lang; - string extra; - istringstream iss(arg.c_str()); - iss >> lang >> extra; - if (extra.empty()) - extra = "noextra"; - - // create normalized expression - string outfile = lyx::tempName(string(), "mathextern"); - ostringstream os; - os << "[" << extra << ' '; - ar.writeNormal(os); - os << "]"; - string code = os.str().c_str(); - - // run external sript - string file = LibFileSearch("mathed", "extern_" + lang); - if (file.empty()) { - lyxerr << "converter to '" << lang << "' not found\n"; - return MathArray(); - } - string script = file + " '" + code + "' " + outfile; - lyxerr << "calling: " << script << endl; - Systemcalls cmd(Systemcalls::System, script, 0); - - // append result - MathArray res; - mathed_parse_cell(res, GetFileContents(outfile)); - return res; - } - -} - InsetFormula::InsetFormula() - : par_(MathAtom(new MathMatrixInset)) -{} - - -InsetFormula::InsetFormula(MathInsetTypes t) - : par_(MathAtom(new MathMatrixInset(t))) + : par_(MathAtom(new MathHullInset)), loader_(0) {} -InsetFormula::InsetFormula(string const & s) +InsetFormula::InsetFormula(BufferView * bv) + : par_(MathAtom(new MathHullInset)), loader_(0) { - if (s.size()) { - bool res = mathed_parse_normal(par_, s); + view_ = bv; +} - if (!res) - res = mathed_parse_normal(par_, "$" + s + "$"); - if (!res) { - lyxerr << "cannot interpret '" << s << "' as math\n"; - par_ = MathAtom(new MathMatrixInset(LM_OT_SIMPLE)); - } - } - metrics(); +InsetFormula::InsetFormula(string const & data) + : par_(MathAtom(new MathHullInset)), loader_(0) +{ + if (!data.size()) + return; + if (!mathed_parse_normal(par_, data)) + lyxerr << "cannot interpret '" << data << "' as math\n"; } + Inset * InsetFormula::clone(Buffer const &, bool) const { return new InsetFormula(*this); } -void InsetFormula::write(Buffer const * buf, ostream & os) const +void InsetFormula::write(Buffer const *, ostream & os) const { os << "Formula "; - latex(buf, os, false, false); + WriteStream wi(os, false, false); + par_->write(wi); } -int InsetFormula::latex(Buffer const * buf, ostream & os, bool fragil, bool) - const +int InsetFormula::latex(Buffer const *, ostream & os, bool fragile, bool) const { - MathWriteInfo wi(buf, os, fragil); + WriteStream wi(os, fragile, true); par_->write(wi); - return 1; + return wi.line(); } -int InsetFormula::ascii(Buffer const * buf, ostream & os, int) const + +int InsetFormula::ascii(Buffer const *, ostream & os, int) const { - MathWriteInfo wi(buf, os, false); +#if 0 + TextMetricsInfo mi; + par()->metricsT(mi); + TextPainter tpain(par()->width(), par()->height()); + par()->drawT(tpain, 0, par()->ascent()); + tpain.show(os); + // reset metrics cache to "real" values + metrics(); + return tpain.textheight(); +#else + WriteStream wi(os, false, true); par_->write(wi); - return 1; + return wi.line(); +#endif } int InsetFormula::linuxdoc(Buffer const * buf, ostream & os) const { - return ascii(buf, os, 0); + return docbook(buf, os, false); } -int InsetFormula::docbook(Buffer const * buf, ostream & os) const +int InsetFormula::docbook(Buffer const * buf, ostream & os, bool) const { - return ascii(buf, os, 0); + MathMLStream ms(os); + ms << MTag("equation"); + ms << MTag("alt"); + ms << "<[CDATA["; + int res = ascii(buf, ms.os(), 0); + ms << "]]>"; + ms << ETag("alt"); + ms << MTag("math"); + ms << par_.nucleus(); + ms << ETag("math"); + ms << ETag("equation"); + return ms.line() + res; } @@ -173,30 +151,50 @@ void InsetFormula::read(Buffer const *, LyXLex & lex) { mathed_parse_normal(par_, lex); metrics(); + updatePreview(); } +//ostream & operator<<(ostream & os, LyXCursor const & c) +//{ +// os << '[' << c.x() << ' ' << c.y() << ' ' << c.pos() << ']'; +// return os; +//} + + void InsetFormula::draw(BufferView * bv, LyXFont const & font, int y, float & xx, bool) const { - int x = int(xx) - 1; - y -= 2; + int const x = int(xx); + int const w = width(bv, font); + int const d = descent(bv, font); + int const a = ascent(bv, font); + int const h = a + d; - Painter & pain = bv->painter(); + MathPainterInfo pi(bv->painter()); - metrics(bv, font); - int w = par_->width(); - int h = par_->height(); - int a = par_->ascent(); - pain.fillRectangle(x, y - a, w, h, LColor::mathbg); - - if (mathcursor && mathcursor->formula() == this) { - mathcursor->drawSelection(pain); - pain.rectangle(x, y - a, w, h, LColor::mathframe); + if (canPreview()) { + pi.pain.image(x + 1, y - a + 1, w - 2, h - 2, *(loader_->image())); + } else { + //pi.base.style = display() ? LM_ST_DISPLAY : LM_ST_TEXT; + pi.base.style = LM_ST_TEXT; + pi.base.font = font; + pi.base.font.setColor(LColor::math); + if (lcolor.getX11Name(LColor::mathbg) + != lcolor.getX11Name(LColor::background)) + pi.pain.fillRectangle(x, y - a, w, h, LColor::mathbg); + + if (mathcursor && + const_cast(mathcursor->formula()) == this) + { + mathcursor->drawSelection(pi); + pi.pain.rectangle(x, y - a, w, h, LColor::mathframe); + } + + par_->draw(pi, x, y); } - par_->draw(pain, x, y); - xx += par_->width(); + xx += w; xo_ = x; yo_ = y; @@ -206,7 +204,7 @@ void InsetFormula::draw(BufferView * bv, LyXFont const & font, vector const InsetFormula::getLabelList() const { - return mat()->getLabelList(); + return hull()->getLabelList(); } @@ -218,7 +216,7 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, switch (action) { - case LFUN_BREAKLINE: + case LFUN_BREAKLINE: bv->lockedInsetStoreUndo(Undo::INSERT); mathcursor->breakLine(); mathcursor->normalize(); @@ -230,9 +228,9 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, //lyxerr << "toggling all numbers\n"; if (display()) { bv->lockedInsetStoreUndo(Undo::INSERT); - bool old = mat()->numberedType(); + bool old = hull()->numberedType(); for (MathInset::row_type row = 0; row < par_->nrows(); ++row) - mat()->numbered(row, !old); + hull()->numbered(row, !old); bv->owner()->message(old ? _("No number") : _("Number")); updateLocal(bv, true); } @@ -244,10 +242,10 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, //lyxerr << "toggling line number\n"; if (display()) { bv->lockedInsetStoreUndo(Undo::INSERT); - MathCursor::row_type row = mathcursor->row(); - bool old = mat()->numbered(row); + MathCursor::row_type row = mathcursor->hullRow(); + bool old = hull()->numbered(row); bv->owner()->message(old ? _("No number") : _("Number")); - mat()->numbered(row, !old); + hull()->numbered(row, !old); updateLocal(bv, true); } break; @@ -257,18 +255,16 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, { bv->lockedInsetStoreUndo(Undo::INSERT); - MathCursor::row_type row = mathcursor->row(); - string old_label = mat()->label(row); + MathCursor::row_type row = mathcursor->hullRow(); + string old_label = hull()->label(row); string new_label = arg; if (new_label.empty()) { string const default_label = (lyxrc.label_init_length >= 0) ? "eq:" : ""; pair const res = old_label.empty() - ? askForText(_("Enter new label to insert:"), default_label) - : askForText(_("Enter label:"), old_label); - - lyxerr << "res: " << res.first << " - '" << res.second << "'\n"; + ? Alert::askForText(_("Enter new label to insert:"), default_label) + : Alert::askForText(_("Enter label:"), old_label); if (!res.first) break; new_label = frontStrip(strip(res.second)); @@ -279,13 +275,15 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, if (!new_label.empty()) { lyxerr << "setting label to '" << new_label << "'\n"; - mat()->numbered(row, true); + hull()->numbered(row, true); } +#warning FIXME: please check you really mean repaint() ... is it needed, +#warning and if so, should it be update() instead ? if (!new_label.empty() && bv->ChangeRefsIfUnique(old_label, new_label)) - bv->redraw(); + bv->repaint(); - mat()->label(row, new_label); + hull()->label(row, new_label); updateLocal(bv, true); break; @@ -297,7 +295,7 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, int x; int y; mathcursor->getPos(x, y); - mat()->mutate(arg); + mutate(arg); mathcursor->setPos(x, y); mathcursor->normalize(); updateLocal(bv, true); @@ -307,7 +305,8 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, case LFUN_MATH_EXTERN: { bv->lockedInsetStoreUndo(Undo::EDIT); - handleExtern(arg); + if (mathcursor) + mathcursor->handleExtern(arg); // re-compute inset dimension metrics(bv); updateLocal(bv, true); @@ -316,85 +315,54 @@ InsetFormula::localDispatch(BufferView * bv, kb_action action, case LFUN_MATH_DISPLAY: { - int x; - int y; + int x = 0; + int y = 0; mathcursor->getPos(x, y); - if (mat()->getType() == LM_OT_SIMPLE) - mat()->mutate(LM_OT_EQUATION); + if (hullType() == "simple") + mutate("equation"); else - mat()->mutate(LM_OT_SIMPLE); + mutate("simple"); mathcursor->setPos(x, y); mathcursor->normalize(); updateLocal(bv, true); break; } - + case LFUN_PASTESELECTION: { string const clip = bv->getClipboard(); - if (!clip.empty()) + if (!clip.empty()) mathed_parse_normal(par_, clip); break; } - case LFUN_MATH_COLUMN_INSERT: - { - if (mat()->getType() == LM_OT_ALIGN) - mat()->mutate(LM_OT_ALIGNAT); - mat()->addCol(mat()->ncols()); - mathcursor->normalize(); - updateLocal(bv, true); - } - default: result = InsetFormulaBase::localDispatch(bv, action, arg); } - return result; -} - - -void InsetFormula::handleExtern(const string & arg) -{ - // where are we? - if (!mathcursor) - return; - - bool selected = mathcursor->selection(); + //updatePreview(); - MathArray ar; - if (selected) { - mathcursor->selGet(ar); - lyxerr << "use selection: " << ar << "\n"; - } else { - mathcursor->end(); - ar = mathcursor->cursor().cell(); - stripFromLastEqualSign(ar); - mathcursor->insert(MathAtom(new MathCharInset('=', LM_TC_VAR))); - lyxerr << "use whole cell: " << ar << "\n"; - } - - mathcursor->insert(pipeThroughExtern(arg, ar)); + return result; } bool InsetFormula::display() const { - return mat()->getType() != LM_OT_SIMPLE; + return hullType() != "simple" && hullType() != "none"; } -MathMatrixInset const * InsetFormula::mat() const +MathHullInset const * InsetFormula::hull() const { - lyx::Assert(par_->asMatrixInset()); - return par_->asMatrixInset(); + lyx::Assert(par_->asHullInset()); + return par_->asHullInset(); } -MathMatrixInset * InsetFormula::mat() +MathHullInset * InsetFormula::hull() { - lyx::Assert(par_->asMatrixInset()); - return par_->asMatrixInset(); + lyx::Assert(par_->asHullInset()); + return par_->asHullInset(); } @@ -412,30 +380,129 @@ void InsetFormula::validate(LaTeXFeatures & features) const bool InsetFormula::insetAllowed(Inset::Code code) const { - return code == Inset::LABEL_CODE && display(); + return + (code == Inset::LABEL_CODE && display()) + || code == Inset::REF_CODE + || code == Inset::ERT_CODE; } int InsetFormula::ascent(BufferView *, LyXFont const &) const { - return par_->ascent() + 2; + const int a = par_->ascent(); + if (!canPreview()) + return a + 1; + return a + 1 - (par_->height() - loader_->image()->getHeight()) / 2; } int InsetFormula::descent(BufferView *, LyXFont const &) const { - return par_->descent() - 2; + const int d = par_->descent(); + if (!canPreview()) + return d + 1; + return d + 1 - (par_->height() - loader_->image()->getHeight()) / 2; } int InsetFormula::width(BufferView * bv, LyXFont const & font) const { metrics(bv, font); - return par_->width(); + return canPreview() ? loader_->image()->getWidth() : par_->width(); +} + + +string InsetFormula::hullType() const +{ + return hull() ? hull()->getType() : "none"; } -MathInsetTypes InsetFormula::getType() const +void InsetFormula::mutate(string const & type ) { - return mat()->getType(); + if (hull()) + hull()->mutate(type); } + + +// +// preview stuff +// + +bool InsetFormula::canPreview() const +{ + return lyxrc.preview && loader_ && !par_->asNestInset()->editing() + && loader_->status() == grfx::Ready; +} + + +void InsetFormula::statusChanged() +{ + lyxerr << "### InsetFormula::statusChanged called!, status: " + << loader_->status() << "\n"; + if (loader_->status() == grfx::Ready) + view()->updateInset(this, false); + else if (loader_->status() == grfx::WaitingToLoad) + loader_->startLoading(); +} + + +void InsetFormula::updatePreview() +{ + // nothing to be done if no preview requested + lyxerr << "### updatePreview() called\n"; + if (!lyxrc.preview) + return; + + // get LaTeX + ostringstream ls; + WriteStream wi(ls, false, false); + par_->write(wi); + string const data = ls.str(); + + // the preview cache, maps contents to image loaders + typedef std::map > cache_type; + static cache_type theCache; + static int theCounter = 0; + + // set our loader corresponding to our current data + cache_type::const_iterator it = theCache.find(data); + + // is this old data? + if (it != theCache.end()) { + // we have already a loader, connect to it anyway + //lyxerr << "### updatePreview(), old loader: " << loader_ << "\n"; + loader_ = it->second.get(); + loader_->statusChanged.connect + (boost::bind(&InsetFormula::statusChanged, this)); + return; + } + + // construct new file name + static string const dir = OnlyPath(lyx::tempName()); + ostringstream os; + os << dir << theCounter++ << ".lyxpreview"; + string file = os.str(); + + // the real work starts + //lyxerr << "### updatePreview(), new file " << file << "\n"; + std::ofstream of(file.c_str()); + of << "\\batchmode" + << "\\documentclass{article}" + << "\\usepackage{amssymb}" + << "\\thispagestyle{empty}" + << "\\pdfoutput=0" + << "\\begin{document}" + << data + << "\\end{document}\n"; + of.close(); + + // now we are done, start actual loading we will get called back via + // InsetFormula::statusChanged() if this is finished + theCache[data].reset(new grfx::Loader(file)); + //lyxerr << "### updatePreview(), new loader: " << loader_ << "\n"; + loader_ = theCache.find(data)->second.get(); + loader_->startLoading(); + loader_->statusChanged.connect(boost::bind(&InsetFormula::statusChanged, this)); +} +