]> git.lyx.org Git - lyx.git/blob - src/mathed/math_nestinset.C
revert Buffer LyxText->InsetText commit
[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 "bufferview_funcs.h"
32 #include "cursor.h"
33 #include "debug.h"
34 #include "dispatchresult.h"
35 #include "funcrequest.h"
36 #include "gettext.h"
37 #include "LColor.h"
38 #include "undo.h"
39
40 #include "support/std_sstream.h"
41 #include "support/lstrings.h"
42
43 #include "frontends/Dialogs.h"
44 #include "frontends/LyXView.h"
45 #include "frontends/Painter.h"
46
47
48 using std::endl;
49 using std::string;
50 using std::istringstream;
51
52
53 namespace {
54
55 // local global
56 int first_x;
57 int first_y;
58
59 } // namespace anon
60
61
62
63
64 MathNestInset::MathNestInset(idx_type nargs)
65         : cells_(nargs), lock_(false)
66 {}
67
68
69 MathInset::idx_type MathNestInset::nargs() const
70 {
71         return cells_.size();
72 }
73
74
75 MathArray & MathNestInset::cell(idx_type i)
76 {
77         return cells_[i];
78 }
79
80
81 MathArray const & MathNestInset::cell(idx_type i) const
82 {
83         return cells_[i];
84 }
85
86
87 void MathNestInset::getCursorPos(CursorSlice const & cur,
88         int & x, int & y) const
89 {
90         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
91         MathArray const & ar = cur.cell();
92         x = ar.xo() + ar.pos2x(cur.pos());
93         y = ar.yo();
94         // move cursor visually into empty cells ("blue rectangles");
95         if (cur.cell().empty())
96                 x += 2;
97 }
98
99
100 void MathNestInset::substitute(MathMacro const & m)
101 {
102         for (idx_type i = 0; i < nargs(); ++i)
103                 cell(i).substitute(m);
104 }
105
106
107 void MathNestInset::metrics(MetricsInfo const & mi) const
108 {
109         MetricsInfo m = mi;
110         for (idx_type i = 0; i < nargs(); ++i)
111                 cell(i).metrics(m);
112 }
113
114
115 bool MathNestInset::idxNext(LCursor & cur) const
116 {
117         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
118         if (cur.idx() == cur.lastidx())
119                 return false;
120         ++cur.idx();
121         cur.pos() = 0;
122         return true;
123 }
124
125
126 bool MathNestInset::idxRight(LCursor & cur) const
127 {
128         return idxNext(cur);
129 }
130
131
132 bool MathNestInset::idxPrev(LCursor & cur) const
133 {
134         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
135         if (cur.idx() == 0)
136                 return false;
137         --cur.idx();
138         cur.pos() = cur.lastpos();
139         return true;
140 }
141
142
143 bool MathNestInset::idxLeft(LCursor & cur) const
144 {
145         return idxPrev(cur);
146 }
147
148
149 bool MathNestInset::idxFirst(LCursor & cur) const
150 {
151         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
152         if (nargs() == 0)
153                 return false;
154         cur.idx() = 0;
155         cur.pos() = 0;
156         return true;
157 }
158
159
160 bool MathNestInset::idxLast(LCursor & cur) const
161 {
162         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
163         if (nargs() == 0)
164                 return false;
165         cur.idx() = cur.lastidx();
166         cur.pos() = cur.lastpos();
167         return true;
168 }
169
170
171 void MathNestInset::dump() const
172 {
173         WriteStream os(lyxerr);
174         os << "---------------------------------------------\n";
175         write(os);
176         os << "\n";
177         for (idx_type i = 0; i < nargs(); ++i)
178                 os << cell(i) << "\n";
179         os << "---------------------------------------------\n";
180 }
181
182
183 //void MathNestInset::draw(PainterInfo & pi, int x, int y) const
184 void MathNestInset::draw(PainterInfo &, int, int) const
185 {
186 #if 0
187         if (lock_)
188                 pi.pain.fillRectangle(x, y - ascent(), width(), height(),
189                                         LColor::mathlockbg);
190 #endif
191 }
192
193
194 void MathNestInset::drawSelection(PainterInfo & pi, int, int) const
195 {
196         // this should use the x/y values given, not the cached values
197         LCursor & cur = pi.base.bv->cursor();
198         if (!cur.selection())
199                 return;
200         if (!ptr_cmp(cur.inset(), this))
201                 return;
202         CursorSlice & s1 = cur.selBegin();
203         CursorSlice & s2 = cur.selEnd();
204         if (s1.idx() == s2.idx()) {
205                 MathArray const & c = cell(s1.idx());
206                 int x1 = c.xo() + c.pos2x(s1.pos());
207                 int y1 = c.yo() - c.ascent();
208                 int x2 = c.xo() + c.pos2x(s2.pos());
209                 int y2 = c.yo() + c.descent();
210                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
211         } else {
212                 for (idx_type i = 0; i < nargs(); ++i) {
213                         if (idxBetween(i, s1.idx(), s2.idx())) {
214                                 MathArray const & c = cell(i);
215                                 int x1 = c.xo();
216                                 int y1 = c.yo() - c.ascent();
217                                 int x2 = c.xo() + c.width();
218                                 int y2 = c.yo() + c.descent();
219                                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
220                         }
221                 }
222         }
223 }
224
225
226 void MathNestInset::validate(LaTeXFeatures & features) const
227 {
228         for (idx_type i = 0; i < nargs(); ++i)
229                 cell(i).validate(features);
230 }
231
232
233 void MathNestInset::replace(ReplaceData & rep)
234 {
235         for (idx_type i = 0; i < nargs(); ++i)
236                 cell(i).replace(rep);
237 }
238
239
240 bool MathNestInset::contains(MathArray const & ar) const
241 {
242         for (idx_type i = 0; i < nargs(); ++i)
243                 if (cell(i).contains(ar))
244                         return true;
245         return false;
246 }
247
248
249 bool MathNestInset::lock() const
250 {
251         return lock_;
252 }
253
254
255 void MathNestInset::lock(bool l)
256 {
257         lock_ = l;
258 }
259
260
261 bool MathNestInset::isActive() const
262 {
263         return nargs() > 0;
264 }
265
266
267 MathArray MathNestInset::glue() const
268 {
269         MathArray ar;
270         for (size_t i = 0; i < nargs(); ++i)
271                 ar.append(cell(i));
272         return ar;
273 }
274
275
276 void MathNestInset::write(WriteStream & os) const
277 {
278         os << '\\' << name().c_str();
279         for (size_t i = 0; i < nargs(); ++i)
280                 os << '{' << cell(i) << '}';
281         if (nargs() == 0)
282                 os.pendingSpace(true);
283         if (lock_ && !os.latex()) {
284                 os << "\\lyxlock";
285                 os.pendingSpace(true);
286         }
287 }
288
289
290 void MathNestInset::normalize(NormalStream & os) const
291 {
292         os << '[' << name().c_str();
293         for (size_t i = 0; i < nargs(); ++i)
294                 os << ' ' << cell(i);
295         os << ']';
296 }
297
298
299 void MathNestInset::notifyCursorLeaves(idx_type idx)
300 {
301         cell(idx).notifyCursorLeaves();
302 }
303
304
305 void MathNestInset::handleFont
306         (LCursor & cur, string const & arg, string const & font)
307 {
308         // this whole function is a hack and won't work for incremental font
309         // changes...
310         recordUndo(cur, Undo::ATOMIC);
311
312         if (cur.inset()->asMathInset()->name() == font)
313                 cur.handleFont(font);
314         else {
315                 cur.handleNest(createMathInset(font));
316                 cur.insert(arg);
317         }
318 }
319
320
321 void MathNestInset::handleFont2(LCursor & cur, string const & arg)
322 {
323         recordUndo(cur, Undo::ATOMIC);
324         LyXFont font;
325         bool b;
326         bv_funcs::string2font(arg, font, b);
327         if (font.color() != LColor::inherit) {
328                 MathAtom at = createMathInset("color");
329                 asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
330                 cur.handleNest(at, 1);
331         }
332 }
333
334
335 void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
336 {
337         lyxerr << "MathNestInset: request: " << cmd << std::endl;
338         //CursorSlice sl = cur.current();
339
340         switch (cmd.action) {
341
342         case LFUN_PASTE:
343                 if (!cmd.argument.empty()) {
344                         MathArray ar;
345                         mathed_parse_cell(ar, cmd.argument);
346                         cur.cell().insert(cur.pos(), ar);
347                         cur.pos() += ar.size();
348                 }
349                 break;
350 /*
351         case LFUN_PASTE: {
352                 size_t n = 0;
353                 istringstream is(cmd.argument.c_str());
354                 is >> n;
355                 if (was_macro)
356                         cur.macroModeClose();
357                 recordUndo(cur, Undo::ATOMIC);
358                 cur.selPaste(n);
359                 break;
360         }
361 */
362
363         case LFUN_PASTESELECTION:
364                 dispatch(cur, FuncRequest(LFUN_PASTE, cur.bv().getClipboard()));
365                 break;
366
367         case LFUN_MOUSE_PRESS:
368                 lfunMousePress(cur, cmd);
369                 break;
370
371         case LFUN_MOUSE_MOTION:
372                 lfunMouseMotion(cur, cmd);
373                 break;
374
375         case LFUN_MOUSE_RELEASE:
376                 lfunMouseRelease(cur, cmd);
377                 break;
378
379         case LFUN_MOUSE_DOUBLE:
380         case LFUN_MOUSE_TRIPLE:
381                 //lyxerr << "Mouse double" << endl;
382                 //lyxerr << "Mouse triple" << endl;
383                 dispatch(cur, FuncRequest(LFUN_WORDSEL));
384                 break;
385
386         case LFUN_FINISHED_LEFT:
387                 cur.bv().cursor() = cur;
388                 break;
389
390         case LFUN_FINISHED_RIGHT:
391                 ++cur.pos();
392                 cur.bv().cursor() = cur;
393                 break;
394
395         case LFUN_FINISHED_UP:
396                 //idxUpDown(cur, true);
397                 cur.bv().cursor() = cur;
398                 break;
399
400         case LFUN_FINISHED_DOWN:
401                 //idxUpDown(cur, false);
402                 cur.bv().cursor() = cur;
403                 break;
404
405         case LFUN_RIGHTSEL:
406         case LFUN_RIGHT:
407                 lyxerr << "mathnest RIGHT: from:\n" << cur << endl;
408                 cur.selHandle(cmd.action == LFUN_RIGHTSEL);
409                 cur.autocorrect() = false;
410                 cur.clearTargetX();
411                 if (cur.inMacroMode())
412                         cur.macroModeClose();
413                 else if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) {
414                         cur.pushLeft(cur.nextAtom().nucleus());
415                         cur.inset()->idxFirst(cur);
416                 } else if (cur.posRight() || idxRight(cur)
417                         || cur.popRight() || cur.selection())
418                         ;
419                 else
420                         cur.dispatched(FINISHED_RIGHT);
421                 lyxerr << "mathnest RIGHT: to:\n" << cur << endl;
422                 break;
423
424         case LFUN_LEFTSEL:
425         case LFUN_LEFT:
426                 cur.selHandle(cmd.action == LFUN_LEFTSEL);
427                 cur.autocorrect() = false;
428                 cur.clearTargetX();
429                 if (cur.inMacroMode())
430                         cur.macroModeClose();
431                 else if (cur.pos() != 0 && cur.openable(cur.prevAtom())) {
432                         cur.posLeft();
433                         cur.push(cur.nextAtom().nucleus());
434                         cur.inset()->idxLast(cur);
435                 } else if (cur.posLeft() || idxLeft(cur)
436                         || cur.popLeft() || cur.selection())
437                         ;
438                 else
439                         cur.dispatched(FINISHED_LEFT);
440                 break;
441
442         case LFUN_UPSEL:
443         case LFUN_UP:
444                 cur.selHandle(cmd.action == LFUN_UPSEL);
445                 if (!cur.up())
446                         cur.dispatched(FINISHED_UP);
447                 break;
448
449         case LFUN_DOWNSEL:
450         case LFUN_DOWN:
451                 cur.selHandle(cmd.action == LFUN_DOWNSEL);
452                 if (!cur.down())
453                         cur.dispatched(FINISHED_DOWN);
454                 break;
455
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                         cur.dispatched(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                         cur.dispatched(FINISHED_RIGHT);
507                 }
508                 break;
509
510         case LFUN_PRIORSEL:
511         case LFUN_PRIOR:
512         case LFUN_BEGINNINGBUFSEL:
513         case LFUN_BEGINNINGBUF:
514                 cur.dispatched(FINISHED_LEFT);
515                 break;
516
517         case LFUN_NEXTSEL:
518         case LFUN_NEXT:
519         case LFUN_ENDBUFSEL:
520         case LFUN_ENDBUF:
521                 cur.dispatched(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                 cur.dispatched(FINISHED_LEFT);
543                 break;
544
545         case LFUN_ESCAPE:
546                 if (cur.selection()) 
547                         cur.selClear();
548                 else 
549                         cur.dispatched(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                         cur.dispatched(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                         cur.dispatched(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                         base->dispatch(cur, FuncRequest(LFUN_INSET_MODIFY, cmd.argument));
780                         break;
781                 }
782                 MathArray ar;
783                 if (createMathInset_fromDialogStr(cmd.argument, ar)) {
784                         cur.insert(ar);
785                         break;
786                 }
787                 cur.undispatched();
788                 break;
789         }
790
791 #warning look here
792 #if 0
793
794         case LFUN_WORD_REPLACE:
795         case LFUN_WORD_FIND:
796                 if (!searchForward(&cur.bv(), cmd.getArg(0), false, false))
797                         cur.undispatched();
798                 break;
799
800         cur.normalize();
801         cur.touch();
802
803         BOOST_ASSERT(cur.inMathed());
804
805         if (result.dispatched()) {
806                 revealCodes(cur);
807                 cur.bv().stuffClipboard(cur.grabSelection());
808         } else {
809                 if (remove_inset)
810                         cur.bv().owner()->dispatch(FuncRequest(LFUN_DELETE));
811         }
812         break;
813 #endif
814
815         default:
816                 MathDimInset::priv_dispatch(cur, cmd);
817                 break;
818         }
819 }
820
821
822 void MathNestInset::edit(LCursor & cur, bool left)
823 {
824         cur.push(this);
825         cur.idx() = left ? 0 : cur.lastidx();
826         cur.pos() = left ? 0 : cur.lastpos();
827         cur.resetAnchor();
828 }
829
830
831 InsetBase * MathNestInset::editXY(LCursor & cur, int x, int y)
832 {
833         int idx_min = 0;
834         int dist_min = 1000000;
835         for (idx_type i = 0; i < nargs(); ++i) {
836                 int d = cell(i).dist(x, y);
837                 if (d < dist_min) {
838                         dist_min = d;
839                         idx_min = i;
840                 }
841         }
842         MathArray & ar = cell(idx_min);
843         cur.push(this);
844         cur.idx() = idx_min;
845         cur.pos() = ar.x2pos(x - ar.xo());
846         lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl;
847         if (dist_min == 0) {
848                 // hit inside cell
849                 for (pos_type i = 0, n = ar.size(); i < n; ++i)
850                         if (ar[i]->covers(x, y))
851                                 return ar[i].nucleus()->editXY(cur, x, y);
852         }
853         return this;
854 }
855
856
857 void MathNestInset::lfunMouseRelease(LCursor & cur, FuncRequest const & cmd)
858 {
859         //lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl;
860
861         if (cmd.button() == mouse_button::button1) {
862                 // try to dispatch to enclosed insets first
863                 //cur.bv().stuffClipboard(cur.grabSelection());
864                 return;
865         }
866
867         if (cmd.button() == mouse_button::button2) {
868                 MathArray ar;
869                 asArray(cur.bv().getClipboard(), ar);
870                 cur.selClear();
871                 cur.setScreenPos(cmd.x, cmd.y);
872                 cur.insert(ar);
873                 cur.bv().update();
874                 return;
875         }
876
877         if (cmd.button() == mouse_button::button3) {
878                 // try to dispatch to enclosed insets first
879                 cur.bv().owner()->getDialogs().show("mathpanel");
880                 return;
881         }
882
883         cur.undispatched();
884 }
885
886
887 void MathNestInset::lfunMousePress(LCursor & cur, FuncRequest const & cmd)
888 {
889         lyxerr << "lfunMousePress: buttons: " << cmd.button() << endl;
890         if (cmd.button() == mouse_button::button1) {
891                 first_x = cmd.x;
892                 first_y = cmd.y;
893                 cur.selClear();
894                 //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
895                 lyxerr << "lfunMousePress: setting cursor to: " << cur << endl;
896                 cur.bv().cursor() = cur;
897         }
898
899         if (cmd.button() == mouse_button::button2) {
900                 priv_dispatch(cur, FuncRequest(LFUN_PASTESELECTION));
901         }
902 }
903
904
905 void MathNestInset::lfunMouseMotion(LCursor & cur, FuncRequest const & cmd)
906 {
907         // only select with button 1
908         if (cmd.button() != mouse_button::button1)
909                 return;
910
911         if (abs(cmd.x - first_x) < 2 && abs(cmd.y - first_y) < 2)
912                 return;
913
914         first_x = cmd.x;
915         first_y = cmd.y;
916
917         if (!cur.selection())
918                 cur.selBegin();
919
920         //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
921         cur.bv().cursor().setCursor(cur, true);
922 }
923
924
925 bool MathNestInset::interpret(LCursor & cur, char c)
926 {
927         //lyxerr << "interpret 2: '" << c << "'" << endl;
928         cur.clearTargetX();
929         if (cur.inMacroArgMode()) {
930                 cur.posLeft();
931                 cur.plainErase();
932 #warning FIXME
933 #if 0
934                 int n = c - '0';
935                 MathMacroTemplate const * p = formula()->asMacroTemplate();
936                 if (p && 1 <= n && n <= p->numargs())
937                         cur.insert(MathAtom(new MathMacroArgument(c - '0')));
938                 else {
939                         cur.insert(createMathInset("#"));
940                         interpret(cur, c); // try again
941                 }
942 #endif
943                 return true;
944         }
945
946         // handle macroMode
947         if (cur.inMacroMode()) {
948                 string name = cur.macroName();
949                 //lyxerr << "interpret name: '" << name << "'" << endl;
950
951                 if (isalpha(c)) {
952                         cur.activeMacro()->setName(cur.activeMacro()->name() + c);
953                         return true;
954                 }
955
956                 // handle 'special char' macros
957                 if (name == "\\") {
958                         // remove the '\\'
959                         cur.backspace();
960                         if (c == '\\') {
961                                 if (currentMode() == MathInset::TEXT_MODE)
962                                         cur.niceInsert(createMathInset("textbackslash"));
963                                 else
964                                         cur.niceInsert(createMathInset("backslash"));
965                         } else if (c == '{') {
966                                 cur.niceInsert(MathAtom(new MathBraceInset));
967                         } else {
968                                 cur.niceInsert(createMathInset(string(1, c)));
969                         }
970                         return true;
971                 }
972
973                 // leave macro mode and try again if necessary
974                 cur.macroModeClose();
975                 if (c == '{')
976                         cur.niceInsert(MathAtom(new MathBraceInset));
977                 else if (c != ' ')
978                         interpret(cur, c);
979                 return true;
980         }
981
982         // This is annoying as one has to press <space> far too often.
983         // Disable it.
984
985 #if 0
986                 // leave autocorrect mode if necessary
987                 if (autocorrect() && c == ' ') {
988                         autocorrect() = false;
989                         return true;
990                 }
991 #endif
992
993         // just clear selection on pressing the space bar
994         if (cur.selection() && c == ' ') {
995                 cur.selection() = false;
996                 return true;
997         }
998
999         cur.selClearOrDel();
1000
1001         if (c == '\\') {
1002                 //lyxerr << "starting with macro" << endl;
1003                 cur.insert(MathAtom(new MathUnknownInset("\\", false)));
1004                 return true;
1005         }
1006
1007         if (c == '\n') {
1008                 if (currentMode() == MathInset::TEXT_MODE)
1009                         cur.insert(c);
1010                 return true;
1011         }
1012
1013         if (c == ' ') {
1014                 if (currentMode() == MathInset::TEXT_MODE) {
1015                         // insert spaces in text mode,
1016                         // but suppress direct insertion of two spaces in a row
1017                         // the still allows typing  '<space>a<space>' and deleting the 'a', but
1018                         // it is better than nothing...
1019                         if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ')
1020                                 cur.insert(c);
1021                         return true;
1022                 }
1023                 if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) {
1024                         cur.prevAtom().nucleus()->asSpaceInset()->incSpace();
1025                         return true;
1026                 }
1027                 if (cur.popRight())
1028                         return true;
1029                 // if are at the very end, leave the formula
1030                 return cur.pos() != cur.lastpos();
1031         }
1032
1033         if (c == '_') {
1034                 script(cur, false);
1035                 return true;
1036         }
1037
1038         if (c == '^') {
1039                 script(cur, true);
1040                 return true;
1041         }
1042
1043         if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
1044                 cur.niceInsert(createMathInset(string(1, c)));
1045                 return true;
1046         }
1047
1048         if (c == '%') {
1049                 cur.niceInsert(MathAtom(new MathCommentInset));
1050                 return true;
1051         }
1052
1053         // try auto-correction
1054         //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
1055         //      return true;
1056
1057         // no special circumstances, so insert the character without any fuss
1058         cur.insert(c);
1059         cur.autocorrect() = true;
1060         return true;
1061 }
1062
1063
1064 bool MathNestInset::script(LCursor & cur, bool up)
1065 {
1066         // Hack to get \\^ and \\_ working
1067         lyxerr << "handling script: up: " << up << endl;
1068         if (cur.inMacroMode() && cur.macroName() == "\\") {
1069                 if (up)
1070                         cur.niceInsert(createMathInset("mathcircumflex"));
1071                 else
1072                         interpret(cur, '_');
1073                 return true;
1074         }
1075
1076         cur.macroModeClose();
1077         string safe = cur.grabAndEraseSelection();
1078         if (asScriptInset() && cur.idx() == 2) {
1079                 // we are in a nucleus of a script inset, move to _our_ script
1080                 asScriptInset()->ensure(up);
1081                 cur.idx() = up;
1082                 cur.pos() = 0;
1083         } else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) {
1084                 --cur.pos();
1085                 cur.nextAtom().nucleus()->asScriptInset()->ensure(up);
1086                 cur.push(cur.nextInset());
1087                 cur.idx() = up;
1088                 cur.pos() = cur.lastpos();
1089         } else if (cur.pos() != 0) {
1090                 --cur.pos();
1091                 cur.cell()[cur.pos()] = MathAtom(new MathScriptInset(cur.nextAtom(), up));
1092                 cur.push(cur.nextInset());
1093                 cur.idx() = up;
1094                 cur.pos() = 0;
1095         } else {
1096                 cur.plainInsert(MathAtom(new MathScriptInset(up)));
1097                 --cur.pos();
1098                 cur.nextAtom().nucleus()->asScriptInset()->ensure(up);
1099                 cur.push(cur.nextInset());
1100                 cur.idx() = up;
1101                 cur.pos() = 0;
1102         }
1103         cur.paste(safe);
1104         return true;
1105 }