lyx_mirror/src/insets/InsetPreview.cpp
Enrico Forestieri 11c2b7792c Replacement for commits bc47054b and ad0d0f6d
The strategy adopted in bc47054b had some drawbacks related to the way
instant preview snippets are generated. See the subthread starting at
http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg187916.html
for details.

The strategy adopted in this commit is that of adding macro definitions
only for the macros actually used in a preview snippet, independently
of whether some macro was already used in a previous snippet. In this way
the snippets don't need to be changed according to whether they are
compiled as a whole or separately from each other. This fact was causing
the regeneration of a preview snippet whenever the cursor entered the
corresponding inset, even if the generated image would have not changed.
The problem of defining or redefining a macro is taken care by the
python scripts.
2015-06-14 18:10:29 +02:00

194 lines
4.2 KiB
C++

/**
* \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 "Lexer.h"
#include "MetricsInfo.h"
#include "OutputParams.h"
#include "RenderPreview.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)), use_preview_(true)
{
setDrawFrame(true);
setFrameColor(Color_previewframe);
}
InsetPreview::~InsetPreview()
{}
InsetPreview::InsetPreview(InsetPreview const & other)
: InsetText(other)
{
preview_.reset(new RenderPreview(*other.preview_, 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);
}
void InsetPreview::preparePreview(DocIterator const & pos) const
{
TexRow texrow;
odocstringstream str;
otexstream os(str, texrow);
OutputParams runparams(&pos.buffer()->params().encoding());
latex(os, runparams);
// collect macros at this position
MacroNameSet macros;
pos.buffer()->listMacroNames(macros);
// look for math insets and collect definitions for the used macros
MacroNameSet defs;
DocIterator dit = doc_iterator_begin(pos.buffer(), this);
DocIterator const dend = doc_iterator_end(pos.buffer(), this);
if (!dit.nextInset())
dit.forwardInset();
for (; dit != dend; dit.forwardInset()) {
InsetMath * im = dit.nextInset()->asInsetMath();
InsetMathHull * hull = im ? im->asHullInset() : 0;
if (!hull)
continue;
for (idx_type idx = 0; idx < hull->nargs(); ++idx)
hull->usedMacros(hull->cell(idx), pos, macros, defs);
}
MacroNameSet::iterator it = defs.begin();
MacroNameSet::iterator end = defs.end();
docstring macro_preamble;
for (; it != end; ++it)
macro_preamble.append(*it);
docstring const snippet = macro_preamble + str.str();
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
{
use_preview_ = previewState(pi.base.bv);
if (use_preview_) {
// one pixel gap in front
preview_->draw(pi, x + 1 + TEXT_TO_INSET_OFFSET, y);
setPosCache(pi, x, y);
return;
}
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 (use_preview_) {
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);
mi.base.textwidth += 2 * TEXT_TO_INSET_OFFSET;
dim.wid = max(dim.wid, 4);
dim.asc = max(dim.asc, 4);
dim.asc += TEXT_TO_INSET_OFFSET;
dim.des += TEXT_TO_INSET_OFFSET;
dim.wid += TEXT_TO_INSET_OFFSET;
dim_ = dim;
dim.wid += TEXT_TO_INSET_OFFSET;
// insert a one pixel gap
dim.wid += 1;
// Cache the inset dimension.
setDimCache(mi, dim);
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