X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2Fmath_nestinset.C;h=79d058907e3ce0f105bca9010f9d95b3ddebe3d4;hb=183239b7def8ca0e51432f2d88891d4b9f055953;hp=f2f485a81c8872c3da9095166dee5c9a33bf4c23;hpb=1eaa3eb913b16f4e6f5991b9c53b0b9ab3f84948;p=lyx.git diff --git a/src/mathed/math_nestinset.C b/src/mathed/math_nestinset.C index f2f485a81c..79d058907e 100644 --- a/src/mathed/math_nestinset.C +++ b/src/mathed/math_nestinset.C @@ -12,19 +12,67 @@ #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_macroarg.h" +#include "math_mboxinset.h" +#include "math_parser.h" +#include "math_scriptinset.h" +#include "math_spaceinset.h" +#include "math_symbolinset.h" +#include "math_support.h" +#include "math_unknowninset.h" + #include "BufferView.h" +#include "CutAndPaste.h" +#include "FuncStatus.h" #include "LColor.h" +#include "bufferview_funcs.h" #include "cursor.h" #include "debug.h" #include "dispatchresult.h" #include "funcrequest.h" -#include "math_data.h" -#include "math_mathmlstream.h" -#include "math_parser.h" +#include "gettext.h" +#include "outputparams.h" #include "undo.h" +#include "support/lstrings.h" + +#include "frontends/Dialogs.h" +#include "frontends/LyXView.h" #include "frontends/Painter.h" +#include + +using lyx::cap::copySelection; +using lyx::cap::grabAndEraseSelection; +using lyx::cap::cutSelection; +using lyx::cap::pasteSelection; +using lyx::cap::replaceSelection; +using lyx::cap::selClearOrDel; + +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) @@ -49,24 +97,18 @@ MathArray const & MathNestInset::cell(idx_type i) const } -void MathNestInset::getScreenPos(idx_type idx, pos_type pos, int & x, int & y) const +void MathNestInset::getCursorPos(LCursor const & cur, int & x, int & y) const { - MathArray const & ar = cell(idx); - x = ar.xo() + ar.pos2x(pos); - y = ar.yo(); + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); + MathArray const & ar = cur.cell(); + x = ar.xo() + ar.pos2x(cur.pos()); + y = ar.yo() + cur.bv().top_y(); // move cursor visually into empty cells ("blue rectangles"); - if (cell(idx).empty()) + if (cur.cell().empty()) x += 2; } -void MathNestInset::substitute(MathMacro const & m) -{ - for (idx_type i = 0; i < nargs(); ++i) - cell(i).substitute(m); -} - - void MathNestInset::metrics(MetricsInfo const & mi) const { MetricsInfo m = mi; @@ -77,7 +119,8 @@ void MathNestInset::metrics(MetricsInfo const & mi) const bool MathNestInset::idxNext(LCursor & cur) const { - if (cur.idx() + 1 >= nargs()) + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); + if (cur.idx() == cur.lastidx()) return false; ++cur.idx(); cur.pos() = 0; @@ -93,6 +136,7 @@ bool MathNestInset::idxRight(LCursor & cur) const bool MathNestInset::idxPrev(LCursor & cur) const { + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); if (cur.idx() == 0) return false; --cur.idx(); @@ -109,6 +153,7 @@ bool MathNestInset::idxLeft(LCursor & cur) const bool MathNestInset::idxFirst(LCursor & cur) const { + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); if (nargs() == 0) return false; cur.idx() = 0; @@ -119,27 +164,10 @@ bool MathNestInset::idxFirst(LCursor & cur) const bool MathNestInset::idxLast(LCursor & cur) const { + BOOST_ASSERT(ptr_cmp(&cur.inset(), this)); if (nargs() == 0) return false; - cur.idx() = nargs() - 1; - cur.pos() = cur.lastpos(); - return true; -} - - -bool MathNestInset::idxHome(LCursor & cur) const -{ - if (cur.pos() == 0) - return false; - cur.pos() = 0; - return true; -} - - -bool MathNestInset::idxEnd(LCursor & cur) const -{ - if (cur.lastpos() == cur.lastpos()) - return false; + cur.idx() = cur.lastidx(); cur.pos() = cur.lastpos(); return true; } @@ -157,30 +185,45 @@ void MathNestInset::dump() const } -//void MathNestInset::draw(PainterInfo & pi, int x, int y) const -void MathNestInset::draw(PainterInfo &, int, int) const +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, - idx_type idx1, pos_type pos1, idx_type idx2, pos_type pos2) const +void MathNestInset::drawSelection(PainterInfo & pi, int x, int y) const { - if (idx1 == idx2) { - MathArray const & c = cell(idx1); - int x1 = c.xo() + c.pos2x(pos1); + // FIXME: hack to get position cache warm + draw(pi, x, y); + + // 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; + 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(pos2); + 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, idx1, idx2)) { + if (idxBetween(i, s1.idx(), s2.idx())) { MathArray const & c = cell(i); int x1 = c.xo(); int y1 = c.yo() - c.ascent(); @@ -216,12 +259,6 @@ bool MathNestInset::contains(MathArray const & ar) const } -bool MathNestInset::editing(BufferView * bv) const -{ - return bv->cursor().isInside(this); -} - - bool MathNestInset::lock() const { return lock_; @@ -272,241 +309,315 @@ void MathNestInset::normalize(NormalStream & os) const } -void MathNestInset::notifyCursorLeaves(idx_type idx) +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*/) { - cell(idx).notifyCursorLeaves(); +#ifdef WITH_WARNINGS +#warning look here +#endif +#if 0 + MathArray & ar = cur.cell(); + // remove base-only "scripts" + for (pos_type i = 0; i + 1 < ar.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 } -DispatchResult -MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) +void MathNestInset::handleFont + (LCursor & cur, string const & arg, string const & font) { - //lyxerr << "InsetFormulaBase::localDispatch: act: " << cmd.action - // << " arg: '" << cmd.argument - // << "' x: '" << cmd.x - // << " y: '" << cmd.y - // << "' button: " << cmd.button() << endl; + // 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::doDispatch(LCursor & cur, FuncRequest & cmd) +{ + //lyxerr << "MathNestInset: request: " << cmd << std::endl; + //CursorSlice sl = cur.current(); switch (cmd.action) { case LFUN_PASTE: { - MathArray ar; - mathed_parse_cell(ar, cmd.argument); - cur.cell().insert(cur.pos(), ar); - cur.pos() += ar.size(); - return DispatchResult(true, true); + recordUndo(cur); + cur.message(_("Paste")); + replaceSelection(cur); + size_t n = 0; + istringstream is(cmd.argument); + is >> n; + pasteSelection(cur, n); + cur.clearSelection(); // bug 393 + cur.bv().switchKeyMap(); + finishUndo(); + break; } - case LFUN_PASTESELECTION: - return dispatch(cur, FuncRequest(LFUN_PASTE, cur.bv().getClipboard())); + case LFUN_CUT: + cutSelection(cur, true, true); + cur.message(_("Cut")); + break; + + case LFUN_COPY: + copySelection(cur); + cur.message(_("Copy")); + break; case LFUN_MOUSE_PRESS: - if (cmd.button() == mouse_button::button2) - return priv_dispatch(cur, FuncRequest(LFUN_PASTESELECTION)); - return DispatchResult(false); + 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: + cur.bv().cursor() = cur; + break; + + case LFUN_FINISHED_DOWN: + cur.bv().cursor() = cur; + break; case LFUN_RIGHTSEL: - cur.selection() = true; // fall through... case LFUN_RIGHT: - return cur.right() ? - DispatchResult(true, true) : DispatchResult(false, FINISHED_RIGHT); - //lyxerr << "calling scroll 20" << endl; - //scroll(&cur.bv(), 20); - // write something to the minibuffer - //cur.bv().owner()->message(cur.info()); + cur.selHandle(cmd.action == LFUN_RIGHTSEL); + cur.autocorrect() = false; + cur.clearTargetX(); + cur.macroModeClose(); + 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); + break; case LFUN_LEFTSEL: - cur.selection() = true; // fall through case LFUN_LEFT: - return cur.left() ? - DispatchResult(true, true) : DispatchResult(false, FINISHED); + cur.selHandle(cmd.action == LFUN_LEFTSEL); + cur.autocorrect() = false; + cur.clearTargetX(); + cur.macroModeClose(); + 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: - cur.selection() = true; // fall through case LFUN_UP: - return cur.up() ? - DispatchResult(true, true) : DispatchResult(false, FINISHED_UP); + cur.selHandle(cmd.action == LFUN_UPSEL); + if (!cur.up()) + cmd = FuncRequest(LFUN_FINISHED_UP); + break; case LFUN_DOWNSEL: - cur.selection() = true; // fall through case LFUN_DOWN: - return cur.down() ? - DispatchResult(true, true) : DispatchResult(false, FINISHED_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.home(); + cur.pos() = 0; + cur.idx() = 0; + cur.resetAnchor(); cur.selection() = true; - cur.end(); - return DispatchResult(true, 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: - return DispatchResult(true, FINISHED); + break; case LFUN_HOMESEL: - case LFUN_WORDLEFTSEL: - cur.selection() = true; // fall through case LFUN_HOME: + case LFUN_WORDLEFTSEL: case LFUN_WORDLEFT: - return cur.home() - ? DispatchResult(true, true) : DispatchResult(true, FINISHED); + 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_ENDSEL: case LFUN_WORDRIGHTSEL: - cur.selection() = true; // fall through - case LFUN_END: case LFUN_WORDRIGHT: - return cur.end() - ? DispatchResult(true, true) : DispatchResult(false, FINISHED_RIGHT); + 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: - return DispatchResult(true, FINISHED); + cmd = FuncRequest(LFUN_FINISHED_LEFT); + break; case LFUN_NEXTSEL: case LFUN_NEXT: - case LFUN_ENDBUFSEL: - case LFUN_ENDBUF: - return DispatchResult(false, FINISHED_RIGHT); + cmd = FuncRequest(LFUN_FINISHED_RIGHT); + break; case LFUN_CELL_FORWARD: - cur.inset()->idxNext(cur); - return DispatchResult(true, true); + cur.inset().idxNext(cur); + break; case LFUN_CELL_BACKWARD: - cur.inset()->idxPrev(cur); - return DispatchResult(true, true); + cur.inset().idxPrev(cur); + break; case LFUN_DELETE_WORD_BACKWARD: case LFUN_BACKSPACE: recordUndo(cur, Undo::ATOMIC); cur.backspace(); - return DispatchResult(true, true); + break; case LFUN_DELETE_WORD_FORWARD: case LFUN_DELETE: - recordUndo(cur, Undo::ATOMIC); + recordUndo(cur); cur.erase(); - return DispatchResult(true, FINISHED); + cmd = FuncRequest(LFUN_FINISHED_LEFT); + break; case LFUN_ESCAPE: - if (!cur.selection()) - return DispatchResult(true, true); - cur.selClear(); - return DispatchResult(false); + if (cur.selection()) + cur.clearSelection(); + else + cmd = FuncRequest(LFUN_FINISHED_LEFT); + break; case LFUN_INSET_TOGGLE: - cur.lockToggle(); - return DispatchResult(true, true); + recordUndo(cur); + //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()) { - recordUndo(cur, Undo::ATOMIC); - if (cmd.argument.size() == 1) { - if (cur.interpret(cmd.argument[0])) - return DispatchResult(true, true); - else - return DispatchResult(false, FINISHED_RIGHT); - } + recordUndo(cur); + if (cmd.argument.size() != 1) { cur.insert(cmd.argument); - } - return DispatchResult(false, FINISHED_RIGHT); - - -#if 0 -// -// this needs to bee incorporated -// - //lyxerr << "InsetFormulaBase::localDispatch: act: " << cmd.action - // << " arg: '" << cmd.argument - // << "' x: '" << cmd.x - // << " y: '" << cmd.y - // << "' button: " << cmd.button() << endl; - - // delete empty mathbox (LFUN_BACKSPACE and LFUN_DELETE) - bool remove_inset = false; - - switch (cmd.action) { - case LFUN_MOUSE_PRESS: - //lyxerr << "Mouse single press" << endl; - return lfunMousePress(cur, cmd); - case LFUN_MOUSE_MOTION: - //lyxerr << "Mouse motion" << endl; - return lfunMouseMotion(cur, cmd); - case LFUN_MOUSE_RELEASE: - //lyxerr << "Mouse single release" << endl; - return lfunMouseRelease(cur, cmd); - case LFUN_MOUSE_DOUBLE: - //lyxerr << "Mouse double" << endl; - return dispatch(cur, FuncRequest(LFUN_WORDSEL)); - default: break; - } - - DispatchResult result(true); - string argument = cmd.argument; - bool was_macro = cur.inMacroMode(); - - cur.normalize(); - cur.touch(); - - switch (cmd.action) { - - case LFUN_MATH_MUTATE: - case LFUN_MATH_DISPLAY: - case LFUN_MATH_NUMBER: - case LFUN_MATH_NONUMBER: - case LFUN_CELL_SPLIT: - case LFUN_BREAKLINE: - case LFUN_DELETE_LINE_FORWARD: - case LFUN_INSERT_LABEL: - case LFUN_MATH_EXTERN: - case LFUN_TABULAR_FEATURE: - case LFUN_PASTESELECTION: - case LFUN_MATH_LIMITS: - recordUndo(cur, Undo::ATOMIC); - cur.dispatch(cmd); + } + if (!interpret(cur, cmd.argument[0])) + cmd = FuncRequest(LFUN_FINISHED_RIGHT); break; - // case LFUN_GETXY: - // sprintf(dispatch_buffer, "%d %d",); - // DispatchResult= dispatch_buffer; - // break; + //case LFUN_GETXY: + // sprintf(dispatch_buffer, "%d %d",); + // break; + case LFUN_SETXY: { lyxerr << "LFUN_SETXY broken!" << endl; int x = 0; int y = 0; - istringstream is(cmd.argument.c_str()); + istringstream is(cmd.argument); is >> x >> y; cur.setScreenPos(x, y); 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_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: @@ -514,7 +625,7 @@ MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) // do superscript if LyX handles // deadkeys recordUndo(cur, Undo::ATOMIC); - cur.script(true); + script(cur, true); } break; @@ -540,31 +651,62 @@ MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) 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_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 (cur.currentMode() == InsetBase::TEXT_MODE) +#if 1 + // ignore math-mode on when already in math mode + if (currentMode() == InsetBase::MATH_MODE && cmd.argument == "on") + break; + cur.macroModeClose(); + selClearOrDel(cur); + 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 + cur.message(_("create new math text environment ($...$)")); + } else { handleFont(cur, cmd.argument, "textrm"); - //cur.owner()->message(_("math text mode toggled")); + cur.message(_("entered math text mode (textrm)")); + } +#endif break; case LFUN_MATH_SIZE: #if 0 - if (!arg.empty()) { - recordUndo(cur, Undo::ATOMIC); - cur.setSize(arg); - } + recordUndo(cur); + cur.setSize(arg); #endif break; @@ -574,10 +716,12 @@ MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) unsigned int n = 1; string v_align; string h_align; - istringstream is(argument); + istringstream is(cmd.argument); is >> m >> n >> v_align >> h_align; - m = max(1u, m); - n = max(1u, n); + 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))); @@ -585,9 +729,9 @@ MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) } case LFUN_MATH_DELIM: { - //lyxerr << "formulabase::LFUN_MATH_DELIM, arg: '" << arg << "'" << endl; + lyxerr << "MathNestInset::LFUN_MATH_DELIM" << endl; string ls; - string rs = split(cmd.argument, ls, ' '); + string rs = lyx::support::split(cmd.argument, ls, ' '); // Reasonable default values if (ls.empty()) ls = '('; @@ -604,55 +748,30 @@ MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) cur.insert(MathAtom(new MathSpaceInset(","))); break; - case LFUN_UNDO: - cur.bv().owner()->message(_("Invalid action in math mode!")); - break; - - - case LFUN_EXEC_COMMAND: - result = DispatchResult(false); - break; - case LFUN_INSET_ERT: // interpret this as if a backslash was typed recordUndo(cur, Undo::ATOMIC); - cur.interpret('\\'); + interpret(cur, '\\'); break; - case LFUN_BREAKPARAGRAPH: - case LFUN_BREAKPARAGRAPHKEEPLAYOUT: - case LFUN_BREAKPARAGRAPH_SKIP: - argument = "\n"; - // fall through - // 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(argument); - break; - - case LFUN_INSET_TOGGLE: - cur.lockToggle(); - break; - - case LFUN_DIALOG_SHOW: - result = DispatchResult(false); + cur.niceInsert(cmd.argument); break; case LFUN_DIALOG_SHOW_NEW_INSET: { - string const & name = argument; + string const & name = cmd.argument; string data; +#if 0 if (name == "ref") { RefInset tmp(name); data = tmp.createDialogStr(name); } - - if (data.empty()) - result = DispatchResult(false); - else - cur.bv().owner()->getDialogs().show(name, data, 0); +#endif + cur.bv().owner()->getDialogs().show(name, data, 0); break; } @@ -662,105 +781,380 @@ MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd) if (base) { FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument); - result = base->dispatch(cur, fr); - } else { - MathArray ar; - if (createMathInset_fromDialogStr(cmd.argument, ar)) { - cur.insert(ar); - result = DispatchResult(true, true); - } else { - result = DispatchResult(false); - } + base->dispatch(cur, fr); + break; + } + MathArray ar; + if (createMathInset_fromDialogStr(cmd.argument, ar)) { + cur.insert(ar); + break; } + cur.undispatched(); break; } - case LFUN_WORD_REPLACE: - case LFUN_WORD_FIND: { - result = - searchForward(&cur.bv(), cmd.getArg(0), false, false) - ? DispatchResult(true, true) : DispatchResult(false); + default: + MathDimInset::doDispatch(cur, cmd); break; } +} - case LFUN_INSERT_MATH: - case LFUN_INSERT_MATRIX: - case LFUN_MATH_DELIM: { - MathHullInset * f = new MathHullInset; - if (openNewInset(cur, f)) { - cur.inset()->dispatch(cur, FuncRequest(LFUN_MATH_MUTATE, "simple")); - cur.inset()->dispatch(cur, cmd); + +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: - result = DispatchResult(false); + ret = false; + break; } + return ret; +} - if (result == DispatchResult(true, true)) - cur.bv().update(); - cur.normalize(); - cur.touch(); +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; +} - BOOST_ASSERT(cur.inMathed()); - if (result.dispatched()) { - revealCodes(cur); - cur.bv().stuffClipboard(cur.grabSelection()); - } else { - cur.releaseMathCursor(); - if (remove_inset) - cur.bv().owner()->dispatch(FuncRequest(LFUN_DELETE)); +InsetBase * MathNestInset::editXY(LCursor & cur, int x, int y) const +{ + 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 const & ar = cell(idx_min); + cur.push(const_cast(*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 const_cast(this); +} - return result; // original version -#endif - default: - return MathInset::priv_dispatch(cur, cmd); +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; + 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::metricsMarkers(int) const +void MathNestInset::lfunMouseMotion(LCursor & cur, FuncRequest & cmd) { - dim_.wid += 2; - dim_.asc += 1; + // only select with button 1 + if (cmd.button() == mouse_button::button1) { + LCursor & bvcur = cur.bv().cursor(); + if (abs(cmd.x - first_x) + abs(cmd.y - first_y) > 4 + && bvcur.anchor_.hasPart(cur)) { + first_x = cmd.x; + first_y = cmd.y; + + bvcur.setCursor(cur); + bvcur.selection() = true; + } + } } -void MathNestInset::metricsMarkers2(int) const +void MathNestInset::lfunMouseRelease(LCursor & cur, FuncRequest & cmd) { - dim_.wid += 2; - dim_.asc += 1; - dim_.des += 1; + lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl; + + if (cmd.button() == mouse_button::button1) { + //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::drawMarkers(PainterInfo & pi, int x, int y) const +bool MathNestInset::interpret(LCursor & cur, char c) { - if (!editing(pi.base.bv)) - return; - int t = x + dim_.width() - 1; - int d = y + dim_.descent(); - pi.pain.line(x, d - 3, x, d, LColor::mathframe); - pi.pain.line(t, d - 3, t, d, LColor::mathframe); - pi.pain.line(x, d, x + 3, d, LColor::mathframe); - pi.pain.line(t - 3, d, t, d, LColor::mathframe); + lyxerr << "interpret 2: '" << c << "'" << endl; + cur.clearTargetX(); + + // handle macroMode + if (cur.inMacroMode()) { + string name = cur.macroName(); + + /// are we currently typing '#1' or '#2' or...? + if (name == "\\#") { + cur.backspace(); + int n = c - '0'; + if (n >= 1 && n <= 9) + cur.insert(new MathMacroArgument(n)); + return true; + } + + if (isalpha(c)) { + cur.activeMacro()->setName(name + c); + return true; + } + + // handle 'special char' macros + if (name == "\\") { + // remove the '\\' + if (c == '\\') { + cur.backspace(); + if (currentMode() == MathInset::TEXT_MODE) + cur.niceInsert(createMathInset("textbackslash")); + else + cur.niceInsert(createMathInset("backslash")); + } else if (c == '{') { + cur.backspace(); + cur.niceInsert(MathAtom(new MathBraceInset)); + } else if (c == '%') { + cur.backspace(); + cur.niceInsert(MathAtom(new MathCommentInset)); + } else if (c == '#') { + BOOST_ASSERT(cur.activeMacro()); + cur.activeMacro()->setName(name + c); + } else { + cur.backspace(); + 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 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; + } + + selClearOrDel(cur); + + 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 'a' 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 == '#' || c == '%') { + cur.niceInsert(createMathInset(string(1, c))); + return true; + } + + if (c == '~') { + cur.niceInsert(createMathInset("sim")); + 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; } -void MathNestInset::drawMarkers2(PainterInfo & pi, int x, int y) const +bool MathNestInset::script(LCursor & cur, bool up) { - if (!editing(pi.base.bv)) - return; - drawMarkers(pi, x, y); - int t = x + dim_.width() - 1; - int a = y - dim_.ascent(); - pi.pain.line(x, a + 3, x, a, LColor::mathframe); - pi.pain.line(t, a + 3, t, a, LColor::mathframe); - pi.pain.line(x, a, x + 3, a, LColor::mathframe); - pi.pain.line(t - 3, a, t, a, LColor::mathframe); + // 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 = grabAndEraseSelection(cur); + if (asScriptInset() && cur.idx() == 0) { + // we are in a nucleus of a script inset, move to _our_ script + 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(); + MathScriptInset * inset = cur.nextAtom().nucleus()->asScriptInset(); + cur.push(*inset); + cur.idx() = inset->idxOfScript(up); + cur.pos() = cur.lastpos(); + } else { + // 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; + cur.insert(new MathScriptInset(up)); + } else { + lyxerr << "converting prev atom " << endl; + cur.prevAtom() = MathAtom(new MathScriptInset(cur.prevAtom(), up)); + } + --cur.pos(); + MathScriptInset * inset = cur.nextAtom().nucleus()->asScriptInset(); + 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; }