-/**\r
- * \file InsetPreview.cpp\r
- * This file is part of LyX, the document processor.\r
- * Licence details can be found in the file COPYING.\r
- *\r
- * \author Vincent van Ravesteijn\r
- *\r
- * Full author contact details are available in file CREDITS.\r
- */\r
-#include "config.h"\r
-\r
-#include "InsetPreview.h"\r
-\r
-#include "Buffer.h"\r
-#include "BufferParams.h"\r
-#include "BufferView.h"\r
-#include "Cursor.h"\r
-#include "Lexer.h"\r
-#include "LyXRC.h"\r
-#include "MetricsInfo.h"\r
-#include "OutputParams.h"\r
-\r
-#include "frontends/Painter.h"\r
-\r
-#include "graphics/PreviewImage.h"\r
-\r
-#include <sstream>\r
-\r
-using namespace std;\r
-\r
-namespace lyx {\r
-\r
-\r
-InsetPreview::InsetPreview(Buffer * buf) \r
- : InsetText(buf),\r
- preview_(new RenderPreview(this)), use_preview_(true)\r
-{\r
- setAutoBreakRows(true);\r
- setDrawFrame(true);\r
- setFrameColor(Color_previewframe);\r
-}\r
-\r
-\r
-InsetPreview::~InsetPreview() \r
-{}\r
-\r
-\r
-InsetPreview::InsetPreview(InsetPreview const & other)\r
- : InsetText(other)\r
-{\r
- preview_.reset(new RenderPreview(*other.preview_, this));\r
-}\r
-\r
-\r
-void InsetPreview::write(ostream & os) const\r
-{\r
- os << "Preview" << "\n";\r
- text().write(os);\r
-}\r
-\r
-\r
-void InsetPreview::addPreview(DocIterator const & inset_pos,\r
- graphics::PreviewLoader & ploader) const\r
-{\r
- preparePreview(inset_pos);\r
-}\r
-\r
-\r
-void InsetPreview::preparePreview(DocIterator const & pos) const \r
-{\r
- odocstringstream str; \r
- OutputParams runparams(&pos.buffer()->params().encoding());\r
- latex(str, runparams);\r
- docstring const snippet = str.str();\r
- preview_->addPreview(snippet, *pos.buffer()); \r
-}\r
-\r
-\r
-bool InsetPreview::previewState(BufferView * bv) const\r
-{\r
- if (!editing(bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) {\r
- graphics::PreviewImage const * pimage =\r
- preview_->getPreviewImage(bv->buffer());\r
- return pimage && pimage->image();\r
- }\r
- return false;\r
-}\r
-\r
-\r
-void InsetPreview::reloadPreview(DocIterator const & pos) const\r
-{\r
- preparePreview(pos);\r
- preview_->startLoading(*pos.buffer());\r
-}\r
-\r
-\r
-void InsetPreview::draw(PainterInfo & pi, int x, int y) const\r
-{\r
- use_preview_ = previewState(pi.base.bv);\r
-\r
- if (use_preview_) {\r
- // one pixel gap in front\r
- preview_->draw(pi, x + 1 + TEXT_TO_INSET_OFFSET, y);\r
- setPosCache(pi, x, y);\r
- return;\r
- }\r
- InsetText::draw(pi, x, y);\r
-}\r
-\r
-\r
-void InsetPreview::edit(Cursor & cur, bool front, EntryDirection entry_from)\r
-{\r
- cur.push(*this);\r
- InsetText::edit(cur, front, entry_from);\r
-}\r
-\r
-\r
-Inset * InsetPreview::editXY(Cursor & cur, int x, int y)\r
-{\r
- if (use_preview_) {\r
- edit(cur, true, ENTRY_DIRECTION_IGNORE);\r
- return this;\r
- }\r
- cur.push(*this);\r
- return InsetText::editXY(cur, x, y);\r
-}\r
-\r
-\r
-void InsetPreview::metrics(MetricsInfo & mi, Dimension & dim) const\r
-{\r
- if (previewState(mi.base.bv)) {\r
- preview_->metrics(mi, dim);\r
- mi.base.textwidth += 2 * TEXT_TO_INSET_OFFSET;\r
- \r
- dim.wid = max(dim.wid, 4);\r
- dim.asc = max(dim.asc, 4);\r
- \r
- dim.asc += TEXT_TO_INSET_OFFSET;\r
- dim.des += TEXT_TO_INSET_OFFSET;\r
- dim.wid += TEXT_TO_INSET_OFFSET;\r
- dim_ = dim;\r
- dim.wid += TEXT_TO_INSET_OFFSET;\r
- // insert a one pixel gap\r
- dim.wid += 1;\r
- // Cache the inset dimension.\r
- setDimCache(mi, dim);\r
- Dimension dim_dummy;\r
- MetricsInfo mi_dummy = mi;\r
- InsetText::metrics(mi_dummy, dim_dummy);\r
- return;\r
- }\r
- InsetText::metrics(mi, dim);\r
-}\r
-\r
-\r
-bool InsetPreview::notifyCursorLeaves(Cursor const & old, Cursor & cur)\r
-{\r
- reloadPreview(old);\r
- cur.updateFlags(Update::Force);\r
- return InsetText::notifyCursorLeaves(old, cur);\r
-}\r
-\r
-\r
-} // namespace lyx\r
+/**
+ * \file InsetPreview.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Vincent van Ravesteijn
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+#include "config.h"
+
+#include "InsetPreview.h"
+
+#include "Buffer.h"
+#include "BufferParams.h"
+#include "BufferView.h"
+#include "Cursor.h"
+#include "Dimension.h"
+#include "MetricsInfo.h"
+#include "RenderPreview.h"
+#include "texstream.h"
+
+#include "frontends/Painter.h"
+
+#include "graphics/PreviewImage.h"
+
+#include "mathed/InsetMathHull.h"
+#include "mathed/MacroTable.h"
+
+#include <sstream>
+
+using namespace std;
+
+namespace lyx {
+
+
+InsetPreview::InsetPreview(Buffer * buf)
+ : InsetText(buf), preview_(new RenderPreview(this))
+{
+ setDrawFrame(true);
+ setFrameColor(Color_previewframe);
+}
+
+
+InsetPreview::~InsetPreview()
+{}
+
+
+InsetPreview::InsetPreview(InsetPreview const & other)
+ : InsetText(other)
+{
+ preview_.reset(new RenderPreview(*other.preview_, this));
+}
+
+
+InsetPreview & InsetPreview::operator=(InsetPreview const & other)
+{
+ if (&other == this)
+ return *this;
+
+ InsetText::operator=(other);
+ preview_.reset(new RenderPreview(*other.preview_, this));
+
+ return *this;
+}
+
+
+void InsetPreview::write(ostream & os) const
+{
+ os << "Preview" << "\n";
+ text().write(os);
+}
+
+
+void InsetPreview::addPreview(DocIterator const & inset_pos,
+ graphics::PreviewLoader &) const
+{
+ preparePreview(inset_pos);
+}
+
+
+MacroNameSet gatherMacroDefinitions(const Buffer* buffer, const Inset * inset)
+{
+ // Collect macros for this inset.
+ // Not done yet: this function returns a list of macro *definitions*.
+ MacroNameSet macros;
+ buffer->listMacroNames(macros);
+
+ // Look for math insets and collect definitions for the used macros.
+ MacroNameSet defs;
+ DocIterator const dbeg = doc_iterator_begin(buffer, inset);
+ DocIterator dit = dbeg;
+ DocIterator const dend = doc_iterator_end(buffer, inset);
+ if (!dit.nextInset())
+ dit.forwardInset();
+
+ for (; dit != dend; dit.forwardInset()) {
+ InsetMath * im = dit.nextInset()->asInsetMath();
+ InsetMathHull * hull = im ? im->asHullInset() : nullptr;
+ if (!hull)
+ continue;
+ for (idx_type idx = 0; idx < hull->nargs(); ++idx)
+ hull->usedMacros(hull->cell(idx), dbeg, macros, defs);
+ }
+
+ return defs;
+}
+
+
+docstring insetToLaTeXSnippet(const Buffer* buffer, const Inset * inset)
+{
+ odocstringstream str;
+ otexstream os(str);
+ OutputParams runparams(&buffer->params().encoding());
+ inset->latex(os, runparams);
+
+ MacroNameSet defs = gatherMacroDefinitions(buffer, inset);
+ docstring macro_preamble;
+ for (const auto& def : defs)
+ macro_preamble.append(def);
+
+ return macro_preamble + str.str();
+}
+
+
+void InsetPreview::preparePreview(DocIterator const & pos) const
+{
+ docstring const snippet = insetToLaTeXSnippet(pos.buffer(), this);
+ preview_->addPreview(snippet, *pos.buffer());
+}
+
+
+bool InsetPreview::previewState(BufferView * bv) const
+{
+ if (!editing(bv) && RenderPreview::previewText()) {
+ graphics::PreviewImage const * pimage =
+ preview_->getPreviewImage(bv->buffer());
+ return pimage && pimage->image();
+ }
+ return false;
+}
+
+
+void InsetPreview::reloadPreview(DocIterator const & pos) const
+{
+ preparePreview(pos);
+ preview_->startLoading(*pos.buffer());
+}
+
+
+void InsetPreview::draw(PainterInfo & pi, int x, int y) const
+{
+ if (previewState(pi.base.bv)) {
+ // one pixel gap in front
+ preview_->draw(pi, x + 1, y);
+ } else
+ InsetText::draw(pi, x, y);
+}
+
+
+void InsetPreview::edit(Cursor & cur, bool front, EntryDirection entry_from)
+{
+ cur.push(*this);
+ InsetText::edit(cur, front, entry_from);
+}
+
+
+Inset * InsetPreview::editXY(Cursor & cur, int x, int y)
+{
+ if (previewState(&cur.bv())) {
+ edit(cur, true, ENTRY_DIRECTION_IGNORE);
+ return this;
+ }
+ cur.push(*this);
+ return InsetText::editXY(cur, x, y);
+}
+
+
+void InsetPreview::metrics(MetricsInfo & mi, Dimension & dim) const
+{
+ if (previewState(mi.base.bv)) {
+ preview_->metrics(mi, dim);
+
+ dim.wid = max(dim.wid, 4);
+ dim.asc = max(dim.asc, 4);
+
+ dim.asc += topOffset(mi.base.bv);
+ dim.des += bottomOffset(mi.base.bv);
+ // insert a one pixel gap
+ dim.wid += 1;
+ Dimension dim_dummy;
+ MetricsInfo mi_dummy = mi;
+ InsetText::metrics(mi_dummy, dim_dummy);
+ return;
+ }
+ InsetText::metrics(mi, dim);
+}
+
+
+bool InsetPreview::notifyCursorLeaves(Cursor const & old, Cursor & cur)
+{
+ reloadPreview(old);
+ cur.screenUpdateFlags(Update::Force);
+ return InsetText::notifyCursorLeaves(old, cur);
+}
+
+
+} // namespace lyx