]> git.lyx.org Git - lyx.git/blob - src/mathed/math_nestinset.C
09d562504915c07e6e22851f4ea2f1ca00d3de5d
[lyx.git] / src / mathed / math_nestinset.C
1 /**
2  * \file math_nestinset.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "math_nestinset.h"
14
15 #include "math_arrayinset.h"
16 #include "math_braceinset.h"
17 #include "math_commentinset.h"
18 #include "math_data.h"
19 #include "math_deliminset.h"
20 #include "math_factory.h"
21 #include "math_hullinset.h"
22 #include "math_mathmlstream.h"
23 #include "math_parser.h"
24 #include "math_scriptinset.h"
25 #include "math_spaceinset.h"
26 #include "math_support.h"
27 #include "math_mboxinset.h"
28 #include "math_unknowninset.h"
29
30 #include "BufferView.h"
31 #include "FuncStatus.h"
32 #include "bufferview_funcs.h"
33 #include "cursor.h"
34 #include "debug.h"
35 #include "dispatchresult.h"
36 #include "funcrequest.h"
37 #include "gettext.h"
38 #include "LColor.h"
39 #include "undo.h"
40
41 #include "support/std_sstream.h"
42 #include "support/lstrings.h"
43
44 #include "frontends/Dialogs.h"
45 #include "frontends/LyXView.h"
46 #include "frontends/Painter.h"
47
48
49 using std::endl;
50 using std::string;
51 using std::istringstream;
52
53
54 namespace {
55
56 // local global
57 int first_x;
58 int first_y;
59
60 } // namespace anon
61
62
63
64
65 MathNestInset::MathNestInset(idx_type nargs)
66         : cells_(nargs), lock_(false)
67 {}
68
69
70 MathInset::idx_type MathNestInset::nargs() const
71 {
72         return cells_.size();
73 }
74
75
76 MathArray & MathNestInset::cell(idx_type i)
77 {
78         return cells_[i];
79 }
80
81
82 MathArray const & MathNestInset::cell(idx_type i) const
83 {
84         return cells_[i];
85 }
86
87
88 void MathNestInset::getCursorPos(CursorSlice const & cur,
89         int & x, int & y) const
90 {
91         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
92         MathArray const & ar = cur.cell();
93         x = ar.xo() + ar.pos2x(cur.pos());
94         y = ar.yo();
95         // move cursor visually into empty cells ("blue rectangles");
96         if (cur.cell().empty())
97                 x += 2;
98 }
99
100
101 void MathNestInset::substitute(MathMacro const & m)
102 {
103         for (idx_type i = 0; i < nargs(); ++i)
104                 cell(i).substitute(m);
105 }
106
107
108 void MathNestInset::metrics(MetricsInfo const & mi) const
109 {
110         MetricsInfo m = mi;
111         for (idx_type i = 0; i < nargs(); ++i)
112                 cell(i).metrics(m);
113 }
114
115
116 bool MathNestInset::idxNext(LCursor & cur) const
117 {
118         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
119         if (cur.idx() == cur.lastidx())
120                 return false;
121         ++cur.idx();
122         cur.pos() = 0;
123         return true;
124 }
125
126
127 bool MathNestInset::idxRight(LCursor & cur) const
128 {
129         return idxNext(cur);
130 }
131
132
133 bool MathNestInset::idxPrev(LCursor & cur) const
134 {
135         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
136         if (cur.idx() == 0)
137                 return false;
138         --cur.idx();
139         cur.pos() = cur.lastpos();
140         return true;
141 }
142
143
144 bool MathNestInset::idxLeft(LCursor & cur) const
145 {
146         return idxPrev(cur);
147 }
148
149
150 bool MathNestInset::idxFirst(LCursor & cur) const
151 {
152         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
153         if (nargs() == 0)
154                 return false;
155         cur.idx() = 0;
156         cur.pos() = 0;
157         return true;
158 }
159
160
161 bool MathNestInset::idxLast(LCursor & cur) const
162 {
163         BOOST_ASSERT(ptr_cmp(&cur.inset(), this));
164         if (nargs() == 0)
165                 return false;
166         cur.idx() = cur.lastidx();
167         cur.pos() = cur.lastpos();
168         return true;
169 }
170
171
172 void MathNestInset::dump() const
173 {
174         WriteStream os(lyxerr);
175         os << "---------------------------------------------\n";
176         write(os);
177         os << "\n";
178         for (idx_type i = 0; i < nargs(); ++i)
179                 os << cell(i) << "\n";
180         os << "---------------------------------------------\n";
181 }
182
183
184 //void MathNestInset::draw(PainterInfo & pi, int x, int y) const
185 void MathNestInset::draw(PainterInfo &, int, int) const
186 {
187 #if 0
188         if (lock_)
189                 pi.pain.fillRectangle(x, y - ascent(), width(), height(),
190                                         LColor::mathlockbg);
191 #endif
192 }
193
194
195 void MathNestInset::drawSelection(PainterInfo & pi, int, int) const
196 {
197         // this should use the x/y values given, not the cached values
198         LCursor & cur = pi.base.bv->cursor();
199         if (!cur.selection())
200                 return;
201         if (!ptr_cmp(&cur.inset(), this))
202                 return;
203         CursorSlice s1 = cur.selBegin();
204         CursorSlice s2 = cur.selEnd();
205         if (s1.idx() == s2.idx()) {
206                 MathArray const & c = cell(s1.idx());
207                 int x1 = c.xo() + c.pos2x(s1.pos());
208                 int y1 = c.yo() - c.ascent();
209                 int x2 = c.xo() + c.pos2x(s2.pos());
210                 int y2 = c.yo() + c.descent();
211                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
212         } else {
213                 for (idx_type i = 0; i < nargs(); ++i) {
214                         if (idxBetween(i, s1.idx(), s2.idx())) {
215                                 MathArray const & c = cell(i);
216                                 int x1 = c.xo();
217                                 int y1 = c.yo() - c.ascent();
218                                 int x2 = c.xo() + c.width();
219                                 int y2 = c.yo() + c.descent();
220                                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
221                         }
222                 }
223         }
224 }
225
226
227 void MathNestInset::validate(LaTeXFeatures & features) const
228 {
229         for (idx_type i = 0; i < nargs(); ++i)
230                 cell(i).validate(features);
231 }
232
233
234 void MathNestInset::replace(ReplaceData & rep)
235 {
236         for (idx_type i = 0; i < nargs(); ++i)
237                 cell(i).replace(rep);
238 }
239
240
241 bool MathNestInset::contains(MathArray const & ar) const
242 {
243         for (idx_type i = 0; i < nargs(); ++i)
244                 if (cell(i).contains(ar))
245                         return true;
246         return false;
247 }
248
249
250 bool MathNestInset::lock() const
251 {
252         return lock_;
253 }
254
255
256 void MathNestInset::lock(bool l)
257 {
258         lock_ = l;
259 }
260
261
262 bool MathNestInset::isActive() const
263 {
264         return nargs() > 0;
265 }
266
267
268 MathArray MathNestInset::glue() const
269 {
270         MathArray ar;
271         for (size_t i = 0; i < nargs(); ++i)
272                 ar.append(cell(i));
273         return ar;
274 }
275
276
277 void MathNestInset::write(WriteStream & os) const
278 {
279         os << '\\' << name().c_str();
280         for (size_t i = 0; i < nargs(); ++i)
281                 os << '{' << cell(i) << '}';
282         if (nargs() == 0)
283                 os.pendingSpace(true);
284         if (lock_ && !os.latex()) {
285                 os << "\\lyxlock";
286                 os.pendingSpace(true);
287         }
288 }
289
290
291 void MathNestInset::normalize(NormalStream & os) const
292 {
293         os << '[' << name().c_str();
294         for (size_t i = 0; i < nargs(); ++i)
295                 os << ' ' << cell(i);
296         os << ']';
297 }
298
299
300 void MathNestInset::notifyCursorLeaves(idx_type idx)
301 {
302         cell(idx).notifyCursorLeaves();
303 }
304
305
306 void MathNestInset::handleFont
307         (LCursor & cur, string const & arg, string const & font)
308 {
309         // this whole function is a hack and won't work for incremental font
310         // changes...
311         recordUndo(cur, Undo::ATOMIC);
312
313         if (cur.inset().asMathInset()->name() == font)
314                 cur.handleFont(font);
315         else {
316                 cur.handleNest(createMathInset(font));
317                 cur.insert(arg);
318         }
319 }
320
321
322 void MathNestInset::handleFont2(LCursor & cur, string const & arg)
323 {
324         recordUndo(cur, Undo::ATOMIC);
325         LyXFont font;
326         bool b;
327         bv_funcs::string2font(arg, font, b);
328         if (font.color() != LColor::inherit) {
329                 MathAtom at = createMathInset("color");
330                 asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
331                 cur.handleNest(at, 1);
332         }
333 }
334
335
336 void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest & cmd)
337 {
338         //lyxerr << "MathNestInset: request: " << cmd << std::endl;
339         //CursorSlice sl = cur.current();
340
341         switch (cmd.action) {
342
343         case LFUN_PASTESELECTION: {
344                 MathArray ar;
345                 mathed_parse_cell(ar, cur.bv().getClipboard());
346                 cur.cell().insert(cur.pos(), ar);
347                 cur.pos() += ar.size();
348                 break;
349         }
350
351         case LFUN_PASTE:
352                 if (!cmd.argument.empty()) {
353                         MathArray ar;
354                         mathed_parse_cell(ar, cmd.argument);
355                         cur.cell().insert(cur.pos(), ar);
356                         cur.pos() += ar.size();
357                 }
358                 break;
359 /*
360         case LFUN_PASTE: {
361                 size_t n = 0;
362                 istringstream is(cmd.argument.c_str());
363                 is >> n;
364                 if (was_macro)
365                         cur.macroModeClose();
366                 recordUndo(cur, Undo::ATOMIC);
367                 cur.selPaste(n);
368                 break;
369         }
370 */
371
372         case LFUN_MOUSE_PRESS:
373                 lfunMousePress(cur, cmd);
374                 break;
375
376         case LFUN_MOUSE_MOTION:
377                 lfunMouseMotion(cur, cmd);
378                 break;
379
380         case LFUN_MOUSE_RELEASE:
381                 lfunMouseRelease(cur, cmd);
382                 break;
383
384         case LFUN_FINISHED_LEFT:
385                 cur.bv().cursor() = cur;
386                 break;
387
388         case LFUN_FINISHED_RIGHT:
389                 ++cur.pos();
390                 cur.bv().cursor() = cur;
391                 break;
392
393         case LFUN_FINISHED_UP:
394                 //idxUpDown(cur, true);
395                 cur.bv().cursor() = cur;
396                 break;
397
398         case LFUN_FINISHED_DOWN:
399                 //idxUpDown(cur, false);
400                 cur.bv().cursor() = cur;
401                 break;
402
403         case LFUN_RIGHTSEL:
404         case LFUN_RIGHT:
405                 lyxerr << "mathnest RIGHT: from:\n" << cur << endl;
406                 cur.selHandle(cmd.action == LFUN_RIGHTSEL);
407                 cur.autocorrect() = false;
408                 cur.clearTargetX();
409                 if (cur.inMacroMode())
410                         cur.macroModeClose();
411                 else if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) {
412                         cur.pushLeft(*cur.nextAtom().nucleus());
413                         cur.inset().idxFirst(cur);
414                 } else if (cur.posRight() || idxRight(cur)
415                         || cur.popRight() || cur.selection())
416                         ;
417                 else
418                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
419                 lyxerr << "mathnest RIGHT: to:\n" << cur << endl;
420                 break;
421
422         case LFUN_LEFTSEL:
423         case LFUN_LEFT:
424                 cur.selHandle(cmd.action == LFUN_LEFTSEL);
425                 cur.autocorrect() = false;
426                 cur.clearTargetX();
427                 if (cur.inMacroMode())
428                         cur.macroModeClose();
429                 else if (cur.pos() != 0 && cur.openable(cur.prevAtom())) {
430                         cur.posLeft();
431                         cur.push(*cur.nextAtom().nucleus());
432                         cur.inset().idxLast(cur);
433                 } else if (cur.posLeft() || idxLeft(cur)
434                         || cur.popLeft() || cur.selection())
435                         ;
436                 else
437                         cmd = FuncRequest(LFUN_FINISHED_LEFT);
438                 break;
439
440         case LFUN_UPSEL:
441         case LFUN_UP:
442                 cur.selHandle(cmd.action == LFUN_UPSEL);
443                 if (!cur.up())
444                         cmd = FuncRequest(LFUN_FINISHED_UP);
445                 break;
446
447         case LFUN_DOWNSEL:
448         case LFUN_DOWN:
449                 cur.selHandle(cmd.action == LFUN_DOWNSEL);
450                 if (!cur.down())
451                         cmd = FuncRequest(LFUN_FINISHED_DOWN);
452                 break;
453
454         case LFUN_MOUSE_DOUBLE:
455         case LFUN_MOUSE_TRIPLE:
456         case LFUN_WORDSEL:
457                 cur.pos() = 0;
458                 cur.idx() = 0;
459                 cur.resetAnchor();
460                 cur.selection() = true;
461                 cur.pos() = cur.lastpos();
462                 cur.idx() = cur.lastidx();
463                 break;
464
465         case LFUN_UP_PARAGRAPHSEL:
466         case LFUN_UP_PARAGRAPH:
467         case LFUN_DOWN_PARAGRAPHSEL:
468         case LFUN_DOWN_PARAGRAPH:
469                 break;
470
471         case LFUN_HOMESEL:
472         case LFUN_HOME:
473         case LFUN_WORDLEFTSEL:
474         case LFUN_WORDLEFT:
475                 cur.selHandle(cmd.action == LFUN_WORDLEFTSEL || cmd.action == LFUN_HOMESEL);
476                 cur.macroModeClose();
477                 if (cur.pos() != 0) {
478                         cur.pos() = 0;
479                 } else if (cur.col() != 0) {
480                         cur.idx() -= cur.col();
481                         cur.pos() = 0;
482                 } else if (cur.idx() != 0) {
483                         cur.idx() = 0;
484                         cur.pos() = 0;
485                 } else {
486                         cmd = FuncRequest(LFUN_FINISHED_LEFT);
487                 }
488                 break;
489
490         case LFUN_WORDRIGHTSEL:
491         case LFUN_WORDRIGHT:
492         case LFUN_ENDSEL:
493         case LFUN_END:
494                 cur.selHandle(cmd.action == LFUN_WORDRIGHTSEL || cmd.action == LFUN_ENDSEL);
495                 cur.macroModeClose();
496                 cur.clearTargetX();
497                 if (cur.pos() != cur.lastpos()) {
498                         cur.pos() = cur.lastpos();
499                 } else if (cur.col() != cur.lastcol()) {
500                         cur.idx() = cur.idx() - cur.col() + cur.lastcol();
501                         cur.pos() = cur.lastpos();
502                 } else if (cur.idx() != cur.lastidx()) {
503                         cur.idx() = cur.lastidx();
504                         cur.pos() = cur.lastpos();
505                 } else {
506                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
507                 }
508                 break;
509
510         case LFUN_PRIORSEL:
511         case LFUN_PRIOR:
512         case LFUN_BEGINNINGBUFSEL:
513         case LFUN_BEGINNINGBUF:
514                 cmd = FuncRequest(LFUN_FINISHED_LEFT);
515                 break;
516
517         case LFUN_NEXTSEL:
518         case LFUN_NEXT:
519         case LFUN_ENDBUFSEL:
520         case LFUN_ENDBUF:
521                 cmd = FuncRequest(LFUN_FINISHED_RIGHT);
522                 break;
523
524         case LFUN_CELL_FORWARD:
525                 cur.inset().idxNext(cur);
526                 break;
527
528         case LFUN_CELL_BACKWARD:
529                 cur.inset().idxPrev(cur);
530                 break;
531
532         case LFUN_DELETE_WORD_BACKWARD:
533         case LFUN_BACKSPACE:
534                 recordUndo(cur, Undo::ATOMIC);
535                 cur.backspace();
536                 break;
537
538         case LFUN_DELETE_WORD_FORWARD:
539         case LFUN_DELETE:
540                 recordUndo(cur, Undo::ATOMIC);
541                 cur.erase();
542                 cmd = FuncRequest(LFUN_FINISHED_LEFT);
543                 break;
544
545         case LFUN_ESCAPE:
546                 if (cur.selection())
547                         cur.selClear();
548                 else
549                         cmd = FuncRequest(LFUN_FINISHED_LEFT);
550                 break;
551
552         case LFUN_INSET_TOGGLE:
553                 //lockToggle();
554                 if (cur.pos() != cur.lastpos()) {
555                         // toggle previous inset ...
556                         cur.nextAtom().nucleus()->lock(!cur.nextAtom()->lock());
557                 } else if (cur.popLeft() && cur.pos() != cur.lastpos()) {
558                         // ... or enclosing inset if we are in the last inset position
559                         cur.nextAtom().nucleus()->lock(!cur.nextAtom()->lock());
560                         ++cur.pos();
561                 }
562                 break;
563
564         case LFUN_SELFINSERT:
565                 if (cmd.argument.empty()) {
566                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
567                         break;
568                 }
569                 recordUndo(cur, Undo::ATOMIC);
570                 if (cmd.argument.size() != 1) {
571                         cur.insert(cmd.argument);
572                         break;
573                 }
574                 if (!interpret(cur, cmd.argument[0]))
575                         cmd = FuncRequest(LFUN_FINISHED_RIGHT);
576                 break;
577
578 #if 0
579 //
580 // this needs to be incorporated
581 //
582         // delete empty mathbox (LFUN_BACKSPACE and LFUN_DELETE)
583         bool remove_inset = false;
584
585         DispatchResult result(true);
586         bool was_macro     = cur.inMacroMode();
587
588         cur.normalize();
589         cur.touch();
590 #endif
591
592         //    case LFUN_GETXY:
593         //      sprintf(dispatch_buffer, "%d %d",);
594         //      DispatchResult= dispatch_buffer;
595         //      break;
596         case LFUN_SETXY: {
597                 lyxerr << "LFUN_SETXY broken!" << endl;
598                 int x = 0;
599                 int y = 0;
600                 istringstream is(cmd.argument.c_str());
601                 is >> x >> y;
602                 cur.setScreenPos(x, y);
603                 break;
604         }
605
606         case LFUN_CUT:
607                 recordUndo(cur, Undo::DELETE);
608                 cur.selCut();
609                 break;
610
611         case LFUN_COPY:
612                 cur.selCopy();
613                 break;
614
615         // Special casing for superscript in case of LyX handling
616         // dead-keys:
617         case LFUN_CIRCUMFLEX:
618                 if (cmd.argument.empty()) {
619                         // do superscript if LyX handles
620                         // deadkeys
621                         recordUndo(cur, Undo::ATOMIC);
622                         script(cur, true);
623                 }
624                 break;
625
626         case LFUN_UMLAUT:
627         case LFUN_ACUTE:
628         case LFUN_GRAVE:
629         case LFUN_BREVE:
630         case LFUN_DOT:
631         case LFUN_MACRON:
632         case LFUN_CARON:
633         case LFUN_TILDE:
634         case LFUN_CEDILLA:
635         case LFUN_CIRCLE:
636         case LFUN_UNDERDOT:
637         case LFUN_TIE:
638         case LFUN_OGONEK:
639         case LFUN_HUNG_UMLAUT:
640                 break;
641
642         //  Math fonts
643         case LFUN_FREEFONT_APPLY:
644         case LFUN_FREEFONT_UPDATE:
645                 handleFont2(cur, cmd.argument);
646                 break;
647
648         case LFUN_BOLD:
649                 handleFont(cur, cmd.argument, "mathbf");
650                 break;
651         case LFUN_SANS:
652                 handleFont(cur, cmd.argument, "mathsf");
653                 break;
654         case LFUN_EMPH:
655                 handleFont(cur, cmd.argument, "mathcal");
656                 break;
657         case LFUN_ROMAN:
658                 handleFont(cur, cmd.argument, "mathrm");
659                 break;
660         case LFUN_CODE:
661                 handleFont(cur, cmd.argument, "texttt");
662                 break;
663         case LFUN_FRAK:
664                 handleFont(cur, cmd.argument, "mathfrak");
665                 break;
666         case LFUN_ITAL:
667                 handleFont(cur, cmd.argument, "mathit");
668                 break;
669         case LFUN_NOUN:
670                 handleFont(cur, cmd.argument, "mathbb");
671                 break;
672         //case LFUN_FREEFONT_APPLY:
673                 handleFont(cur, cmd.argument, "textrm");
674                 break;
675         case LFUN_DEFAULT:
676                 handleFont(cur, cmd.argument, "textnormal");
677                 break;
678
679         case LFUN_MATH_MODE:
680 #if 1
681                 cur.macroModeClose();
682                 cur.selClearOrDel();
683                 cur.plainInsert(MathAtom(new MathMBoxInset(cur.bv())));
684                 cur.posLeft();
685                 cur.pushLeft(*cur.nextInset());
686 #else
687                 if (currentMode() == InsetBase::TEXT_MODE)
688                         cur.niceInsert(MathAtom(new MathHullInset("simple")));
689                 else
690                         handleFont(cur, cmd.argument, "textrm");
691                 //cur.owner()->message(_("math text mode toggled"));
692 #endif
693                 break;
694
695         case LFUN_MATH_SIZE:
696 #if 0
697                 if (!arg.empty()) {
698                         recordUndo(cur, Undo::ATOMIC);
699                         cur.setSize(arg);
700                 }
701 #endif
702                 break;
703
704         case LFUN_INSERT_MATRIX: {
705                 recordUndo(cur, Undo::ATOMIC);
706                 unsigned int m = 1;
707                 unsigned int n = 1;
708                 string v_align;
709                 string h_align;
710                 istringstream is(cmd.argument);
711                 is >> m >> n >> v_align >> h_align;
712                 if (m < 1)
713                         m = 1;
714                 if (n < 1)
715                         n = 1;
716                 v_align += 'c';
717                 cur.niceInsert(
718                         MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
719                 break;
720         }
721
722         case LFUN_MATH_DELIM: {
723                 lyxerr << "MathNestInset::LFUN_MATH_DELIM" << endl;
724                 string ls;
725                 string rs = lyx::support::split(cmd.argument, ls, ' ');
726                 // Reasonable default values
727                 if (ls.empty())
728                         ls = '(';
729                 if (rs.empty())
730                         rs = ')';
731                 recordUndo(cur, Undo::ATOMIC);
732                 cur.handleNest(MathAtom(new MathDelimInset(ls, rs)));
733                 break;
734         }
735
736         case LFUN_SPACE_INSERT:
737         case LFUN_MATH_SPACE:
738                 recordUndo(cur, Undo::ATOMIC);
739                 cur.insert(MathAtom(new MathSpaceInset(",")));
740                 break;
741
742         case LFUN_INSET_ERT:
743                 // interpret this as if a backslash was typed
744                 recordUndo(cur, Undo::ATOMIC);
745                 interpret(cur, '\\');
746                 break;
747
748 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
749 // handling such that "self-insert" works on "arbitrary stuff" too, and
750 // math-insert only handles special math things like "matrix".
751         case LFUN_INSERT_MATH:
752                 recordUndo(cur, Undo::ATOMIC);
753                 cur.niceInsert(cmd.argument);
754                 break;
755
756         case LFUN_DIALOG_SHOW_NEW_INSET: {
757                 string const & name = cmd.argument;
758                 string data;
759 #if 0
760                 if (name == "ref") {
761                         RefInset tmp(name);
762                         data = tmp.createDialogStr(name);
763                 }
764 #endif
765                 cur.bv().owner()->getDialogs().show(name, data, 0);
766                 break;
767         }
768
769         case LFUN_INSET_APPLY: {
770                 string const name = cmd.getArg(0);
771                 InsetBase * base = cur.bv().owner()->getDialogs().getOpenInset(name);
772
773                 if (base) {
774                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
775                         base->dispatch(cur, fr);
776                         break;
777                 }
778                 MathArray ar;
779                 if (createMathInset_fromDialogStr(cmd.argument, ar)) {
780                         cur.insert(ar);
781                         break;
782                 }
783                 cur.undispatched();
784                 break;
785         }
786
787 #ifdef WITH_WARNINGS
788 #warning look here
789 #endif
790 #if 0
791
792         case LFUN_WORD_REPLACE:
793         case LFUN_WORD_FIND:
794                 if (!searchForward(&cur.bv(), cmd.getArg(0), false, false))
795                         cur.undispatched();
796                 break;
797
798         cur.normalize();
799         cur.touch();
800
801         BOOST_ASSERT(cur.inMathed());
802
803         if (result.dispatched()) {
804                 revealCodes(cur);
805                 cur.bv().stuffClipboard(cur.grabSelection());
806         } else {
807                 if (remove_inset)
808                         cur.bv().owner()->dispatch(FuncRequest(LFUN_DELETE));
809         }
810         break;
811 #endif
812
813         default:
814                 MathDimInset::priv_dispatch(cur, cmd);
815                 break;
816         }
817 }
818
819
820 bool MathNestInset::getStatus(LCursor & /*cur*/, FuncRequest const & cmd,
821                 FuncStatus & flag) const
822 {
823         // the font related toggles
824         //string tc = mathcursor::getLastCode();
825         bool ret = true;
826         switch (cmd.action) {
827 #if 0
828         case LFUN_TABULAR_FEATURE:
829                 // FIXME: check temporarily disabled
830                 // valign code
831                 char align = mathcursor::valign();
832                 if (align == '\0') {
833                         enable = false;
834                         break;
835                 }
836                 if (cmd.argument.empty()) {
837                         flag.clear();
838                         break;
839                 }
840                 if (!contains("tcb", cmd.argument[0])) {
841                         enable = false;
842                         break;
843                 }
844                 flag.setOnOff(cmd.argument[0] == align);
845                 break;
846         case LFUN_BOLD:
847                 flag.setOnOff(tc == "mathbf");
848                 break;
849         case LFUN_SANS:
850                 flag.setOnOff(tc == "mathsf");
851                 break;
852         case LFUN_EMPH:
853                 flag.setOnOff(tc == "mathcal");
854                 break;
855         case LFUN_ROMAN:
856                 flag.setOnOff(tc == "mathrm");
857                 break;
858         case LFUN_CODE:
859                 flag.setOnOff(tc == "mathtt");
860                 break;
861         case LFUN_NOUN:
862                 flag.setOnOff(tc == "mathbb");
863                 break;
864         case LFUN_DEFAULT:
865                 flag.setOnOff(tc == "mathnormal");
866                 break;
867 #endif
868         case LFUN_MATH_MUTATE:
869                 //flag.setOnOff(mathcursor::formula()->hullType() == cmd.argument);
870                 flag.setOnOff(false);
871                 break;
872
873         // we just need to be in math mode to enable that
874         case LFUN_MATH_SIZE:
875         case LFUN_MATH_SPACE:
876         case LFUN_MATH_LIMITS:
877         case LFUN_MATH_NONUMBER:
878         case LFUN_MATH_NUMBER:
879         case LFUN_MATH_EXTERN:
880                 flag.enabled(true);
881                 break;
882
883         default:
884                 ret = false;
885                 break;
886         }
887         return ret;
888 }
889
890
891 void MathNestInset::edit(LCursor & cur, bool left)
892 {
893         cur.push(*this);
894         cur.idx() = left ? 0 : cur.lastidx();
895         cur.pos() = left ? 0 : cur.lastpos();
896         cur.resetAnchor();
897         lyxerr << "MathNestInset::edit, cur:\n" << cur << endl;
898 }
899
900
901 InsetBase * MathNestInset::editXY(LCursor & cur, int x, int y)
902 {
903         int idx_min = 0;
904         int dist_min = 1000000;
905         for (idx_type i = 0; i < nargs(); ++i) {
906                 int d = cell(i).dist(x, y);
907                 if (d < dist_min) {
908                         dist_min = d;
909                         idx_min = i;
910                 }
911         }
912         MathArray & ar = cell(idx_min);
913         cur.push(*this);
914         cur.idx() = idx_min;
915         cur.pos() = ar.x2pos(x - ar.xo());
916         lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl;
917         if (dist_min == 0) {
918                 // hit inside cell
919                 for (pos_type i = 0, n = ar.size(); i < n; ++i)
920                         if (ar[i]->covers(x, y))
921                                 return ar[i].nucleus()->editXY(cur, x, y);
922         }
923         return this;
924 }
925
926
927 void MathNestInset::lfunMouseRelease(LCursor & cur, FuncRequest & cmd)
928 {
929         //lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl;
930
931         if (cmd.button() == mouse_button::button1) {
932                 // try to dispatch to enclosed insets first
933                 //cur.bv().stuffClipboard(cur.grabSelection());
934                 return;
935         }
936
937         if (cmd.button() == mouse_button::button2) {
938                 MathArray ar;
939                 asArray(cur.bv().getClipboard(), ar);
940                 cur.selClear();
941                 cur.setScreenPos(cmd.x, cmd.y);
942                 cur.insert(ar);
943                 cur.bv().update();
944                 return;
945         }
946
947         if (cmd.button() == mouse_button::button3) {
948                 // try to dispatch to enclosed insets first
949                 cur.bv().owner()->getDialogs().show("mathpanel");
950                 return;
951         }
952
953         cur.undispatched();
954 }
955
956
957 void MathNestInset::lfunMousePress(LCursor & cur, FuncRequest & cmd)
958 {
959         lyxerr << "lfunMousePress: buttons: " << cmd.button() << endl;
960         if (cmd.button() == mouse_button::button1) {
961                 first_x = cmd.x;
962                 first_y = cmd.y;
963                 cur.selClear();
964                 //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
965                 lyxerr << "lfunMousePress: setting cursor to: " << cur << endl;
966                 cur.bv().cursor() = cur;
967         }
968
969         if (cmd.button() == mouse_button::button2) {
970                 cur.dispatch(FuncRequest(LFUN_PASTESELECTION));
971         }
972 }
973
974
975 void MathNestInset::lfunMouseMotion(LCursor & cur, FuncRequest & cmd)
976 {
977         // only select with button 1
978         if (cmd.button() != mouse_button::button1)
979                 return;
980
981         if (abs(cmd.x - first_x) < 2 && abs(cmd.y - first_y) < 2)
982                 return;
983
984         first_x = cmd.x;
985         first_y = cmd.y;
986
987         if (!cur.selection())
988                 cur.selBegin();
989
990         //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
991         cur.bv().cursor().setCursor(cur, true);
992 }
993
994
995 bool MathNestInset::interpret(LCursor & cur, char c)
996 {
997         //lyxerr << "interpret 2: '" << c << "'" << endl;
998         cur.clearTargetX();
999         if (cur.inMacroArgMode()) {
1000                 cur.posLeft();
1001                 cur.plainErase();
1002 #ifdef WITH_WARNINGS
1003 #warning FIXME
1004 #endif
1005 #if 0
1006                 int n = c - '0';
1007                 MathMacroTemplate const * p = formula()->asMacroTemplate();
1008                 if (p && 1 <= n && n <= p->numargs())
1009                         cur.insert(MathAtom(new MathMacroArgument(c - '0')));
1010                 else {
1011                         cur.insert(createMathInset("#"));
1012                         interpret(cur, c); // try again
1013                 }
1014 #endif
1015                 return true;
1016         }
1017
1018         // handle macroMode
1019         if (cur.inMacroMode()) {
1020                 string name = cur.macroName();
1021                 //lyxerr << "interpret name: '" << name << "'" << endl;
1022
1023                 if (isalpha(c)) {
1024                         cur.activeMacro()->setName(cur.activeMacro()->name() + c);
1025                         return true;
1026                 }
1027
1028                 // handle 'special char' macros
1029                 if (name == "\\") {
1030                         // remove the '\\'
1031                         cur.backspace();
1032                         if (c == '\\') {
1033                                 if (currentMode() == MathInset::TEXT_MODE)
1034                                         cur.niceInsert(createMathInset("textbackslash"));
1035                                 else
1036                                         cur.niceInsert(createMathInset("backslash"));
1037                         } else if (c == '{') {
1038                                 cur.niceInsert(MathAtom(new MathBraceInset));
1039                         } else {
1040                                 cur.niceInsert(createMathInset(string(1, c)));
1041                         }
1042                         return true;
1043                 }
1044
1045                 // leave macro mode and try again if necessary
1046                 cur.macroModeClose();
1047                 if (c == '{')
1048                         cur.niceInsert(MathAtom(new MathBraceInset));
1049                 else if (c != ' ')
1050                         interpret(cur, c);
1051                 return true;
1052         }
1053
1054         // This is annoying as one has to press <space> far too often.
1055         // Disable it.
1056
1057 #if 0
1058                 // leave autocorrect mode if necessary
1059                 if (autocorrect() && c == ' ') {
1060                         autocorrect() = false;
1061                         return true;
1062                 }
1063 #endif
1064
1065         // just clear selection on pressing the space bar
1066         if (cur.selection() && c == ' ') {
1067                 cur.selection() = false;
1068                 return true;
1069         }
1070
1071         cur.selClearOrDel();
1072
1073         if (c == '\\') {
1074                 //lyxerr << "starting with macro" << endl;
1075                 cur.insert(MathAtom(new MathUnknownInset("\\", false)));
1076                 return true;
1077         }
1078
1079         if (c == '\n') {
1080                 if (currentMode() == MathInset::TEXT_MODE)
1081                         cur.insert(c);
1082                 return true;
1083         }
1084
1085         if (c == ' ') {
1086                 if (currentMode() == MathInset::TEXT_MODE) {
1087                         // insert spaces in text mode,
1088                         // but suppress direct insertion of two spaces in a row
1089                         // the still allows typing  '<space>a<space>' and deleting the 'a', but
1090                         // it is better than nothing...
1091                         if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ')
1092                                 cur.insert(c);
1093                         return true;
1094                 }
1095                 if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) {
1096                         cur.prevAtom().nucleus()->asSpaceInset()->incSpace();
1097                         return true;
1098                 }
1099                 if (cur.popRight())
1100                         return true;
1101                 // if are at the very end, leave the formula
1102                 return cur.pos() != cur.lastpos();
1103         }
1104
1105         if (c == '_') {
1106                 script(cur, false);
1107                 return true;
1108         }
1109
1110         if (c == '^') {
1111                 script(cur, true);
1112                 return true;
1113         }
1114
1115         if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
1116                 cur.niceInsert(createMathInset(string(1, c)));
1117                 return true;
1118         }
1119
1120         if (c == '%') {
1121                 cur.niceInsert(MathAtom(new MathCommentInset));
1122                 return true;
1123         }
1124
1125         // try auto-correction
1126         //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
1127         //      return true;
1128
1129         // no special circumstances, so insert the character without any fuss
1130         cur.insert(c);
1131         cur.autocorrect() = true;
1132         return true;
1133 }
1134
1135
1136 bool MathNestInset::script(LCursor & cur, bool up)
1137 {
1138         // Hack to get \\^ and \\_ working
1139         lyxerr << "handling script: up: " << up << endl;
1140         if (cur.inMacroMode() && cur.macroName() == "\\") {
1141                 if (up)
1142                         cur.niceInsert(createMathInset("mathcircumflex"));
1143                 else
1144                         interpret(cur, '_');
1145                 return true;
1146         }
1147
1148         cur.macroModeClose();
1149         string safe = cur.grabAndEraseSelection();
1150         if (asScriptInset() && cur.idx() == 0) {
1151                 // we are in a nucleus of a script inset, move to _our_ script
1152                 MathScriptInset * inset = asScriptInset();
1153                 lyxerr << " going to cell " << inset->idxOfScript(up) << endl;
1154                 inset->ensure(up);
1155                 cur.idx() = inset->idxOfScript(up);
1156                 cur.pos() = 0;
1157         } else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) {
1158                 --cur.pos();
1159                 MathScriptInset * inset = cur.nextAtom().nucleus()->asScriptInset();
1160                 cur.push(*inset);
1161                 cur.idx() = inset->idxOfScript(up);
1162                 cur.pos() = cur.lastpos();
1163         } else {
1164                 // convert the thing to our left to a scriptinset or create a new
1165                 // one if in the very first position of the array
1166                 if (cur.pos() == 0) {
1167                         cur.insert(new MathScriptInset(up));
1168                 } else {
1169                         --cur.pos();
1170                         cur.cell()[cur.pos()] = MathAtom(new MathScriptInset(cur.nextAtom(), up));
1171                 }
1172                 MathScriptInset * inset = cur.nextAtom().nucleus()->asScriptInset();
1173                 cur.push(*inset);
1174                 cur.idx() = 1;
1175                 cur.pos() = 0;
1176         }
1177         cur.paste(safe);
1178         return true;
1179 }