lyx_mirror/src/mathed/math_nestinset.C

1217 lines
26 KiB
C++
Raw Normal View History

/**
* \file math_nestinset.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Andr<EFBFBD> P<EFBFBD>nitz
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "math_nestinset.h"
#include "math_arrayinset.h"
#include "math_braceinset.h"
#include "math_commentinset.h"
#include "math_data.h"
#include "math_deliminset.h"
#include "math_factory.h"
#include "math_hullinset.h"
#include "math_mathmlstream.h"
#include "math_parser.h"
#include "math_scriptinset.h"
#include "math_spaceinset.h"
#include "math_support.h"
#include "math_mboxinset.h"
#include "math_unknowninset.h"
#include "BufferView.h"
#include "FuncStatus.h"
#include "LColor.h"
#include "bufferview_funcs.h"
#include "cursor.h"
#include "debug.h"
#include "dispatchresult.h"
#include "funcrequest.h"
#include "gettext.h"
#include "outputparams.h"
#include "undo.h"
#include "support/std_sstream.h"
#include "support/lstrings.h"
#include "frontends/Dialogs.h"
#include "frontends/LyXView.h"
#include "frontends/Painter.h"
using std::endl;
using std::string;
using std::istringstream;
namespace {
// local global
int first_x;
int first_y;
} // namespace anon
MathNestInset::MathNestInset(idx_type nargs)
: cells_(nargs), lock_(false)
{}
MathInset::idx_type MathNestInset::nargs() const
{
return cells_.size();
}
MathArray & MathNestInset::cell(idx_type i)
{
return cells_[i];
}
MathArray const & MathNestInset::cell(idx_type i) const
{
return cells_[i];
}
void MathNestInset::getCursorPos(CursorSlice const & cur,
int & x, int & y) const
{
BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
MathArray const & ar = cur.cell();
x = ar.xo() + ar.pos2x(cur.pos());
y = ar.yo();
// move cursor visually into empty cells ("blue rectangles");
if (cur.cell().empty())
x += 2;
}
void MathNestInset::metrics(MetricsInfo const & mi) const
{
MetricsInfo m = mi;
for (idx_type i = 0; i < nargs(); ++i)
cell(i).metrics(m);
}
bool MathNestInset::idxNext(LCursor & cur) const
{
BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
if (cur.idx() == cur.lastidx())
return false;
++cur.idx();
cur.pos() = 0;
return true;
}
bool MathNestInset::idxRight(LCursor & cur) const
{
return idxNext(cur);
}
bool MathNestInset::idxPrev(LCursor & cur) const
{
BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
if (cur.idx() == 0)
return false;
--cur.idx();
cur.pos() = cur.lastpos();
return true;
}
bool MathNestInset::idxLeft(LCursor & cur) const
{
return idxPrev(cur);
}
bool MathNestInset::idxFirst(LCursor & cur) const
{
BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
if (nargs() == 0)
return false;
cur.idx() = 0;
cur.pos() = 0;
return true;
}
bool MathNestInset::idxLast(LCursor & cur) const
{
BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
if (nargs() == 0)
return false;
cur.idx() = cur.lastidx();
cur.pos() = cur.lastpos();
return true;
}
void MathNestInset::dump() const
{
WriteStream os(lyxerr);
os << "---------------------------------------------\n";
write(os);
os << "\n";
for (idx_type i = 0; i < nargs(); ++i)
os << cell(i) << "\n";
os << "---------------------------------------------\n";
}
void MathNestInset::draw(PainterInfo & pi, int x, int y) const
{
#if 0
if (lock_)
pi.pain.fillRectangle(x, y - ascent(), width(), height(),
LColor::mathlockbg);
#endif
setPosCache(pi, x, y);
}
void MathNestInset::drawSelection(PainterInfo & pi, int x, int y) const
{
// this should use the x/y values given, not the cached values
LCursor & cur = pi.base.bv->cursor();
if (!cur.selection())
return;
if (!ptr_cmp(&cur.inset(), this))
return;
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
CursorSlice s1 = cur.selBegin();
CursorSlice s2 = cur.selEnd();
lyxerr << "MathNestInset::drawing selection: "
<< " s1: " << s1 << " s2: " << s2 << endl;
if (s1.idx() == s2.idx()) {
MathArray const & c = cell(s1.idx());
int x1 = c.xo() + c.pos2x(s1.pos());
int y1 = c.yo() - c.ascent();
int x2 = c.xo() + c.pos2x(s2.pos());
int y2 = c.yo() + c.descent();
pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
lyxerr << "MathNestInset::drawing selection 3: "
<< " x1: " << x1 << " x2: " << x2
<< " y1: " << y1 << " y2: " << y2 << endl;
} else {
for (idx_type i = 0; i < nargs(); ++i) {
if (idxBetween(i, s1.idx(), s2.idx())) {
MathArray const & c = cell(i);
int x1 = c.xo();
int y1 = c.yo() - c.ascent();
int x2 = c.xo() + c.width();
int y2 = c.yo() + c.descent();
pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
}
}
}
}
void MathNestInset::validate(LaTeXFeatures & features) const
{
for (idx_type i = 0; i < nargs(); ++i)
cell(i).validate(features);
}
void MathNestInset::replace(ReplaceData & rep)
{
for (idx_type i = 0; i < nargs(); ++i)
cell(i).replace(rep);
}
bool MathNestInset::contains(MathArray const & ar) const
{
for (idx_type i = 0; i < nargs(); ++i)
if (cell(i).contains(ar))
return true;
return false;
}
bool MathNestInset::lock() const
{
return lock_;
}
void MathNestInset::lock(bool l)
{
lock_ = l;
}
bool MathNestInset::isActive() const
{
return nargs() > 0;
}
MathArray MathNestInset::glue() const
{
MathArray ar;
for (size_t i = 0; i < nargs(); ++i)
ar.append(cell(i));
return ar;
}
void MathNestInset::write(WriteStream & os) const
{
os << '\\' << name().c_str();
for (size_t i = 0; i < nargs(); ++i)
os << '{' << cell(i) << '}';
if (nargs() == 0)
os.pendingSpace(true);
if (lock_ && !os.latex()) {
os << "\\lyxlock";
os.pendingSpace(true);
}
}
void MathNestInset::normalize(NormalStream & os) const
{
os << '[' << name().c_str();
for (size_t i = 0; i < nargs(); ++i)
os << ' ' << cell(i);
os << ']';
}
int MathNestInset::latex(Buffer const &, std::ostream & os,
OutputParams const & runparams) const
{
WriteStream wi(os, runparams.moving_arg, true);
write(wi);
return wi.line();
}
void MathNestInset::notifyCursorLeaves(LCursor & cur)
{
#warning look here
#if 0
MathArray & ar = cur.cell();
// remove base-only "scripts"
for (pos_type i = 0; i + 1 < size(); ++i) {
MathScriptInset * p = operator[](i).nucleus()->asScriptInset();
if (p && p->nargs() == 1) {
MathArray ar = p->nuc();
erase(i);
insert(i, ar);
cur.adjust(i, ar.size() - 1);
}
}
// glue adjacent font insets of the same kind
for (pos_type i = 0; i + 1 < size(); ++i) {
MathFontInset * p = operator[](i).nucleus()->asFontInset();
MathFontInset const * q = operator[](i + 1)->asFontInset();
if (p && q && p->name() == q->name()) {
p->cell(0).append(q->cell(0));
erase(i + 1);
cur.adjust(i, -1);
}
}
#endif
}
void MathNestInset::handleFont
(LCursor & cur, string const & arg, string const & font)
{
// this whole function is a hack and won't work for incremental font
// changes...
recordUndo(cur, Undo::ATOMIC);
if (cur.inset().asMathInset()->name() == font)
cur.handleFont(font);
else {
cur.handleNest(createMathInset(font));
cur.insert(arg);
}
}
void MathNestInset::handleFont2(LCursor & cur, string const & arg)
{
recordUndo(cur, Undo::ATOMIC);
LyXFont font;
bool b;
bv_funcs::string2font(arg, font, b);
if (font.color() != LColor::inherit) {
MathAtom at = createMathInset("color");
asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
cur.handleNest(at, 1);
}
}
void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest & cmd)
{
//lyxerr << "MathNestInset: request: " << cmd << std::endl;
//CursorSlice sl = cur.current();
switch (cmd.action) {
case LFUN_PASTESELECTION: {
MathArray ar;
mathed_parse_cell(ar, cur.bv().getClipboard());
cur.cell().insert(cur.pos(), ar);
cur.pos() += ar.size();
break;
}
case LFUN_PASTE:
if (!cmd.argument.empty()) {
MathArray ar;
mathed_parse_cell(ar, cmd.argument);
cur.cell().insert(cur.pos(), ar);
cur.pos() += ar.size();
}
break;
/*
case LFUN_PASTE: {
size_t n = 0;
istringstream is(cmd.argument.c_str());
is >> n;
if (was_macro)
cur.macroModeClose();
recordUndo(cur, Undo::ATOMIC);
cur.selPaste(n);
break;
}
*/
case LFUN_MOUSE_PRESS:
lfunMousePress(cur, cmd);
break;
case LFUN_MOUSE_MOTION:
lfunMouseMotion(cur, cmd);
break;
case LFUN_MOUSE_RELEASE:
lfunMouseRelease(cur, cmd);
break;
case LFUN_FINISHED_LEFT:
cur.bv().cursor() = cur;
break;
case LFUN_FINISHED_RIGHT:
++cur.pos();
cur.bv().cursor() = cur;
break;
case LFUN_FINISHED_UP:
//idxUpDown(cur, true);
cur.bv().cursor() = cur;
break;
case LFUN_FINISHED_DOWN:
//idxUpDown(cur, false);
cur.bv().cursor() = cur;
break;
case LFUN_RIGHTSEL:
case LFUN_RIGHT:
lyxerr << "mathnest RIGHT: from:\n" << cur << endl;
cur.selHandle(cmd.action == LFUN_RIGHTSEL);
cur.autocorrect() = false;
cur.clearTargetX();
if (cur.inMacroMode())
cur.macroModeClose();
else if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) {
cur.pushLeft(*cur.nextAtom().nucleus());
cur.inset().idxFirst(cur);
} else if (cur.posRight() || idxRight(cur)
|| cur.popRight() || cur.selection())
;
else
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
lyxerr << "mathnest RIGHT: to:\n" << cur << endl;
break;
case LFUN_LEFTSEL:
case LFUN_LEFT:
cur.selHandle(cmd.action == LFUN_LEFTSEL);
cur.autocorrect() = false;
cur.clearTargetX();
if (cur.inMacroMode())
cur.macroModeClose();
else if (cur.pos() != 0 && cur.openable(cur.prevAtom())) {
cur.posLeft();
cur.push(*cur.nextAtom().nucleus());
cur.inset().idxLast(cur);
} else if (cur.posLeft() || idxLeft(cur)
|| cur.popLeft() || cur.selection())
;
else
cmd = FuncRequest(LFUN_FINISHED_LEFT);
break;
case LFUN_UPSEL:
case LFUN_UP:
cur.selHandle(cmd.action == LFUN_UPSEL);
if (!cur.up())
cmd = FuncRequest(LFUN_FINISHED_UP);
break;
case LFUN_DOWNSEL:
case LFUN_DOWN:
cur.selHandle(cmd.action == LFUN_DOWNSEL);
if (!cur.down())
cmd = FuncRequest(LFUN_FINISHED_DOWN);
break;
case LFUN_MOUSE_DOUBLE:
case LFUN_MOUSE_TRIPLE:
case LFUN_WORDSEL:
cur.pos() = 0;
cur.idx() = 0;
cur.resetAnchor();
cur.selection() = true;
cur.pos() = cur.lastpos();
cur.idx() = cur.lastidx();
break;
case LFUN_UP_PARAGRAPHSEL:
case LFUN_UP_PARAGRAPH:
case LFUN_DOWN_PARAGRAPHSEL:
case LFUN_DOWN_PARAGRAPH:
break;
case LFUN_HOMESEL:
case LFUN_HOME:
case LFUN_WORDLEFTSEL:
case LFUN_WORDLEFT:
cur.selHandle(cmd.action == LFUN_WORDLEFTSEL || cmd.action == LFUN_HOMESEL);
cur.macroModeClose();
if (cur.pos() != 0) {
cur.pos() = 0;
} else if (cur.col() != 0) {
cur.idx() -= cur.col();
cur.pos() = 0;
} else if (cur.idx() != 0) {
cur.idx() = 0;
cur.pos() = 0;
} else {
cmd = FuncRequest(LFUN_FINISHED_LEFT);
}
break;
case LFUN_WORDRIGHTSEL:
case LFUN_WORDRIGHT:
case LFUN_ENDSEL:
case LFUN_END:
cur.selHandle(cmd.action == LFUN_WORDRIGHTSEL || cmd.action == LFUN_ENDSEL);
cur.macroModeClose();
cur.clearTargetX();
if (cur.pos() != cur.lastpos()) {
cur.pos() = cur.lastpos();
} else if (cur.col() != cur.lastcol()) {
cur.idx() = cur.idx() - cur.col() + cur.lastcol();
cur.pos() = cur.lastpos();
} else if (cur.idx() != cur.lastidx()) {
cur.idx() = cur.lastidx();
cur.pos() = cur.lastpos();
} else {
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
}
break;
case LFUN_PRIORSEL:
case LFUN_PRIOR:
case LFUN_BEGINNINGBUFSEL:
case LFUN_BEGINNINGBUF:
cmd = FuncRequest(LFUN_FINISHED_LEFT);
break;
case LFUN_NEXTSEL:
case LFUN_NEXT:
case LFUN_ENDBUFSEL:
case LFUN_ENDBUF:
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
break;
case LFUN_CELL_FORWARD:
cur.inset().idxNext(cur);
break;
case LFUN_CELL_BACKWARD:
cur.inset().idxPrev(cur);
break;
case LFUN_DELETE_WORD_BACKWARD:
case LFUN_BACKSPACE:
recordUndo(cur, Undo::ATOMIC);
cur.backspace();
break;
case LFUN_DELETE_WORD_FORWARD:
case LFUN_DELETE:
recordUndo(cur, Undo::ATOMIC);
cur.erase();
cmd = FuncRequest(LFUN_FINISHED_LEFT);
break;
case LFUN_ESCAPE:
if (cur.selection())
cur.clearSelection();
else
cmd = FuncRequest(LFUN_FINISHED_LEFT);
break;
case LFUN_INSET_TOGGLE:
//lockToggle();
if (cur.pos() != cur.lastpos()) {
// toggle previous inset ...
cur.nextAtom().nucleus()->lock(!cur.nextAtom()->lock());
} else if (cur.popLeft() && cur.pos() != cur.lastpos()) {
// ... or enclosing inset if we are in the last inset position
cur.nextAtom().nucleus()->lock(!cur.nextAtom()->lock());
++cur.pos();
}
break;
case LFUN_SELFINSERT:
if (cmd.argument.empty()) {
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
break;
}
recordUndo(cur, Undo::ATOMIC);
if (cmd.argument.size() != 1) {
cur.insert(cmd.argument);
break;
}
if (!interpret(cur, cmd.argument[0]))
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
break;
#if 0
//
// this needs to be incorporated
//
// delete empty mathbox (LFUN_BACKSPACE and LFUN_DELETE)
bool remove_inset = false;
DispatchResult result(true);
bool was_macro = cur.inMacroMode();
cur.normalize();
cur.touch();
#endif
// case LFUN_GETXY:
// sprintf(dispatch_buffer, "%d %d",);
// DispatchResult= dispatch_buffer;
// break;
case LFUN_SETXY: {
lyxerr << "LFUN_SETXY broken!" << endl;
int x = 0;
int y = 0;
istringstream is(cmd.argument.c_str());
is >> x >> y;
cur.setScreenPos(x, y);
break;
}
case LFUN_CUT:
recordUndo(cur, Undo::DELETE);
cur.selCut();
break;
case LFUN_COPY:
cur.selCopy();
break;
// Special casing for superscript in case of LyX handling
// dead-keys:
case LFUN_CIRCUMFLEX:
if (cmd.argument.empty()) {
// do superscript if LyX handles
// deadkeys
recordUndo(cur, Undo::ATOMIC);
script(cur, true);
}
break;
case LFUN_UMLAUT:
case LFUN_ACUTE:
case LFUN_GRAVE:
case LFUN_BREVE:
case LFUN_DOT:
case LFUN_MACRON:
case LFUN_CARON:
case LFUN_TILDE:
case LFUN_CEDILLA:
case LFUN_CIRCLE:
case LFUN_UNDERDOT:
case LFUN_TIE:
case LFUN_OGONEK:
case LFUN_HUNG_UMLAUT:
break;
// Math fonts
case LFUN_FREEFONT_APPLY:
case LFUN_FREEFONT_UPDATE:
handleFont2(cur, cmd.argument);
break;
case LFUN_BOLD:
handleFont(cur, cmd.argument, "mathbf");
break;
case LFUN_SANS:
handleFont(cur, cmd.argument, "mathsf");
break;
case LFUN_EMPH:
handleFont(cur, cmd.argument, "mathcal");
break;
case LFUN_ROMAN:
handleFont(cur, cmd.argument, "mathrm");
break;
case LFUN_CODE:
handleFont(cur, cmd.argument, "texttt");
break;
case LFUN_FRAK:
handleFont(cur, cmd.argument, "mathfrak");
break;
case LFUN_ITAL:
handleFont(cur, cmd.argument, "mathit");
break;
case LFUN_NOUN:
handleFont(cur, cmd.argument, "mathbb");
break;
//case LFUN_FREEFONT_APPLY:
handleFont(cur, cmd.argument, "textrm");
break;
case LFUN_DEFAULT:
handleFont(cur, cmd.argument, "textnormal");
break;
case LFUN_MATH_MODE:
#if 1
cur.macroModeClose();
cur.selClearOrDel();
cur.plainInsert(MathAtom(new MathMBoxInset(cur.bv())));
cur.posLeft();
cur.pushLeft(*cur.nextInset());
#else
if (currentMode() == InsetBase::TEXT_MODE)
cur.niceInsert(MathAtom(new MathHullInset("simple")));
else
handleFont(cur, cmd.argument, "textrm");
//cur.owner()->message(_("math text mode toggled"));
#endif
break;
case LFUN_MATH_SIZE:
#if 0
if (!arg.empty()) {
recordUndo(cur, Undo::ATOMIC);
cur.setSize(arg);
}
#endif
break;
case LFUN_INSERT_MATRIX: {
recordUndo(cur, Undo::ATOMIC);
unsigned int m = 1;
unsigned int n = 1;
string v_align;
string h_align;
istringstream is(cmd.argument);
is >> m >> n >> v_align >> h_align;
if (m < 1)
m = 1;
if (n < 1)
n = 1;
v_align += 'c';
cur.niceInsert(
MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
break;
}
case LFUN_MATH_DELIM: {
lyxerr << "MathNestInset::LFUN_MATH_DELIM" << endl;
string ls;
string rs = lyx::support::split(cmd.argument, ls, ' ');
// Reasonable default values
if (ls.empty())
ls = '(';
if (rs.empty())
rs = ')';
recordUndo(cur, Undo::ATOMIC);
cur.handleNest(MathAtom(new MathDelimInset(ls, rs)));
break;
}
case LFUN_SPACE_INSERT:
case LFUN_MATH_SPACE:
recordUndo(cur, Undo::ATOMIC);
cur.insert(MathAtom(new MathSpaceInset(",")));
break;
case LFUN_INSET_ERT:
// interpret this as if a backslash was typed
recordUndo(cur, Undo::ATOMIC);
interpret(cur, '\\');
break;
// FIXME: We probably should swap parts of "math-insert" and "self-insert"
// handling such that "self-insert" works on "arbitrary stuff" too, and
// math-insert only handles special math things like "matrix".
case LFUN_INSERT_MATH:
recordUndo(cur, Undo::ATOMIC);
cur.niceInsert(cmd.argument);
break;
case LFUN_DIALOG_SHOW_NEW_INSET: {
string const & name = cmd.argument;
string data;
#if 0
if (name == "ref") {
RefInset tmp(name);
data = tmp.createDialogStr(name);
}
#endif
cur.bv().owner()->getDialogs().show(name, data, 0);
break;
}
case LFUN_INSET_APPLY: {
string const name = cmd.getArg(0);
InsetBase * base = cur.bv().owner()->getDialogs().getOpenInset(name);
if (base) {
FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
base->dispatch(cur, fr);
break;
}
MathArray ar;
if (createMathInset_fromDialogStr(cmd.argument, ar)) {
cur.insert(ar);
break;
}
cur.undispatched();
break;
}
#ifdef WITH_WARNINGS
#warning look here
#endif
#if 0
case LFUN_WORD_REPLACE:
case LFUN_WORD_FIND:
if (!searchForward(&cur.bv(), cmd.getArg(0), false, false))
cur.undispatched();
break;
cur.normalize();
cur.touch();
BOOST_ASSERT(cur.inMathed());
if (result.dispatched()) {
revealCodes(cur);
cur.bv().stuffClipboard(cur.grabSelection());
} else {
if (remove_inset)
cur.bv().owner()->dispatch(FuncRequest(LFUN_DELETE));
}
break;
#endif
default:
MathDimInset::priv_dispatch(cur, cmd);
break;
}
}
bool MathNestInset::getStatus(LCursor & /*cur*/, FuncRequest const & cmd,
FuncStatus & flag) const
{
// the font related toggles
//string tc = "mathnormal";
bool ret = true;
switch (cmd.action) {
#if 0
case LFUN_TABULAR_FEATURE:
// FIXME: check temporarily disabled
// valign code
char align = mathcursor::valign();
if (align == '\0') {
enable = false;
break;
}
if (cmd.argument.empty()) {
flag.clear();
break;
}
if (!contains("tcb", cmd.argument[0])) {
enable = false;
break;
}
flag.setOnOff(cmd.argument[0] == align);
break;
case LFUN_BOLD:
flag.setOnOff(tc == "mathbf");
break;
case LFUN_SANS:
flag.setOnOff(tc == "mathsf");
break;
case LFUN_EMPH:
flag.setOnOff(tc == "mathcal");
break;
case LFUN_ROMAN:
flag.setOnOff(tc == "mathrm");
break;
case LFUN_CODE:
flag.setOnOff(tc == "mathtt");
break;
case LFUN_NOUN:
flag.setOnOff(tc == "mathbb");
break;
case LFUN_DEFAULT:
flag.setOnOff(tc == "mathnormal");
break;
#endif
case LFUN_MATH_MUTATE:
//flag.setOnOff(mathcursor::formula()->hullType() == cmd.argument);
flag.setOnOff(false);
break;
// we just need to be in math mode to enable that
case LFUN_MATH_SIZE:
case LFUN_MATH_SPACE:
case LFUN_MATH_LIMITS:
case LFUN_MATH_NONUMBER:
case LFUN_MATH_NUMBER:
case LFUN_MATH_EXTERN:
flag.enabled(true);
break;
default:
ret = false;
break;
}
return ret;
}
void MathNestInset::edit(LCursor & cur, bool left)
{
cur.push(*this);
cur.idx() = left ? 0 : cur.lastidx();
cur.pos() = left ? 0 : cur.lastpos();
cur.resetAnchor();
lyxerr << "MathNestInset::edit, cur:\n" << cur << endl;
}
InsetBase * MathNestInset::editXY(LCursor & cur, int x, int y)
{
int idx_min = 0;
int dist_min = 1000000;
for (idx_type i = 0; i < nargs(); ++i) {
int d = cell(i).dist(x, y);
if (d < dist_min) {
dist_min = d;
idx_min = i;
}
}
MathArray & ar = cell(idx_min);
cur.push(*this);
cur.idx() = idx_min;
cur.pos() = ar.x2pos(x - ar.xo());
lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl;
if (dist_min == 0) {
// hit inside cell
for (pos_type i = 0, n = ar.size(); i < n; ++i)
if (ar[i]->covers(x, y))
return ar[i].nucleus()->editXY(cur, x, y);
}
return this;
}
void MathNestInset::lfunMouseRelease(LCursor & cur, FuncRequest & cmd)
{
//lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl;
if (cmd.button() == mouse_button::button1) {
// try to dispatch to enclosed insets first
//cur.bv().stuffClipboard(cur.grabSelection());
return;
}
if (cmd.button() == mouse_button::button2) {
MathArray ar;
asArray(cur.bv().getClipboard(), ar);
cur.clearSelection();
cur.setScreenPos(cmd.x, cmd.y);
cur.insert(ar);
cur.bv().update();
return;
}
if (cmd.button() == mouse_button::button3) {
// try to dispatch to enclosed insets first
cur.bv().owner()->getDialogs().show("mathpanel");
return;
}
cur.undispatched();
}
void MathNestInset::lfunMousePress(LCursor & cur, FuncRequest & cmd)
{
lyxerr << "lfunMousePress: buttons: " << cmd.button() << endl;
if (cmd.button() == mouse_button::button1) {
first_x = cmd.x;
first_y = cmd.y;
//cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
lyxerr << "lfunMousePress: setting cursor to: " << cur << endl;
cur.resetAnchor();
cur.bv().cursor() = cur;
}
if (cmd.button() == mouse_button::button2) {
cur.dispatch(FuncRequest(LFUN_PASTESELECTION));
}
}
void MathNestInset::lfunMouseMotion(LCursor & cur, FuncRequest & cmd)
{
// only select with button 1
if (cmd.button() != mouse_button::button1)
return;
if (abs(cmd.x - first_x) < 2 && abs(cmd.y - first_y) < 2)
return;
first_x = cmd.x;
first_y = cmd.y;
cur.bv().cursor().setCursor(cur, true);
}
bool MathNestInset::interpret(LCursor & cur, char c)
{
lyxerr << "interpret 2: '" << c << "'" << endl;
cur.clearTargetX();
/// are we currently typing '#1' or '#2' or...?
if (cur.pos() > 0 && cur.prevAtom()->getChar() == '#') {
cur.posLeft();
cur.plainErase();
#ifdef WITH_WARNINGS
#warning FIXME
#endif
#if 0
int n = c - '0';
MathMacroTemplate const * p = formula()->asMacroTemplate();
if (p && 1 <= n && n <= p->numargs())
cur.insert(MathAtom(new MathMacroArgument(c - '0')));
else {
cur.insert(createMathInset("#"));
interpret(cur, c); // try again
}
#endif
return true;
}
// handle macroMode
if (cur.inMacroMode()) {
string name = cur.macroName();
//lyxerr << "interpret name: '" << name << "'" << endl;
if (isalpha(c)) {
cur.activeMacro()->setName(cur.activeMacro()->name() + c);
return true;
}
// handle 'special char' macros
if (name == "\\") {
// remove the '\\'
cur.backspace();
if (c == '\\') {
if (currentMode() == MathInset::TEXT_MODE)
cur.niceInsert(createMathInset("textbackslash"));
else
cur.niceInsert(createMathInset("backslash"));
} else if (c == '{') {
cur.niceInsert(MathAtom(new MathBraceInset));
} else {
cur.niceInsert(createMathInset(string(1, c)));
}
return true;
}
// leave macro mode and try again if necessary
cur.macroModeClose();
if (c == '{')
cur.niceInsert(MathAtom(new MathBraceInset));
else if (c != ' ')
interpret(cur, c);
return true;
}
// This is annoying as one has to press <space> far too often.
// Disable it.
#if 0
// leave autocorrect mode if necessary
if (autocorrect() && c == ' ') {
autocorrect() = false;
return true;
}
#endif
// just clear selection on pressing the space bar
if (cur.selection() && c == ' ') {
cur.selection() = false;
return true;
}
cur.selClearOrDel();
if (c == '\\') {
//lyxerr << "starting with macro" << endl;
cur.insert(MathAtom(new MathUnknownInset("\\", false)));
return true;
}
if (c == '\n') {
if (currentMode() == MathInset::TEXT_MODE)
cur.insert(c);
return true;
}
if (c == ' ') {
if (currentMode() == MathInset::TEXT_MODE) {
// insert spaces in text mode,
// but suppress direct insertion of two spaces in a row
// the still allows typing '<space>a<space>' and deleting the 'a', but
// it is better than nothing...
if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ')
cur.insert(c);
return true;
}
if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) {
cur.prevAtom().nucleus()->asSpaceInset()->incSpace();
return true;
}
if (cur.popRight())
return true;
// if are at the very end, leave the formula
return cur.pos() != cur.lastpos();
}
if (c == '_') {
script(cur, false);
return true;
}
if (c == '^') {
script(cur, true);
return true;
}
if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
cur.niceInsert(createMathInset(string(1, c)));
return true;
}
if (c == '%') {
cur.niceInsert(MathAtom(new MathCommentInset));
return true;
}
// try auto-correction
//if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
// return true;
// no special circumstances, so insert the character without any fuss
cur.insert(c);
cur.autocorrect() = true;
return true;
}
bool MathNestInset::script(LCursor & cur, bool up)
{
// Hack to get \\^ and \\_ working
lyxerr << "handling script: up: " << up << endl;
if (cur.inMacroMode() && cur.macroName() == "\\") {
if (up)
cur.niceInsert(createMathInset("mathcircumflex"));
else
interpret(cur, '_');
return true;
}
cur.macroModeClose();
string safe = cur.grabAndEraseSelection();
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
if (asScriptInset() && cur.idx() == 0) {
// we are in a nucleus of a script inset, move to _our_ script
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
MathScriptInset * inset = asScriptInset();
lyxerr << " going to cell " << inset->idxOfScript(up) << endl;
inset->ensure(up);
cur.idx() = inset->idxOfScript(up);
cur.pos() = 0;
} else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) {
--cur.pos();
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
MathScriptInset * inset = cur.nextAtom().nucleus()->asScriptInset();
cur.push(*inset);
cur.idx() = inset->idxOfScript(up);
cur.pos() = cur.lastpos();
} else {
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
// convert the thing to our left to a scriptinset or create a new
// one if in the very first position of the array
if (cur.pos() == 0) {
lyxerr << "new scriptinset" << endl;
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
cur.insert(new MathScriptInset(up));
} else {
lyxerr << "converting prev atom " << endl;
cur.prevAtom() = MathAtom(new MathScriptInset(cur.prevAtom(), up));
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
}
lyxerr << "new scriptinset 2: cur:\n" << cur << endl;
--cur.pos();
lyxerr << "new scriptinset 3: cur:\n" << cur << endl;
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
MathScriptInset * inset = cur.nextAtom().nucleus()->asScriptInset();
lyxerr << "new scriptinset 3: inset:\n" << inset << endl;
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
cur.push(*inset);
cur.idx() = 1;
cur.pos() = 0;
}
lyxerr << "pasting 1: safe:\n" << safe << endl;
cur.paste(safe);
cur.resetAnchor();
lyxerr << "pasting 2: safe:\n" << safe << endl;
return true;
}