]> git.lyx.org Git - lyx.git/blob - src/mathed/math_nestinset.C
90a3f74b4dfc5fb790b22e8e66de53b9082f9e78
[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_data.h"
17 #include "math_deliminset.h"
18 #include "math_factory.h"
19 #include "math_hullinset.h"
20 #include "math_mathmlstream.h"
21 #include "math_parser.h"
22 #include "math_spaceinset.h"
23 #include "math_support.h"
24 #include "math_mboxinset.h"
25
26 #include "BufferView.h"
27 #include "bufferview_funcs.h"
28 #include "cursor.h"
29 #include "debug.h"
30 #include "dispatchresult.h"
31 #include "funcrequest.h"
32 #include "gettext.h"
33 #include "LColor.h"
34 #include "undo.h"
35
36 #include "support/std_sstream.h"
37 #include "support/lstrings.h"
38
39 #include "frontends/Dialogs.h"
40 #include "frontends/LyXView.h"
41 #include "frontends/Painter.h"
42
43
44 using std::endl;
45 using std::string;
46 using std::istringstream;
47
48
49 namespace {
50
51 // local global
52 int first_x;
53 int first_y;
54
55 } // namespace anon
56
57
58
59
60 MathNestInset::MathNestInset(idx_type nargs)
61         : cells_(nargs), lock_(false)
62 {}
63
64
65 MathInset::idx_type MathNestInset::nargs() const
66 {
67         return cells_.size();
68 }
69
70
71 MathArray & MathNestInset::cell(idx_type i)
72 {
73         return cells_[i];
74 }
75
76
77 MathArray const & MathNestInset::cell(idx_type i) const
78 {
79         return cells_[i];
80 }
81
82
83 void MathNestInset::getCursorPos(CursorSlice const & cur,
84         int & x, int & y) const
85 {
86         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
87         MathArray const & ar = cur.cell();
88         x = ar.xo() + ar.pos2x(cur.pos());
89         y = ar.yo();
90         // move cursor visually into empty cells ("blue rectangles");
91         if (cur.cell().empty())
92                 x += 2;
93 }
94
95
96 void MathNestInset::substitute(MathMacro const & m)
97 {
98         for (idx_type i = 0; i < nargs(); ++i)
99                 cell(i).substitute(m);
100 }
101
102
103 void MathNestInset::metrics(MetricsInfo const & mi) const
104 {
105         MetricsInfo m = mi;
106         for (idx_type i = 0; i < nargs(); ++i)
107                 cell(i).metrics(m);
108 }
109
110
111 bool MathNestInset::idxNext(LCursor & cur) const
112 {
113         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
114         if (cur.idx() == cur.lastidx())
115                 return false;
116         ++cur.idx();
117         cur.pos() = 0;
118         return true;
119 }
120
121
122 bool MathNestInset::idxRight(LCursor & cur) const
123 {
124         return idxNext(cur);
125 }
126
127
128 bool MathNestInset::idxPrev(LCursor & cur) const
129 {
130         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
131         if (cur.idx() == 0)
132                 return false;
133         --cur.idx();
134         cur.pos() = cur.lastpos();
135         return true;
136 }
137
138
139 bool MathNestInset::idxLeft(LCursor & cur) const
140 {
141         return idxPrev(cur);
142 }
143
144
145 bool MathNestInset::idxFirst(LCursor & cur) const
146 {
147         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
148         if (nargs() == 0)
149                 return false;
150         cur.idx() = 0;
151         cur.pos() = 0;
152         return true;
153 }
154
155
156 bool MathNestInset::idxLast(LCursor & cur) const
157 {
158         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
159         if (nargs() == 0)
160                 return false;
161         cur.idx() = cur.lastidx();
162         cur.pos() = cur.lastpos();
163         return true;
164 }
165
166
167 bool MathNestInset::idxHome(LCursor & cur) const
168 {
169         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
170         if (cur.pos() == 0)
171                 return false;
172         cur.pos() = 0;
173         return true;
174 }
175
176
177 bool MathNestInset::idxEnd(LCursor & cur) const
178 {
179         BOOST_ASSERT(ptr_cmp(cur.inset(), this));
180         if (cur.lastpos() == cur.lastpos())
181                 return false;
182         cur.pos() = cur.lastpos();
183         return true;
184 }
185
186
187 void MathNestInset::dump() const
188 {
189         WriteStream os(lyxerr);
190         os << "---------------------------------------------\n";
191         write(os);
192         os << "\n";
193         for (idx_type i = 0; i < nargs(); ++i)
194                 os << cell(i) << "\n";
195         os << "---------------------------------------------\n";
196 }
197
198
199 //void MathNestInset::draw(PainterInfo & pi, int x, int y) const
200 void MathNestInset::draw(PainterInfo &, int, int) const
201 {
202 #if 0
203         if (lock_)
204                 pi.pain.fillRectangle(x, y - ascent(), width(), height(),
205                                         LColor::mathlockbg);
206 #endif
207 }
208
209
210 void MathNestInset::drawSelection(PainterInfo & pi, int, int) const
211 {
212         // this should use the x/y values given, not the cached values
213         LCursor & cur = pi.base.bv->cursor();
214         if (!cur.selection())
215                 return;
216         if (!ptr_cmp(cur.inset(), this))
217                 return;
218         CursorSlice & s1 = cur.selBegin();
219         CursorSlice & s2 = cur.selEnd();
220         if (s1.idx() == s2.idx()) {
221                 MathArray const & c = cell(s1.idx());
222                 int x1 = c.xo() + c.pos2x(s1.pos());
223                 int y1 = c.yo() - c.ascent();
224                 int x2 = c.xo() + c.pos2x(s2.pos());
225                 int y2 = c.yo() + c.descent();
226                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
227         } else {
228                 for (idx_type i = 0; i < nargs(); ++i) {
229                         if (idxBetween(i, s1.idx(), s2.idx())) {
230                                 MathArray const & c = cell(i);
231                                 int x1 = c.xo();
232                                 int y1 = c.yo() - c.ascent();
233                                 int x2 = c.xo() + c.width();
234                                 int y2 = c.yo() + c.descent();
235                                 pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
236                         }
237                 }
238         }
239 }
240
241
242 void MathNestInset::validate(LaTeXFeatures & features) const
243 {
244         for (idx_type i = 0; i < nargs(); ++i)
245                 cell(i).validate(features);
246 }
247
248
249 void MathNestInset::replace(ReplaceData & rep)
250 {
251         for (idx_type i = 0; i < nargs(); ++i)
252                 cell(i).replace(rep);
253 }
254
255
256 bool MathNestInset::contains(MathArray const & ar) const
257 {
258         for (idx_type i = 0; i < nargs(); ++i)
259                 if (cell(i).contains(ar))
260                         return true;
261         return false;
262 }
263
264
265 bool MathNestInset::lock() const
266 {
267         return lock_;
268 }
269
270
271 void MathNestInset::lock(bool l)
272 {
273         lock_ = l;
274 }
275
276
277 bool MathNestInset::isActive() const
278 {
279         return nargs() > 0;
280 }
281
282
283 MathArray MathNestInset::glue() const
284 {
285         MathArray ar;
286         for (size_t i = 0; i < nargs(); ++i)
287                 ar.append(cell(i));
288         return ar;
289 }
290
291
292 void MathNestInset::write(WriteStream & os) const
293 {
294         os << '\\' << name().c_str();
295         for (size_t i = 0; i < nargs(); ++i)
296                 os << '{' << cell(i) << '}';
297         if (nargs() == 0)
298                 os.pendingSpace(true);
299         if (lock_ && !os.latex()) {
300                 os << "\\lyxlock";
301                 os.pendingSpace(true);
302         }
303 }
304
305
306 void MathNestInset::normalize(NormalStream & os) const
307 {
308         os << '[' << name().c_str();
309         for (size_t i = 0; i < nargs(); ++i)
310                 os << ' ' << cell(i);
311         os << ']';
312 }
313
314
315 void MathNestInset::notifyCursorLeaves(idx_type idx)
316 {
317         cell(idx).notifyCursorLeaves();
318 }
319
320
321 void MathNestInset::handleFont
322         (LCursor & cur, string const & arg, string const & font)
323 {
324         // this whole function is a hack and won't work for incremental font
325         // changes...
326         //recordUndo(cur, Undo::ATOMIC);
327
328         if (cur.inset()->asMathInset()->name() == font)
329                 cur.handleFont(font);
330         else {
331                 cur.handleNest(createMathInset(font));
332                 cur.insert(arg);
333         }
334 }
335
336
337 void MathNestInset::handleFont2(LCursor & cur, string const & arg)
338 {
339         //recordUndo(cur, Undo::ATOMIC);
340         LyXFont font;
341         bool b;
342         bv_funcs::string2font(arg, font, b);
343         if (font.color() != LColor::inherit) {
344                 MathAtom at = createMathInset("color");
345                 asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
346                 cur.handleNest(at, 1);
347         }
348 }
349
350
351 void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
352 {
353         lyxerr << "MathNestInset: request: " << cmd << std::endl;
354
355         switch (cmd.action) {
356
357         case LFUN_PASTE:
358                 if (!cmd.argument.empty()) {
359                         MathArray ar;
360                         mathed_parse_cell(ar, cmd.argument);
361                         cur.cell().insert(cur.pos(), ar);
362                         cur.pos() += ar.size();
363                 }
364                 break;
365 /*
366         case LFUN_PASTE: {
367                 size_t n = 0;
368                 istringstream is(cmd.argument.c_str());
369                 is >> n;
370                 if (was_macro)
371                         cur.macroModeClose();
372                 //recordUndo(cur, Undo::ATOMIC);
373                 cur.selPaste(n);
374                 break;
375         }
376 */
377
378         case LFUN_PASTESELECTION:
379                 dispatch(cur, FuncRequest(LFUN_PASTE, cur.bv().getClipboard()));
380                 break;
381
382         case LFUN_MOUSE_PRESS:
383                 lfunMousePress(cur, cmd);
384                 break;
385
386         case LFUN_MOUSE_MOTION:
387                 lfunMouseMotion(cur, cmd);
388                 break;
389
390         case LFUN_MOUSE_RELEASE:
391                 lfunMouseRelease(cur, cmd);
392                 break;
393
394         case LFUN_MOUSE_DOUBLE:
395         case LFUN_MOUSE_TRIPLE:
396                 //lyxerr << "Mouse double" << endl;
397                 //lyxerr << "Mouse triple" << endl;
398                 dispatch(cur, FuncRequest(LFUN_WORDSEL));
399                 break;
400
401         case LFUN_FINISHED_LEFT:
402                 cur.pop(cur.currentDepth());
403                 cur.bv().cursor() = cur;
404                 break;
405
406         case LFUN_FINISHED_RIGHT:
407                 cur.pop(cur.currentDepth());
408                 ++cur.pos();
409                 cur.bv().cursor() = cur;
410                 break;
411
412         case LFUN_FINISHED_UP:
413                 cur.pop(cur.currentDepth());
414                 //idxUpDown(cur, true);
415                 cur.bv().cursor() = cur;
416                 break;
417
418         case LFUN_FINISHED_DOWN:
419                 cur.pop(cur.currentDepth());
420                 //idxUpDown(cur, false);
421                 cur.bv().cursor() = cur;
422                 break;
423
424         case LFUN_RIGHTSEL:
425         case LFUN_RIGHT:
426                 cur.selHandle(cmd.action == LFUN_RIGHTSEL);
427                 if (!cur.right()) 
428                         cur.dispatched(FINISHED_RIGHT);
429                 break;
430
431         case LFUN_LEFTSEL:
432         case LFUN_LEFT:
433                 cur.selHandle(cmd.action == LFUN_LEFTSEL);
434                 if (!cur.left())
435                         cur.dispatched(FINISHED);
436                 break;
437
438         case LFUN_UPSEL:
439         case LFUN_UP:
440                 cur.selHandle(cmd.action == LFUN_UPSEL);
441                 if (!cur.up())
442                         cur.dispatched(FINISHED_UP);
443                 break;
444
445         case LFUN_DOWNSEL:
446         case LFUN_DOWN:
447                 cur.selHandle(cmd.action == LFUN_DOWNSEL);
448                 if (!cur.down())
449                         cur.dispatched(FINISHED_DOWN);
450                 break;
451
452         case LFUN_WORDSEL:
453                 cur.home();
454                 cur.resetAnchor();
455                 cur.selection() = true;
456                 cur.end();
457                 break;
458
459         case LFUN_UP_PARAGRAPHSEL:
460         case LFUN_UP_PARAGRAPH:
461         case LFUN_DOWN_PARAGRAPHSEL:
462         case LFUN_DOWN_PARAGRAPH:
463                 break;
464
465         case LFUN_WORDLEFTSEL:
466         case LFUN_WORDLEFT:
467                 cur.selHandle(cmd.action == LFUN_WORDLEFTSEL);
468                 if (!cur.home())
469                         cur.dispatched(FINISHED);
470                 break;
471
472         case LFUN_WORDRIGHTSEL:
473         case LFUN_WORDRIGHT:
474                 cur.selHandle(cmd.action == LFUN_WORDRIGHTSEL);
475                 if (!cur.end())
476                         cur.dispatched(FINISHED_RIGHT);
477                 break;
478
479         case LFUN_HOMESEL:
480         case LFUN_HOME:
481                 cur.selHandle(cmd.action == LFUN_HOMESEL);
482                 if (!cur.home())
483                         cur.dispatched(FINISHED_RIGHT);
484                 break;
485
486         case LFUN_ENDSEL:
487         case LFUN_END:
488                 cur.selHandle(cmd.action == LFUN_ENDSEL);
489                 if (!cur.end())
490                         cur.dispatched(FINISHED_RIGHT);
491                 break;
492
493         case LFUN_PRIORSEL:
494         case LFUN_PRIOR:
495         case LFUN_BEGINNINGBUFSEL:
496         case LFUN_BEGINNINGBUF:
497                 cur.dispatched(FINISHED);
498                 break;
499
500         case LFUN_NEXTSEL:
501         case LFUN_NEXT:
502         case LFUN_ENDBUFSEL:
503         case LFUN_ENDBUF:
504                 cur.dispatched(FINISHED_RIGHT);
505                 break;
506
507         case LFUN_CELL_FORWARD:
508                 cur.inset()->idxNext(cur);
509                 break;
510
511         case LFUN_CELL_BACKWARD:
512                 cur.inset()->idxPrev(cur);
513                 break;
514
515         case LFUN_DELETE_WORD_BACKWARD:
516         case LFUN_BACKSPACE:
517                 //recordUndo(cur, Undo::ATOMIC);
518                 cur.backspace();
519                 break;
520
521         case LFUN_DELETE_WORD_FORWARD:
522         case LFUN_DELETE:
523                 //recordUndo(cur, Undo::ATOMIC);
524                 cur.erase();
525                 cur.dispatched(FINISHED);
526                 break;
527
528         case LFUN_ESCAPE:
529                 if (cur.selection()) 
530                         cur.selClear();
531                 else 
532                         cur.dispatched(FINISHED);
533                 break;
534
535         case LFUN_INSET_TOGGLE:
536                 cur.lockToggle();
537                 break;
538
539         case LFUN_SELFINSERT:
540                 if (cmd.argument.empty()) {
541                         cur.dispatched(FINISHED_RIGHT);
542                         break;
543                 }
544                 //recordUndo(cur, Undo::ATOMIC);
545                 if (cmd.argument.size() != 1) {
546                         cur.insert(cmd.argument);
547                         break;
548                 }
549                 if (!cur.interpret(cmd.argument[0]))
550                         cur.dispatched(FINISHED_RIGHT);
551                 break;
552
553 #if 0
554 //
555 // this needs to be incorporated
556 //
557         // delete empty mathbox (LFUN_BACKSPACE and LFUN_DELETE)
558         bool remove_inset = false;
559
560         DispatchResult result(true);
561         bool was_macro     = cur.inMacroMode();
562
563         cur.normalize();
564         cur.touch();
565 #endif
566
567         //    case LFUN_GETXY:
568         //      sprintf(dispatch_buffer, "%d %d",);
569         //      DispatchResult= dispatch_buffer;
570         //      break;
571         case LFUN_SETXY: {
572                 lyxerr << "LFUN_SETXY broken!" << endl;
573                 int x = 0;
574                 int y = 0;
575                 istringstream is(cmd.argument.c_str());
576                 is >> x >> y;
577                 cur.setScreenPos(x, y);
578                 break;
579         }
580
581         case LFUN_CUT:
582                 //recordUndo(cur, Undo::DELETE);
583                 cur.selCut();
584                 break;
585
586         case LFUN_COPY:
587                 cur.selCopy();
588                 break;
589
590         // Special casing for superscript in case of LyX handling
591         // dead-keys:
592         case LFUN_CIRCUMFLEX:
593                 if (cmd.argument.empty()) {
594                         // do superscript if LyX handles
595                         // deadkeys
596                         //recordUndo(cur, Undo::ATOMIC);
597                         cur.script(true);
598                 }
599                 break;
600
601         case LFUN_UMLAUT:
602         case LFUN_ACUTE:
603         case LFUN_GRAVE:
604         case LFUN_BREVE:
605         case LFUN_DOT:
606         case LFUN_MACRON:
607         case LFUN_CARON:
608         case LFUN_TILDE:
609         case LFUN_CEDILLA:
610         case LFUN_CIRCLE:
611         case LFUN_UNDERDOT:
612         case LFUN_TIE:
613         case LFUN_OGONEK:
614         case LFUN_HUNG_UMLAUT:
615                 break;
616
617         //  Math fonts
618         case LFUN_FREEFONT_APPLY:
619         case LFUN_FREEFONT_UPDATE:
620                 handleFont2(cur, cmd.argument);
621                 break;
622
623         case LFUN_BOLD:
624                 handleFont(cur, cmd.argument, "mathbf");
625                 break;
626         case LFUN_SANS:
627                 handleFont(cur, cmd.argument, "mathsf");
628                 break;
629         case LFUN_EMPH:
630                 handleFont(cur, cmd.argument, "mathcal");
631                 break;
632         case LFUN_ROMAN:
633                 handleFont(cur, cmd.argument, "mathrm");
634                 break;
635         case LFUN_CODE:
636                 handleFont(cur, cmd.argument, "texttt");
637                 break;
638         case LFUN_FRAK:
639                 handleFont(cur, cmd.argument, "mathfrak");
640                 break;
641         case LFUN_ITAL:
642                 handleFont(cur, cmd.argument, "mathit");
643                 break;
644         case LFUN_NOUN:
645                 handleFont(cur, cmd.argument, "mathbb");
646                 break;
647         //case LFUN_FREEFONT_APPLY:
648                 handleFont(cur, cmd.argument, "textrm");
649                 break;
650         case LFUN_DEFAULT:
651                 handleFont(cur, cmd.argument, "textnormal");
652                 break;
653
654         case LFUN_MATH_MODE:
655 #if 1
656                 cur.macroModeClose();
657                 cur.selClearOrDel();
658                 cur.plainInsert(MathAtom(new MathMBoxInset(cur.bv())));
659                 cur.posLeft();
660                 cur.pushLeft(cur.nextInset());
661 #else
662                 if (cur.currentMode() == InsetBase::TEXT_MODE)
663                         cur.niceInsert(MathAtom(new MathHullInset("simple")));
664                 else
665                         handleFont(cur, cmd.argument, "textrm");
666                 //cur.owner()->message(_("math text mode toggled"));
667 #endif
668                 break;
669
670         case LFUN_MATH_SIZE:
671 #if 0
672                 if (!arg.empty()) {
673                         //recordUndo(cur, Undo::ATOMIC);
674                         cur.setSize(arg);
675                 }
676 #endif
677                 break;
678
679         case LFUN_INSERT_MATRIX: {
680                 //recordUndo(cur, Undo::ATOMIC);
681                 unsigned int m = 1;
682                 unsigned int n = 1;
683                 string v_align;
684                 string h_align;
685                 istringstream is(cmd.argument);
686                 is >> m >> n >> v_align >> h_align;
687                 if (m < 1)
688                         m = 1;
689                 if (n < 1)
690                         n = 1;
691                 v_align += 'c';
692                 cur.niceInsert(
693                         MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
694                 break;
695         }
696
697         case LFUN_MATH_DELIM: {
698                 lyxerr << "MathNestInset::LFUN_MATH_DELIM" << endl;
699                 string ls;
700                 string rs = lyx::support::split(cmd.argument, ls, ' ');
701                 // Reasonable default values
702                 if (ls.empty())
703                         ls = '(';
704                 if (rs.empty())
705                         rs = ')';
706                 //recordUndo(cur, Undo::ATOMIC);
707                 cur.handleNest(MathAtom(new MathDelimInset(ls, rs)));
708                 break;
709         }
710
711         case LFUN_SPACE_INSERT:
712         case LFUN_MATH_SPACE:
713                 //recordUndo(cur, Undo::ATOMIC);
714                 cur.insert(MathAtom(new MathSpaceInset(",")));
715                 break;
716
717         case LFUN_UNDO:
718 #warning look here
719                 //cur.bv().owner()->message(_("Invalid action in math mode!"));
720                 break;
721
722         case LFUN_INSET_ERT:
723                 // interpret this as if a backslash was typed
724                 //recordUndo(cur, Undo::ATOMIC);
725                 cur.interpret('\\');
726                 break;
727
728 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
729 // handling such that "self-insert" works on "arbitrary stuff" too, and
730 // math-insert only handles special math things like "matrix".
731         case LFUN_INSERT_MATH:
732                 //recordUndo(cur, Undo::ATOMIC);
733                 cur.niceInsert(cmd.argument);
734                 break;
735
736         case LFUN_DIALOG_SHOW_NEW_INSET: {
737                 string const & name = cmd.argument;
738                 string data;
739 #if 0
740                 if (name == "ref") {
741                         RefInset tmp(name);
742                         data = tmp.createDialogStr(name);
743                 }
744 #endif
745                 cur.bv().owner()->getDialogs().show(name, data, 0);
746                 break;
747         }
748
749         case LFUN_INSET_APPLY: {
750                 string const name = cmd.getArg(0);
751                 InsetBase * base = cur.bv().owner()->getDialogs().getOpenInset(name);
752
753                 if (base) {
754                         base->dispatch(cur, FuncRequest(LFUN_INSET_MODIFY, cmd.argument));
755                         break;
756                 }
757                 MathArray ar;
758                 if (createMathInset_fromDialogStr(cmd.argument, ar)) {
759                         cur.insert(ar);
760                         break;
761                 }
762                 cur.notdispatched();
763                 break;
764         }
765
766 #warning look here
767 #if 0
768
769         case LFUN_WORD_REPLACE:
770         case LFUN_WORD_FIND:
771                 if (!searchForward(&cur.bv(), cmd.getArg(0), false, false))
772                         cur.notdispatched();
773                 break;
774
775         cur.normalize();
776         cur.touch();
777
778         BOOST_ASSERT(cur.inMathed());
779
780         if (result.dispatched()) {
781                 revealCodes(cur);
782                 cur.bv().stuffClipboard(cur.grabSelection());
783         } else {
784                 if (remove_inset)
785                         cur.bv().owner()->dispatch(FuncRequest(LFUN_DELETE));
786         }
787         break;
788 #endif
789
790         default:
791                 MathDimInset::priv_dispatch(cur, cmd);
792                 break;
793         }
794 }
795
796
797 void MathNestInset::edit(LCursor & cur, bool left)
798 {
799         cur.push(this);
800         cur.idx() = left ? 0 : cur.lastidx();
801         cur.pos() = left ? 0 : cur.lastpos();
802         cur.resetAnchor();
803 }
804
805
806 InsetBase * MathNestInset::editXY(LCursor & cur, int x, int y)
807 {
808         int idx_min = 0;
809         int dist_min = 1000000;
810         for (idx_type i = 0; i < nargs(); ++i) {
811                 int d = cell(i).dist(x, y);
812                 if (d < dist_min) {
813                         dist_min = d;
814                         idx_min = i;
815                 }
816         }
817         MathArray & ar = cell(idx_min);
818         cur.push(this);
819         cur.idx() = idx_min;
820         cur.pos() = ar.x2pos(x - ar.xo());
821         lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl;
822         if (dist_min == 0) {
823                 // hit inside cell
824                 for (pos_type i = 0, n = ar.size(); i < n; ++i)
825                         if (ar[i]->covers(x, y))
826                                 return ar[i].nucleus()->editXY(cur, x, y);
827         }
828         return this;
829 }
830
831
832 void MathNestInset::lfunMouseRelease(LCursor & cur, FuncRequest const & cmd)
833 {
834         //lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl;
835
836         if (cmd.button() == mouse_button::button1) {
837                 // try to dispatch to enclosed insets first
838                 //cur.bv().stuffClipboard(cur.grabSelection());
839                 return;
840         }
841
842         if (cmd.button() == mouse_button::button2) {
843                 MathArray ar;
844                 asArray(cur.bv().getClipboard(), ar);
845                 cur.selClear();
846                 cur.setScreenPos(cmd.x, cmd.y);
847                 cur.insert(ar);
848                 cur.bv().update();
849                 return;
850         }
851
852         if (cmd.button() == mouse_button::button3) {
853                 // try to dispatch to enclosed insets first
854                 cur.bv().owner()->getDialogs().show("mathpanel");
855                 return;
856         }
857
858         cur.notdispatched();
859 }
860
861
862 void MathNestInset::lfunMousePress(LCursor & cur, FuncRequest const & cmd)
863 {
864         lyxerr << "lfunMousePress: buttons: " << cmd.button() << endl;
865         if (cmd.button() == mouse_button::button1) {
866                 first_x = cmd.x;
867                 first_y = cmd.y;
868                 cur.selClear();
869                 //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
870                 lyxerr << "lfunMousePress: setting cursor to: " << cur << endl;
871                 cur.bv().cursor() = cur;
872         }
873
874         if (cmd.button() == mouse_button::button2) {
875                 priv_dispatch(cur, FuncRequest(LFUN_PASTESELECTION));
876         }
877 }
878
879
880 void MathNestInset::lfunMouseMotion(LCursor & cur, FuncRequest const & cmd)
881 {
882         // only select with button 1
883         if (cmd.button() != mouse_button::button1)
884                 return;
885
886         if (abs(cmd.x - first_x) < 2 && abs(cmd.y - first_y) < 2)
887                 return;
888
889         first_x = cmd.x;
890         first_y = cmd.y;
891
892         if (!cur.selection())
893                 cur.selBegin();
894
895         //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
896         cur.bv().cursor().cursor_ = cur.cursor_;
897         cur.bv().cursor().selection() = true;
898         return;
899 }