]> git.lyx.org Git - lyx.git/blob - src/mathed/math_nestinset.C
7a331083ece8e749504d87f35a5a19c4ec8e12b1
[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_UNDO:
743 #warning look here
744                 //cur.bv().owner()->message(_("Invalid action in math mode!"));
745                 break;
746
747         case LFUN_INSET_ERT:
748                 // interpret this as if a backslash was typed
749                 recordUndo(cur, Undo::ATOMIC);
750                 interpret(cur, '\\');
751                 break;
752
753 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
754 // handling such that "self-insert" works on "arbitrary stuff" too, and
755 // math-insert only handles special math things like "matrix".
756         case LFUN_INSERT_MATH:
757                 recordUndo(cur, Undo::ATOMIC);
758                 cur.niceInsert(cmd.argument);
759                 break;
760
761         case LFUN_DIALOG_SHOW_NEW_INSET: {
762                 string const & name = cmd.argument;
763                 string data;
764 #if 0
765                 if (name == "ref") {
766                         RefInset tmp(name);
767                         data = tmp.createDialogStr(name);
768                 }
769 #endif
770                 cur.bv().owner()->getDialogs().show(name, data, 0);
771                 break;
772         }
773
774         case LFUN_INSET_APPLY: {
775                 string const name = cmd.getArg(0);
776                 InsetBase * base = cur.bv().owner()->getDialogs().getOpenInset(name);
777
778                 if (base) {
779                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
780                         base->dispatch(cur, fr);
781                         break;
782                 }
783                 MathArray ar;
784                 if (createMathInset_fromDialogStr(cmd.argument, ar)) {
785                         cur.insert(ar);
786                         break;
787                 }
788                 cur.undispatched();
789                 break;
790         }
791
792 #warning look here
793 #if 0
794
795         case LFUN_WORD_REPLACE:
796         case LFUN_WORD_FIND:
797                 if (!searchForward(&cur.bv(), cmd.getArg(0), false, false))
798                         cur.undispatched();
799                 break;
800
801         cur.normalize();
802         cur.touch();
803
804         BOOST_ASSERT(cur.inMathed());
805
806         if (result.dispatched()) {
807                 revealCodes(cur);
808                 cur.bv().stuffClipboard(cur.grabSelection());
809         } else {
810                 if (remove_inset)
811                         cur.bv().owner()->dispatch(FuncRequest(LFUN_DELETE));
812         }
813         break;
814 #endif
815
816         default:
817                 MathDimInset::priv_dispatch(cur, cmd);
818                 break;
819         }
820 }
821
822
823 bool MathNestInset::getStatus(LCursor & /*cur*/, FuncRequest const & cmd,
824                 FuncStatus & flag) const
825 {
826         // the font related toggles
827         //string tc = mathcursor::getLastCode();
828         bool ret = true;
829         switch (cmd.action) {
830 #if 0
831         case LFUN_TABULAR_FEATURE:
832                 // FIXME: check temporarily disabled
833                 // valign code
834                 char align = mathcursor::valign();
835                 if (align == '\0') {
836                         enable = false;
837                         break;
838                 }
839                 if (cmd.argument.empty()) {
840                         flag.clear();
841                         break;
842                 }
843                 if (!contains("tcb", cmd.argument[0])) {
844                         enable = false;
845                         break;
846                 }
847                 flag.setOnOff(cmd.argument[0] == align);
848                 break;
849         case LFUN_BOLD:
850                 flag.setOnOff(tc == "mathbf");
851                 break;
852         case LFUN_SANS:
853                 flag.setOnOff(tc == "mathsf");
854                 break;
855         case LFUN_EMPH:
856                 flag.setOnOff(tc == "mathcal");
857                 break;
858         case LFUN_ROMAN:
859                 flag.setOnOff(tc == "mathrm");
860                 break;
861         case LFUN_CODE:
862                 flag.setOnOff(tc == "mathtt");
863                 break;
864         case LFUN_NOUN:
865                 flag.setOnOff(tc == "mathbb");
866                 break;
867         case LFUN_DEFAULT:
868                 flag.setOnOff(tc == "mathnormal");
869                 break;
870 #endif
871         case LFUN_MATH_MUTATE:
872                 //flag.setOnOff(mathcursor::formula()->hullType() == cmd.argument);
873                 flag.setOnOff(false);
874                 break;
875
876         // we just need to be in math mode to enable that
877         case LFUN_MATH_SIZE:
878         case LFUN_MATH_SPACE:
879         case LFUN_MATH_LIMITS:
880         case LFUN_MATH_NONUMBER:
881         case LFUN_MATH_NUMBER:
882         case LFUN_MATH_EXTERN:
883                 flag.enabled(true);
884                 break;
885
886         default:
887                 ret = false;
888                 break;
889         }
890         return ret;
891 }
892
893 void MathNestInset::edit(LCursor & cur, bool left)
894 {
895         cur.push(*this);
896         cur.idx() = left ? 0 : cur.lastidx();
897         cur.pos() = left ? 0 : cur.lastpos();
898         cur.resetAnchor();
899 }
900
901
902 InsetBase * MathNestInset::editXY(LCursor & cur, int x, int y)
903 {
904         int idx_min = 0;
905         int dist_min = 1000000;
906         for (idx_type i = 0; i < nargs(); ++i) {
907                 int d = cell(i).dist(x, y);
908                 if (d < dist_min) {
909                         dist_min = d;
910                         idx_min = i;
911                 }
912         }
913         MathArray & ar = cell(idx_min);
914         cur.push(*this);
915         cur.idx() = idx_min;
916         cur.pos() = ar.x2pos(x - ar.xo());
917         lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl;
918         if (dist_min == 0) {
919                 // hit inside cell
920                 for (pos_type i = 0, n = ar.size(); i < n; ++i)
921                         if (ar[i]->covers(x, y))
922                                 return ar[i].nucleus()->editXY(cur, x, y);
923         }
924         return this;
925 }
926
927
928 void MathNestInset::lfunMouseRelease(LCursor & cur, FuncRequest & cmd)
929 {
930         //lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl;
931
932         if (cmd.button() == mouse_button::button1) {
933                 // try to dispatch to enclosed insets first
934                 //cur.bv().stuffClipboard(cur.grabSelection());
935                 return;
936         }
937
938         if (cmd.button() == mouse_button::button2) {
939                 MathArray ar;
940                 asArray(cur.bv().getClipboard(), ar);
941                 cur.selClear();
942                 cur.setScreenPos(cmd.x, cmd.y);
943                 cur.insert(ar);
944                 cur.bv().update();
945                 return;
946         }
947
948         if (cmd.button() == mouse_button::button3) {
949                 // try to dispatch to enclosed insets first
950                 cur.bv().owner()->getDialogs().show("mathpanel");
951                 return;
952         }
953
954         cur.undispatched();
955 }
956
957
958 void MathNestInset::lfunMousePress(LCursor & cur, FuncRequest & cmd)
959 {
960         lyxerr << "lfunMousePress: buttons: " << cmd.button() << endl;
961         if (cmd.button() == mouse_button::button1) {
962                 first_x = cmd.x;
963                 first_y = cmd.y;
964                 cur.selClear();
965                 //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
966                 lyxerr << "lfunMousePress: setting cursor to: " << cur << endl;
967                 cur.bv().cursor() = cur;
968         }
969
970         if (cmd.button() == mouse_button::button2) {
971                 cur.dispatch(FuncRequest(LFUN_PASTESELECTION));
972         }
973 }
974
975
976 void MathNestInset::lfunMouseMotion(LCursor & cur, FuncRequest & cmd)
977 {
978         // only select with button 1
979         if (cmd.button() != mouse_button::button1)
980                 return;
981
982         if (abs(cmd.x - first_x) < 2 && abs(cmd.y - first_y) < 2)
983                 return;
984
985         first_x = cmd.x;
986         first_y = cmd.y;
987
988         if (!cur.selection())
989                 cur.selBegin();
990
991         //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
992         cur.bv().cursor().setCursor(cur, true);
993 }
994
995
996 bool MathNestInset::interpret(LCursor & cur, char c)
997 {
998         //lyxerr << "interpret 2: '" << c << "'" << endl;
999         cur.clearTargetX();
1000         if (cur.inMacroArgMode()) {
1001                 cur.posLeft();
1002                 cur.plainErase();
1003 #warning FIXME
1004 #if 0
1005                 int n = c - '0';
1006                 MathMacroTemplate const * p = formula()->asMacroTemplate();
1007                 if (p && 1 <= n && n <= p->numargs())
1008                         cur.insert(MathAtom(new MathMacroArgument(c - '0')));
1009                 else {
1010                         cur.insert(createMathInset("#"));
1011                         interpret(cur, c); // try again
1012                 }
1013 #endif
1014                 return true;
1015         }
1016
1017         // handle macroMode
1018         if (cur.inMacroMode()) {
1019                 string name = cur.macroName();
1020                 //lyxerr << "interpret name: '" << name << "'" << endl;
1021
1022                 if (isalpha(c)) {
1023                         cur.activeMacro()->setName(cur.activeMacro()->name() + c);
1024                         return true;
1025                 }
1026
1027                 // handle 'special char' macros
1028                 if (name == "\\") {
1029                         // remove the '\\'
1030                         cur.backspace();
1031                         if (c == '\\') {
1032                                 if (currentMode() == MathInset::TEXT_MODE)
1033                                         cur.niceInsert(createMathInset("textbackslash"));
1034                                 else
1035                                         cur.niceInsert(createMathInset("backslash"));
1036                         } else if (c == '{') {
1037                                 cur.niceInsert(MathAtom(new MathBraceInset));
1038                         } else {
1039                                 cur.niceInsert(createMathInset(string(1, c)));
1040                         }
1041                         return true;
1042                 }
1043
1044                 // leave macro mode and try again if necessary
1045                 cur.macroModeClose();
1046                 if (c == '{')
1047                         cur.niceInsert(MathAtom(new MathBraceInset));
1048                 else if (c != ' ')
1049                         interpret(cur, c);
1050                 return true;
1051         }
1052
1053         // This is annoying as one has to press <space> far too often.
1054         // Disable it.
1055
1056 #if 0
1057                 // leave autocorrect mode if necessary
1058                 if (autocorrect() && c == ' ') {
1059                         autocorrect() = false;
1060                         return true;
1061                 }
1062 #endif
1063
1064         // just clear selection on pressing the space bar
1065         if (cur.selection() && c == ' ') {
1066                 cur.selection() = false;
1067                 return true;
1068         }
1069
1070         cur.selClearOrDel();
1071
1072         if (c == '\\') {
1073                 //lyxerr << "starting with macro" << endl;
1074                 cur.insert(MathAtom(new MathUnknownInset("\\", false)));
1075                 return true;
1076         }
1077
1078         if (c == '\n') {
1079                 if (currentMode() == MathInset::TEXT_MODE)
1080                         cur.insert(c);
1081                 return true;
1082         }
1083
1084         if (c == ' ') {
1085                 if (currentMode() == MathInset::TEXT_MODE) {
1086                         // insert spaces in text mode,
1087                         // but suppress direct insertion of two spaces in a row
1088                         // the still allows typing  '<space>a<space>' and deleting the 'a', but
1089                         // it is better than nothing...
1090                         if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ')
1091                                 cur.insert(c);
1092                         return true;
1093                 }
1094                 if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) {
1095                         cur.prevAtom().nucleus()->asSpaceInset()->incSpace();
1096                         return true;
1097                 }
1098                 if (cur.popRight())
1099                         return true;
1100                 // if are at the very end, leave the formula
1101                 return cur.pos() != cur.lastpos();
1102         }
1103
1104         if (c == '_') {
1105                 script(cur, false);
1106                 return true;
1107         }
1108
1109         if (c == '^') {
1110                 script(cur, true);
1111                 return true;
1112         }
1113
1114         if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
1115                 cur.niceInsert(createMathInset(string(1, c)));
1116                 return true;
1117         }
1118
1119         if (c == '%') {
1120                 cur.niceInsert(MathAtom(new MathCommentInset));
1121                 return true;
1122         }
1123
1124         // try auto-correction
1125         //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
1126         //      return true;
1127
1128         // no special circumstances, so insert the character without any fuss
1129         cur.insert(c);
1130         cur.autocorrect() = true;
1131         return true;
1132 }
1133
1134
1135 bool MathNestInset::script(LCursor & cur, bool up)
1136 {
1137         // Hack to get \\^ and \\_ working
1138         lyxerr << "handling script: up: " << up << endl;
1139         if (cur.inMacroMode() && cur.macroName() == "\\") {
1140                 if (up)
1141                         cur.niceInsert(createMathInset("mathcircumflex"));
1142                 else
1143                         interpret(cur, '_');
1144                 return true;
1145         }
1146
1147         cur.macroModeClose();
1148         string safe = cur.grabAndEraseSelection();
1149         if (asScriptInset() && cur.idx() == 2) {
1150                 // we are in a nucleus of a script inset, move to _our_ script
1151                 asScriptInset()->ensure(up);
1152                 cur.idx() = up;
1153                 cur.pos() = 0;
1154         } else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) {
1155                 --cur.pos();
1156                 cur.nextAtom().nucleus()->asScriptInset()->ensure(up);
1157                 cur.push(*cur.nextInset());
1158                 cur.idx() = up;
1159                 cur.pos() = cur.lastpos();
1160         } else if (cur.pos() != 0) {
1161                 --cur.pos();
1162                 cur.cell()[cur.pos()] = MathAtom(new MathScriptInset(cur.nextAtom(), up));
1163                 cur.push(*cur.nextInset());
1164                 cur.idx() = up;
1165                 cur.pos() = 0;
1166         } else {
1167                 cur.plainInsert(MathAtom(new MathScriptInset(up)));
1168                 --cur.pos();
1169                 cur.nextAtom().nucleus()->asScriptInset()->ensure(up);
1170                 cur.push(*cur.nextInset());
1171                 cur.idx() = up;
1172                 cur.pos() = 0;
1173         }
1174         cur.paste(safe);
1175         return true;
1176 }