mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-29 05:01:49 +00:00
* dynamic macros as described in http://1stein.org/download/dynmacro.pdf
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21328 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
2ad61c0366
commit
1231489798
108
src/Buffer.cpp
108
src/Buffer.cpp
@ -4,6 +4,7 @@
|
|||||||
* Licence details can be found in the file COPYING.
|
* Licence details can be found in the file COPYING.
|
||||||
*
|
*
|
||||||
* \author Lars Gullik Bjønnes
|
* \author Lars Gullik Bjønnes
|
||||||
|
* \author Stefan Schimanski
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* Full author contact details are available in file CREDITS.
|
||||||
*/
|
*/
|
||||||
@ -68,8 +69,8 @@
|
|||||||
#include "insets/InsetInclude.h"
|
#include "insets/InsetInclude.h"
|
||||||
#include "insets/InsetText.h"
|
#include "insets/InsetText.h"
|
||||||
|
|
||||||
#include "mathed/MathMacroTemplate.h"
|
|
||||||
#include "mathed/MacroTable.h"
|
#include "mathed/MacroTable.h"
|
||||||
|
#include "mathed/MathMacroTemplate.h"
|
||||||
#include "mathed/MathSupport.h"
|
#include "mathed/MathSupport.h"
|
||||||
|
|
||||||
#include "frontends/alert.h"
|
#include "frontends/alert.h"
|
||||||
@ -200,12 +201,14 @@ public:
|
|||||||
/// our Text that should be wrapped in an InsetText
|
/// our Text that should be wrapped in an InsetText
|
||||||
InsetText inset;
|
InsetText inset;
|
||||||
|
|
||||||
///
|
|
||||||
MacroTable macros;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
TocBackend toc_backend;
|
TocBackend toc_backend;
|
||||||
|
|
||||||
|
/// macro table
|
||||||
|
typedef std::map<unsigned int, MacroData, std::greater<int> > PositionToMacroMap;
|
||||||
|
typedef std::map<docstring, PositionToMacroMap> NameToPositionMacroMap;
|
||||||
|
NameToPositionMacroMap macros;
|
||||||
|
|
||||||
/// Container for all sort of Buffer dependant errors.
|
/// Container for all sort of Buffer dependant errors.
|
||||||
map<string, ErrorList> errorLists;
|
map<string, ErrorList> errorLists;
|
||||||
|
|
||||||
@ -823,10 +826,6 @@ Buffer::ReadStatus Buffer::readFile(Lexer & lex, FileName const & filename,
|
|||||||
from_utf8(filename.absFilename())));
|
from_utf8(filename.absFilename())));
|
||||||
}
|
}
|
||||||
|
|
||||||
//lyxerr << "removing " << MacroTable::localMacros().size()
|
|
||||||
// << " temporary macro entries" << endl;
|
|
||||||
//MacroTable::localMacros().clear();
|
|
||||||
|
|
||||||
pimpl_->file_fully_loaded = true;
|
pimpl_->file_fully_loaded = true;
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -1725,7 +1724,7 @@ void Buffer::setParentName(string const & name)
|
|||||||
Buffer const * Buffer::masterBuffer() const
|
Buffer const * Buffer::masterBuffer() const
|
||||||
{
|
{
|
||||||
if (!params().parentname.empty()
|
if (!params().parentname.empty()
|
||||||
&& theBufferList().exists(params().parentname)) {
|
&& theBufferList().exists(params().parentname)) {
|
||||||
Buffer const * buf = theBufferList().getBuffer(params().parentname);
|
Buffer const * buf = theBufferList().getBuffer(params().parentname);
|
||||||
//We need to check if the parent is us...
|
//We need to check if the parent is us...
|
||||||
//FIXME RECURSIVE INCLUDE
|
//FIXME RECURSIVE INCLUDE
|
||||||
@ -1754,44 +1753,103 @@ Buffer * Buffer::masterBuffer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MacroData const & Buffer::getMacro(docstring const & name) const
|
bool Buffer::hasMacro(docstring const & name, Paragraph const & par) const
|
||||||
{
|
{
|
||||||
return pimpl_->macros.get(name);
|
Impl::PositionToMacroMap::iterator it;
|
||||||
|
it = pimpl_->macros[name].upper_bound(par.macrocontextPosition());
|
||||||
|
if( it != pimpl_->macros[name].end() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If there is a master buffer, query that
|
||||||
|
const Buffer *master = masterBuffer();
|
||||||
|
if (master && master!=this)
|
||||||
|
return master->hasMacro(name);
|
||||||
|
|
||||||
|
return MacroTable::globalMacros().has(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Buffer::hasMacro(docstring const & name) const
|
bool Buffer::hasMacro(docstring const & name) const
|
||||||
{
|
{
|
||||||
return pimpl_->macros.has(name);
|
if( !pimpl_->macros[name].empty() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If there is a master buffer, query that
|
||||||
|
const Buffer *master = masterBuffer();
|
||||||
|
if (master && master!=this)
|
||||||
|
return master->hasMacro(name);
|
||||||
|
|
||||||
|
return MacroTable::globalMacros().has(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Buffer::insertMacro(docstring const & name, MacroData const & data)
|
MacroData const & Buffer::getMacro(docstring const & name, Paragraph const & par) const
|
||||||
{
|
{
|
||||||
MacroTable::globalMacros().insert(name, data);
|
Impl::PositionToMacroMap::iterator it;
|
||||||
pimpl_->macros.insert(name, data);
|
it = pimpl_->macros[name].upper_bound(par.macrocontextPosition());
|
||||||
|
if( it != pimpl_->macros[name].end() )
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
// If there is a master buffer, query that
|
||||||
|
const Buffer *master = masterBuffer();
|
||||||
|
if (master && master!=this)
|
||||||
|
return master->getMacro(name);
|
||||||
|
|
||||||
|
return MacroTable::globalMacros().get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Buffer::buildMacros()
|
MacroData const & Buffer::getMacro(docstring const & name) const
|
||||||
{
|
{
|
||||||
// Start with global table.
|
Impl::PositionToMacroMap::iterator it;
|
||||||
pimpl_->macros = MacroTable::globalMacros();
|
it = pimpl_->macros[name].begin();
|
||||||
|
if( it != pimpl_->macros[name].end() )
|
||||||
|
return it->second;
|
||||||
|
|
||||||
// Now add our own.
|
// If there is a master buffer, query that
|
||||||
ParagraphList const & pars = text().paragraphs();
|
const Buffer *master = masterBuffer();
|
||||||
|
if (master && master!=this)
|
||||||
|
return master->getMacro(name);
|
||||||
|
|
||||||
|
return MacroTable::globalMacros().get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Buffer::updateMacros()
|
||||||
|
{
|
||||||
|
// start with empty table
|
||||||
|
pimpl_->macros = Impl::NameToPositionMacroMap();
|
||||||
|
|
||||||
|
// Iterate over buffer
|
||||||
|
ParagraphList & pars = text().paragraphs();
|
||||||
for (size_t i = 0, n = pars.size(); i != n; ++i) {
|
for (size_t i = 0, n = pars.size(); i != n; ++i) {
|
||||||
|
// set position again
|
||||||
|
pars[i].setMacrocontextPosition(i);
|
||||||
|
|
||||||
//lyxerr << "searching main par " << i
|
//lyxerr << "searching main par " << i
|
||||||
// << " for macro definitions" << std::endl;
|
// << " for macro definitions" << std::endl;
|
||||||
InsetList const & insets = pars[i].insetList();
|
InsetList const & insets = pars[i].insetList();
|
||||||
InsetList::const_iterator it = insets.begin();
|
InsetList::const_iterator it = insets.begin();
|
||||||
InsetList::const_iterator end = insets.end();
|
InsetList::const_iterator end = insets.end();
|
||||||
for ( ; it != end; ++it) {
|
for ( ; it != end; ++it) {
|
||||||
//lyxerr << "found inset code " << it->inset->lyxCode() << std::endl;
|
if (it->inset->lyxCode() != MATHMACRO_CODE)
|
||||||
if (it->inset->lyxCode() == MATHMACRO_CODE) {
|
continue;
|
||||||
MathMacroTemplate const & mac
|
|
||||||
= static_cast<MathMacroTemplate const &>(*it->inset);
|
// get macro data
|
||||||
insertMacro(mac.name(), mac.asMacroData());
|
MathMacroTemplate const & macroTemplate
|
||||||
|
= static_cast<MathMacroTemplate const &>(*it->inset);
|
||||||
|
|
||||||
|
// valid?
|
||||||
|
if (macroTemplate.validMacro()) {
|
||||||
|
MacroData macro = macroTemplate.asMacroData();
|
||||||
|
|
||||||
|
// redefinition?
|
||||||
|
// call hasMacro here instead of directly querying mc to
|
||||||
|
// also take the master document into consideration
|
||||||
|
macro.setRedefinition(hasMacro(macroTemplate.name()));
|
||||||
|
|
||||||
|
// register macro (possibly overwrite the previous one of this paragraph)
|
||||||
|
pimpl_->macros[macroTemplate.name()][i] = macro;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/Buffer.h
15
src/Buffer.h
@ -43,6 +43,7 @@ class LaTeXFeatures;
|
|||||||
class Language;
|
class Language;
|
||||||
class MacroData;
|
class MacroData;
|
||||||
class OutputParams;
|
class OutputParams;
|
||||||
|
class Paragraph;
|
||||||
class ParConstIterator;
|
class ParConstIterator;
|
||||||
class ParIterator;
|
class ParIterator;
|
||||||
class ParagraphList;
|
class ParagraphList;
|
||||||
@ -355,14 +356,16 @@ public:
|
|||||||
//
|
//
|
||||||
// Macro handling
|
// Macro handling
|
||||||
//
|
//
|
||||||
///
|
/// Collect macros in paragraphs
|
||||||
void buildMacros();
|
void updateMacros();
|
||||||
///
|
/// Look for macro defined before par (or in the master buffer)
|
||||||
|
bool hasMacro(docstring const & name, Paragraph const & par) const;
|
||||||
|
/// Look for macro defined anywhere in the buffer (or in the master buffer)
|
||||||
bool hasMacro(docstring const & name) const;
|
bool hasMacro(docstring const & name) const;
|
||||||
///
|
/// Return macro defined before par (or in the master buffer)
|
||||||
|
MacroData const & getMacro(docstring const & name, Paragraph const & par) const;
|
||||||
|
/// Return macro defined anywhere in the buffer (or in the master buffer)
|
||||||
MacroData const & getMacro(docstring const & name) const;
|
MacroData const & getMacro(docstring const & name) const;
|
||||||
///
|
|
||||||
void insertMacro(docstring const & name, MacroData const & data);
|
|
||||||
|
|
||||||
/// Replace the inset contents for insets which InsetCode is equal
|
/// Replace the inset contents for insets which InsetCode is equal
|
||||||
/// to the passed \p inset_code.
|
/// to the passed \p inset_code.
|
||||||
|
@ -507,7 +507,7 @@ void BufferView::processUpdateFlags(Update::flags flags)
|
|||||||
|
|
||||||
// Update macro store
|
// Update macro store
|
||||||
if (!(cursor().inMathed() && cursor().inMacroMode()))
|
if (!(cursor().inMathed() && cursor().inMacroMode()))
|
||||||
buffer_.buildMacros();
|
buffer_.updateMacros();
|
||||||
|
|
||||||
// Now do the first drawing step if needed. This consists on updating
|
// Now do the first drawing step if needed. This consists on updating
|
||||||
// the CoordCache in updateMetrics().
|
// the CoordCache in updateMetrics().
|
||||||
|
@ -38,17 +38,12 @@ MetricsBase::MetricsBase(BufferView * b, FontInfo const & f, int w)
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
MetricsInfo::MetricsInfo(BufferView * bv, FontInfo const & font, int textwidth,
|
||||||
MetricsInfo::MetricsInfo()
|
MacroContext const & mc)
|
||||||
|
: base(bv, font, textwidth), macrocontext(mc)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
MetricsInfo::MetricsInfo(BufferView * bv, FontInfo const & font, int textwidth)
|
|
||||||
: base(bv, font, textwidth)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PainterInfo::PainterInfo(BufferView * bv, lyx::frontend::Painter & painter)
|
PainterInfo::PainterInfo(BufferView * bv, lyx::frontend::Painter & painter)
|
||||||
: pain(painter), ltr_pos(false), erased_(false), full_repaint(true),
|
: pain(painter), ltr_pos(false), erased_(false), full_repaint(true),
|
||||||
background_color(Color_background)
|
background_color(Color_background)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* Licence details can be found in the file COPYING.
|
* Licence details can be found in the file COPYING.
|
||||||
*
|
*
|
||||||
* \author André Pönitz
|
* \author André Pönitz
|
||||||
|
* \author Stefan Schimanski
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* Full author contact details are available in file CREDITS.
|
||||||
*/
|
*/
|
||||||
@ -25,6 +26,7 @@ class BufferView;
|
|||||||
namespace lyx {
|
namespace lyx {
|
||||||
|
|
||||||
namespace frontend { class Painter; }
|
namespace frontend { class Painter; }
|
||||||
|
class MacroContext;
|
||||||
|
|
||||||
|
|
||||||
/// Standard Sizes (mode styles)
|
/// Standard Sizes (mode styles)
|
||||||
@ -72,10 +74,12 @@ public:
|
|||||||
///
|
///
|
||||||
MetricsInfo();
|
MetricsInfo();
|
||||||
///
|
///
|
||||||
MetricsInfo(BufferView * bv, FontInfo const & font, int textwidth);
|
MetricsInfo(BufferView * bv, FontInfo const & font, int textwidth, MacroContext const & mc);
|
||||||
|
|
||||||
///
|
///
|
||||||
MetricsBase base;
|
MetricsBase base;
|
||||||
|
/// The context to resolve macros
|
||||||
|
MacroContext const & macrocontext;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,6 +190,10 @@ public:
|
|||||||
///
|
///
|
||||||
ParagraphParameters params_;
|
ParagraphParameters params_;
|
||||||
|
|
||||||
|
/// position of the paragraph in the buffer. Only macros from
|
||||||
|
/// paragraphs strictly smaller are visible in this paragraph
|
||||||
|
unsigned int macrocontext_position_;
|
||||||
|
|
||||||
/// for recording and looking up changes
|
/// for recording and looking up changes
|
||||||
Changes changes_;
|
Changes changes_;
|
||||||
|
|
||||||
@ -243,6 +247,7 @@ Paragraph::Private::Private(Paragraph * owner)
|
|||||||
: owner_(owner), inset_owner_(0), begin_of_body_(0)
|
: owner_(owner), inset_owner_(0), begin_of_body_(0)
|
||||||
{
|
{
|
||||||
id_ = paragraph_id++;
|
id_ = paragraph_id++;
|
||||||
|
macrocontext_position_ = 0;
|
||||||
text_.reserve(100);
|
text_.reserve(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2489,6 +2494,18 @@ int Paragraph::checkBiblio(bool track_changes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int Paragraph::macrocontextPosition() const
|
||||||
|
{
|
||||||
|
return d->macrocontext_position_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Paragraph::setMacrocontextPosition(unsigned int pos)
|
||||||
|
{
|
||||||
|
d->macrocontext_position_ = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Paragraph::checkAuthors(AuthorList const & authorList)
|
void Paragraph::checkAuthors(AuthorList const & authorList)
|
||||||
{
|
{
|
||||||
d->changes_.checkAuthors(authorList);
|
d->changes_.checkAuthors(authorList);
|
||||||
|
@ -347,6 +347,15 @@ public:
|
|||||||
/// was previously past that position. Return 0 otherwise.
|
/// was previously past that position. Return 0 otherwise.
|
||||||
int checkBiblio(bool track_changes);
|
int checkBiblio(bool track_changes);
|
||||||
|
|
||||||
|
/// To resolve macros properly the paragraphs are numbered.
|
||||||
|
/// Every macro definition is stored with its paragraph number
|
||||||
|
/// as well. Only those macros with a smaller number become
|
||||||
|
/// visible in a paragraph (plus those in the same paragraph, but
|
||||||
|
/// in an earlier inset.
|
||||||
|
unsigned int macrocontextPosition() const;
|
||||||
|
///
|
||||||
|
void setMacrocontextPosition(unsigned int pos);
|
||||||
|
|
||||||
/// For each author, set 'used' to true if there is a change
|
/// For each author, set 'used' to true if there is a change
|
||||||
/// by this author in the paragraph.
|
/// by this author in the paragraph.
|
||||||
void checkAuthors(AuthorList const & authorList);
|
void checkAuthors(AuthorList const & authorList);
|
||||||
|
@ -1298,7 +1298,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
|
|||||||
int const nargs = s1.empty() ? 0 : convert<int>(s1);
|
int const nargs = s1.empty() ? 0 : convert<int>(s1);
|
||||||
string const s2 = token(s, ' ', 2);
|
string const s2 = token(s, ' ', 2);
|
||||||
string const type = s2.empty() ? "newcommand" : s2;
|
string const type = s2.empty() ? "newcommand" : s2;
|
||||||
cur.insert(new MathMacroTemplate(from_utf8(token(s, ' ', 0)), nargs, from_utf8(type)));
|
cur.insert(new MathMacroTemplate(from_utf8(token(s, ' ', 0)), nargs, false, from_utf8(type)));
|
||||||
//cur.nextInset()->edit(cur, true);
|
//cur.nextInset()->edit(cur, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -40,6 +40,9 @@
|
|||||||
#include "Text.h"
|
#include "Text.h"
|
||||||
#include "VSpace.h"
|
#include "VSpace.h"
|
||||||
|
|
||||||
|
#include "mathed/MacroTable.h"
|
||||||
|
#include "mathed/MathMacroTemplate.h"
|
||||||
|
|
||||||
#include "frontends/FontMetrics.h"
|
#include "frontends/FontMetrics.h"
|
||||||
#include "frontends/Painter.h"
|
#include "frontends/Painter.h"
|
||||||
|
|
||||||
@ -382,15 +385,40 @@ bool TextMetrics::redoParagraph(pit_type const pit)
|
|||||||
// FIXME: We should always use getFont(), see documentation of
|
// FIXME: We should always use getFont(), see documentation of
|
||||||
// noFontChange() in Inset.h.
|
// noFontChange() in Inset.h.
|
||||||
Font const bufferfont = buffer.params().getFont();
|
Font const bufferfont = buffer.params().getFont();
|
||||||
|
MacroContext mc(buffer, par);
|
||||||
InsetList::const_iterator ii = par.insetList().begin();
|
InsetList::const_iterator ii = par.insetList().begin();
|
||||||
InsetList::const_iterator iend = par.insetList().end();
|
InsetList::const_iterator iend = par.insetList().end();
|
||||||
for (; ii != iend; ++ii) {
|
for (; ii != iend; ++ii) {
|
||||||
|
// the macro must come here, _before_ the metric call, because
|
||||||
|
// the macro should see itself to detect recursions. To find out
|
||||||
|
// whether the macro definition is a redefinition it will look
|
||||||
|
// at the MacroData::redefinition_. So it doesn't get confused
|
||||||
|
// by the already existing macro definition of itself in the
|
||||||
|
// macro context.
|
||||||
|
if (ii->inset->lyxCode() == MATHMACRO_CODE) {
|
||||||
|
// get macro data
|
||||||
|
MathMacroTemplate const & macroTemplate
|
||||||
|
= static_cast<MathMacroTemplate const &>(*ii->inset);
|
||||||
|
|
||||||
|
// valid?
|
||||||
|
if (macroTemplate.validMacro()) {
|
||||||
|
MacroData macro = macroTemplate.asMacroData();
|
||||||
|
|
||||||
|
// redefinition?
|
||||||
|
macro.setRedefinition(mc.has(macroTemplate.name()));
|
||||||
|
|
||||||
|
// register macro (possibly overwrite the previous one of this paragraph)
|
||||||
|
mc.insert(macroTemplate.name(), macro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the metric calculation
|
||||||
Dimension dim;
|
Dimension dim;
|
||||||
int const w = max_width_ - leftMargin(max_width_, pit, ii->pos)
|
int const w = max_width_ - leftMargin(max_width_, pit, ii->pos)
|
||||||
- right_margin;
|
- right_margin;
|
||||||
Font const & font = ii->inset->noFontChange() ?
|
Font const & font = ii->inset->noFontChange() ?
|
||||||
bufferfont : getDisplayFont(pit, ii->pos);
|
bufferfont : getDisplayFont(pit, ii->pos);
|
||||||
MetricsInfo mi(bv_, font.fontInfo(), w);
|
MetricsInfo mi(bv_, font.fontInfo(), w, mc);
|
||||||
ii->inset->metrics(mi, dim);
|
ii->inset->metrics(mi, dim);
|
||||||
Dimension const old_dim = pm.insetDimension(ii->inset);
|
Dimension const old_dim = pm.insetDimension(ii->inset);
|
||||||
pm.setInsetDimension(ii->inset, dim);
|
pm.setInsetDimension(ii->inset, dim);
|
||||||
|
@ -542,18 +542,6 @@ Inset * readInset(Lexer & lex, Buffer const & buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inset->read(buf, lex);
|
inset->read(buf, lex);
|
||||||
|
|
||||||
// FIXME: hack..
|
|
||||||
if (inset->lyxCode() == MATHMACRO_CODE) {
|
|
||||||
MathMacroTemplate const * tmpl =
|
|
||||||
static_cast<MathMacroTemplate*>(inset.get());
|
|
||||||
MacroTable::globalMacros().insert
|
|
||||||
(tmpl->name(), tmpl->asMacroData());
|
|
||||||
LYXERR(Debug::DEBUG)
|
|
||||||
<< BOOST_CURRENT_FUNCTION
|
|
||||||
<< ": creating local macro " << to_utf8(tmpl->name())
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return inset.release();
|
return inset.release();
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
#include "MathSupport.h"
|
#include "MathSupport.h"
|
||||||
#include "InsetMathSqrt.h"
|
#include "InsetMathSqrt.h"
|
||||||
|
|
||||||
|
#include "InsetMathNest.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "DocIterator.h"
|
#include "DocIterator.h"
|
||||||
|
|
||||||
@ -36,20 +39,25 @@ using std::size_t;
|
|||||||
|
|
||||||
|
|
||||||
MacroData::MacroData()
|
MacroData::MacroData()
|
||||||
: numargs_(0), lockCount_(0)
|
: numargs_(0), lockCount_(0), redefinition_(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
MacroData::MacroData(docstring const & def, int numargs, docstring const & disp, string const & requires)
|
MacroData::MacroData(docstring const & definition, std::vector<docstring> const & defaults,
|
||||||
: def_(def), numargs_(numargs), disp_(disp), requires_(requires), lockCount_(0)
|
int numargs, int optionals, docstring const & display, string const & requires)
|
||||||
{}
|
: definition_(definition), numargs_(numargs), display_(display),
|
||||||
|
requires_(requires), lockCount_(0), redefinition_(false), optionals_(optionals),
|
||||||
|
defaults_(defaults)
|
||||||
|
{
|
||||||
|
defaults_.resize(optionals);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroData::expand(vector<MathData> const & args, MathData & to) const
|
void MacroData::expand(vector<MathData> const & args, MathData & to) const
|
||||||
{
|
{
|
||||||
InsetMathSqrt inset; // Hack. Any inset with a cell would do.
|
InsetMathSqrt inset; // Hack. Any inset with a cell would do.
|
||||||
// FIXME UNICODE
|
// FIXME UNICODE
|
||||||
asArray(disp_.empty() ? def_ : disp_, inset.cell(0));
|
asArray(display_.empty() ? definition_ : display_, inset.cell(0));
|
||||||
//lyxerr << "MathData::expand: args: " << args << endl;
|
//lyxerr << "MathData::expand: args: " << args << endl;
|
||||||
//lyxerr << "MathData::expand: ar: " << inset.cell(0) << endl;
|
//lyxerr << "MathData::expand: ar: " << inset.cell(0) << endl;
|
||||||
for (DocIterator it = doc_iterator_begin(inset); it; it.forwardChar()) {
|
for (DocIterator it = doc_iterator_begin(inset); it; it.forwardChar()) {
|
||||||
@ -70,6 +78,18 @@ void MacroData::expand(vector<MathData> const & args, MathData & to) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MacroData::optionals() const
|
||||||
|
{
|
||||||
|
return optionals_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<docstring> const & MacroData::defaults() const
|
||||||
|
{
|
||||||
|
return defaults_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// The global table.
|
// The global table.
|
||||||
MacroTable & MacroTable::globalMacros()
|
MacroTable & MacroTable::globalMacros()
|
||||||
{
|
{
|
||||||
@ -114,11 +134,45 @@ void MacroTable::dump()
|
|||||||
lyxerr << "\n------------------------------------------" << endl;
|
lyxerr << "\n------------------------------------------" << endl;
|
||||||
for (const_iterator it = begin(); it != end(); ++it)
|
for (const_iterator it = begin(); it != end(); ++it)
|
||||||
lyxerr << to_utf8(it->first)
|
lyxerr << to_utf8(it->first)
|
||||||
<< " [" << to_utf8(it->second.def()) << "] : "
|
<< " [" << to_utf8(it->second.definition()) << "] : "
|
||||||
<< " [" << to_utf8(it->second.disp()) << "] : "
|
<< " [" << to_utf8(it->second.display()) << "] : "
|
||||||
<< endl;
|
<< endl;
|
||||||
lyxerr << "------------------------------------------" << endl;
|
lyxerr << "------------------------------------------" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MacroContext::MacroContext(Buffer const & buf, Paragraph const & par)
|
||||||
|
: buf_(buf), par_(par)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MacroContext::has(docstring const & name) const
|
||||||
|
{
|
||||||
|
// check if it's a local macro
|
||||||
|
if (macros_.has(name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// otherwise ask the buffer
|
||||||
|
return buf_.hasMacro(name, par_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MacroData const & MacroContext::get(docstring const & name) const
|
||||||
|
{
|
||||||
|
// check if it's a local macro
|
||||||
|
if (macros_.has(name))
|
||||||
|
return macros_.get(name);
|
||||||
|
|
||||||
|
// ask the buffer for its macros
|
||||||
|
return buf_.getMacro(name, par_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroContext::insert(docstring const & name, MacroData const & data)
|
||||||
|
{
|
||||||
|
macros_.insert(name, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace lyx
|
} // namespace lyx
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* Licence details can be found in the file COPYING.
|
* Licence details can be found in the file COPYING.
|
||||||
*
|
*
|
||||||
* \author André Pönitz
|
* \author André Pönitz
|
||||||
|
* \author Stefan Schimanski
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* Full author contact details are available in file CREDITS.
|
||||||
*/
|
*/
|
||||||
@ -21,7 +22,9 @@
|
|||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
|
|
||||||
|
class Buffer;
|
||||||
class MathData;
|
class MathData;
|
||||||
|
class Paragraph;
|
||||||
|
|
||||||
///
|
///
|
||||||
class MacroData {
|
class MacroData {
|
||||||
@ -29,54 +32,77 @@ public:
|
|||||||
///
|
///
|
||||||
MacroData();
|
MacroData();
|
||||||
///
|
///
|
||||||
MacroData(docstring const & def, int nargs, docstring const & disp, std::string const &);
|
MacroData(docstring const & definition, std::vector<docstring> const & defaults,
|
||||||
|
int nargs, int optionals,
|
||||||
|
docstring const & display, std::string const & requires);
|
||||||
///
|
///
|
||||||
docstring def() const { return def_; }
|
docstring const & definition() const { return definition_; }
|
||||||
///
|
|
||||||
docstring disp() const { return disp_; }
|
|
||||||
///
|
///
|
||||||
|
docstring const & display() const { return display_; }
|
||||||
|
/// arity including optional arguments (if there is any)
|
||||||
int numargs() const { return numargs_; }
|
int numargs() const { return numargs_; }
|
||||||
/// replace #1,#2,... by given MathAtom 0,1,..
|
/// replace #1,#2,... by given MathAtom 0,1,.., _including_ the possible optional argument
|
||||||
void expand(std::vector<MathData> const & from, MathData & to) const;
|
void expand(std::vector<MathData> const & from, MathData & to) const;
|
||||||
|
/// number of optional arguments
|
||||||
|
int optionals() const;
|
||||||
|
///
|
||||||
|
std::vector<docstring> const & defaults() const;
|
||||||
///
|
///
|
||||||
std::string requires() const { return requires_; }
|
std::string requires() const { return requires_; }
|
||||||
///
|
///
|
||||||
std::string & requires() { return requires_; }
|
std::string & requires() { return requires_; }
|
||||||
/// lock while being drawn
|
|
||||||
|
/// lock while being drawn to avoid recursions
|
||||||
int lock() const { return ++lockCount_; }
|
int lock() const { return ++lockCount_; }
|
||||||
/// is it being drawn?
|
/// is it being drawn?
|
||||||
bool locked() const { return lockCount_ != 0; }
|
bool locked() const { return lockCount_ != 0; }
|
||||||
///
|
///
|
||||||
void unlock() const { --lockCount_; BOOST_ASSERT(lockCount_ >= 0); }
|
void unlock() const { --lockCount_; BOOST_ASSERT(lockCount_ >= 0); }
|
||||||
|
|
||||||
|
///
|
||||||
|
bool redefinition() const { return redefinition_; }
|
||||||
|
///
|
||||||
|
void setRedefinition(bool redefined) { redefinition_ = redefined; }
|
||||||
|
|
||||||
///
|
///
|
||||||
bool operator==(MacroData const & x) const {
|
bool operator==(MacroData const & x) const {
|
||||||
return def_ == x.def_ &&
|
return definition_ == x.definition_
|
||||||
numargs_ == x.numargs_ &&
|
&& numargs_ == x.numargs_
|
||||||
disp_ == x.disp_ &&
|
&& display_ == x.display_
|
||||||
requires_ == x.requires_;
|
&& requires_ == x.requires_
|
||||||
|
&& optionals_ == x.optionals_
|
||||||
|
&& defaults_ == x.defaults_;
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
bool operator!=(MacroData const & x) const { return !operator==(x); }
|
bool operator!=(MacroData const & x) const { return !operator==(x); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
docstring def_;
|
docstring definition_;
|
||||||
///
|
///
|
||||||
int numargs_;
|
int numargs_;
|
||||||
///
|
///
|
||||||
docstring disp_;
|
docstring display_;
|
||||||
///
|
///
|
||||||
std::string requires_;
|
std::string requires_;
|
||||||
///
|
///
|
||||||
mutable int lockCount_;
|
mutable int lockCount_;
|
||||||
|
///
|
||||||
|
bool redefinition_;
|
||||||
|
///
|
||||||
|
int optionals_;
|
||||||
|
///
|
||||||
|
std::vector<docstring> defaults_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// This contains a table of "global" macros that are always accessible,
|
/// A lookup table of macro definitions.
|
||||||
// either because they implement a feature of standard LaTeX or some
|
/**
|
||||||
// hack to display certain contents nicely.
|
* This contains a table of "global" macros that are always accessible,
|
||||||
|
* either because they implement a feature of standard LaTeX or some
|
||||||
|
* hack to display certain contents nicely.
|
||||||
|
*
|
||||||
|
**/
|
||||||
class MacroTable : public std::map<docstring, MacroData>
|
class MacroTable : public std::map<docstring, MacroData>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -93,11 +119,39 @@ public:
|
|||||||
|
|
||||||
/// the global list
|
/// the global list
|
||||||
static MacroTable & globalMacros();
|
static MacroTable & globalMacros();
|
||||||
/// the local list hack
|
|
||||||
//static MacroTable & localMacros();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// A context to lookup macros at a certain position in a buffer.
|
||||||
|
/**
|
||||||
|
* The MacroContext is used during metrics calculation to resolve
|
||||||
|
* macro instances according to the position of them in the buffer
|
||||||
|
* document. Only macro definition in front of the macro instance
|
||||||
|
* are visible and are resolved.
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
class MacroContext {
|
||||||
|
public:
|
||||||
|
/// construct context for insets in par (not including the ones defined in par itself)
|
||||||
|
MacroContext(Buffer const & buf, Paragraph const & par);
|
||||||
|
|
||||||
|
/// Look for macro
|
||||||
|
bool has(docstring const & name) const;
|
||||||
|
/// Lookup macro
|
||||||
|
MacroData const & get(docstring const & name) const;
|
||||||
|
|
||||||
|
/// Insert pre-digested macro definition
|
||||||
|
void insert(docstring const & name, MacroData const & data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// context local macros
|
||||||
|
MacroTable macros_;
|
||||||
|
///
|
||||||
|
Buffer const & buf_;
|
||||||
|
///
|
||||||
|
Paragraph const & par_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace lyx
|
} // namespace lyx
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* Licence details can be found in the file COPYING.
|
* Licence details can be found in the file COPYING.
|
||||||
*
|
*
|
||||||
* \author André Pönitz
|
* \author André Pönitz
|
||||||
|
* \author Stefan Schimanski
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* Full author contact details are available in file CREDITS.
|
||||||
*/
|
*/
|
||||||
@ -11,10 +12,11 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include "MathData.h"
|
#include "MathData.h"
|
||||||
|
#include "InsetMathBrace.h"
|
||||||
#include "InsetMathFont.h"
|
#include "InsetMathFont.h"
|
||||||
#include "InsetMathScript.h"
|
#include "InsetMathScript.h"
|
||||||
#include "MathMacro.h"
|
|
||||||
#include "MacroTable.h"
|
#include "MacroTable.h"
|
||||||
|
#include "MathMacro.h"
|
||||||
#include "MathStream.h"
|
#include "MathStream.h"
|
||||||
#include "MathSupport.h"
|
#include "MathSupport.h"
|
||||||
#include "ReplaceData.h"
|
#include "ReplaceData.h"
|
||||||
@ -247,35 +249,14 @@ void MathData::metrics(MetricsInfo & mi, Dimension & dim) const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const_cast<MathData*>(this)->updateMacros(mi);
|
||||||
|
|
||||||
dim.asc = 0;
|
dim.asc = 0;
|
||||||
dim.wid = 0;
|
dim.wid = 0;
|
||||||
Dimension d;
|
Dimension d;
|
||||||
atom_dims_.clear();
|
atom_dims_.clear();
|
||||||
//BufferView & bv = *mi.base.bv;
|
|
||||||
//Buffer const & buf = bv.buffer();
|
|
||||||
for (size_t i = 0, n = size(); i != n; ++i) {
|
for (size_t i = 0, n = size(); i != n; ++i) {
|
||||||
MathAtom const & at = operator[](i);
|
MathAtom const & at = operator[](i);
|
||||||
#if 0
|
|
||||||
MathMacro const * mac = at->asMacro();
|
|
||||||
if (mac && buf.hasMacro(mac->name())) {
|
|
||||||
MacroData const & tmpl = buf.getMacro(mac->name());
|
|
||||||
int numargs = tmpl.numargs();
|
|
||||||
if (i + numargs > n)
|
|
||||||
numargs = n - i - 1;
|
|
||||||
lyxerr << "metrics:found macro: " << mac->name()
|
|
||||||
<< " numargs: " << numargs << endl;
|
|
||||||
if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
|
|
||||||
MathData args(begin() + i + 1, begin() + i + numargs + 1);
|
|
||||||
MathData exp;
|
|
||||||
tmpl.expand(args, exp);
|
|
||||||
mac->setExpansion(exp, args);
|
|
||||||
mac->metricsExpanded(mi, d);
|
|
||||||
dim.wid += mac->widthExpanded();
|
|
||||||
i += numargs;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
at->metrics(mi, d);
|
at->metrics(mi, d);
|
||||||
atom_dims_.push_back(d);
|
atom_dims_.push_back(d);
|
||||||
dim += d;
|
dim += d;
|
||||||
@ -309,23 +290,6 @@ void MathData::draw(PainterInfo & pi, int x, int y) const
|
|||||||
|
|
||||||
for (size_t i = 0, n = size(); i != n; ++i) {
|
for (size_t i = 0, n = size(); i != n; ++i) {
|
||||||
MathAtom const & at = operator[](i);
|
MathAtom const & at = operator[](i);
|
||||||
#if 0
|
|
||||||
Buffer const & buf = bv.buffer();
|
|
||||||
// special macro handling
|
|
||||||
MathMacro const * mac = at->asMacro();
|
|
||||||
if (mac && buf.hasMacro(mac->name())) {
|
|
||||||
MacroData const & tmpl = buf.getMacro(mac->name());
|
|
||||||
int numargs = tmpl.numargs();
|
|
||||||
if (i + numargs > n)
|
|
||||||
numargs = n - i - 1;
|
|
||||||
if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) {
|
|
||||||
mac->drawExpanded(pi, x, y);
|
|
||||||
x += mac->widthExpanded();
|
|
||||||
i += numargs;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bv.coordCache().insets().add(at.nucleus(), x, y);
|
bv.coordCache().insets().add(at.nucleus(), x, y);
|
||||||
at->drawSelection(pi, x, y);
|
at->drawSelection(pi, x, y);
|
||||||
at->draw(pi, x, y);
|
at->draw(pi, x, y);
|
||||||
@ -360,6 +324,355 @@ void MathData::drawT(TextPainter & pain, int x, int y) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathData::updateMacros(MetricsInfo & mi)
|
||||||
|
{
|
||||||
|
Cursor & cur = mi.base.bv->cursor();
|
||||||
|
|
||||||
|
// go over the array and look for macros
|
||||||
|
for (size_t i = 0; i < size(); ++i) {
|
||||||
|
MathMacro * macroInset = operator[](i).nucleus()->asMacro();
|
||||||
|
if (!macroInset)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// get macro
|
||||||
|
macroInset->updateMacro(mi);
|
||||||
|
size_t macroNumArgs = 0;
|
||||||
|
int macroOptionals = 0;
|
||||||
|
MacroData const * macro = macroInset->macro();
|
||||||
|
if (macro) {
|
||||||
|
macroNumArgs = macro->numargs();
|
||||||
|
macroOptionals = macro->optionals();
|
||||||
|
}
|
||||||
|
|
||||||
|
// store old and compute new display mode
|
||||||
|
MathMacro::DisplayMode newDisplayMode;
|
||||||
|
MathMacro::DisplayMode oldDisplayMode = macroInset->displayMode();
|
||||||
|
newDisplayMode = macroInset->computeDisplayMode(mi);
|
||||||
|
|
||||||
|
// arity changed or other reason to detach?
|
||||||
|
if (oldDisplayMode == MathMacro::DISPLAY_NORMAL
|
||||||
|
&& (macroInset->arity() != macroNumArgs
|
||||||
|
|| macroInset->optionals() != macroOptionals
|
||||||
|
|| newDisplayMode == MathMacro::DISPLAY_UNFOLDED)) {
|
||||||
|
detachMacroParameters(cur, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the macro could have been copied while resizing this
|
||||||
|
macroInset = operator[](i).nucleus()->asMacro();
|
||||||
|
|
||||||
|
// Cursor in \label?
|
||||||
|
if (newDisplayMode != MathMacro::DISPLAY_UNFOLDED
|
||||||
|
&& oldDisplayMode == MathMacro::DISPLAY_UNFOLDED) {
|
||||||
|
// put cursor in front of macro
|
||||||
|
int macroSlice = cur.find(macroInset);
|
||||||
|
if (macroSlice != -1)
|
||||||
|
cur.cutOff(macroSlice - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the display mode
|
||||||
|
macroInset->setDisplayMode(newDisplayMode);
|
||||||
|
|
||||||
|
// arity changed?
|
||||||
|
if (newDisplayMode == MathMacro::DISPLAY_NORMAL
|
||||||
|
&& (macroInset->arity() != macroNumArgs
|
||||||
|
|| macroInset->optionals() != macroOptionals)) {
|
||||||
|
// is it a virgin macro which was never attached to parameters?
|
||||||
|
bool fromInitToNormalMode
|
||||||
|
= oldDisplayMode == MathMacro::DISPLAY_INIT
|
||||||
|
&& newDisplayMode == MathMacro::DISPLAY_NORMAL;
|
||||||
|
|
||||||
|
// attach parameters
|
||||||
|
attachMacroParameters(cur, i, macroNumArgs, macroOptionals,
|
||||||
|
fromInitToNormalMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// give macro the chance to adapt to new situation
|
||||||
|
InsetMath * inset = operator[](i).nucleus();
|
||||||
|
if (inset->asScriptInset())
|
||||||
|
inset = inset->asScriptInset()->nuc()[0].nucleus();
|
||||||
|
BOOST_ASSERT(inset->asMacro());
|
||||||
|
inset->asMacro()->updateRepresentation(mi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathData::detachMacroParameters(Cursor & cur, const size_type macroPos)
|
||||||
|
{
|
||||||
|
MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
|
||||||
|
|
||||||
|
// detach all arguments
|
||||||
|
std::vector<MathData> detachedArgs;
|
||||||
|
if (macroPos + 1 == size())
|
||||||
|
// strip arguments if we are at the MathData end
|
||||||
|
macroInset->detachArguments(detachedArgs, true);
|
||||||
|
else
|
||||||
|
macroInset->detachArguments(detachedArgs, false);
|
||||||
|
|
||||||
|
// find cursor slice
|
||||||
|
int curMacroSlice = cur.find(macroInset);
|
||||||
|
int curMacroIdx = -1;
|
||||||
|
int curMacroPos = -1;
|
||||||
|
std::vector<CursorSlice> argSlices;
|
||||||
|
if (curMacroSlice != -1) {
|
||||||
|
curMacroPos = cur[curMacroSlice].pos();
|
||||||
|
curMacroIdx = cur[curMacroSlice].idx();
|
||||||
|
cur.cutOff(curMacroSlice, argSlices);
|
||||||
|
cur.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// only [] after the last non-empty argument can be dropped later
|
||||||
|
size_t lastNonEmptyOptional = 0;
|
||||||
|
for (size_t l = 0; l < detachedArgs.size() && l < macroInset->optionals(); ++l) {
|
||||||
|
if (!detachedArgs[l].empty())
|
||||||
|
lastNonEmptyOptional = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional arguments to be put back?
|
||||||
|
size_t p = macroPos + 1;
|
||||||
|
size_t j = 0;
|
||||||
|
for (; j < detachedArgs.size() && j < macroInset->optionals(); ++j) {
|
||||||
|
// another non-empty parameter follows?
|
||||||
|
bool canDropEmptyOptional = j >= lastNonEmptyOptional;
|
||||||
|
|
||||||
|
// then we can drop empty optional parameters
|
||||||
|
if (detachedArgs[j].empty() && canDropEmptyOptional) {
|
||||||
|
if (curMacroIdx == j)
|
||||||
|
cur[curMacroSlice - 1].pos() = macroPos + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we don't drop an empty optional, put it back normally
|
||||||
|
MathData optarg;
|
||||||
|
asArray(from_ascii("[]"), optarg);
|
||||||
|
MathData & arg = detachedArgs[j];
|
||||||
|
|
||||||
|
// 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
|
||||||
|
brace = new InsetMathBrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// put arg between []
|
||||||
|
if (brace) {
|
||||||
|
brace->cell(0) = arg;
|
||||||
|
optarg.insert(1, MathAtom(brace));
|
||||||
|
} else
|
||||||
|
optarg.insert(1, arg);
|
||||||
|
|
||||||
|
// insert it into the array
|
||||||
|
insert(p, optarg);
|
||||||
|
p += optarg.size();
|
||||||
|
|
||||||
|
// cursor in optional argument of macro?
|
||||||
|
if (curMacroIdx == j) {
|
||||||
|
if (brace) {
|
||||||
|
cur.append(0, curMacroPos);
|
||||||
|
cur[curMacroSlice - 1].pos() = macroPos + 2;
|
||||||
|
} else
|
||||||
|
cur[curMacroSlice - 1].pos() = macroPos + 2 + curMacroPos;
|
||||||
|
cur.append(argSlices);
|
||||||
|
} else if (cur[curMacroSlice - 1].pos() >= int(p))
|
||||||
|
// cursor right of macro
|
||||||
|
cur[curMacroSlice - 1].pos() += optarg.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// put them back into the MathData
|
||||||
|
for (; j < detachedArgs.size(); ++j) {
|
||||||
|
MathData const & arg = detachedArgs[j];
|
||||||
|
if (arg.size() == 1 && !arg[0]->asScriptInset()) // && arg[0]->asCharInset())
|
||||||
|
insert(p, arg[0]);
|
||||||
|
else
|
||||||
|
insert(p, MathAtom(new InsetMathBrace(arg)));
|
||||||
|
|
||||||
|
// cursor in j-th argument of macro?
|
||||||
|
if (curMacroIdx == int(j)) {
|
||||||
|
if (operator[](p).nucleus()->asBraceInset()) {
|
||||||
|
cur[curMacroSlice - 1].pos() = p;
|
||||||
|
cur.append(0, curMacroPos);
|
||||||
|
cur.append(argSlices);
|
||||||
|
} else {
|
||||||
|
cur[curMacroSlice - 1].pos() = p; // + macroPos;
|
||||||
|
cur.append(argSlices);
|
||||||
|
}
|
||||||
|
} else if (cur[curMacroSlice - 1].pos() >= int(p))
|
||||||
|
++cur[curMacroSlice - 1].pos();
|
||||||
|
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: proper anchor handling, this removes the selection
|
||||||
|
cur.clearSelection();
|
||||||
|
cur.updateInsets(&cur.bottom().inset());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathData::attachMacroParameters(Cursor & cur,
|
||||||
|
const size_type macroPos, const size_type macroNumArgs,
|
||||||
|
const int macroOptionals, const bool fromInitToNormalMode)
|
||||||
|
{
|
||||||
|
MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
|
||||||
|
|
||||||
|
// start at atom behind the macro again, maybe with some new arguments from above
|
||||||
|
// to add them back into the macro inset
|
||||||
|
size_t p = macroPos + 1;
|
||||||
|
size_t j = 0;
|
||||||
|
std::vector<MathData>detachedArgs;
|
||||||
|
MathAtom scriptToPutAround;
|
||||||
|
|
||||||
|
// find cursor slice again
|
||||||
|
int thisSlice = cur.find(*this);
|
||||||
|
int thisPos = -1;
|
||||||
|
if (thisSlice != -1)
|
||||||
|
thisPos = cur[thisSlice].pos();
|
||||||
|
|
||||||
|
// insert optional arguments?
|
||||||
|
for (; j < macroOptionals && p < size(); ++j) {
|
||||||
|
// is a [] block following which could be an optional parameter?
|
||||||
|
if (operator[](p)->getChar() != '[') {
|
||||||
|
detachedArgs.push_back(MathData());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found optional argument, look for "]"
|
||||||
|
size_t right = p + 1;
|
||||||
|
for (; right < size(); ++right) {
|
||||||
|
if (operator[](right)->getChar() == ']')
|
||||||
|
// found right end
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found?
|
||||||
|
if (right < size()) {
|
||||||
|
// add everything between [ and ] as optional argument
|
||||||
|
MathData optarg(begin() + p + 1, begin() + right);
|
||||||
|
// a brace?
|
||||||
|
bool brace = false;
|
||||||
|
if (optarg.size() == 1 && optarg[0]->asBraceInset()) {
|
||||||
|
brace = true;
|
||||||
|
detachedArgs.push_back(optarg[0]->asBraceInset()->cell(0));
|
||||||
|
} else
|
||||||
|
detachedArgs.push_back(optarg);
|
||||||
|
// place cursor in optional argument of macro
|
||||||
|
if (thisPos >= int(p) && thisPos <= int(right)) {
|
||||||
|
int pos = std::max(0, thisPos - int(p) - 1);
|
||||||
|
std::vector<CursorSlice> x;
|
||||||
|
cur.cutOff(thisSlice, x);
|
||||||
|
cur[thisSlice].pos() = macroPos;
|
||||||
|
if (brace) {
|
||||||
|
pos = x[0].pos();
|
||||||
|
x.erase(x.begin());
|
||||||
|
}
|
||||||
|
cur.append(0, pos);
|
||||||
|
cur.append(x);
|
||||||
|
}
|
||||||
|
p = right + 1;
|
||||||
|
} else {
|
||||||
|
// no ] found, so it's not an optional argument
|
||||||
|
// Note: This was "macroPos = p" before, which probably
|
||||||
|
// does not make sense. We want to stop with optional
|
||||||
|
// argument handling instead, so go back to the beginning.
|
||||||
|
j = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert normal arguments
|
||||||
|
for (; j < macroNumArgs && p < size(); ++j) {
|
||||||
|
MathAtom & cell = operator[](p);
|
||||||
|
|
||||||
|
// fix cursor
|
||||||
|
std::vector<CursorSlice> argSlices;
|
||||||
|
int argPos = 0;
|
||||||
|
if (thisPos == int(p)) {
|
||||||
|
cur.cutOff(thisSlice, argSlices);
|
||||||
|
}
|
||||||
|
|
||||||
|
InsetMathBrace const * brace = cell->asBraceInset();
|
||||||
|
if (brace) {
|
||||||
|
// found brace, convert into argument
|
||||||
|
detachedArgs.push_back(brace->cell(0));
|
||||||
|
|
||||||
|
// cursor inside of the brace or just in front of?
|
||||||
|
if (thisPos == int(p) && !argSlices.empty()) {
|
||||||
|
argPos = argSlices[0].pos();
|
||||||
|
argSlices.erase(argSlices.begin());
|
||||||
|
}
|
||||||
|
} else if (cell->asScriptInset() && j + 1 == macroNumArgs) {
|
||||||
|
// 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!
|
||||||
|
detachedArgs.push_back(script->nuc()[0]->asBraceInset()->cell(0));
|
||||||
|
else
|
||||||
|
detachedArgs.push_back(script->nuc());
|
||||||
|
|
||||||
|
// script will be put around below
|
||||||
|
scriptToPutAround = cell;
|
||||||
|
|
||||||
|
// this should only happen after loading, so make cursor handling simple
|
||||||
|
if (thisPos >= int(macroPos) && thisPos <= int(macroPos + macroNumArgs)) {
|
||||||
|
argSlices.clear();
|
||||||
|
cur.append(0, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MathData array;
|
||||||
|
array.insert(0, cell);
|
||||||
|
detachedArgs.push_back(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// put cursor in argument again
|
||||||
|
if (thisPos == int(p)) {
|
||||||
|
cur.append(j, argPos);
|
||||||
|
cur.append(argSlices);
|
||||||
|
cur[thisSlice].pos() = macroPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach arguments back to macro inset
|
||||||
|
macroInset->attachArguments(detachedArgs, macroNumArgs, macroOptionals);
|
||||||
|
|
||||||
|
// found tail script? E.g. \foo{a}b^x
|
||||||
|
if (scriptToPutAround.nucleus()) {
|
||||||
|
// put macro into a script inset
|
||||||
|
scriptToPutAround.nucleus()->asScriptInset()->nuc()[0]
|
||||||
|
= operator[](macroPos);
|
||||||
|
operator[](macroPos) = scriptToPutAround;
|
||||||
|
|
||||||
|
if (thisPos == int(macroPos))
|
||||||
|
cur.append(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove them from the MathData
|
||||||
|
erase(begin() + macroPos + 1, begin() + p);
|
||||||
|
|
||||||
|
// fix cursor if right of p
|
||||||
|
if (thisPos >= int(p))
|
||||||
|
cur[thisSlice].pos() -= p - (macroPos + 1);
|
||||||
|
|
||||||
|
// was the macro inset just inserted and was now folded?
|
||||||
|
if (cur[thisSlice].pos() == int(macroPos + 1)
|
||||||
|
&& fromInitToNormalMode
|
||||||
|
&& macroInset->arity() > 0
|
||||||
|
&& thisSlice + 1 == int(cur.depth())) {
|
||||||
|
// then enter it if the cursor was just behind
|
||||||
|
cur[thisSlice].pos() = macroPos;
|
||||||
|
cur.push_back(CursorSlice(*macroInset));
|
||||||
|
macroInset->idxFirst(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: proper anchor handling, this removes the selection
|
||||||
|
cur.updateInsets(&cur.bottom().inset());
|
||||||
|
cur.clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int MathData::pos2x(size_type pos) const
|
int MathData::pos2x(size_type pos) const
|
||||||
{
|
{
|
||||||
return pos2x(pos, 0);
|
return pos2x(pos, 0);
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
* \author Alejandro Aguilar Sierra
|
* \author Alejandro Aguilar Sierra
|
||||||
* \author André Pönitz
|
* \author André Pönitz
|
||||||
* \author Lars Gullik Bjønnes
|
* \author Lars Gullik Bjønnes
|
||||||
|
* \author Stefan Schimanski
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* Full author contact details are available in file CREDITS.
|
||||||
*/
|
*/
|
||||||
@ -16,8 +17,9 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "MathAtom.h"
|
#include "Cursor.h"
|
||||||
#include "Dimension.h"
|
#include "Dimension.h"
|
||||||
|
#include "MathAtom.h"
|
||||||
|
|
||||||
#include "support/docstream.h"
|
#include "support/docstream.h"
|
||||||
|
|
||||||
@ -27,6 +29,7 @@ namespace lyx {
|
|||||||
class BufferView;
|
class BufferView;
|
||||||
class LaTeXFeatures;
|
class LaTeXFeatures;
|
||||||
class ReplaceData;
|
class ReplaceData;
|
||||||
|
class MathMacro;
|
||||||
class MetricsInfo;
|
class MetricsInfo;
|
||||||
class PainterInfo;
|
class PainterInfo;
|
||||||
class TextMetricsInfo;
|
class TextMetricsInfo;
|
||||||
@ -163,6 +166,14 @@ private:
|
|||||||
/// is this an exact match at this position?
|
/// is this an exact match at this position?
|
||||||
bool find1(MathData const & ar, size_type pos) const;
|
bool find1(MathData const & ar, size_type pos) const;
|
||||||
|
|
||||||
|
/// attach/detach arguments to macros
|
||||||
|
void updateMacros(MetricsInfo & mi);
|
||||||
|
///
|
||||||
|
void detachMacroParameters(Cursor & cur, const size_type macroPos);
|
||||||
|
///
|
||||||
|
void attachMacroParameters(Cursor & cur, const size_type macroPos,
|
||||||
|
const size_type macroNumArgs, const int macroOptionals,
|
||||||
|
const bool fromInitToNormalMode);
|
||||||
///
|
///
|
||||||
mutable std::vector<Dimension> atom_dims_;
|
mutable std::vector<Dimension> atom_dims_;
|
||||||
};
|
};
|
||||||
|
@ -403,15 +403,7 @@ MathAtom createInsetMath(docstring const & s)
|
|||||||
if (s == "vphantom")
|
if (s == "vphantom")
|
||||||
return MathAtom(new InsetMathPhantom(InsetMathPhantom::vphantom));
|
return MathAtom(new InsetMathPhantom(InsetMathPhantom::vphantom));
|
||||||
|
|
||||||
if (MacroTable::globalMacros().has(s))
|
return MathAtom(new MathMacro(s));
|
||||||
return MathAtom(new MathMacro(s,
|
|
||||||
MacroTable::globalMacros().get(s).numargs()));
|
|
||||||
//if (MacroTable::localMacros().has(s))
|
|
||||||
// return MathAtom(new MathMacro(s,
|
|
||||||
// MacroTable::localMacros().get(s).numargs()));
|
|
||||||
|
|
||||||
//lyxerr << "creating unknown inset '" << s << "'" << endl;
|
|
||||||
return MathAtom(new InsetMathUnknown(s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*
|
*
|
||||||
* \author Alejandro Aguilar Sierra
|
* \author Alejandro Aguilar Sierra
|
||||||
* \author André Pönitz
|
* \author André Pönitz
|
||||||
|
* \author Stefan Schimanski
|
||||||
*
|
*
|
||||||
* Full author contact details are available in file CREDITS.
|
* Full author contact details are available in file CREDITS.
|
||||||
*/
|
*/
|
||||||
@ -17,12 +18,17 @@
|
|||||||
#include "MathStream.h"
|
#include "MathStream.h"
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "BufferView.h"
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "BufferView.h"
|
|
||||||
#include "LaTeXFeatures.h"
|
#include "LaTeXFeatures.h"
|
||||||
|
#include "FuncStatus.h"
|
||||||
|
#include "FuncRequest.h"
|
||||||
|
#include "Undo.h"
|
||||||
|
|
||||||
#include "frontends/Painter.h"
|
#include "frontends/Painter.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
|
|
||||||
@ -30,70 +36,85 @@ using std::string;
|
|||||||
using std::max;
|
using std::max;
|
||||||
|
|
||||||
|
|
||||||
/// This class is the value of a macro argument, technically
|
/// A proxy for the macro values
|
||||||
/// a wrapper of the cells of MathMacro.
|
class ArgumentProxy : public InsetMath {
|
||||||
class MathMacroArgumentValue : public InsetMath {
|
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
MathMacroArgumentValue(MathMacro const & mathMacro, size_t idx)
|
ArgumentProxy(MathMacro & mathMacro, size_t idx)
|
||||||
: mathMacro_(mathMacro), idx_(idx) {}
|
: mathMacro_(mathMacro), idx_(idx) {}
|
||||||
///
|
///
|
||||||
void metrics(MetricsInfo & mi, Dimension & dim) const;
|
ArgumentProxy(MathMacro & mathMacro, size_t idx, docstring const & def)
|
||||||
|
: mathMacro_(mathMacro), idx_(idx)
|
||||||
|
{
|
||||||
|
asArray(def, def_);
|
||||||
|
}
|
||||||
///
|
///
|
||||||
void draw(PainterInfo &, int x, int y) const;
|
void metrics(MetricsInfo & mi, Dimension & dim) const {
|
||||||
|
mathMacro_.macro()->unlock();
|
||||||
|
mathMacro_.cell(idx_).metrics(mi, dim);
|
||||||
|
if (!mathMacro_.editing() && !def_.empty())
|
||||||
|
def_.metrics(mi, dim);
|
||||||
|
mathMacro_.macro()->lock();
|
||||||
|
}
|
||||||
|
///
|
||||||
|
void draw(PainterInfo & pi, int x, int y) const {
|
||||||
|
if (mathMacro_.editing()) {
|
||||||
|
pi.pain.leaveMonochromeMode();
|
||||||
|
mathMacro_.cell(idx_).draw(pi, x, y);
|
||||||
|
// FIXME: use real min/max colors here, not necessarely the ones of MathMacro are set
|
||||||
|
pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend);
|
||||||
|
} else {
|
||||||
|
if (def_.empty())
|
||||||
|
mathMacro_.cell(idx_).draw(pi, x, y);
|
||||||
|
else {
|
||||||
|
mathMacro_.cell(idx_).setXY(*pi.base.bv, x, y);
|
||||||
|
def_.draw(pi, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///
|
||||||
|
size_t idx() const { return idx_; }
|
||||||
///
|
///
|
||||||
int kerning() const { return mathMacro_.cell(idx_).kerning(); }
|
int kerning() const { return mathMacro_.cell(idx_).kerning(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Inset * clone() const;
|
///
|
||||||
MathMacro const & mathMacro_;
|
Inset * clone() const
|
||||||
|
{
|
||||||
|
return new ArgumentProxy(*this);
|
||||||
|
}
|
||||||
|
///
|
||||||
|
MathMacro & mathMacro_;
|
||||||
|
///
|
||||||
size_t idx_;
|
size_t idx_;
|
||||||
|
///
|
||||||
|
MathData def_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Inset * MathMacroArgumentValue::clone() const
|
MathMacro::MathMacro(docstring const & name)
|
||||||
{
|
: InsetMathNest(0), name_(name), displayMode_(DISPLAY_INIT),
|
||||||
return new MathMacroArgumentValue(*this);
|
attachedArgsNum_(0), previousCurIdx_(-1),
|
||||||
}
|
optionals_(0), nextFoldMode_(true),
|
||||||
|
macro_(0), editing_(false), needsUpdate_(false)
|
||||||
|
|
||||||
void MathMacroArgumentValue::metrics(MetricsInfo & mi, Dimension & dim) const
|
|
||||||
{
|
|
||||||
// unlock outer macro in arguments, and lock it again later
|
|
||||||
MacroData const & macro = MacroTable::globalMacros().get(mathMacro_.name());
|
|
||||||
macro.unlock();
|
|
||||||
mathMacro_.cell(idx_).metrics(mi, dim);
|
|
||||||
macro.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MathMacroArgumentValue::draw(PainterInfo & pi, int x, int y) const
|
|
||||||
{
|
|
||||||
// unlock outer macro in arguments, and lock it again later
|
|
||||||
MacroData const & macro = MacroTable::globalMacros().get(mathMacro_.name());
|
|
||||||
macro.unlock();
|
|
||||||
mathMacro_.cell(idx_).draw(pi, x, y);
|
|
||||||
macro.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MathMacro::MathMacro(docstring const & name, int numargs)
|
|
||||||
: InsetMathNest(numargs), name_(name), editing_(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
Inset * MathMacro::clone() const
|
Inset * MathMacro::clone() const
|
||||||
{
|
{
|
||||||
MathMacro * x = new MathMacro(*this);
|
MathMacro * copy = new MathMacro(*this);
|
||||||
x->expanded_ = MathData();
|
copy->needsUpdate_ = true;
|
||||||
x->macroBackup_ = MacroData();
|
copy->expanded_.cell(0).clear();
|
||||||
return x;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
docstring MathMacro::name() const
|
docstring MathMacro::name() const
|
||||||
{
|
{
|
||||||
return name_;
|
if (displayMode_ == DISPLAY_UNFOLDED)
|
||||||
|
return asString(cell(0));
|
||||||
|
else
|
||||||
|
return name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -106,133 +127,353 @@ void MathMacro::cursorPos(BufferView const & bv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MathMacro::cursorIdx(Cursor const & cur) const {
|
||||||
|
for (size_t i = 0; i != cur.depth(); ++i)
|
||||||
|
if (&cur[i].inset() == this)
|
||||||
|
return cur[i].idx();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MathMacro::editMode(Cursor const & cur) const {
|
||||||
|
// find this in cursor trace
|
||||||
|
for (size_t i = 0; i != cur.depth(); ++i)
|
||||||
|
if (&cur[i].inset() == this) {
|
||||||
|
// look if there is no other macro in edit mode above
|
||||||
|
++i;
|
||||||
|
for (; i != cur.depth(); ++i) {
|
||||||
|
MathMacro const * macro = dynamic_cast<MathMacro const *>(&cur[i].inset());
|
||||||
|
if (macro && macro->displayMode() == DISPLAY_NORMAL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok, none found, I am the highest one
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
|
void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||||
{
|
{
|
||||||
kerning_ = 0;
|
// calculate new metrics according to display mode
|
||||||
if (!MacroTable::globalMacros().has(name())) {
|
if (displayMode_ == DISPLAY_INIT) {
|
||||||
mathed_string_dim(mi.base.font, "Unknown: " + name(), dim);
|
mathed_string_dim(mi.base.font, from_ascii("\\") + name(), dim);
|
||||||
|
} else if (displayMode_ == DISPLAY_UNFOLDED) {
|
||||||
|
cell(0).metrics(mi, dim);
|
||||||
|
Dimension bsdim;
|
||||||
|
mathed_string_dim(mi.base.font, from_ascii("\\"), bsdim);
|
||||||
|
dim.wid += bsdim.width() + 1;
|
||||||
|
dim.asc = std::max(bsdim.ascent(), dim.ascent());
|
||||||
|
dim.des = std::max(bsdim.descent(), dim.descent());
|
||||||
|
metricsMarkers(dim);
|
||||||
} else {
|
} else {
|
||||||
MacroData const & macro = MacroTable::globalMacros().get(name());
|
BOOST_ASSERT(macro_ != 0);
|
||||||
|
|
||||||
if (macroBackup_ != macro)
|
// calculate metric finally
|
||||||
updateExpansion();
|
macro_->lock();
|
||||||
|
expanded_.cell(0).metrics(mi, dim);
|
||||||
|
macro_->unlock();
|
||||||
|
|
||||||
if (macro.locked()) {
|
// calculate dimension with label while editing
|
||||||
mathed_string_dim(mi.base.font, "Self reference: " + name(), dim);
|
if (editing_) {
|
||||||
} else if (editing(mi.base.bv)) {
|
|
||||||
FontInfo font = mi.base.font;
|
FontInfo font = mi.base.font;
|
||||||
augmentFont(font, from_ascii("lyxtex"));
|
augmentFont(font, from_ascii("lyxtex"));
|
||||||
tmpl_.metrics(mi, dim);
|
Dimension namedim;
|
||||||
// FIXME UNICODE
|
mathed_string_dim(font, name(), namedim);
|
||||||
dim.wid += mathed_string_width(font, name()) + 10;
|
#if 0
|
||||||
// FIXME UNICODE
|
dim.wid += 2 + namedim.wid + 2 + 2;
|
||||||
int ww = mathed_string_width(font, from_ascii("#1: "));
|
dim.asc = std::max(dim.asc, namedim.asc) + 2;
|
||||||
for (idx_type i = 0; i < nargs(); ++i) {
|
dim.des = std::max(dim.des, namedim.des) + 2;
|
||||||
MathData const & c = cell(i);
|
#endif
|
||||||
Dimension dimc;
|
dim.wid = std::max(1 + namedim.wid + 1, 2 + dim.wid + 2);
|
||||||
c.metrics(mi, dimc);
|
dim.asc += 1 + namedim.height() + 1;
|
||||||
dim.wid = max(dim.wid, dimc.width() + ww);
|
dim.des += 2;
|
||||||
dim.des += dimc.height() + 10;
|
|
||||||
}
|
|
||||||
editing_ = true;
|
|
||||||
} else {
|
|
||||||
macro.lock();
|
|
||||||
expanded_.metrics(mi, dim);
|
|
||||||
macro.unlock();
|
|
||||||
kerning_ = expanded_.kerning();
|
|
||||||
editing_ = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the inset dimension.
|
// Cache the inset dimension.
|
||||||
setDimCache(mi, dim);
|
setDimCache(mi, dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MathMacro::kerning() const {
|
||||||
|
if (displayMode_ == DISPLAY_NORMAL && !editing_)
|
||||||
|
return expanded_.kerning();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::updateMacro(MetricsInfo & mi)
|
||||||
|
{
|
||||||
|
if (validName() && mi.macrocontext.has(name())) {
|
||||||
|
macro_ = &mi.macrocontext.get(name());
|
||||||
|
if (macroBackup_ != *macro_) {
|
||||||
|
macroBackup_ = *macro_;
|
||||||
|
needsUpdate_ = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
macro_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::updateRepresentation(MetricsInfo & mi)
|
||||||
|
{
|
||||||
|
// index of child where the cursor is (or -1 if none is edited)
|
||||||
|
int curIdx = cursorIdx(mi.base.bv->cursor());
|
||||||
|
previousCurIdx_ = curIdx;
|
||||||
|
|
||||||
|
// known macro?
|
||||||
|
if (macro_) {
|
||||||
|
requires_ = macro_->requires();
|
||||||
|
|
||||||
|
if (displayMode_ == DISPLAY_NORMAL) {
|
||||||
|
// set edit mode to draw box around if needed
|
||||||
|
bool prevEditing = editing_;
|
||||||
|
editing_ = editMode(mi.base.bv->cursor());
|
||||||
|
|
||||||
|
// editMode changed and we have to switch default value and hole of optional?
|
||||||
|
if (optionals_ > 0 && nargs() > 0 &&
|
||||||
|
prevEditing != editing_)
|
||||||
|
needsUpdate_ = true;
|
||||||
|
|
||||||
|
// macro changed?
|
||||||
|
if (needsUpdate_) {
|
||||||
|
needsUpdate_ = false;
|
||||||
|
|
||||||
|
// get default values of macro
|
||||||
|
std::vector<docstring> const & defaults = macro_->defaults();
|
||||||
|
|
||||||
|
// create MathMacroArgumentValue objects pointing to the cells of the macro
|
||||||
|
std::vector<MathData> values(nargs());
|
||||||
|
for (size_t i = 0; i < nargs(); ++i) {
|
||||||
|
if (!cell(i).empty() || i >= defaults.size() ||
|
||||||
|
defaults[i].empty() || curIdx == (int)i)
|
||||||
|
values[i].insert(0, MathAtom(new ArgumentProxy(*this, i)));
|
||||||
|
else
|
||||||
|
values[i].insert(0, MathAtom(new ArgumentProxy(*this, i, defaults[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// expanding macro with the values
|
||||||
|
macro_->expand(values, expanded_.cell(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::draw(PainterInfo & pi, int x, int y) const
|
void MathMacro::draw(PainterInfo & pi, int x, int y) const
|
||||||
{
|
{
|
||||||
if (!MacroTable::globalMacros().has(name())) {
|
Dimension const dim = dimension(*pi.base.bv);
|
||||||
// FIXME UNICODE
|
|
||||||
drawStrRed(pi, x, y, "Unknown: " + name());
|
|
||||||
} else {
|
|
||||||
MacroData const & macro = MacroTable::globalMacros().get(name());
|
|
||||||
|
|
||||||
// warm up cache
|
setPosCache(pi, x, y);
|
||||||
|
int expx = x;
|
||||||
|
int expy = y;
|
||||||
|
|
||||||
|
if (displayMode_ == DISPLAY_INIT) {
|
||||||
|
PainterInfo pi2(pi.base.bv, pi.pain);
|
||||||
|
pi2.base.font.setColor(macro_ ? Color_latex : Color_error);
|
||||||
|
//pi2.base.style = LM_ST_TEXT;
|
||||||
|
pi2.pain.text(x, y, from_ascii("\\") + name(), pi2.base.font);
|
||||||
|
} else if (displayMode_ == DISPLAY_UNFOLDED) {
|
||||||
|
PainterInfo pi2(pi.base.bv, pi.pain);
|
||||||
|
pi2.base.font.setColor(macro_ ? Color_latex : Color_error);
|
||||||
|
//pi2.base.style = LM_ST_TEXT;
|
||||||
|
pi2.pain.text(x, y, from_ascii("\\"), pi2.base.font);
|
||||||
|
x += mathed_string_width(pi2.base.font, from_ascii("\\")) + 1;
|
||||||
|
cell(0).draw(pi2, x, y);
|
||||||
|
drawMarkers(pi2, expx, expy);
|
||||||
|
} else {
|
||||||
|
// warm up cells
|
||||||
for (size_t i = 0; i < nargs(); ++i)
|
for (size_t i = 0; i < nargs(); ++i)
|
||||||
cell(i).setXY(*pi.base.bv, x, y);
|
cell(i).setXY(*pi.base.bv, x, y);
|
||||||
|
|
||||||
if (macro.locked()) {
|
if (editing_) {
|
||||||
// FIXME UNICODE
|
// draw header and rectangle around
|
||||||
drawStrRed(pi, x, y, "Self reference: " + name());
|
|
||||||
} else if (editing_) {
|
|
||||||
FontInfo font = pi.base.font;
|
FontInfo font = pi.base.font;
|
||||||
augmentFont(font, from_ascii("lyxtex"));
|
augmentFont(font, from_ascii("lyxtex"));
|
||||||
Dimension const dim = dimension(*pi.base.bv);
|
font.setSize(FONT_SIZE_TINY);
|
||||||
Dimension const & dim_tmpl = tmpl_.dimension(*pi.base.bv);
|
font.setColor(Color_mathmacrolabel);
|
||||||
int h = y - dim.ascent() + 2 + dim_tmpl.ascent();
|
Dimension namedim;
|
||||||
pi.pain.text(x + 3, h, name(), font);
|
mathed_string_dim(font, name(), namedim);
|
||||||
int const w = mathed_string_width(font, name());
|
#if 0
|
||||||
tmpl_.draw(pi, x + w + 12, h);
|
pi.pain.fillRectangle(x, y - dim.asc, 2 + namedim.width() + 2, dim.height(), Color_mathmacrobg);
|
||||||
h += dim_tmpl.descent();
|
pi.pain.text(x + 2, y, name(), font);
|
||||||
Dimension ldim;
|
expx += 2 + namew + 2;
|
||||||
docstring t = from_ascii("#1: ");
|
#endif
|
||||||
mathed_string_dim(font, t, ldim);
|
pi.pain.fillRectangle(x, y - dim.asc, dim.wid, 1 + namedim.height() + 1, Color_mathmacrobg);
|
||||||
for (idx_type i = 0; i < nargs(); ++i) {
|
pi.pain.text(x + 1, y - dim.asc + namedim.asc + 2, name(), font);
|
||||||
MathData const & c = cell(i);
|
expx += (dim.wid - expanded_.cell(0).dimension(*pi.base.bv).width()) / 2;
|
||||||
Dimension const & dimc = c.dimension(*pi.base.bv);
|
|
||||||
h += max(dimc.ascent(), ldim.asc) + 5;
|
|
||||||
c.draw(pi, x + ldim.wid, h);
|
|
||||||
char_type str[] = { '#', '1', ':', '\0' };
|
|
||||||
str[1] += static_cast<char_type>(i);
|
|
||||||
pi.pain.text(x + 3, h, str, font);
|
|
||||||
h += max(dimc.descent(), ldim.des) + 5;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
macro.lock();
|
|
||||||
expanded_.draw(pi, x, y);
|
|
||||||
macro.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// edit mode changed?
|
pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend);
|
||||||
if (editing_ != editing(pi.base.bv) || macroBackup_ != macro)
|
expanded_.cell(0).draw(pi, expx, expy);
|
||||||
pi.base.bv->cursor().updateFlags(Update::Force);
|
pi.pain.leaveMonochromeMode();
|
||||||
|
} else
|
||||||
|
expanded_.cell(0).draw(pi, expx, expy);
|
||||||
|
|
||||||
|
// draw frame while editing
|
||||||
|
if (editing_)
|
||||||
|
pi.pain.rectangle(x, y - dim.asc, dim.wid, dim.height(), Color_mathmacroframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// another argument selected?
|
||||||
|
int curIdx = cursorIdx(pi.base.bv->cursor());
|
||||||
|
if (previousCurIdx_ != curIdx || editing_ != editMode(pi.base.bv->cursor()))
|
||||||
|
pi.base.bv->cursor().updateFlags(Update::Force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const
|
void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const
|
||||||
{
|
{
|
||||||
// We may have 0 arguments, but InsetMathNest requires at least one.
|
// We may have 0 arguments, but InsetMathNest requires at least one.
|
||||||
if (nargs() > 0)
|
if (cells_.size() > 0)
|
||||||
InsetMathNest::drawSelection(pi, x, y);
|
InsetMathNest::drawSelection(pi, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::setDisplayMode(MathMacro::DisplayMode mode)
|
||||||
|
{
|
||||||
|
if (displayMode_ != mode) {
|
||||||
|
// transfer name if changing from or to DISPLAY_UNFOLDED
|
||||||
|
if (mode == DISPLAY_UNFOLDED) {
|
||||||
|
cells_.resize(1);
|
||||||
|
asArray(name_, cell(0));
|
||||||
|
} else if (displayMode_ == DISPLAY_UNFOLDED) {
|
||||||
|
name_ = asString(cell(0));
|
||||||
|
cells_.resize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayMode_ = mode;
|
||||||
|
needsUpdate_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MathMacro::DisplayMode MathMacro::computeDisplayMode(MetricsInfo const & mi) const
|
||||||
|
{
|
||||||
|
if (nextFoldMode_ == true && macro_ && !macro_->locked())
|
||||||
|
return DISPLAY_NORMAL;
|
||||||
|
else
|
||||||
|
return DISPLAY_UNFOLDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MathMacro::validName() const
|
||||||
|
{
|
||||||
|
docstring n = name();
|
||||||
|
|
||||||
|
// empty name?
|
||||||
|
if (n.size() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// converting back and force doesn't swallow anything?
|
||||||
|
/*MathData ma;
|
||||||
|
asArray(n, ma);
|
||||||
|
if (asString(ma) != n)
|
||||||
|
return false;*/
|
||||||
|
|
||||||
|
// valid characters?
|
||||||
|
for (size_t i = 0; i<n.size(); ++i) {
|
||||||
|
if (!(n[i] >= 'a' && n[i] <= 'z') &&
|
||||||
|
!(n[i] >= 'A' && n[i] <= 'Z'))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::validate(LaTeXFeatures & features) const
|
void MathMacro::validate(LaTeXFeatures & features) const
|
||||||
{
|
{
|
||||||
string const require = MacroTable::globalMacros().get(name()).requires();
|
if (!requires_.empty())
|
||||||
if (!require.empty())
|
features.require(requires_);
|
||||||
features.require(require);
|
|
||||||
|
|
||||||
if (name() == "binom" || name() == "mathcircumflex")
|
if (name() == "binom" || name() == "mathcircumflex")
|
||||||
features.require(to_utf8(name()));
|
features.require(to_utf8(name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::edit(Cursor & cur, bool left)
|
||||||
|
{
|
||||||
|
cur.updateFlags(Update::Force);
|
||||||
|
InsetMathNest::edit(cur, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Inset * MathMacro::editXY(Cursor & cur, int x, int y)
|
Inset * MathMacro::editXY(Cursor & cur, int x, int y)
|
||||||
{
|
{
|
||||||
// We may have 0 arguments, but InsetMathNest requires at least one.
|
// We may have 0 arguments, but InsetMathNest requires at least one.
|
||||||
if (nargs() > 0) {
|
if (nargs() > 0) {
|
||||||
// Prevent crash due to cold coordcache
|
cur.updateFlags(Update::Force);
|
||||||
// FIXME: This is only a workaround, the call of
|
|
||||||
// InsetMathNest::editXY is correct. The correct fix would
|
|
||||||
// ensure that the coordcache of the arguments is valid.
|
|
||||||
if (!editing(&cur.bv())) {
|
|
||||||
edit(cur, true);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
return InsetMathNest::editXY(cur, x, y);
|
return InsetMathNest::editXY(cur, x, y);
|
||||||
|
} else
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::removeArgument(size_t pos) {
|
||||||
|
if (displayMode_ == DISPLAY_NORMAL) {
|
||||||
|
BOOST_ASSERT(pos >= 0 && pos < cells_.size());
|
||||||
|
cells_.erase(cells_.begin() + pos);
|
||||||
|
if (pos < attachedArgsNum_)
|
||||||
|
--attachedArgsNum_;
|
||||||
|
if (pos < optionals_) {
|
||||||
|
--optionals_;
|
||||||
|
}
|
||||||
|
|
||||||
|
needsUpdate_ = true;
|
||||||
}
|
}
|
||||||
return this;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::insertArgument(size_t pos) {
|
||||||
|
if (displayMode_ == DISPLAY_NORMAL) {
|
||||||
|
BOOST_ASSERT(pos >= 0 && pos <= cells_.size());
|
||||||
|
cells_.insert(cells_.begin() + pos, MathData());
|
||||||
|
if (pos < attachedArgsNum_)
|
||||||
|
++attachedArgsNum_;
|
||||||
|
if (pos < optionals_)
|
||||||
|
++optionals_;
|
||||||
|
|
||||||
|
needsUpdate_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::detachArguments(std::vector<MathData> & args, bool strip)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(displayMode_ == DISPLAY_NORMAL);
|
||||||
|
args = cells_;
|
||||||
|
|
||||||
|
// strip off empty cells, but not more than arity-attachedArgsNum_
|
||||||
|
if (strip) {
|
||||||
|
size_t i;
|
||||||
|
for (i = cells_.size(); i > attachedArgsNum_; --i)
|
||||||
|
if (!cell(i - 1).empty()) break;
|
||||||
|
args.resize(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
attachedArgsNum_ = 0;
|
||||||
|
expanded_.cell(0) = MathData();
|
||||||
|
cells_.resize(0);
|
||||||
|
|
||||||
|
needsUpdate_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::attachArguments(std::vector<MathData> const & args, size_t arity, int optionals)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(displayMode_ == DISPLAY_NORMAL);
|
||||||
|
cells_ = args;
|
||||||
|
attachedArgsNum_ = args.size();
|
||||||
|
cells_.resize(arity);
|
||||||
|
expanded_.cell(0) = MathData();
|
||||||
|
optionals_ = optionals;
|
||||||
|
|
||||||
|
needsUpdate_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -250,22 +491,6 @@ bool MathMacro::idxLast(Cursor & cur) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MathMacro::idxUpDown(Cursor & cur, bool up) const
|
|
||||||
{
|
|
||||||
if (up) {
|
|
||||||
if (cur.idx() == 0)
|
|
||||||
return false;
|
|
||||||
--cur.idx();
|
|
||||||
} else {
|
|
||||||
if (cur.idx() + 1 >= nargs())
|
|
||||||
return false;
|
|
||||||
++cur.idx();
|
|
||||||
}
|
|
||||||
cur.pos() = cell(cur.idx()).x2pos(cur.x_target());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool MathMacro::notifyCursorLeaves(Cursor & cur)
|
bool MathMacro::notifyCursorLeaves(Cursor & cur)
|
||||||
{
|
{
|
||||||
cur.updateFlags(Update::Force);
|
cur.updateFlags(Update::Force);
|
||||||
@ -273,38 +498,98 @@ bool MathMacro::notifyCursorLeaves(Cursor & cur)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::fold(Cursor & cur)
|
||||||
|
{
|
||||||
|
if (!nextFoldMode_) {
|
||||||
|
nextFoldMode_ = true;
|
||||||
|
cur.updateFlags(Update::Force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::unfold(Cursor & cur)
|
||||||
|
{
|
||||||
|
if (nextFoldMode_) {
|
||||||
|
nextFoldMode_ = false;
|
||||||
|
cur.updateFlags(Update::Force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MathMacro::folded() const
|
||||||
|
{
|
||||||
|
return nextFoldMode_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacro::write(WriteStream & os) const
|
||||||
|
{
|
||||||
|
if (displayMode_ == DISPLAY_NORMAL) {
|
||||||
|
BOOST_ASSERT(macro_);
|
||||||
|
|
||||||
|
os << "\\" << name();
|
||||||
|
bool first = true;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
// Use macroBackup_ instead of macro_ here, because
|
||||||
|
// this is outside the metrics/draw calls, hence the macro_
|
||||||
|
// variable can point to a MacroData which was freed already.
|
||||||
|
std::vector<docstring> const & defaults = macroBackup_.defaults();
|
||||||
|
|
||||||
|
// Optional argument
|
||||||
|
if (os.latex()) {
|
||||||
|
if (i < optionals_) {
|
||||||
|
// the first real optional, the others are non-optional in latex
|
||||||
|
if (!cell(i).empty()) {
|
||||||
|
first = false;
|
||||||
|
os << "[" << cell(0) << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// In lyx mode print all in any case
|
||||||
|
for (; i < cells_.size() && i < optionals_; ++i) {
|
||||||
|
first = false;
|
||||||
|
os << "[" << cell(i) << "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < cells_.size(); ++i) {
|
||||||
|
if (cell(i).empty() && i < optionals_) {
|
||||||
|
os << "{" << defaults[i] << "}";
|
||||||
|
} else if (cell(i).size() == 1 && cell(i)[0].nucleus()->asCharInset()) {
|
||||||
|
if (first)
|
||||||
|
os << " ";
|
||||||
|
os << cell(i);
|
||||||
|
} else
|
||||||
|
os << "{" << cell(i) << "}";
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
if (first)
|
||||||
|
os.pendingSpace(true);
|
||||||
|
} else {
|
||||||
|
os << "\\" << name() << " ";
|
||||||
|
os.pendingSpace(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::maple(MapleStream & os) const
|
void MathMacro::maple(MapleStream & os) const
|
||||||
{
|
{
|
||||||
updateExpansion();
|
lyx::maple(expanded_.cell(0), os);
|
||||||
lyx::maple(expanded_, os);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::mathmlize(MathStream & os) const
|
void MathMacro::mathmlize(MathStream & os) const
|
||||||
{
|
{
|
||||||
updateExpansion();
|
lyx::mathmlize(expanded_.cell(0), os);
|
||||||
lyx::mathmlize(expanded_, os);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::octave(OctaveStream & os) const
|
void MathMacro::octave(OctaveStream & os) const
|
||||||
{
|
{
|
||||||
updateExpansion();
|
lyx::octave(expanded_.cell(0), os);
|
||||||
lyx::octave(expanded_, os);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MathMacro::updateExpansion() const
|
|
||||||
{
|
|
||||||
MacroData const & macro = MacroTable::globalMacros().get(name());
|
|
||||||
|
|
||||||
// create MathMacroArgumentValue object pointing to the cells of the macro
|
|
||||||
std::vector<MathData> values(nargs());
|
|
||||||
for (size_t i = 0; i != nargs(); ++i)
|
|
||||||
values[i].insert(0, MathAtom(new MathMacroArgumentValue(*this, i)));
|
|
||||||
macro.expand(values, expanded_);
|
|
||||||
asArray(macro.def(), tmpl_);
|
|
||||||
macroBackup_ = macro;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
#define MATH_MACRO_H
|
#define MATH_MACRO_H
|
||||||
|
|
||||||
#include "InsetMathNest.h"
|
#include "InsetMathNest.h"
|
||||||
#include "MathData.h"
|
#include "InsetMathSqrt.h"
|
||||||
#include "InsetMathNest.h"
|
|
||||||
#include "MacroTable.h"
|
#include "MacroTable.h"
|
||||||
|
#include "MathData.h"
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
|
|
||||||
@ -26,11 +25,13 @@ namespace lyx {
|
|||||||
class MathMacro : public InsetMathNest {
|
class MathMacro : public InsetMathNest {
|
||||||
public:
|
public:
|
||||||
/// A macro can be built from an existing template
|
/// A macro can be built from an existing template
|
||||||
MathMacro(docstring const & name, int numargs);
|
MathMacro(docstring const & name);
|
||||||
|
///
|
||||||
|
virtual MathMacro * asMacro() { return this; }
|
||||||
|
///
|
||||||
|
virtual MathMacro const * asMacro() const { return this; }
|
||||||
///
|
///
|
||||||
void draw(PainterInfo & pi, int x, int y) const;
|
void draw(PainterInfo & pi, int x, int y) const;
|
||||||
///
|
|
||||||
void drawExpanded(PainterInfo & pi, int x, int y) const;
|
|
||||||
/// draw selection background
|
/// draw selection background
|
||||||
void drawSelection(PainterInfo & pi, int x, int y) const;
|
void drawSelection(PainterInfo & pi, int x, int y) const;
|
||||||
/// draw decorations.
|
/// draw decorations.
|
||||||
@ -38,29 +39,34 @@ public:
|
|||||||
{ drawMarkers2(pi, x, y); }
|
{ drawMarkers2(pi, x, y); }
|
||||||
///
|
///
|
||||||
void metrics(MetricsInfo & mi, Dimension & dim) const;
|
void metrics(MetricsInfo & mi, Dimension & dim) const;
|
||||||
|
///
|
||||||
|
int kerning() const;
|
||||||
/// get cursor position
|
/// get cursor position
|
||||||
void cursorPos(BufferView const & bv, CursorSlice const & sl,
|
void cursorPos(BufferView const & bv, CursorSlice const & sl,
|
||||||
bool boundary, int & x, int & y) const;
|
bool boundary, int & x, int & y) const;
|
||||||
///
|
///
|
||||||
|
void edit(Cursor & cur, bool left);
|
||||||
|
///
|
||||||
Inset * editXY(Cursor & cur, int x, int y);
|
Inset * editXY(Cursor & cur, int x, int y);
|
||||||
|
|
||||||
/// target pos when we enter the inset from the left by pressing "Right"
|
/// target pos when we enter the inset from the left by pressing "Right"
|
||||||
bool idxFirst(Cursor &) const;
|
bool idxFirst(Cursor &) const;
|
||||||
/// target pos when we enter the inset from the right by pressing "Left"
|
/// target pos when we enter the inset from the right by pressing "Left"
|
||||||
bool idxLast(Cursor &) const;
|
bool idxLast(Cursor &) const;
|
||||||
///
|
|
||||||
bool idxUpDown(Cursor & cur, bool up) const;
|
|
||||||
///
|
///
|
||||||
virtual bool notifyCursorLeaves(Cursor &);
|
virtual bool notifyCursorLeaves(Cursor &);
|
||||||
///
|
|
||||||
docstring name() const;
|
/// Remove cell (starting from 0)
|
||||||
///
|
void removeArgument(size_t pos);
|
||||||
int kerning() const { return kerning_; }
|
/// Insert empty cell (starting from 0)
|
||||||
///
|
void insertArgument(size_t pos);
|
||||||
void setExpansion(MathData const & exp, MathData const & args) const;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
void validate(LaTeXFeatures &) const;
|
void validate(LaTeXFeatures &) const;
|
||||||
|
|
||||||
|
///
|
||||||
|
void MathMacro::write(WriteStream & os) const;
|
||||||
///
|
///
|
||||||
void maple(MapleStream &) const;
|
void maple(MapleStream &) const;
|
||||||
///
|
///
|
||||||
@ -72,27 +78,104 @@ public:
|
|||||||
///
|
///
|
||||||
void infoize2(odocstream &) const;
|
void infoize2(odocstream &) const;
|
||||||
|
|
||||||
private:
|
/// fold the macro in the next metrics call
|
||||||
virtual Inset * clone() const;
|
void fold(Cursor & cur);
|
||||||
|
/// unfold the macro in the next metrics call
|
||||||
|
void unfold(Cursor & cur);
|
||||||
|
/// will it be folded or unfolded in the next metric call?
|
||||||
|
bool folded() const;
|
||||||
|
|
||||||
|
enum DisplayMode {
|
||||||
|
DISPLAY_INIT,
|
||||||
|
DISPLAY_UNFOLDED,
|
||||||
|
DISPLAY_NORMAL,
|
||||||
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
void updateExpansion() const;
|
DisplayMode displayMode() const { return displayMode_; }
|
||||||
|
|
||||||
|
///
|
||||||
|
bool extraBraces() const { return displayMode_ == DISPLAY_NORMAL && arity() > 0; }
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
docstring name() const;
|
||||||
|
///
|
||||||
|
bool validName() const;
|
||||||
|
///
|
||||||
|
size_t arity() const {
|
||||||
|
if (displayMode_ == DISPLAY_NORMAL )
|
||||||
|
return cells_.size();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
int optionals() const { return optionals_; }
|
||||||
|
///
|
||||||
|
void setOptionals(int n) {
|
||||||
|
if (n <= int(nargs()))
|
||||||
|
optionals_ = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class MathData;
|
||||||
|
friend class ArgumentProxy;
|
||||||
|
|
||||||
|
/// update the display mode (should only be called after detaching arguments)
|
||||||
|
void setDisplayMode(DisplayMode mode);
|
||||||
|
/// compute the next display mode
|
||||||
|
DisplayMode computeDisplayMode(MetricsInfo const & mi) const;
|
||||||
|
/// update macro definition
|
||||||
|
void updateMacro(MetricsInfo & mi);
|
||||||
|
/// check if macro definition changed, argument changed etc. and adapt
|
||||||
|
void updateRepresentation(MetricsInfo & mi);
|
||||||
|
/// empty macro, put arguments into args, possibly strip arity-attachedArgsNum_ empty ones.
|
||||||
|
/// Includes the optional arguments.
|
||||||
|
void detachArguments(std::vector<MathData> & args, bool strip);
|
||||||
|
/// attach arguments (maybe less than arity at the end of an MathData),
|
||||||
|
/// including the optional ones (even if it can be empty here)
|
||||||
|
void attachArguments(std::vector<MathData> const & args, size_t arity, int optionals);
|
||||||
|
///
|
||||||
|
bool editing() { return editing_; }
|
||||||
|
///
|
||||||
|
MacroData const * macro() { return macro_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
///
|
||||||
|
virtual Inset * clone() const;
|
||||||
|
/// the index of the cursor slice of the macro, or -1 if it is not edited
|
||||||
|
int cursorIdx(Cursor const & cur) const;
|
||||||
|
///
|
||||||
|
bool editMode(Cursor const & cur) const;
|
||||||
|
|
||||||
/// name of macro
|
/// name of macro
|
||||||
docstring name_;
|
docstring name_;
|
||||||
/// the unexpanded macro defintition
|
/// current display mode
|
||||||
mutable MathData tmpl_;
|
DisplayMode displayMode_;
|
||||||
/// the macro substituted with our args
|
/// display mode before change
|
||||||
mutable MathData expanded_;
|
InsetMathSqrt expanded_;
|
||||||
|
/// number of arguments that were really attached
|
||||||
|
size_t attachedArgsNum_;
|
||||||
|
/// cursor position during last draw
|
||||||
|
int previousCurIdx_;
|
||||||
|
/// optional argument attached? (only in DISPLAY_NORMAL mode)
|
||||||
|
int optionals_;
|
||||||
|
/// fold mode to be set in next metrics call?
|
||||||
|
bool nextFoldMode_;
|
||||||
|
/// if macro_ == true, then here is a copy of the macro
|
||||||
|
/// don't use it for locking
|
||||||
|
MacroData macroBackup_;
|
||||||
|
/// if macroNotFound_ == false, then here is a reference to the macro
|
||||||
|
/// this might invalidate after metrics was called
|
||||||
|
MacroData const * macro_;
|
||||||
///
|
///
|
||||||
mutable MacroData macroBackup_;
|
bool editing_;
|
||||||
///
|
///
|
||||||
mutable bool editing_;
|
std::string requires_;
|
||||||
///
|
/// update macro representation
|
||||||
mutable int kerning_;
|
bool needsUpdate_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lyx
|
} // namespace lyx
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "MathMacroArgument.h"
|
#include "MathMacroArgument.h"
|
||||||
#include "MathStream.h"
|
#include "MathStream.h"
|
||||||
#include "MathSupport.h"
|
#include "MathSupport.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ MathMacroArgument::MathMacroArgument(size_t n)
|
|||||||
lyxerr << "MathMacroArgument::MathMacroArgument: wrong Argument id: "
|
lyxerr << "MathMacroArgument::MathMacroArgument: wrong Argument id: "
|
||||||
<< n << endl;
|
<< n << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The profiler tells us not to use
|
// The profiler tells us not to use
|
||||||
// str_ = '#' + convert<docstring>(n);
|
// str_ = '#' + convert<docstring>(n);
|
||||||
// so we do the conversion of n to ASCII manually.
|
// so we do the conversion of n to ASCII manually.
|
||||||
@ -46,6 +48,18 @@ Inset * MathMacroArgument::clone() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroArgument::setNumber(std::size_t n)
|
||||||
|
{
|
||||||
|
if (n < 1 || n > 9) {
|
||||||
|
lyxerr << "MathMacroArgument::setNumber: wrong Argument id: "
|
||||||
|
<< n << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
number_ = n;
|
||||||
|
str_[1] = '0' + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacroArgument::write(WriteStream & os) const
|
void MathMacroArgument::write(WriteStream & os) const
|
||||||
{
|
{
|
||||||
os << str_;
|
os << str_;
|
||||||
|
@ -31,6 +31,8 @@ public:
|
|||||||
///
|
///
|
||||||
std::size_t number() const { return number_; }
|
std::size_t number() const { return number_; }
|
||||||
///
|
///
|
||||||
|
void setNumber(std::size_t n);
|
||||||
|
///
|
||||||
InsetCode lyxCode() const { return MATHMACROARG_CODE; }
|
InsetCode lyxCode() const { return MATHMACROARG_CODE; }
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -10,22 +10,43 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "DocIterator.h"
|
||||||
|
#include "InsetMathBrace.h"
|
||||||
|
#include "InsetMathChar.h"
|
||||||
|
#include "InsetMathSqrt.h"
|
||||||
|
#include "MathMacro.h"
|
||||||
|
#include "MathMacroArgument.h"
|
||||||
#include "MathMacroTemplate.h"
|
#include "MathMacroTemplate.h"
|
||||||
#include "MathStream.h"
|
#include "MathStream.h"
|
||||||
#include "MathParser.h"
|
#include "MathParser.h"
|
||||||
#include "MathSupport.h"
|
#include "MathSupport.h"
|
||||||
|
#include "MathMacroArgument.h"
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "Color.h"
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "DispatchResult.h"
|
||||||
|
#include "FuncRequest.h"
|
||||||
|
#include "FuncStatus.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "Lexer.h"
|
#include "Lexer.h"
|
||||||
|
#include "Undo.h"
|
||||||
|
|
||||||
#include "frontends/FontMetrics.h"
|
#include "frontends/FontMetrics.h"
|
||||||
#include "frontends/Painter.h"
|
#include "frontends/Painter.h"
|
||||||
|
|
||||||
|
#include "support/convert.h"
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
namespace lyx {
|
namespace lyx {
|
||||||
|
|
||||||
@ -35,29 +56,74 @@ using std::ostream;
|
|||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
class InsetMathWrapper : public InsetMath {
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
InsetMathWrapper(MathData const * value) : value_(value) {}
|
||||||
|
///
|
||||||
|
void metrics(MetricsInfo & mi, Dimension & dim) const;
|
||||||
|
///
|
||||||
|
void draw(PainterInfo &, int x, int y) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
///
|
||||||
|
Inset * clone() const;
|
||||||
|
///
|
||||||
|
MathData const * value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Inset * InsetMathWrapper::clone() const
|
||||||
|
{
|
||||||
|
return new InsetMathWrapper(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InsetMathWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||||
|
{
|
||||||
|
value_->metrics(mi, dim);
|
||||||
|
//metricsMarkers2(dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InsetMathWrapper::draw(PainterInfo & pi, int x, int y) const
|
||||||
|
{
|
||||||
|
value_->draw(pi, x, y);
|
||||||
|
//drawMarkers(pi, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MathMacroTemplate::MathMacroTemplate()
|
MathMacroTemplate::MathMacroTemplate()
|
||||||
: InsetMathNest(2), numargs_(0), name_(), type_(from_ascii("newcommand"))
|
: InsetMathNest(3), numargs_(0), optionals_(0), type_(from_ascii("newcommand"))
|
||||||
{
|
{
|
||||||
initMath();
|
initMath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs,
|
MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs, int optionals,
|
||||||
docstring const & type, MathData const & ar1, MathData const & ar2)
|
docstring const & type,
|
||||||
: InsetMathNest(2), numargs_(numargs), name_(name), type_(type)
|
std::vector<MathData> const & optionalValues,
|
||||||
|
MathData const & def, MathData const & display)
|
||||||
|
: InsetMathNest(optionals + 3), numargs_(numargs),
|
||||||
|
optionals_(optionals), optionalValues_(optionalValues), type_(type)
|
||||||
{
|
{
|
||||||
initMath();
|
initMath();
|
||||||
|
|
||||||
if (numargs_ > 9)
|
if (numargs_ > 9)
|
||||||
lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: "
|
lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: "
|
||||||
<< numargs_ << std::endl;
|
<< numargs_ << std::endl;
|
||||||
cell(0) = ar1;
|
|
||||||
cell(1) = ar2;
|
asArray(name, cell(0));
|
||||||
|
optionalValues_.resize(9);
|
||||||
|
for (int i = 0; i < optionals_; ++i)
|
||||||
|
cell(optIdx(i)) = optionalValues_[i];
|
||||||
|
cell(defIdx()) = def;
|
||||||
|
cell(displayIdx()) = display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MathMacroTemplate::MathMacroTemplate(docstring const & str)
|
MathMacroTemplate::MathMacroTemplate(docstring const & str)
|
||||||
: InsetMathNest(2), numargs_(0), name_()
|
: InsetMathNest(3), numargs_(0)
|
||||||
{
|
{
|
||||||
initMath();
|
initMath();
|
||||||
|
|
||||||
@ -77,110 +143,499 @@ Inset * MathMacroTemplate::clone() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacroTemplate::edit(Cursor & cur, bool)
|
|
||||||
{
|
|
||||||
//lyxerr << "MathMacroTemplate: edit left/right" << endl;
|
|
||||||
cur.push(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int MathMacroTemplate::numargs() const
|
|
||||||
{
|
|
||||||
return numargs_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MathMacroTemplate::numargs(int numargs)
|
|
||||||
{
|
|
||||||
numargs_ = numargs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
docstring MathMacroTemplate::name() const
|
docstring MathMacroTemplate::name() const
|
||||||
{
|
{
|
||||||
return name_;
|
return asString(cell(0));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
docstring MathMacroTemplate::prefix() const
|
|
||||||
{
|
|
||||||
return bformat(_(" Macro: %1$s: "), name_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
|
void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
|
||||||
{
|
{
|
||||||
bool lockMacro = MacroTable::globalMacros().has(name_);
|
FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
|
||||||
if (lockMacro)
|
StyleChanger dummy2(mi.base, LM_ST_TEXT);
|
||||||
MacroTable::globalMacros().get(name_).lock();
|
|
||||||
|
// valid macro?
|
||||||
|
MacroData const * macro = 0;
|
||||||
|
if (validName() && mi.macrocontext.has(name())) {
|
||||||
|
macro = &mi.macrocontext.get(name());
|
||||||
|
if (type_ == from_ascii("newcommand") || type_ == from_ascii("renewcommand")) {
|
||||||
|
// use the MacroData::redefinition_ information instead of MacroContext::has
|
||||||
|
// because the macro is known here already anyway to detect recursive definitions
|
||||||
|
type_ = macro->redefinition() ? from_ascii("renewcommand") : from_ascii("newcommand");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create label "{#1}{#2}:="
|
||||||
|
label_.clear();
|
||||||
|
int i = 0;
|
||||||
|
for (; i < optionals_; ++i) {
|
||||||
|
label_.push_back(MathAtom(new InsetMathChar('[')));
|
||||||
|
label_.push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
|
||||||
|
label_.push_back(MathAtom(new InsetMathChar(']')));
|
||||||
|
}
|
||||||
|
for (; i < numargs_; ++i) {
|
||||||
|
MathData arg;
|
||||||
|
arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
|
||||||
|
label_.push_back(MathAtom(new InsetMathBrace(arg)));
|
||||||
|
}
|
||||||
|
label_.push_back(MathAtom(new InsetMathChar(':')));
|
||||||
|
label_.push_back(MathAtom(new InsetMathChar('=')));
|
||||||
|
|
||||||
|
// do metrics
|
||||||
|
if (macro)
|
||||||
|
macro->lock();
|
||||||
|
|
||||||
Dimension dim0;
|
Dimension dim0;
|
||||||
|
Dimension labeldim;
|
||||||
|
Dimension defdim;
|
||||||
|
Dimension dspdim;
|
||||||
|
|
||||||
cell(0).metrics(mi, dim0);
|
cell(0).metrics(mi, dim0);
|
||||||
Dimension dim1;
|
label_.metrics(mi, labeldim);
|
||||||
cell(1).metrics(mi, dim1);
|
cell(defIdx()).metrics(mi, defdim);
|
||||||
docstring dp = prefix();
|
cell(displayIdx()).metrics(mi, dspdim);
|
||||||
dim.wid = dim0.width() + dim1.width() + 20
|
|
||||||
+ theFontMetrics(mi.base.font).width(dp);
|
|
||||||
dim.asc = std::max(dim0.ascent(), dim1.ascent()) + 7;
|
|
||||||
dim.des = std::max(dim0.descent(), dim1.descent()) + 7;
|
|
||||||
|
|
||||||
if (lockMacro)
|
if (macro)
|
||||||
MacroTable::globalMacros().get(name_).unlock();
|
macro->unlock();
|
||||||
|
|
||||||
|
// calculate metrics taking all cells and labels into account
|
||||||
|
dim.wid = 2 + mathed_string_width(mi.base.font, from_ascii("\\")) +
|
||||||
|
dim0.width() +
|
||||||
|
labeldim.width() +
|
||||||
|
defdim.width() + 16 + dspdim.width() + 2;
|
||||||
|
|
||||||
|
dim.asc = dim0.ascent();
|
||||||
|
dim.asc = std::max(dim.asc, labeldim.ascent());
|
||||||
|
dim.asc = std::max(dim.asc, defdim.ascent());
|
||||||
|
dim.asc = std::max(dim.asc, dspdim.ascent());
|
||||||
|
|
||||||
|
dim.des = dim0.descent();
|
||||||
|
dim.des = std::max(dim.des, labeldim.descent());
|
||||||
|
dim.des = std::max(dim.des, defdim.descent());
|
||||||
|
dim.des = std::max(dim.des, dspdim.descent());
|
||||||
|
|
||||||
|
// make the name cell vertically centered, and 5 pixel lines margin
|
||||||
|
int real_asc = dim.asc - dim0.ascent() / 2;
|
||||||
|
int real_des = dim.des + dim0.ascent() / 2;
|
||||||
|
dim.asc = std::max(real_asc, real_des) + dim0.ascent() / 2 + 5;
|
||||||
|
dim.des = std::max(real_asc, real_des) - dim0.ascent() / 2 + 5;
|
||||||
|
|
||||||
// Cache the inset dimension.
|
|
||||||
setDimCache(mi, dim);
|
setDimCache(mi, dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MathMacroTemplate::draw(PainterInfo & p, int x, int y) const
|
void MathMacroTemplate::draw(PainterInfo & pi, int x, int y) const
|
||||||
{
|
{
|
||||||
bool lockMacro = MacroTable::globalMacros().has(name_);
|
FontSetChanger dummy1(pi.base, from_ascii("mathnormal"));
|
||||||
if (lockMacro)
|
StyleChanger dummy2(pi.base, LM_ST_TEXT);
|
||||||
MacroTable::globalMacros().get(name_).lock();
|
|
||||||
|
|
||||||
setPosCache(p, x, y);
|
setPosCache(pi, x, y);
|
||||||
|
Dimension const dim = dimension(*pi.base.bv);
|
||||||
|
|
||||||
Dimension const dim = dimension(*p.base.bv);
|
// create fonts
|
||||||
|
bool valid = validMacro();
|
||||||
// label
|
FontInfo font = pi.base.font;
|
||||||
FontInfo font = p.base.font;
|
if (valid)
|
||||||
font.setColor(Color_math);
|
font.setColor(Color_latex);
|
||||||
|
else
|
||||||
PainterInfo pi(p.base.bv, p.pain);
|
font.setColor(Color_error);
|
||||||
pi.base.style = LM_ST_TEXT;
|
|
||||||
pi.base.font = font;
|
|
||||||
|
|
||||||
|
// draw outer frame
|
||||||
int const a = y - dim.asc + 1;
|
int const a = y - dim.asc + 1;
|
||||||
int const w = dim.wid - 2;
|
int const w = dim.wid - 2;
|
||||||
int const h = dim.height() - 2;
|
int const h = dim.height() - 2;
|
||||||
|
|
||||||
// Color_mathbg used to be "AntiqueWhite" but is "linen" now, too
|
|
||||||
// the next line would overwrite the selection!
|
|
||||||
//pi.pain.fillRectangle(x, a, w, h, Color_mathmacrobg);
|
|
||||||
pi.pain.rectangle(x, a, w, h, Color_mathframe);
|
pi.pain.rectangle(x, a, w, h, Color_mathframe);
|
||||||
|
x += 4;
|
||||||
|
|
||||||
// FIXME:
|
// draw backslash
|
||||||
#if 0
|
pi.pain.text(x, y, from_ascii("\\"), font);
|
||||||
Cursor & cur = p.base.bv->cursor();
|
x += mathed_string_width(font, from_ascii("\\"));
|
||||||
if (cur.isInside(this))
|
|
||||||
cur.drawSelection(pi);
|
|
||||||
#endif
|
|
||||||
docstring dp = prefix();
|
|
||||||
pi.pain.text(x + 2, y, dp, font);
|
|
||||||
// FIXME: Painter text should retain the drawn text width
|
|
||||||
x += theFontMetrics(font).width(dp) + 6;
|
|
||||||
|
|
||||||
int const w0 = cell(0).dimension(*pi.base.bv).width();
|
// draw name
|
||||||
int const w1 = cell(1).dimension(*pi.base.bv).width();
|
PainterInfo namepi = pi;
|
||||||
cell(0).draw(pi, x + 2, y + 1);
|
namepi.base.font = font;
|
||||||
pi.pain.rectangle(x, y - dim.ascent() + 3,
|
cell(0).draw(namepi, x, y);
|
||||||
w0 + 4, dim.height() - 6, Color_mathline);
|
x += cell(0).dimension(*pi.base.bv).width();
|
||||||
cell(1).draw(pi, x + 8 + w0, y + 1);
|
|
||||||
pi.pain.rectangle(x + w0 + 6, y - dim.ascent() + 3,
|
|
||||||
w1 + 4, dim.height() - 6, Color_mathline);
|
|
||||||
|
|
||||||
if (lockMacro)
|
// draw label
|
||||||
MacroTable::globalMacros().get(name_).unlock();
|
label_.draw(pi, x, y);
|
||||||
|
x += label_.dimension(*pi.base.bv).width();
|
||||||
|
|
||||||
|
// draw definition
|
||||||
|
cell(defIdx()).draw(pi, x + 2, y);
|
||||||
|
int const w1 = cell(defIdx()).dimension(*pi.base.bv).width();
|
||||||
|
pi.pain.rectangle(x, y - dim.ascent() + 3, w1 + 4, dim.height() - 6, Color_mathline);
|
||||||
|
x += w1 + 8;
|
||||||
|
|
||||||
|
// draw display
|
||||||
|
cell(displayIdx()).draw(pi, x + 2, y);
|
||||||
|
int const w2 = cell(displayIdx()).dimension(*pi.base.bv).width();
|
||||||
|
pi.pain.rectangle(x, y - dim.ascent() + 3, w2 + 4, dim.height() - 6, Color_mathline);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroTemplate::removeArguments(Cursor & cur, int from, int to) {
|
||||||
|
for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
|
||||||
|
if (!it.nextInset())
|
||||||
|
continue;
|
||||||
|
if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
|
||||||
|
continue;
|
||||||
|
MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
|
||||||
|
int n = arg->number() - 1;
|
||||||
|
if (from <= n && n <= to) {
|
||||||
|
int cellSlice = cur.find(it.cell());
|
||||||
|
if (cellSlice != -1 && cur[cellSlice].pos() > it.pos())
|
||||||
|
--cur[cellSlice].pos();
|
||||||
|
|
||||||
|
it.cell().erase(it.pos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroTemplate::shiftArguments(size_t from, int by) {
|
||||||
|
for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
|
||||||
|
if (!it.nextInset())
|
||||||
|
continue;
|
||||||
|
if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
|
||||||
|
continue;
|
||||||
|
MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
|
||||||
|
if (arg->number() >= from + 1)
|
||||||
|
arg->setNumber(arg->number() + by);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: factorize those functions here with a functional style, maybe using Boost's function
|
||||||
|
// objects?
|
||||||
|
|
||||||
|
void fixMacroInstancesAddRemove(Cursor const & from, docstring const & name, int n, bool insert) {
|
||||||
|
Cursor dit = from;
|
||||||
|
|
||||||
|
for (; dit; dit.forwardPos()) {
|
||||||
|
// only until a macro is redefined
|
||||||
|
if (dit.inset().lyxCode() == MATHMACRO_CODE) {
|
||||||
|
MathMacroTemplate const & macroTemplate
|
||||||
|
= static_cast<MathMacroTemplate const &>(dit.inset());
|
||||||
|
if (macroTemplate.name() == name)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in front of macro instance?
|
||||||
|
Inset * inset = dit.nextInset();
|
||||||
|
if (inset) {
|
||||||
|
InsetMath * insetMath = inset->asInsetMath();
|
||||||
|
if (insetMath) {
|
||||||
|
MathMacro * macro = insetMath->asMacro();
|
||||||
|
if (macro && macro->name() == name && macro->folded()) {
|
||||||
|
// found macro instance
|
||||||
|
if (insert)
|
||||||
|
macro->insertArgument(n);
|
||||||
|
else
|
||||||
|
macro->removeArgument(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fixMacroInstancesOptional(Cursor const & from, docstring const & name, int optionals) {
|
||||||
|
Cursor dit = from;
|
||||||
|
|
||||||
|
for (; dit; dit.forwardPos()) {
|
||||||
|
// only until a macro is redefined
|
||||||
|
if (dit.inset().lyxCode() == MATHMACRO_CODE) {
|
||||||
|
MathMacroTemplate const & macroTemplate
|
||||||
|
= static_cast<MathMacroTemplate const &>(dit.inset());
|
||||||
|
if (macroTemplate.name() == name)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in front of macro instance?
|
||||||
|
Inset * inset = dit.nextInset();
|
||||||
|
if (inset) {
|
||||||
|
InsetMath * insetMath = inset->asInsetMath();
|
||||||
|
if (insetMath) {
|
||||||
|
MathMacro * macro = insetMath->asMacro();
|
||||||
|
if (macro && macro->name() == name && macro->folded()) {
|
||||||
|
// found macro instance
|
||||||
|
macro->setOptionals(optionals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class F>
|
||||||
|
void fixMacroInstancesFunctional(Cursor const & from,
|
||||||
|
docstring const & name, F & fix) {
|
||||||
|
Cursor dit = from;
|
||||||
|
|
||||||
|
for (; dit; dit.forwardPos()) {
|
||||||
|
// only until a macro is redefined
|
||||||
|
if (dit.inset().lyxCode() == MATHMACRO_CODE) {
|
||||||
|
MathMacroTemplate const & macroTemplate
|
||||||
|
= static_cast<MathMacroTemplate const &>(dit.inset());
|
||||||
|
if (macroTemplate.name() == name)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in front of macro instance?
|
||||||
|
Inset * inset = dit.nextInset();
|
||||||
|
if (inset) {
|
||||||
|
InsetMath * insetMath = inset->asInsetMath();
|
||||||
|
if (insetMath) {
|
||||||
|
MathMacro * macro = insetMath->asMacro();
|
||||||
|
if (macro && macro->name() == name && macro->folded())
|
||||||
|
F(macro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroTemplate::insertParameter(Cursor & cur, int pos, bool greedy)
|
||||||
|
{
|
||||||
|
if (pos <= numargs_ && pos >= optionals_ && numargs_ < 9) {
|
||||||
|
++numargs_;
|
||||||
|
shiftArguments(pos, 1);
|
||||||
|
|
||||||
|
// append example #n
|
||||||
|
cell(defIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
|
||||||
|
if (!cell(displayIdx()).empty())
|
||||||
|
cell(displayIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
|
||||||
|
|
||||||
|
if (!greedy) {
|
||||||
|
Cursor dit = cur;
|
||||||
|
dit.leaveInset(*this);
|
||||||
|
// TODO: this was dit.forwardPosNoDescend before. Check that this is the same
|
||||||
|
dit.top().forwardPos();
|
||||||
|
|
||||||
|
// fix macro instances
|
||||||
|
fixMacroInstancesAddRemove(dit, name(), pos, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroTemplate::removeParameter(Cursor & cur, int pos, bool greedy)
|
||||||
|
{
|
||||||
|
if (pos < numargs_ && pos >= 0) {
|
||||||
|
--numargs_;
|
||||||
|
removeArguments(cur, pos, pos);
|
||||||
|
shiftArguments(pos + 1, -1);
|
||||||
|
|
||||||
|
// removed optional parameter?
|
||||||
|
if (pos < optionals_) {
|
||||||
|
--optionals_;
|
||||||
|
optionalValues_[pos] = cell(optIdx(pos));
|
||||||
|
cells_.erase(cells_.begin() + optIdx(pos));
|
||||||
|
|
||||||
|
// fix cursor
|
||||||
|
int macroSlice = cur.find(this);
|
||||||
|
if (macroSlice != -1) {
|
||||||
|
if (cur[macroSlice].idx() == optIdx(pos)) {
|
||||||
|
cur.cutOff(macroSlice);
|
||||||
|
cur[macroSlice].idx() = 1;
|
||||||
|
cur[macroSlice].pos() = 0;
|
||||||
|
} else if (cur[macroSlice].idx() > optIdx(pos))
|
||||||
|
--cur[macroSlice].idx();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!greedy) {
|
||||||
|
// fix macro instances
|
||||||
|
//boost::function<void(MathMacro *)> fix = _1->insertArgument(n);
|
||||||
|
//fixMacroInstancesFunctional(dit, name(), fix);
|
||||||
|
Cursor dit = cur;
|
||||||
|
dit.leaveInset(*this);
|
||||||
|
// TODO: this was dit.forwardPosNoDescend before. Check that this is the same
|
||||||
|
dit.top().forwardPos();
|
||||||
|
fixMacroInstancesAddRemove(dit, name(), pos, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroTemplate::makeOptional(Cursor & cur) {
|
||||||
|
if (numargs_ > 0 && optionals_ < numargs_) {
|
||||||
|
++optionals_;
|
||||||
|
cells_.insert(cells_.begin() + optIdx(optionals_ - 1), optionalValues_[optionals_ - 1]);
|
||||||
|
// fix cursor
|
||||||
|
int macroSlice = cur.find(this);
|
||||||
|
if (macroSlice != -1 && cur[macroSlice].idx() >= optIdx(optionals_ - 1))
|
||||||
|
++cur[macroSlice].idx();
|
||||||
|
|
||||||
|
// fix macro instances
|
||||||
|
Cursor dit = cur;
|
||||||
|
dit.leaveInset(*this);
|
||||||
|
// TODO: this was dit.forwardPosNoDescend before. Check that this is the same
|
||||||
|
dit.top().forwardPos();
|
||||||
|
fixMacroInstancesOptional(dit, name(), optionals_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroTemplate::makeNonOptional(Cursor & cur) {
|
||||||
|
if (numargs_ > 0 && optionals_ > 0) {
|
||||||
|
--optionals_;
|
||||||
|
optionalValues_[optionals_ - 1] = cell(optIdx(optionals_));
|
||||||
|
cells_.erase(cells_.begin() + optIdx(optionals_));
|
||||||
|
|
||||||
|
// fix cursor
|
||||||
|
int macroSlice = cur.find(this);
|
||||||
|
if (macroSlice != -1) {
|
||||||
|
if (cur[macroSlice].idx() > optIdx(optionals_))
|
||||||
|
--cur[macroSlice].idx();
|
||||||
|
else if (cur[macroSlice].idx() == optIdx(optionals_)) {
|
||||||
|
cur.cutOff(macroSlice);
|
||||||
|
cur[macroSlice].idx() = optIdx(optionals_);
|
||||||
|
cur[macroSlice].pos() = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix macro instances
|
||||||
|
Cursor dit = cur;
|
||||||
|
dit.leaveInset(*this);
|
||||||
|
// TODO: this was dit.forwardPosNoDescend before. Check that this is the same
|
||||||
|
dit.top().forwardPos();
|
||||||
|
fixMacroInstancesOptional(dit, name(), optionals_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MathMacroTemplate::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||||||
|
{
|
||||||
|
std::string const arg = to_utf8(cmd.argument());
|
||||||
|
switch (cmd.action) {
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_ADD_PARAM:
|
||||||
|
if (numargs_ < 9) {
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
size_t pos = numargs_;
|
||||||
|
if (arg.size() != 0)
|
||||||
|
pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
|
||||||
|
insertParameter(cur, pos);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_REMOVE_PARAM:
|
||||||
|
if (numargs_ > 0) {
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
size_t pos = numargs_ - 1;
|
||||||
|
if (arg.size() != 0)
|
||||||
|
pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
|
||||||
|
removeParameter(cur, pos);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
|
||||||
|
if (numargs_ < 9) {
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
insertParameter(cur, numargs_, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_REMOVE_GREEDY_PARAM:
|
||||||
|
if (numargs_ > 0) {
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
removeParameter(cur, numargs_ - 1, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_MAKE_OPTIONAL:
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
makeOptional(cur);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
makeNonOptional(cur);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
|
||||||
|
if (numargs_ < 9) {
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
insertParameter(cur, optionals_);
|
||||||
|
makeOptional(cur);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
|
||||||
|
if (optionals_ > 0)
|
||||||
|
removeParameter(cur, optionals_ - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
|
||||||
|
if (numargs_ == optionals_) {
|
||||||
|
cur.recordUndoFullDocument();
|
||||||
|
insertParameter(cur, 0, true);
|
||||||
|
makeOptional(cur);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
InsetMathNest::doDispatch(cur, cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MathMacroTemplate::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||||
|
FuncStatus & flag) const
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
std::string const arg = to_utf8(cmd.argument());
|
||||||
|
switch (cmd.action) {
|
||||||
|
case LFUN_MATH_MACRO_ADD_PARAM: {
|
||||||
|
int num = numargs_ + 1;
|
||||||
|
if (arg.size() != 0)
|
||||||
|
num = convert<int>(arg);
|
||||||
|
bool on = (num >= optionals_ && numargs_ < 9 && num <= numargs_ + 1);
|
||||||
|
flag.enabled(on);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
|
||||||
|
flag.enabled(numargs_ < 9);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_REMOVE_PARAM: {
|
||||||
|
int num = numargs_;
|
||||||
|
if (arg.size() != 0)
|
||||||
|
num = convert<int>(arg);
|
||||||
|
flag.enabled(num >= 1 && num <= numargs_);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_MAKE_OPTIONAL:
|
||||||
|
flag.enabled(numargs_ > 0 && optionals_ < numargs_ && type_ != from_ascii("def"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
|
||||||
|
flag.enabled(optionals_ > 0 && type_ != from_ascii("def"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
|
||||||
|
flag.enabled(numargs_ < 9);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
|
||||||
|
flag.enabled(optionals_ > 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
|
||||||
|
flag.enabled(numargs_ == 0 && type_ != from_ascii("def"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -210,25 +665,46 @@ void MathMacroTemplate::write(Buffer const &, std::ostream & os) const
|
|||||||
void MathMacroTemplate::write(WriteStream & os) const
|
void MathMacroTemplate::write(WriteStream & os) const
|
||||||
{
|
{
|
||||||
if (type_ == "def") {
|
if (type_ == "def") {
|
||||||
os << "\\def\\" << name_.c_str();
|
os << "\\def\\" << name().c_str();
|
||||||
for (int i = 1; i <= numargs_; ++i)
|
for (int i = 1; i <= numargs_; ++i)
|
||||||
os << '#' << i;
|
os << '#' << i;
|
||||||
} else {
|
} else {
|
||||||
// newcommand or renewcommand
|
// newcommand or renewcommand
|
||||||
os << "\\" << type_.c_str() << "{\\" << name_.c_str() << '}';
|
os << "\\" << type_.c_str() << "{\\" << name().c_str() << '}';
|
||||||
if (numargs_ > 0)
|
if (numargs_ > 0)
|
||||||
os << '[' << numargs_ << ']';
|
os << '[' << numargs_ << ']';
|
||||||
|
|
||||||
|
// optional values
|
||||||
|
if (os.latex()) {
|
||||||
|
// in latex only one optional possible, simulate the others
|
||||||
|
if (optionals_ >= 1) {
|
||||||
|
docstring optValue = asString(cell(optIdx(0)));
|
||||||
|
if (optValue.find(']') != docstring::npos)
|
||||||
|
os << "[{" << cell(optIdx(0)) << "}]";
|
||||||
|
else
|
||||||
|
os << "[" << cell(optIdx(0)) << "]";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// in lyx we handle all optionals as real optionals
|
||||||
|
for (int i = 0; i < optionals_; ++i) {
|
||||||
|
docstring optValue = asString(cell(optIdx(i)));
|
||||||
|
if (optValue.find(']') != docstring::npos)
|
||||||
|
os << "[{" << cell(optIdx(i)) << "}]";
|
||||||
|
else
|
||||||
|
os << "[" << cell(optIdx(i)) << "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os << '{' << cell(0) << "}";
|
os << "{" << cell(defIdx()) << "}";
|
||||||
|
|
||||||
if (os.latex()) {
|
if (os.latex()) {
|
||||||
// writing .tex. done.
|
// writing .tex. done.
|
||||||
os << "\n";
|
os << "\n";
|
||||||
} else {
|
} else {
|
||||||
// writing .lyx, write special .tex export only if necessary
|
// writing .lyx, write special .tex export only if necessary
|
||||||
if (!cell(1).empty())
|
if (!cell(displayIdx()).empty())
|
||||||
os << "\n{" << cell(1) << '}';
|
os << "\n{" << cell(displayIdx()) << '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,9 +719,44 @@ int MathMacroTemplate::plaintext(Buffer const & buf, odocstream & os,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MathMacroTemplate::validName() const
|
||||||
|
{
|
||||||
|
docstring n = name();
|
||||||
|
|
||||||
|
// empty name?
|
||||||
|
if (n.size() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// converting back and force doesn't swallow anything?
|
||||||
|
/*MathData ma;
|
||||||
|
asArray(n, ma);
|
||||||
|
if (asString(ma) != n)
|
||||||
|
return false;*/
|
||||||
|
|
||||||
|
// valid characters?
|
||||||
|
for (size_t i = 0; i < n.size(); ++i) {
|
||||||
|
if (!(n[i] >= 'a' && n[i] <= 'z') &&
|
||||||
|
!(n[i] >= 'A' && n[i] <= 'Z'))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MathMacroTemplate::validMacro() const
|
||||||
|
{
|
||||||
|
return validName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MacroData MathMacroTemplate::asMacroData() const
|
MacroData MathMacroTemplate::asMacroData() const
|
||||||
{
|
{
|
||||||
return MacroData(asString(cell(0)), numargs(), asString(cell(1)), std::string());
|
std::vector<docstring> defaults(numargs_);
|
||||||
|
for (int i = 0; i < optionals_; ++i)
|
||||||
|
defaults[i] = asString(cell(optIdx(i)));
|
||||||
|
return MacroData(asString(cell(defIdx())), defaults,
|
||||||
|
numargs_, optionals_, asString(cell(displayIdx())), std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
#ifndef MATH_MACROTEMPLATE_H
|
#ifndef MATH_MACROTEMPLATE_H
|
||||||
#define MATH_MACROTEMPLATE_H
|
#define MATH_MACROTEMPLATE_H
|
||||||
|
|
||||||
#include "MathData.h"
|
|
||||||
#include "MacroTable.h"
|
|
||||||
#include "InsetMathNest.h"
|
#include "InsetMathNest.h"
|
||||||
|
#include "MacroTable.h"
|
||||||
|
#include "MathData.h"
|
||||||
|
|
||||||
#include "support/types.h"
|
#include "support/types.h"
|
||||||
|
|
||||||
@ -28,15 +28,14 @@ public:
|
|||||||
///
|
///
|
||||||
MathMacroTemplate();
|
MathMacroTemplate();
|
||||||
///
|
///
|
||||||
MathMacroTemplate(docstring const & name, int nargs,
|
MathMacroTemplate(docstring const & name, int nargs, int optional,
|
||||||
docstring const & type,
|
docstring const & type,
|
||||||
MathData const & = MathData(),
|
std::vector<MathData> const & optionalValues = std::vector<MathData>(),
|
||||||
MathData const & = MathData());
|
MathData const & def = MathData(),
|
||||||
|
MathData const & display = MathData());
|
||||||
///
|
///
|
||||||
explicit MathMacroTemplate(const docstring & str);
|
explicit MathMacroTemplate(const docstring & str);
|
||||||
///
|
///
|
||||||
void edit(Cursor & cur, bool left);
|
|
||||||
///
|
|
||||||
EDITABLE editable() const { return HIGHLY_EDITABLE; }
|
EDITABLE editable() const { return HIGHLY_EDITABLE; }
|
||||||
///
|
///
|
||||||
void read(Buffer const &, Lexer & lex);
|
void read(Buffer const &, Lexer & lex);
|
||||||
@ -46,14 +45,14 @@ public:
|
|||||||
void write(WriteStream & os) const;
|
void write(WriteStream & os) const;
|
||||||
///
|
///
|
||||||
int plaintext(Buffer const &, odocstream &,
|
int plaintext(Buffer const &, odocstream &,
|
||||||
OutputParams const &) const;
|
OutputParams const &) const;
|
||||||
|
|
||||||
/// Number of arguments
|
|
||||||
int numargs() const;
|
|
||||||
///
|
|
||||||
void numargs(int);
|
|
||||||
///
|
///
|
||||||
docstring name() const;
|
docstring name() const;
|
||||||
|
/// check name and possible other formal properties
|
||||||
|
bool validMacro() const;
|
||||||
|
///
|
||||||
|
bool validName() const;
|
||||||
///
|
///
|
||||||
MacroData asMacroData() const;
|
MacroData asMacroData() const;
|
||||||
///
|
///
|
||||||
@ -67,17 +66,44 @@ public:
|
|||||||
///
|
///
|
||||||
InsetCode lyxCode() const { return MATHMACRO_CODE; }
|
InsetCode lyxCode() const { return MATHMACRO_CODE; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
///
|
||||||
|
virtual void doDispatch(Cursor & cur, FuncRequest & cmd);
|
||||||
|
/// do we want to handle this event?
|
||||||
|
bool getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||||
|
FuncStatus & status) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual Inset * clone() const;
|
virtual Inset * clone() const;
|
||||||
/// prefix in inset
|
|
||||||
docstring prefix() const;
|
|
||||||
|
|
||||||
|
/// remove #n with from<=n<=to
|
||||||
|
void removeArguments(Cursor & cur, int from, int to);
|
||||||
|
/// shift every #n with from<=n, i.e. #n -> #(n-by)
|
||||||
|
void shiftArguments(size_t from, int by);
|
||||||
///
|
///
|
||||||
int numargs_;
|
void insertParameter(Cursor & cur, int pos, bool greedy = false);
|
||||||
///
|
///
|
||||||
docstring name_;
|
void removeParameter(Cursor & cur, int pos, bool greedy = false );
|
||||||
|
///
|
||||||
|
void makeOptional(Cursor & cur);
|
||||||
|
///
|
||||||
|
void makeNonOptional(Cursor & cur);
|
||||||
|
///
|
||||||
|
pos_type defIdx() const { return optionals_ + 1; }
|
||||||
|
/// index of default value cell of optional parameter (#1 -> n=0)
|
||||||
|
pos_type optIdx(int n) const { return n + 1; }
|
||||||
|
///
|
||||||
|
pos_type displayIdx() const { return optionals_ + 2; }
|
||||||
|
/// The label with some holes to edit
|
||||||
|
mutable MathData label_;
|
||||||
|
///
|
||||||
|
mutable int numargs_;
|
||||||
|
///
|
||||||
|
int optionals_;
|
||||||
|
/// keeps the old optional default value when an optional argument is disabled
|
||||||
|
std::vector<MathData> optionalValues_;
|
||||||
/// newcommand or renewcommand or def
|
/// newcommand or renewcommand or def
|
||||||
docstring type_;
|
mutable docstring type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -905,6 +905,8 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags,
|
|||||||
docstring const type = t.cs();
|
docstring const type = t.cs();
|
||||||
docstring name;
|
docstring name;
|
||||||
int nargs = 0;
|
int nargs = 0;
|
||||||
|
int optionals = 0;
|
||||||
|
std::vector<MathData> optionalValues;
|
||||||
if (t.cs() == "def") {
|
if (t.cs() == "def") {
|
||||||
// get name
|
// get name
|
||||||
name = getToken().cs();
|
name = getToken().cs();
|
||||||
@ -919,7 +921,6 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags,
|
|||||||
//lyxerr << "read \\def parameter list '" << pars << "'" << endl;
|
//lyxerr << "read \\def parameter list '" << pars << "'" << endl;
|
||||||
|
|
||||||
} else { // t.cs() == "newcommand" || t.cs() == "renewcommand"
|
} else { // t.cs() == "newcommand" || t.cs() == "renewcommand"
|
||||||
|
|
||||||
if (getToken().cat() != catBegin) {
|
if (getToken().cat() != catBegin) {
|
||||||
error("'{' in \\newcommand expected (1) ");
|
error("'{' in \\newcommand expected (1) ");
|
||||||
return;
|
return;
|
||||||
@ -936,27 +937,27 @@ void Parser::parse1(InsetMathGrid & grid, unsigned flags,
|
|||||||
if (!arg.empty())
|
if (!arg.empty())
|
||||||
nargs = convert<int>(arg);
|
nargs = convert<int>(arg);
|
||||||
|
|
||||||
|
// optional argument given?
|
||||||
|
skipSpaces();
|
||||||
|
while (nextToken().character() == '[') {
|
||||||
|
getToken();
|
||||||
|
optionalValues.push_back(MathData());
|
||||||
|
parse(optionalValues[optionals], FLAG_BRACK_LAST, mode);
|
||||||
|
++optionals;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MathData ar1;
|
MathData def;
|
||||||
parse(ar1, FLAG_ITEM, InsetMath::UNDECIDED_MODE);
|
parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE);
|
||||||
|
|
||||||
// we cannot handle recursive stuff at all
|
|
||||||
//MathData test;
|
|
||||||
//test.push_back(createInsetMath(name));
|
|
||||||
//if (ar1.contains(test)) {
|
|
||||||
// error("we cannot handle recursive macros at all.");
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// is a version for display attached?
|
// is a version for display attached?
|
||||||
skipSpaces();
|
skipSpaces();
|
||||||
MathData ar2;
|
MathData display;
|
||||||
if (nextToken().cat() == catBegin)
|
if (nextToken().cat() == catBegin)
|
||||||
parse(ar2, FLAG_ITEM, InsetMath::MATH_MODE);
|
parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
|
||||||
|
|
||||||
cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, type,
|
cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, optionals, type,
|
||||||
ar1, ar2)));
|
optionalValues, def, display)));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (t.cs() == "(") {
|
else if (t.cs() == "(") {
|
||||||
|
Loading…
Reference in New Issue
Block a user