2003-08-19 13:00:56 +00:00
|
|
|
/**
|
2007-04-26 16:05:57 +00:00
|
|
|
* \file MathData.cpp
|
2003-08-19 13:00:56 +00:00
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
*
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author André Pönitz
|
2007-11-01 11:13:07 +00:00
|
|
|
* \author Stefan Schimanski
|
2003-08-19 13:00:56 +00:00
|
|
|
*
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
|
|
|
|
2001-12-18 03:16:46 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
#include "MathData.h"
|
2007-11-05 23:46:17 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
#include "InsetMathBrace.h"
|
2006-09-17 09:14:18 +00:00
|
|
|
#include "InsetMathFont.h"
|
|
|
|
#include "InsetMathScript.h"
|
2007-04-28 20:44:46 +00:00
|
|
|
#include "MacroTable.h"
|
2017-07-05 12:31:28 +00:00
|
|
|
#include "InsetMathMacro.h"
|
2006-10-22 10:15:23 +00:00
|
|
|
#include "MathStream.h"
|
2006-09-17 09:14:18 +00:00
|
|
|
#include "MathSupport.h"
|
2007-11-05 23:46:17 +00:00
|
|
|
#include "MetricsInfo.h"
|
2007-04-25 16:11:45 +00:00
|
|
|
#include "ReplaceData.h"
|
2004-04-13 06:27:29 +00:00
|
|
|
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Buffer.h"
|
2007-10-11 09:59:01 +00:00
|
|
|
#include "BufferView.h"
|
|
|
|
#include "CoordCache.h"
|
2007-04-26 14:56:30 +00:00
|
|
|
#include "Cursor.h"
|
2004-01-07 18:28:50 +00:00
|
|
|
|
2008-02-21 19:42:34 +00:00
|
|
|
#include "mathed/InsetMathUnknown.h"
|
|
|
|
|
2006-12-04 10:45:43 +00:00
|
|
|
#include "frontends/FontMetrics.h"
|
2017-02-22 09:43:48 +00:00
|
|
|
#include "frontends/Painter.h"
|
2004-01-07 18:28:50 +00:00
|
|
|
|
2016-11-16 14:07:00 +00:00
|
|
|
#include "support/debug.h"
|
|
|
|
#include "support/docstream.h"
|
2013-04-25 21:27:10 +00:00
|
|
|
#include "support/gettext.h"
|
2008-04-30 08:26:40 +00:00
|
|
|
#include "support/lassert.h"
|
2015-05-15 22:05:23 +00:00
|
|
|
#include "support/lyxalgo.h"
|
2002-08-02 14:29:42 +00:00
|
|
|
|
2008-02-07 17:04:06 +00:00
|
|
|
#include <cstdlib>
|
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
using namespace std;
|
2006-10-21 00:16:43 +00:00
|
|
|
|
|
|
|
namespace lyx {
|
2006-10-19 16:51:30 +00:00
|
|
|
|
2002-08-02 14:29:42 +00:00
|
|
|
|
2009-11-08 11:45:46 +00:00
|
|
|
MathData::MathData(Buffer * buf, const_iterator from, const_iterator to)
|
2015-09-12 20:47:09 +00:00
|
|
|
: base_type(from, to), minasc_(0), mindes_(0), slevel_(0),
|
|
|
|
sshift_(0), kerning_(0), buffer_(buf)
|
2001-11-09 10:44:24 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
2018-10-03 08:39:09 +00:00
|
|
|
void MathData::setBuffer(Buffer & b)
|
|
|
|
{
|
|
|
|
buffer_ = &b;
|
|
|
|
for (MathAtom & at : *this)
|
|
|
|
at.nucleus()->setBuffer(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
MathAtom & MathData::operator[](pos_type pos)
|
2001-04-27 12:35:55 +00:00
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(pos < size());
|
2002-07-30 13:56:02 +00:00
|
|
|
return base_type::operator[](pos);
|
2001-07-12 07:18:29 +00:00
|
|
|
}
|
|
|
|
|
2001-07-24 11:39:38 +00:00
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
MathAtom const & MathData::operator[](pos_type pos) const
|
2001-02-14 17:50:58 +00:00
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(pos < size());
|
2002-07-30 13:56:02 +00:00
|
|
|
return base_type::operator[](pos);
|
2001-10-12 12:02:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::insert(size_type pos, MathAtom const & t)
|
2001-10-12 12:02:49 +00:00
|
|
|
{
|
2015-03-15 12:56:48 +00:00
|
|
|
LBUFERR(pos <= size());
|
2002-07-30 13:56:02 +00:00
|
|
|
base_type::insert(begin() + pos, t);
|
2001-02-14 17:50:58 +00:00
|
|
|
}
|
|
|
|
|
2001-07-24 11:39:38 +00:00
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::insert(size_type pos, MathData const & ar)
|
2001-02-14 17:50:58 +00:00
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(pos <= size());
|
2002-07-30 13:56:02 +00:00
|
|
|
base_type::insert(begin() + pos, ar.begin(), ar.end());
|
2001-10-10 13:20:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::append(MathData const & ar)
|
2001-02-12 08:55:14 +00:00
|
|
|
{
|
2001-11-08 12:55:58 +00:00
|
|
|
insert(size(), ar);
|
2001-02-12 08:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::erase(size_type pos)
|
2001-02-14 17:50:58 +00:00
|
|
|
{
|
2001-08-03 17:10:22 +00:00
|
|
|
if (pos < size())
|
2001-08-07 12:02:21 +00:00
|
|
|
erase(pos, pos + 1);
|
2001-02-14 17:50:58 +00:00
|
|
|
}
|
2001-02-12 08:55:14 +00:00
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::erase(iterator pos1, iterator pos2)
|
2001-11-09 10:44:24 +00:00
|
|
|
{
|
2002-07-30 13:56:02 +00:00
|
|
|
base_type::erase(pos1, pos2);
|
2001-11-09 10:44:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::erase(iterator pos)
|
2001-11-09 10:44:24 +00:00
|
|
|
{
|
2002-07-30 13:56:02 +00:00
|
|
|
base_type::erase(pos);
|
2001-11-09 10:44:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::erase(size_type pos1, size_type pos2)
|
2001-02-12 08:55:14 +00:00
|
|
|
{
|
2002-07-30 13:56:02 +00:00
|
|
|
base_type::erase(begin() + pos1, begin() + pos2);
|
2001-11-09 16:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::dump2() const
|
2001-02-12 08:55:14 +00:00
|
|
|
{
|
2006-10-21 00:16:43 +00:00
|
|
|
odocstringstream os;
|
2006-10-19 16:51:30 +00:00
|
|
|
NormalStream ns(os);
|
2001-08-09 08:53:16 +00:00
|
|
|
for (const_iterator it = begin(); it != end(); ++it)
|
2002-08-08 17:11:30 +00:00
|
|
|
ns << *it << ' ';
|
2006-10-21 00:16:43 +00:00
|
|
|
lyxerr << to_utf8(os.str());
|
2001-02-12 08:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::dump() const
|
2001-02-12 08:55:14 +00:00
|
|
|
{
|
2006-10-21 00:16:43 +00:00
|
|
|
odocstringstream os;
|
2006-10-19 16:51:30 +00:00
|
|
|
NormalStream ns(os);
|
2001-08-09 08:53:16 +00:00
|
|
|
for (const_iterator it = begin(); it != end(); ++it)
|
2002-11-27 10:30:28 +00:00
|
|
|
ns << '<' << *it << '>';
|
2006-10-21 00:16:43 +00:00
|
|
|
lyxerr << to_utf8(os.str());
|
2001-02-12 08:55:14 +00:00
|
|
|
}
|
2001-02-28 17:21:16 +00:00
|
|
|
|
2001-09-11 10:58:17 +00:00
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::validate(LaTeXFeatures & features) const
|
2001-07-13 14:54:56 +00:00
|
|
|
{
|
2001-08-09 08:53:16 +00:00
|
|
|
for (const_iterator it = begin(); it != end(); ++it)
|
2002-08-08 17:11:30 +00:00
|
|
|
(*it)->validate(features);
|
2001-07-13 14:54:56 +00:00
|
|
|
}
|
|
|
|
|
2001-07-26 06:46:50 +00:00
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
bool MathData::match(MathData const & ar) const
|
2001-11-16 09:07:40 +00:00
|
|
|
{
|
2002-01-03 09:41:26 +00:00
|
|
|
return size() == ar.size() && matchpart(ar, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
bool MathData::matchpart(MathData const & ar, pos_type pos) const
|
2002-01-03 09:41:26 +00:00
|
|
|
{
|
|
|
|
if (size() < ar.size() + pos)
|
2001-11-16 09:07:40 +00:00
|
|
|
return false;
|
2002-03-21 17:42:56 +00:00
|
|
|
const_iterator it = begin() + pos;
|
2002-01-03 09:41:26 +00:00
|
|
|
for (const_iterator jt = ar.begin(); jt != ar.end(); ++jt, ++it)
|
2004-01-07 18:28:50 +00:00
|
|
|
if (asString(*it) != asString(*jt))
|
2001-11-16 09:07:40 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2001-11-16 09:55:37 +00:00
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::replace(ReplaceData & rep)
|
2001-11-16 09:55:37 +00:00
|
|
|
{
|
|
|
|
for (size_type i = 0; i < size(); ++i) {
|
2002-06-18 15:44:30 +00:00
|
|
|
if (find1(rep.from, i)) {
|
2001-11-16 09:55:37 +00:00
|
|
|
// match found
|
2003-08-02 11:30:30 +00:00
|
|
|
lyxerr << "match found!" << endl;
|
2002-06-18 15:44:30 +00:00
|
|
|
erase(i, i + rep.from.size());
|
2001-11-16 09:55:37 +00:00
|
|
|
insert(i, rep.to);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-10 11:47:12 +00:00
|
|
|
// FIXME: temporarily disabled
|
2002-08-08 16:08:11 +00:00
|
|
|
// for (const_iterator it = begin(); it != end(); ++it)
|
|
|
|
// it->nucleus()->replace(rep);
|
2001-11-16 09:55:37 +00:00
|
|
|
}
|
2002-02-01 17:01:30 +00:00
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
bool MathData::find1(MathData const & ar, size_type pos) const
|
2002-02-01 17:01:30 +00:00
|
|
|
{
|
2004-01-07 18:28:50 +00:00
|
|
|
lyxerr << "finding '" << ar << "' in '" << *this << "'" << endl;
|
2002-06-18 15:44:30 +00:00
|
|
|
for (size_type i = 0, n = ar.size(); i < n; ++i)
|
2004-01-07 18:28:50 +00:00
|
|
|
if (asString(operator[](pos + i)) != asString(ar[i]))
|
2002-06-18 15:44:30 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
MathData::size_type MathData::find(MathData const & ar) const
|
2002-06-18 15:44:30 +00:00
|
|
|
{
|
|
|
|
for (int i = 0, last = size() - ar.size(); i < last; ++i)
|
|
|
|
if (find1(ar, i))
|
|
|
|
return i;
|
|
|
|
return size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
MathData::size_type MathData::find_last(MathData const & ar) const
|
2002-06-18 15:44:30 +00:00
|
|
|
{
|
2002-08-10 15:21:07 +00:00
|
|
|
for (int i = size() - ar.size(); i >= 0; --i)
|
2002-06-18 15:44:30 +00:00
|
|
|
if (find1(ar, i))
|
|
|
|
return i;
|
|
|
|
return size();
|
|
|
|
}
|
2002-02-01 17:01:30 +00:00
|
|
|
|
2002-06-18 15:44:30 +00:00
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
bool MathData::contains(MathData const & ar) const
|
2002-06-18 15:44:30 +00:00
|
|
|
{
|
|
|
|
if (find(ar) != size())
|
|
|
|
return true;
|
2002-02-01 17:01:30 +00:00
|
|
|
for (const_iterator it = begin(); it != end(); ++it)
|
2002-08-09 10:22:35 +00:00
|
|
|
if ((*it)->contains(ar))
|
2002-02-01 17:01:30 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2002-08-02 14:29:42 +00:00
|
|
|
|
|
|
|
|
2016-10-04 22:25:38 +00:00
|
|
|
bool MathData::addToMathRow(MathRow & mrow, MetricsInfo & mi) const
|
2016-11-16 14:07:00 +00:00
|
|
|
{
|
|
|
|
bool has_contents = false;
|
|
|
|
BufferView * bv = mi.base.bv;
|
|
|
|
MathData * ar = const_cast<MathData*>(this);
|
|
|
|
ar->updateMacros(&bv->cursor(), mi.macrocontext,
|
2016-11-28 12:13:36 +00:00
|
|
|
InternalUpdate, mi.base.macro_nesting);
|
|
|
|
|
2016-11-16 14:07:00 +00:00
|
|
|
|
|
|
|
// FIXME: for completion, try to insert the relevant data in the
|
|
|
|
// mathrow (like is done for text rows). We could add a pair of
|
|
|
|
// InsetMathColor inset, but these come with extra spacing of
|
|
|
|
// their own.
|
|
|
|
DocIterator const & inlineCompletionPos = bv->inlineCompletionPos();
|
|
|
|
bool const has_completion = inlineCompletionPos.inMathed()
|
|
|
|
&& &inlineCompletionPos.cell() == this;
|
|
|
|
size_t const compl_pos = has_completion ? inlineCompletionPos.pos() : 0;
|
|
|
|
|
|
|
|
for (size_t i = 0 ; i < size() ; ++i) {
|
|
|
|
has_contents |= (*this)[i]->addToMathRow(mrow, mi);
|
|
|
|
if (i + 1 == compl_pos) {
|
|
|
|
mrow.back().compl_text = bv->inlineCompletion();
|
|
|
|
mrow.back().compl_unique_to = bv->inlineCompletionUniqueChars();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return has_contents;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-02 16:27:32 +00:00
|
|
|
#if 0
|
2004-04-13 06:27:29 +00:00
|
|
|
namespace {
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
bool isInside(DocIterator const & it, MathData const & ar,
|
2006-10-21 00:16:43 +00:00
|
|
|
pos_type p1, pos_type p2)
|
2004-04-13 06:27:29 +00:00
|
|
|
{
|
2005-02-08 13:18:05 +00:00
|
|
|
for (size_t i = 0; i != it.depth(); ++i) {
|
2004-04-13 06:27:29 +00:00
|
|
|
CursorSlice const & sl = it[i];
|
|
|
|
if (sl.inset().inMathed() && &sl.cell() == &ar)
|
|
|
|
return p1 <= sl.pos() && sl.pos() < p2;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2013-05-02 16:27:32 +00:00
|
|
|
#endif
|
2004-04-13 06:27:29 +00:00
|
|
|
|
2007-04-17 16:49:17 +00:00
|
|
|
|
2018-05-24 09:10:25 +00:00
|
|
|
bool MathData::hasCaret(BufferView * bv) const
|
|
|
|
{
|
|
|
|
Cursor & cur = bv->cursor();
|
|
|
|
return cur.inMathed() && &cur.cell() == this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-19 11:15:43 +00:00
|
|
|
void MathData::metrics(MetricsInfo & mi, Dimension & dim, bool tight) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
2007-03-23 02:12:48 +00:00
|
|
|
frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
|
2018-04-26 22:03:48 +00:00
|
|
|
BufferView * bv = mi.base.bv;
|
2018-04-19 11:15:43 +00:00
|
|
|
int const Iascent = fm.dimension('I').ascent();
|
2018-07-19 20:16:40 +00:00
|
|
|
int xascent = fm.xHeight();
|
2018-04-19 11:15:43 +00:00
|
|
|
if (xascent >= Iascent)
|
|
|
|
xascent = (2 * Iascent) / 3;
|
2007-03-18 15:00:57 +00:00
|
|
|
minasc_ = xascent;
|
|
|
|
mindes_ = (3 * xascent) / 4;
|
|
|
|
slevel_ = (4 * xascent) / 5;
|
|
|
|
sshift_ = xascent / 4;
|
2002-08-02 14:29:42 +00:00
|
|
|
|
2016-11-16 14:07:00 +00:00
|
|
|
MathRow mrow(mi, this);
|
2018-05-24 09:10:25 +00:00
|
|
|
bool has_caret = mrow.metrics(mi, dim);
|
2018-04-26 22:03:48 +00:00
|
|
|
mrow_cache_[bv] = mrow;
|
|
|
|
kerning_ = mrow.kerning(bv);
|
2008-02-21 19:42:34 +00:00
|
|
|
|
2018-04-19 11:15:43 +00:00
|
|
|
// Set a minimal ascent/descent for the cell
|
|
|
|
if (tight)
|
|
|
|
// FIXME: this is the minimal ascent seen empirically, check
|
|
|
|
// what the TeXbook says.
|
2018-07-19 20:16:40 +00:00
|
|
|
dim.asc = max(dim.asc, fm.xHeight());
|
2018-04-19 11:15:43 +00:00
|
|
|
else {
|
|
|
|
dim.asc = max(dim.asc, fm.maxAscent());
|
|
|
|
dim.des = max(dim.des, fm.maxDescent());
|
|
|
|
}
|
|
|
|
|
2018-04-26 22:03:48 +00:00
|
|
|
// This is one of the the few points where the drawing font is known,
|
|
|
|
// so that we can set the caret vertical dimensions.
|
2018-05-24 09:10:25 +00:00
|
|
|
has_caret |= hasCaret(bv);
|
|
|
|
if (has_caret)
|
2018-04-26 22:03:48 +00:00
|
|
|
bv->setCaretAscentDescent(min(dim.asc, fm.maxAscent()),
|
|
|
|
min(dim.des, fm.maxDescent()));
|
|
|
|
|
2007-09-24 13:52:04 +00:00
|
|
|
// Cache the dimension.
|
2018-04-26 22:03:48 +00:00
|
|
|
bv->coordCache().arrays().add(this, dim);
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-22 09:43:48 +00:00
|
|
|
void MathData::drawSelection(PainterInfo & pi, int const x, int const y) const
|
|
|
|
{
|
|
|
|
BufferView const * bv = pi.base.bv;
|
|
|
|
Cursor const & cur = bv->cursor();
|
|
|
|
InsetMath const * inset = cur.inset().asInsetMath();
|
|
|
|
if (!cur.selection() || !inset || inset->nargs() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CursorSlice const s1 = cur.selBegin();
|
|
|
|
CursorSlice const s2 = cur.selEnd();
|
|
|
|
MathData const & c1 = inset->cell(s1.idx());
|
|
|
|
|
|
|
|
if (s1.idx() == s2.idx() && &c1 == this) {
|
|
|
|
// selection indide cell
|
|
|
|
Dimension const dim = bv->coordCache().getArrays().dim(&c1);
|
|
|
|
int const beg = c1.pos2x(bv, s1.pos());
|
|
|
|
int const end = c1.pos2x(bv, s2.pos());
|
|
|
|
pi.pain.fillRectangle(x + beg, y - dim.ascent(),
|
|
|
|
end - beg, dim.height(), Color_selection);
|
|
|
|
} else {
|
|
|
|
for (idx_type i = 0; i < inset->nargs(); ++i) {
|
|
|
|
MathData const & c = inset->cell(i);
|
|
|
|
if (&c == this && inset->idxBetween(i, s1.idx(), s2.idx())) {
|
|
|
|
// The whole cell is selected
|
|
|
|
Dimension const dim = bv->coordCache().getArrays().dim(&c);
|
|
|
|
pi.pain.fillRectangle(x, y - dim.ascent(),
|
|
|
|
dim.width(), dim.height(),
|
|
|
|
Color_selection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-16 14:07:00 +00:00
|
|
|
void MathData::draw(PainterInfo & pi, int const x, int const y) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
2007-04-26 16:05:57 +00:00
|
|
|
//lyxerr << "MathData::draw: x: " << x << " y: " << y << endl;
|
2017-02-24 22:25:40 +00:00
|
|
|
setXY(*pi.base.bv, x, y);
|
2004-04-13 06:27:29 +00:00
|
|
|
|
2017-02-22 09:43:48 +00:00
|
|
|
drawSelection(pi, x, y);
|
2016-11-16 14:07:00 +00:00
|
|
|
MathRow const & mrow = mrow_cache_[pi.base.bv];
|
|
|
|
mrow.draw(pi, x, y);
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
2003-05-28 13:22:36 +00:00
|
|
|
dim.clear();
|
|
|
|
Dimension d;
|
2002-08-02 14:29:42 +00:00
|
|
|
for (const_iterator it = begin(); it != end(); ++it) {
|
2003-05-28 13:22:36 +00:00
|
|
|
(*it)->metricsT(mi, d);
|
|
|
|
dim += d;
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
void MathData::drawT(TextPainter & pain, int x, int y) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
2002-11-27 10:30:28 +00:00
|
|
|
//lyxerr << "x: " << x << " y: " << y << ' ' << pain.workAreaHeight() << endl;
|
2006-10-13 16:44:44 +00:00
|
|
|
|
2006-10-16 09:08:05 +00:00
|
|
|
// FIXME: Abdel 16/10/2006
|
|
|
|
// This drawT() method is never used, this is dead code.
|
2002-08-02 14:29:42 +00:00
|
|
|
|
|
|
|
for (const_iterator it = begin(), et = end(); it != et; ++it) {
|
|
|
|
(*it)->drawT(pain, x, y);
|
2004-08-13 22:39:39 +00:00
|
|
|
//x += (*it)->width_;
|
2004-02-02 17:32:56 +00:00
|
|
|
x += 2;
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-03 22:13:45 +00:00
|
|
|
void MathData::updateBuffer(ParIterator const & it, UpdateType utype)
|
2010-01-28 17:37:22 +00:00
|
|
|
{
|
|
|
|
// pass down
|
|
|
|
for (size_t i = 0, n = size(); i != n; ++i) {
|
|
|
|
MathAtom & at = operator[](i);
|
2010-03-03 22:13:45 +00:00
|
|
|
at.nucleus()->updateBuffer(it, utype);
|
2010-01-28 17:37:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-07 11:57:08 +00:00
|
|
|
void MathData::updateMacros(Cursor * cur, MacroContext const & mc,
|
2016-11-28 12:13:36 +00:00
|
|
|
UpdateType utype, int nesting)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2009-11-15 23:54:45 +00:00
|
|
|
// If we are editing a macro, we cannot update it immediately,
|
2009-11-16 14:11:25 +00:00
|
|
|
// otherwise wrong undo steps will be recorded (bug 6208).
|
2009-11-15 23:54:45 +00:00
|
|
|
InsetMath const * inmath = cur ? cur->inset().asInsetMath() : 0;
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro const * inmacro = inmath ? inmath->asMacro() : 0;
|
2009-11-15 23:54:45 +00:00
|
|
|
docstring const edited_name = inmacro ? inmacro->name() : docstring();
|
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// go over the array and look for macros
|
|
|
|
for (size_t i = 0; i < size(); ++i) {
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro * macroInset = operator[](i).nucleus()->asMacro();
|
2015-04-02 19:20:32 +00:00
|
|
|
if (!macroInset || macroInset->macroName().empty()
|
|
|
|
|| macroInset->macroName()[0] == '^'
|
|
|
|
|| macroInset->macroName()[0] == '_'
|
2010-05-04 16:16:20 +00:00
|
|
|
|| (macroInset->name() == edited_name
|
|
|
|
&& macroInset->displayMode() ==
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::DISPLAY_UNFOLDED))
|
2007-11-01 11:13:07 +00:00
|
|
|
continue;
|
2009-07-08 01:48:19 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// get macro
|
2007-12-21 20:42:46 +00:00
|
|
|
macroInset->updateMacro(mc);
|
2007-11-01 11:13:07 +00:00
|
|
|
size_t macroNumArgs = 0;
|
2007-11-01 15:36:27 +00:00
|
|
|
size_t macroOptionals = 0;
|
2007-11-01 11:13:07 +00:00
|
|
|
MacroData const * macro = macroInset->macro();
|
|
|
|
if (macro) {
|
|
|
|
macroNumArgs = macro->numargs();
|
|
|
|
macroOptionals = macro->optionals();
|
|
|
|
}
|
|
|
|
|
|
|
|
// store old and compute new display mode
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro::DisplayMode newDisplayMode;
|
|
|
|
InsetMathMacro::DisplayMode oldDisplayMode = macroInset->displayMode();
|
2007-12-21 20:42:46 +00:00
|
|
|
newDisplayMode = macroInset->computeDisplayMode();
|
2007-11-01 11:13:07 +00:00
|
|
|
|
|
|
|
// arity changed or other reason to detach?
|
2017-07-05 12:31:28 +00:00
|
|
|
if (oldDisplayMode == InsetMathMacro::DISPLAY_NORMAL
|
2008-03-04 14:49:03 +00:00
|
|
|
&& (macroInset->arity() != macroNumArgs
|
|
|
|
|| macroInset->optionals() != macroOptionals
|
2017-07-05 12:31:28 +00:00
|
|
|
|| newDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED))
|
2007-11-01 11:13:07 +00:00
|
|
|
detachMacroParameters(cur, i);
|
|
|
|
|
|
|
|
// the macro could have been copied while resizing this
|
|
|
|
macroInset = operator[](i).nucleus()->asMacro();
|
|
|
|
|
|
|
|
// Cursor in \label?
|
2017-07-05 12:31:28 +00:00
|
|
|
if (newDisplayMode != InsetMathMacro::DISPLAY_UNFOLDED
|
|
|
|
&& oldDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED) {
|
2007-11-01 11:13:07 +00:00
|
|
|
// put cursor in front of macro
|
2007-12-21 20:42:46 +00:00
|
|
|
if (cur) {
|
|
|
|
int macroSlice = cur->find(macroInset);
|
|
|
|
if (macroSlice != -1)
|
|
|
|
cur->cutOff(macroSlice - 1);
|
|
|
|
}
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// update the display mode
|
2008-03-04 14:49:03 +00:00
|
|
|
size_t appetite = macroInset->appetite();
|
2007-11-01 11:13:07 +00:00
|
|
|
macroInset->setDisplayMode(newDisplayMode);
|
|
|
|
|
|
|
|
// arity changed?
|
2017-07-05 12:31:28 +00:00
|
|
|
if (newDisplayMode == InsetMathMacro::DISPLAY_NORMAL
|
2008-03-04 14:49:03 +00:00
|
|
|
&& (macroInset->arity() != macroNumArgs
|
|
|
|
|| macroInset->optionals() != macroOptionals)) {
|
2007-11-01 11:13:07 +00:00
|
|
|
// is it a virgin macro which was never attached to parameters?
|
|
|
|
bool fromInitToNormalMode
|
2017-07-05 12:31:28 +00:00
|
|
|
= (oldDisplayMode == InsetMathMacro::DISPLAY_INIT
|
|
|
|
|| oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT)
|
|
|
|
&& newDisplayMode == InsetMathMacro::DISPLAY_NORMAL;
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// if the macro was entered interactively (i.e. not by paste or during
|
|
|
|
// loading), it should not be greedy, but the cursor should
|
|
|
|
// automatically jump into the macro when behind
|
2017-07-05 12:31:28 +00:00
|
|
|
bool interactive = (oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT);
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// attach parameters
|
|
|
|
attachMacroParameters(cur, i, macroNumArgs, macroOptionals,
|
2008-03-04 14:49:03 +00:00
|
|
|
fromInitToNormalMode, interactive, appetite);
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2015-08-29 00:51:38 +00:00
|
|
|
if (cur)
|
2007-12-21 20:42:46 +00:00
|
|
|
cur->updateInsets(&cur->bottom().inset());
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// Give macro the chance to adapt to new situation.
|
2015-03-15 17:20:01 +00:00
|
|
|
// The macroInset could be invalid now because it was put into a script
|
2007-11-14 17:33:49 +00:00
|
|
|
// inset and therefore "deep" copied. So get it again from the MathData.
|
2007-11-01 11:13:07 +00:00
|
|
|
InsetMath * inset = operator[](i).nucleus();
|
|
|
|
if (inset->asScriptInset())
|
|
|
|
inset = inset->asScriptInset()->nuc()[0].nucleus();
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(inset->asMacro(), continue);
|
2016-11-28 12:13:36 +00:00
|
|
|
inset->asMacro()->updateRepresentation(cur, mc, utype, nesting + 1);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-03 11:00:21 +00:00
|
|
|
void MathData::detachMacroParameters(DocIterator * cur, const size_type macroPos)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
|
2015-11-03 14:20:09 +00:00
|
|
|
// We store this now, because the inset pointer will be invalidated in the scond loop below
|
|
|
|
size_t const optionals = macroInset->optionals();
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// detach all arguments
|
2007-12-12 19:28:07 +00:00
|
|
|
vector<MathData> detachedArgs;
|
2007-11-01 11:13:07 +00:00
|
|
|
if (macroPos + 1 == size())
|
2007-12-21 20:42:46 +00:00
|
|
|
// strip arguments if we are at the MathData end
|
|
|
|
macroInset->detachArguments(detachedArgs, true);
|
2007-11-01 11:13:07 +00:00
|
|
|
else
|
2007-12-21 20:42:46 +00:00
|
|
|
macroInset->detachArguments(detachedArgs, false);
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// find cursor slice
|
2007-12-21 20:42:46 +00:00
|
|
|
int curMacroSlice = -1;
|
|
|
|
if (cur)
|
|
|
|
curMacroSlice = cur->find(macroInset);
|
2007-11-01 15:36:27 +00:00
|
|
|
idx_type curMacroIdx = -1;
|
|
|
|
pos_type curMacroPos = -1;
|
2007-12-12 19:28:07 +00:00
|
|
|
vector<CursorSlice> argSlices;
|
2007-11-01 11:13:07 +00:00
|
|
|
if (curMacroSlice != -1) {
|
2007-12-21 20:42:46 +00:00
|
|
|
curMacroPos = (*cur)[curMacroSlice].pos();
|
|
|
|
curMacroIdx = (*cur)[curMacroSlice].idx();
|
|
|
|
cur->cutOff(curMacroSlice, argSlices);
|
|
|
|
cur->pop_back();
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
|
|
|
// only [] after the last non-empty argument can be dropped later
|
2007-11-01 11:13:07 +00:00
|
|
|
size_t lastNonEmptyOptional = 0;
|
2015-11-03 14:20:09 +00:00
|
|
|
for (size_t l = 0; l < detachedArgs.size() && l < optionals; ++l) {
|
2007-12-21 20:42:46 +00:00
|
|
|
if (!detachedArgs[l].empty())
|
|
|
|
lastNonEmptyOptional = l;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// optional arguments to be put back?
|
2007-11-01 15:36:27 +00:00
|
|
|
pos_type p = macroPos + 1;
|
2007-11-01 11:13:07 +00:00
|
|
|
size_t j = 0;
|
2015-11-08 20:52:45 +00:00
|
|
|
// We do not want to use macroInset below, the insert() call in
|
|
|
|
// the loop will invalidate it.
|
|
|
|
macroInset = 0;
|
2015-11-03 14:20:09 +00:00
|
|
|
for (; j < detachedArgs.size() && j < optionals; ++j) {
|
2007-11-01 11:13:07 +00:00
|
|
|
// another non-empty parameter follows?
|
|
|
|
bool canDropEmptyOptional = j >= lastNonEmptyOptional;
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// then we can drop empty optional parameters
|
|
|
|
if (detachedArgs[j].empty() && canDropEmptyOptional) {
|
|
|
|
if (curMacroIdx == j)
|
2007-12-21 20:42:46 +00:00
|
|
|
(*cur)[curMacroSlice - 1].pos() = macroPos + 1;
|
2007-11-01 11:13:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// Otherwise we don't drop an empty optional, put it back normally
|
|
|
|
MathData optarg;
|
|
|
|
asArray(from_ascii("[]"), optarg);
|
|
|
|
MathData & arg = detachedArgs[j];
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// look for "]", i.e. put a brace around?
|
|
|
|
InsetMathBrace * brace = 0;
|
|
|
|
for (size_t q = 0; q < arg.size(); ++q) {
|
|
|
|
if (arg[q]->getChar() == ']') {
|
|
|
|
// put brace
|
2010-01-03 11:00:21 +00:00
|
|
|
brace = new InsetMathBrace(buffer_);
|
2007-11-01 11:13:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// put arg between []
|
|
|
|
if (brace) {
|
|
|
|
brace->cell(0) = arg;
|
|
|
|
optarg.insert(1, MathAtom(brace));
|
|
|
|
} else
|
|
|
|
optarg.insert(1, arg);
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// insert it into the array
|
|
|
|
insert(p, optarg);
|
|
|
|
p += optarg.size();
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// cursor in macro?
|
|
|
|
if (curMacroSlice == -1)
|
|
|
|
continue;
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// cursor in optional argument of macro?
|
|
|
|
if (curMacroIdx == j) {
|
|
|
|
if (brace) {
|
2007-12-21 20:42:46 +00:00
|
|
|
cur->append(0, curMacroPos);
|
|
|
|
(*cur)[curMacroSlice - 1].pos() = macroPos + 2;
|
2007-11-01 11:13:07 +00:00
|
|
|
} else
|
2007-12-21 20:42:46 +00:00
|
|
|
(*cur)[curMacroSlice - 1].pos() = macroPos + 2 + curMacroPos;
|
|
|
|
cur->append(argSlices);
|
|
|
|
} else if ((*cur)[curMacroSlice - 1].pos() >= int(p))
|
2007-11-01 11:13:07 +00:00
|
|
|
// cursor right of macro
|
2007-12-21 20:42:46 +00:00
|
|
|
(*cur)[curMacroSlice - 1].pos() += optarg.size();
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// put them back into the MathData
|
2007-11-14 17:33:49 +00:00
|
|
|
for (; j < detachedArgs.size(); ++j, ++p) {
|
2007-11-01 11:13:07 +00:00
|
|
|
MathData const & arg = detachedArgs[j];
|
2015-03-15 17:20:01 +00:00
|
|
|
if (arg.size() == 1
|
2007-12-21 20:42:46 +00:00
|
|
|
&& !arg[0]->asScriptInset()
|
|
|
|
&& !(arg[0]->asMacro() && arg[0]->asMacro()->arity() > 0))
|
2007-11-01 11:13:07 +00:00
|
|
|
insert(p, arg[0]);
|
|
|
|
else
|
|
|
|
insert(p, MathAtom(new InsetMathBrace(arg)));
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// cursor in macro?
|
|
|
|
if (curMacroSlice == -1)
|
|
|
|
continue;
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// cursor in j-th argument of macro?
|
2007-11-01 15:36:27 +00:00
|
|
|
if (curMacroIdx == j) {
|
2007-11-01 11:13:07 +00:00
|
|
|
if (operator[](p).nucleus()->asBraceInset()) {
|
2007-12-21 20:42:46 +00:00
|
|
|
(*cur)[curMacroSlice - 1].pos() = p;
|
|
|
|
cur->append(0, curMacroPos);
|
|
|
|
cur->append(argSlices);
|
2007-11-01 11:13:07 +00:00
|
|
|
} else {
|
2007-12-21 20:42:46 +00:00
|
|
|
(*cur)[curMacroSlice - 1].pos() = p; // + macroPos;
|
|
|
|
cur->append(argSlices);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2007-12-21 20:42:46 +00:00
|
|
|
} else if ((*cur)[curMacroSlice - 1].pos() >= int(p))
|
|
|
|
++(*cur)[curMacroSlice - 1].pos();
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2010-01-03 11:00:21 +00:00
|
|
|
if (cur)
|
2007-12-21 20:42:46 +00:00
|
|
|
cur->updateInsets(&cur->bottom().inset());
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-15 17:20:01 +00:00
|
|
|
void MathData::attachMacroParameters(Cursor * cur,
|
2007-11-01 11:13:07 +00:00
|
|
|
const size_type macroPos, const size_type macroNumArgs,
|
2007-11-01 14:40:15 +00:00
|
|
|
const int macroOptionals, const bool fromInitToNormalMode,
|
2008-03-04 14:49:03 +00:00
|
|
|
const bool interactiveInit, const size_t appetite)
|
2007-11-01 11:13:07 +00:00
|
|
|
{
|
2017-07-05 12:31:28 +00:00
|
|
|
InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
|
2007-11-01 11:13:07 +00:00
|
|
|
|
2015-03-15 17:20:01 +00:00
|
|
|
// start at atom behind the macro again, maybe with some new arguments
|
2007-11-14 17:33:49 +00:00
|
|
|
// from the detach phase above, to add them back into the macro inset
|
2007-11-01 11:13:07 +00:00
|
|
|
size_t p = macroPos + 1;
|
2007-12-12 19:28:07 +00:00
|
|
|
vector<MathData> detachedArgs;
|
2007-11-01 11:13:07 +00:00
|
|
|
MathAtom scriptToPutAround;
|
2010-05-31 23:02:04 +00:00
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// find cursor slice again of this MathData
|
2007-12-21 20:42:46 +00:00
|
|
|
int thisSlice = -1;
|
|
|
|
if (cur)
|
|
|
|
thisSlice = cur->find(*this);
|
2007-11-01 11:13:07 +00:00
|
|
|
int thisPos = -1;
|
|
|
|
if (thisSlice != -1)
|
2007-12-21 20:42:46 +00:00
|
|
|
thisPos = (*cur)[thisSlice].pos();
|
2010-05-31 23:02:04 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// find arguments behind the macro
|
2007-11-14 17:33:49 +00:00
|
|
|
if (!interactiveInit) {
|
2007-11-01 14:40:15 +00:00
|
|
|
collectOptionalParameters(cur, macroOptionals, detachedArgs, p,
|
2008-01-22 17:26:54 +00:00
|
|
|
scriptToPutAround, macroPos, thisPos, thisSlice);
|
2007-11-01 14:40:15 +00:00
|
|
|
}
|
2008-03-04 14:49:03 +00:00
|
|
|
collectParameters(cur, macroNumArgs, detachedArgs, p,
|
|
|
|
scriptToPutAround, macroPos, thisPos, thisSlice, appetite);
|
2010-05-31 23:02:04 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// attach arguments back to macro inset
|
|
|
|
macroInset->attachArguments(detachedArgs, macroNumArgs, macroOptionals);
|
2010-05-31 23:02:04 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// found tail script? E.g. \foo{a}b^x
|
|
|
|
if (scriptToPutAround.nucleus()) {
|
2010-05-31 23:20:30 +00:00
|
|
|
InsetMathScript * scriptInset =
|
|
|
|
scriptToPutAround.nucleus()->asScriptInset();
|
|
|
|
// In the math parser we remove empty braces in the base
|
|
|
|
// of a script inset, but we have to restore them here.
|
|
|
|
if (scriptInset->nuc().empty()) {
|
|
|
|
MathData ar;
|
|
|
|
scriptInset->nuc().push_back(
|
|
|
|
MathAtom(new InsetMathBrace(ar)));
|
|
|
|
}
|
2007-11-01 14:40:15 +00:00
|
|
|
// put macro into a script inset
|
2010-05-31 23:20:30 +00:00
|
|
|
scriptInset->nuc()[0] = operator[](macroPos);
|
2007-11-01 14:40:15 +00:00
|
|
|
operator[](macroPos) = scriptToPutAround;
|
2007-11-14 17:33:49 +00:00
|
|
|
|
|
|
|
// go into the script inset nucleus
|
2007-12-21 20:42:46 +00:00
|
|
|
if (cur && thisPos == int(macroPos))
|
|
|
|
cur->append(0, 0);
|
2010-05-31 23:12:07 +00:00
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// get pointer to "deep" copied macro inset
|
2010-05-31 23:20:30 +00:00
|
|
|
scriptInset = operator[](macroPos).nucleus()->asScriptInset();
|
2015-03-15 17:20:01 +00:00
|
|
|
macroInset = scriptInset->nuc()[0].nucleus()->asMacro();
|
2007-11-01 14:40:15 +00:00
|
|
|
}
|
2010-05-31 23:02:04 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// remove them from the MathData
|
2015-03-22 16:29:22 +00:00
|
|
|
erase(macroPos + 1, p);
|
2007-11-12 22:12:39 +00:00
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// cursor outside this MathData?
|
2007-11-13 07:58:52 +00:00
|
|
|
if (thisSlice == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// fix cursor if right of p
|
|
|
|
if (thisPos >= int(p))
|
2007-12-21 20:42:46 +00:00
|
|
|
(*cur)[thisSlice].pos() -= p - (macroPos + 1);
|
2010-05-31 23:12:07 +00:00
|
|
|
|
2007-11-14 17:33:49 +00:00
|
|
|
// was the macro inset just inserted interactively and was now folded
|
|
|
|
// and the cursor is just behind?
|
2007-12-21 20:42:46 +00:00
|
|
|
if ((*cur)[thisSlice].pos() == int(macroPos + 1)
|
|
|
|
&& interactiveInit
|
|
|
|
&& fromInitToNormalMode
|
|
|
|
&& macroInset->arity() > 0
|
|
|
|
&& thisSlice + 1 == int(cur->depth())) {
|
2007-11-13 07:58:52 +00:00
|
|
|
// then enter it if the cursor was just behind
|
2007-12-21 20:42:46 +00:00
|
|
|
(*cur)[thisSlice].pos() = macroPos;
|
|
|
|
cur->push_back(CursorSlice(*macroInset));
|
|
|
|
macroInset->idxFirst(*cur);
|
2007-11-01 14:40:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-15 17:20:01 +00:00
|
|
|
void MathData::collectOptionalParameters(Cursor * cur,
|
|
|
|
const size_type numOptionalParams, vector<MathData> & params,
|
2008-01-22 17:26:54 +00:00
|
|
|
size_t & pos, MathAtom & scriptToPutAround,
|
|
|
|
const pos_type macroPos, const int thisPos, const int thisSlice)
|
2007-11-01 14:40:15 +00:00
|
|
|
{
|
2009-11-08 11:45:46 +00:00
|
|
|
Buffer * buf = cur ? cur->buffer() : 0;
|
2007-11-01 11:13:07 +00:00
|
|
|
// insert optional arguments?
|
2015-03-15 17:20:01 +00:00
|
|
|
while (params.size() < numOptionalParams
|
2008-01-22 17:26:54 +00:00
|
|
|
&& pos < size()
|
|
|
|
&& !scriptToPutAround.nucleus()) {
|
2007-11-01 11:13:07 +00:00
|
|
|
// is a [] block following which could be an optional parameter?
|
2007-11-01 14:40:15 +00:00
|
|
|
if (operator[](pos)->getChar() != '[')
|
|
|
|
break;
|
2015-03-15 17:20:01 +00:00
|
|
|
|
Fix display and output of math macros with optional arguments
This is a long standing issue, present since the new math macros
inception in version 1.6. It manifests as a display issue when a
macro with optional arguments appears in the optional argument of
another macro. In this case the display is messed up and it is
difficult, if not impossible, changing the arguments as they do not
appear on screen as related to a specific macro instance. It also
manifests as latex errors when compiling, even if the latex output
is formally correct, due to limitations of the xargs package used
to output the macros. Most probably, both aspects have the same
root cause, as simply enclosing in braces the macro and its
parameters solves both issues. However, when reloading a document,
lyx strips the outer braces enclosing a macro argument, thus
frustrating this possible workaround.
This commit solves the display issue by correctly accounting for
macros with optional arguments nested in the argument of another
macro, and circumvents the xargs package limitations causing errors
by enclosing in braces the macros with optional arguments appearing
in the argument of an outer macro when they are output. This means
that when loading an old document with such macros and saving it
again, the macro representation is updated and will have these
additional braces. However, as such braces are stripped by lyx on
loading, there is no risk that they accumulate.
See also this thread:
http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg197828.html
2016-12-01 17:02:47 +00:00
|
|
|
// found possible optional argument, look for pairing "]"
|
|
|
|
int count = 1;
|
2007-11-01 14:40:15 +00:00
|
|
|
size_t right = pos + 1;
|
2007-11-01 11:13:07 +00:00
|
|
|
for (; right < size(); ++right) {
|
2008-01-22 17:26:54 +00:00
|
|
|
MathAtom & cell = operator[](right);
|
|
|
|
|
Fix display and output of math macros with optional arguments
This is a long standing issue, present since the new math macros
inception in version 1.6. It manifests as a display issue when a
macro with optional arguments appears in the optional argument of
another macro. In this case the display is messed up and it is
difficult, if not impossible, changing the arguments as they do not
appear on screen as related to a specific macro instance. It also
manifests as latex errors when compiling, even if the latex output
is formally correct, due to limitations of the xargs package used
to output the macros. Most probably, both aspects have the same
root cause, as simply enclosing in braces the macro and its
parameters solves both issues. However, when reloading a document,
lyx strips the outer braces enclosing a macro argument, thus
frustrating this possible workaround.
This commit solves the display issue by correctly accounting for
macros with optional arguments nested in the argument of another
macro, and circumvents the xargs package limitations causing errors
by enclosing in braces the macros with optional arguments appearing
in the argument of an outer macro when they are output. This means
that when loading an old document with such macros and saving it
again, the macro representation is updated and will have these
additional braces. However, as such braces are stripped by lyx on
loading, there is no risk that they accumulate.
See also this thread:
http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg197828.html
2016-12-01 17:02:47 +00:00
|
|
|
if (cell->getChar() == '[')
|
|
|
|
++count;
|
|
|
|
else if (cell->getChar() == ']' && --count == 0)
|
2007-11-01 11:13:07 +00:00
|
|
|
// found right end
|
|
|
|
break;
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2008-01-22 17:26:54 +00:00
|
|
|
// maybe "]" with a script around?
|
|
|
|
InsetMathScript * script = cell.nucleus()->asScriptInset();
|
|
|
|
if (!script)
|
|
|
|
continue;
|
|
|
|
if (script->nuc().size() != 1)
|
|
|
|
continue;
|
|
|
|
if (script->nuc()[0]->getChar() == ']') {
|
|
|
|
// script will be put around the macro later
|
|
|
|
scriptToPutAround = cell;
|
|
|
|
break;
|
|
|
|
}
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// found?
|
2007-11-01 14:40:15 +00:00
|
|
|
if (right >= size()) {
|
2007-11-01 11:13:07 +00:00
|
|
|
// no ] found, so it's not an optional argument
|
|
|
|
break;
|
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// add everything between [ and ] as optional argument
|
2009-11-08 11:45:46 +00:00
|
|
|
MathData optarg(buf, begin() + pos + 1, begin() + right);
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// a brace?
|
|
|
|
bool brace = false;
|
|
|
|
if (optarg.size() == 1 && optarg[0]->asBraceInset()) {
|
|
|
|
brace = true;
|
|
|
|
params.push_back(optarg[0]->asBraceInset()->cell(0));
|
|
|
|
} else
|
|
|
|
params.push_back(optarg);
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// place cursor in optional argument of macro
|
2017-03-07 10:48:32 +00:00
|
|
|
// Note: The two expressions on the first line are equivalent
|
|
|
|
// (see caller), but making this explicit pleases coverity.
|
|
|
|
if (cur && thisSlice != -1
|
2007-12-21 20:42:46 +00:00
|
|
|
&& thisPos >= int(pos) && thisPos <= int(right)) {
|
2007-12-12 19:28:07 +00:00
|
|
|
int paramPos = max(0, thisPos - int(pos) - 1);
|
|
|
|
vector<CursorSlice> x;
|
2007-12-21 20:42:46 +00:00
|
|
|
cur->cutOff(thisSlice, x);
|
|
|
|
(*cur)[thisSlice].pos() = macroPos;
|
2007-11-01 14:40:15 +00:00
|
|
|
if (brace) {
|
|
|
|
paramPos = x[0].pos();
|
|
|
|
x.erase(x.begin());
|
|
|
|
}
|
2007-12-21 20:42:46 +00:00
|
|
|
cur->append(0, paramPos);
|
|
|
|
cur->append(x);
|
2007-11-01 14:40:15 +00:00
|
|
|
}
|
|
|
|
pos = right + 1;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// fill up empty optional parameters
|
2007-12-21 20:42:46 +00:00
|
|
|
while (params.size() < numOptionalParams)
|
2015-03-15 17:20:01 +00:00
|
|
|
params.push_back(MathData());
|
2007-11-01 14:40:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-15 17:20:01 +00:00
|
|
|
void MathData::collectParameters(Cursor * cur,
|
|
|
|
const size_type numParams, vector<MathData> & params,
|
2007-11-01 14:40:15 +00:00
|
|
|
size_t & pos, MathAtom & scriptToPutAround,
|
2008-03-04 14:49:03 +00:00
|
|
|
const pos_type macroPos, const int thisPos, const int thisSlice,
|
2015-03-15 17:20:01 +00:00
|
|
|
const size_t appetite)
|
2007-11-01 14:40:15 +00:00
|
|
|
{
|
2008-03-04 14:49:03 +00:00
|
|
|
size_t startSize = params.size();
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// insert normal arguments
|
2008-01-22 17:26:54 +00:00
|
|
|
while (params.size() < numParams
|
2008-03-04 14:49:03 +00:00
|
|
|
&& params.size() - startSize < appetite
|
2008-01-22 17:26:54 +00:00
|
|
|
&& pos < size()
|
|
|
|
&& !scriptToPutAround.nucleus()) {
|
2007-11-01 14:40:15 +00:00
|
|
|
MathAtom & cell = operator[](pos);
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// fix cursor
|
2007-12-12 19:28:07 +00:00
|
|
|
vector<CursorSlice> argSlices;
|
2007-11-01 11:13:07 +00:00
|
|
|
int argPos = 0;
|
2017-03-07 10:56:59 +00:00
|
|
|
// Note: The two expressions on the first line are equivalent
|
|
|
|
// (see caller), but making this explicit pleases coverity.
|
|
|
|
if (cur && thisSlice != -1
|
|
|
|
&& thisPos == int(pos))
|
2015-03-15 17:20:01 +00:00
|
|
|
cur->cutOff(thisSlice, argSlices);
|
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
// which kind of parameter is it? In {}? With index x^n?
|
2007-11-01 11:13:07 +00:00
|
|
|
InsetMathBrace const * brace = cell->asBraceInset();
|
|
|
|
if (brace) {
|
|
|
|
// found brace, convert into argument
|
2007-11-01 14:40:15 +00:00
|
|
|
params.push_back(brace->cell(0));
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// cursor inside of the brace or just in front of?
|
2007-11-01 14:40:15 +00:00
|
|
|
if (thisPos == int(pos) && !argSlices.empty()) {
|
2007-11-01 11:13:07 +00:00
|
|
|
argPos = argSlices[0].pos();
|
|
|
|
argSlices.erase(argSlices.begin());
|
|
|
|
}
|
2007-11-01 14:40:15 +00:00
|
|
|
} else if (cell->asScriptInset() && params.size() + 1 == numParams) {
|
2007-11-01 11:13:07 +00:00
|
|
|
// last inset with scripts without braces
|
|
|
|
// -> they belong to the macro, not the argument
|
|
|
|
InsetMathScript * script = cell.nucleus()->asScriptInset();
|
|
|
|
if (script->nuc().size() == 1 && script->nuc()[0]->asBraceInset())
|
|
|
|
// nucleus in brace? Unpack!
|
2007-11-01 14:40:15 +00:00
|
|
|
params.push_back(script->nuc()[0]->asBraceInset()->cell(0));
|
2007-11-01 11:13:07 +00:00
|
|
|
else
|
2007-11-01 14:40:15 +00:00
|
|
|
params.push_back(script->nuc());
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// script will be put around below
|
|
|
|
scriptToPutAround = cell;
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// this should only happen after loading, so make cursor handling simple
|
2007-11-01 14:40:15 +00:00
|
|
|
if (thisPos >= int(macroPos) && thisPos <= int(macroPos + numParams)) {
|
2007-11-01 11:13:07 +00:00
|
|
|
argSlices.clear();
|
2007-12-21 20:42:46 +00:00
|
|
|
if (cur)
|
|
|
|
cur->append(0, 0);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
2007-11-01 14:40:15 +00:00
|
|
|
// the simplest case: plain inset
|
2007-11-01 11:13:07 +00:00
|
|
|
MathData array;
|
|
|
|
array.insert(0, cell);
|
2007-11-01 14:40:15 +00:00
|
|
|
params.push_back(array);
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 11:13:07 +00:00
|
|
|
// put cursor in argument again
|
2017-03-08 15:50:03 +00:00
|
|
|
// Note: The first two expressions on the first line are
|
|
|
|
// equivalent (see caller), but making this explicit pleases
|
|
|
|
// coverity.
|
|
|
|
if (cur && thisSlice != -1 && thisPos == int(pos)) {
|
2007-12-21 20:42:46 +00:00
|
|
|
cur->append(params.size() - 1, argPos);
|
|
|
|
cur->append(argSlices);
|
|
|
|
(*cur)[thisSlice].pos() = macroPos;
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
2015-03-15 17:20:01 +00:00
|
|
|
|
2007-11-01 14:40:15 +00:00
|
|
|
++pos;
|
2015-03-15 17:20:01 +00:00
|
|
|
}
|
2007-11-01 11:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-12-24 10:52:58 +00:00
|
|
|
int MathData::pos2x(BufferView const * bv, size_type pos) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
|
|
|
int x = 0;
|
2003-04-14 06:17:19 +00:00
|
|
|
size_type target = min(pos, size());
|
2015-10-12 14:11:58 +00:00
|
|
|
CoordCache::Insets const & coords = bv->coordCache().getInsets();
|
2003-04-14 06:17:19 +00:00
|
|
|
for (size_type i = 0; i < target; ++i) {
|
2002-08-02 14:29:42 +00:00
|
|
|
const_iterator it = begin() + i;
|
2004-02-03 14:29:00 +00:00
|
|
|
//lyxerr << "char: " << (*it)->getChar()
|
2007-12-12 19:28:07 +00:00
|
|
|
// << "width: " << (*it)->width() << endl;
|
2007-12-24 10:52:58 +00:00
|
|
|
x += coords.dim((*it).nucleus()).wid;
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-12-24 10:52:58 +00:00
|
|
|
MathData::size_type MathData::x2pos(BufferView const * bv, int targetx) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
2003-04-14 06:17:19 +00:00
|
|
|
const_iterator it = begin();
|
2002-08-02 14:29:42 +00:00
|
|
|
int lastx = 0;
|
|
|
|
int currx = 0;
|
2015-10-12 14:11:58 +00:00
|
|
|
CoordCache::Insets const & coords = bv->coordCache().getInsets();
|
2006-02-24 14:41:48 +00:00
|
|
|
// find first position after targetx
|
2015-03-22 16:29:22 +00:00
|
|
|
for (; currx < targetx && it != end(); ++it) {
|
2002-08-02 14:29:42 +00:00
|
|
|
lastx = currx;
|
2007-12-24 10:52:58 +00:00
|
|
|
currx += coords.dim((*it).nucleus()).wid;
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
2005-04-02 14:19:31 +00:00
|
|
|
|
2006-04-05 23:56:29 +00:00
|
|
|
/**
|
2006-02-24 14:41:48 +00:00
|
|
|
* If we are not at the beginning of the array, go to the left
|
|
|
|
* of the inset if one of the following two condition holds:
|
|
|
|
* - the current inset is editable (so that the cursor tip is
|
|
|
|
* deeper than us): in this case, we want all intermediate
|
|
|
|
* cursor slices to be before insets;
|
|
|
|
* - the mouse is closer to the left side of the inset than to
|
|
|
|
* the right one.
|
2006-04-05 23:56:29 +00:00
|
|
|
* See bug 1918 for details.
|
2006-02-24 14:41:48 +00:00
|
|
|
**/
|
2006-03-14 14:47:24 +00:00
|
|
|
if (it != begin() && currx >= targetx
|
2015-05-15 22:05:23 +00:00
|
|
|
&& ((*prev(it, 1))->asNestInset()
|
2006-02-24 14:41:48 +00:00
|
|
|
|| abs(lastx - targetx) < abs(currx - targetx))) {
|
2002-08-02 14:29:42 +00:00
|
|
|
--it;
|
2005-09-26 10:34:24 +00:00
|
|
|
}
|
2005-04-26 11:12:20 +00:00
|
|
|
|
2002-08-02 14:29:42 +00:00
|
|
|
return it - begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
int MathData::dist(BufferView const & bv, int x, int y) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
2007-09-24 13:52:04 +00:00
|
|
|
return bv.coordCache().getArrays().squareDistance(this, x, y);
|
|
|
|
}
|
2002-08-02 14:29:42 +00:00
|
|
|
|
2004-08-14 14:03:42 +00:00
|
|
|
|
2007-09-24 13:52:04 +00:00
|
|
|
void MathData::setXY(BufferView & bv, int x, int y) const
|
|
|
|
{
|
2007-12-12 19:28:07 +00:00
|
|
|
//lyxerr << "setting position cache for MathData " << this << endl;
|
2007-09-24 13:52:04 +00:00
|
|
|
bv.coordCache().arrays().add(this, x, y);
|
|
|
|
}
|
2002-08-02 14:29:42 +00:00
|
|
|
|
|
|
|
|
2007-09-24 13:52:04 +00:00
|
|
|
Dimension const & MathData::dimension(BufferView const & bv) const
|
|
|
|
{
|
|
|
|
return bv.coordCache().getArrays().dim(this);
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-24 13:52:04 +00:00
|
|
|
int MathData::xm(BufferView const & bv) const
|
2002-08-02 14:29:42 +00:00
|
|
|
{
|
2007-09-24 13:52:04 +00:00
|
|
|
Geometry const & g = bv.coordCache().getArrays().geometry(this);
|
|
|
|
|
|
|
|
return g.pos.x_ + g.dim.wid / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int MathData::ym(BufferView const & bv) const
|
|
|
|
{
|
|
|
|
Geometry const & g = bv.coordCache().getArrays().geometry(this);
|
|
|
|
|
|
|
|
return g.pos.y_ + (g.dim.des - g.dim.asc) / 2;
|
2004-08-14 14:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
int MathData::xo(BufferView const & bv) const
|
2004-08-14 14:03:42 +00:00
|
|
|
{
|
2006-10-13 16:44:44 +00:00
|
|
|
return bv.coordCache().getArrays().x(this);
|
2002-08-02 14:29:42 +00:00
|
|
|
}
|
2004-08-14 14:03:42 +00:00
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
int MathData::yo(BufferView const & bv) const
|
2004-08-14 14:03:42 +00:00
|
|
|
{
|
2006-10-13 16:44:44 +00:00
|
|
|
return bv.coordCache().getArrays().y(this);
|
2004-08-14 14:03:42 +00:00
|
|
|
}
|
2006-10-19 16:51:30 +00:00
|
|
|
|
|
|
|
|
2017-01-03 19:17:20 +00:00
|
|
|
MathClass MathData::mathClass() const
|
|
|
|
{
|
|
|
|
MathClass res = MC_UNKNOWN;
|
|
|
|
for (MathAtom const & at : *this) {
|
|
|
|
MathClass mc = at->mathClass();
|
|
|
|
if (res == MC_UNKNOWN)
|
|
|
|
res = mc;
|
|
|
|
else if (mc != MC_UNKNOWN && res != mc)
|
|
|
|
return MC_ORD;
|
|
|
|
}
|
|
|
|
return res == MC_UNKNOWN ? MC_ORD : res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-12-12 19:28:07 +00:00
|
|
|
ostream & operator<<(ostream & os, MathData const & ar)
|
2006-10-19 16:51:30 +00:00
|
|
|
{
|
2006-10-21 00:16:43 +00:00
|
|
|
odocstringstream oss;
|
2006-10-19 16:51:30 +00:00
|
|
|
NormalStream ns(oss);
|
|
|
|
ns << ar;
|
2006-10-21 00:16:43 +00:00
|
|
|
return os << to_utf8(oss.str());
|
2006-10-19 16:51:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 16:05:57 +00:00
|
|
|
odocstream & operator<<(odocstream & os, MathData const & ar)
|
2006-10-19 16:51:30 +00:00
|
|
|
{
|
|
|
|
NormalStream ns(os);
|
|
|
|
ns << ar;
|
|
|
|
return os;
|
|
|
|
}
|
2006-10-21 00:16:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
} // namespace lyx
|