]> git.lyx.org Git - lyx.git/blob - src/mathed/formulabase.C
guii2
[lyx.git] / src / mathed / formulabase.C
1 /*
2 *  File:        formulabase.C
3 *  Purpose:     Implementation of common parts of the LyX  math insets
4 *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5 *  Created:     January 1996
6 *
7 *  Copyright: 1996-1998 Alejandro Aguilar Sierra
8 *
9 *  Version: 0.4, Lyx project.
10 *
11 *   You are free to use and modify this code under the terms of
12 *   the GNU General Public Licence version 2 or later.
13 */
14
15 #include <config.h>
16 #include <fstream>
17
18 #include "Lsstream.h"
19 #include "support/LAssert.h"
20
21 #ifdef __GNUG__
22 #pragma implementation
23 #endif
24
25 #include "formula.h"
26 #include "formulamacro.h"
27 #include "commandtags.h"
28 #include "BufferView.h"
29 #include "lyxtext.h"
30 #include "lyxfunc.h"
31 #include "gettext.h"
32 #include "LaTeXFeatures.h"
33 #include "debug.h"
34 #include "math_support.h"
35 #include "support/lstrings.h"
36 #include "frontends/LyXView.h"
37 #include "frontends/Painter.h"
38 #include "font.h"
39 #include "Lsstream.h"
40 #include "math_arrayinset.h"
41 #include "math_charinset.h"
42 #include "math_cursor.h"
43 #include "math_factory.h"
44 #include "math_hullinset.h"
45 #include "math_iterator.h"
46 #include "math_macrotable.h"
47 #include "math_parser.h"
48 #include "math_pos.h"
49 #include "math_spaceinset.h"
50 #include "undo_funcs.h"
51 #include "textpainter.h"
52 #include "frontends/Dialogs.h"
53 #include "intl.h"
54
55 using std::endl;
56 using std::ostream;
57 using std::vector;
58
59 MathCursor * mathcursor = 0;
60
61
62 namespace {
63
64
65 // local global
66 int first_x;
67 int first_y;
68
69
70 bool openNewInset(BufferView * bv, UpdatableInset * new_inset)
71 {
72         if (!bv->insertInset(new_inset)) {
73                 delete new_inset;
74                 return false;
75         }
76         new_inset->edit(bv, 0, 0, 0);
77         return true;
78 }
79
80
81 } // namespace anon
82
83
84
85 InsetFormulaBase::InsetFormulaBase()
86         : view_(0), font_(), xo_(0), yo_(0)
87 {
88         // This is needed as long the math parser is not re-entrant
89         MathMacroTable::builtinMacros();
90         //lyxerr << "sizeof MathInset: " << sizeof(MathInset) << "\n";
91         //lyxerr << "sizeof(MathMetricsInfo): " << sizeof(MathMetricsInfo) << "\n";
92         //lyxerr << "sizeof(MathCharInset): " << sizeof(MathCharInset) << "\n";
93 }
94
95
96 // simply scrap this function if you want
97 void InsetFormulaBase::mutateToText()
98 {
99 #if 0
100         // translate to latex
101         ostringstream os;
102         latex(NULL, os, false, false);
103         string str = os.str();
104
105         // insert this text
106         LyXText * lt = view_->getLyXText();
107         string::const_iterator cit = str.begin();
108         string::const_iterator end = str.end();
109         for (; cit != end; ++cit)
110                 view_->owner()->getIntl()->getTrans().TranslateAndInsert(*cit, lt);
111
112         // remove ourselves
113         //view_->owner()->getLyXFunc()->dispatch(LFUN_ESCAPE);
114 #endif
115 }
116
117
118 // Check if uses AMS macros
119 void InsetFormulaBase::validate(LaTeXFeatures &) const
120 {}
121
122
123 void InsetFormulaBase::metrics(BufferView * bv, LyXFont const & f) const
124 {
125         font_ = f;
126         metrics(bv);
127 }
128
129
130 void InsetFormulaBase::metrics(BufferView * bv) const
131 {
132         if (bv)
133                 view_ = bv;
134         MathMetricsInfo mi(view_, font_, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
135         par()->metrics(mi);
136 }
137
138
139 string const InsetFormulaBase::editMessage() const
140 {
141         return _("Math editor mode");
142 }
143
144
145 void InsetFormulaBase::edit(BufferView * bv, int x, int y, unsigned int)
146 {
147         if (!bv->lockInset(this))
148                 lyxerr[Debug::MATHED] << "Cannot lock inset!!!" << endl;
149         delete mathcursor;
150         mathcursor = new MathCursor(this, true);
151         metrics(bv);
152         mathcursor->setPos(x, y);
153         //lyxerr << "setting pos to " << x << "," << y << "\n";
154
155         // if that is removed, we won't get the magenta box when entering an
156         // inset for the first time
157         bv->updateInset(this, false);
158 }
159
160
161 void InsetFormulaBase::edit(BufferView * bv, bool front)
162 {
163         if (!bv->lockInset(this))
164                 lyxerr[Debug::MATHED] << "Cannot lock inset!!!" << endl;
165         delete mathcursor;
166         mathcursor = new MathCursor(this, front);
167         metrics(bv);
168         bv->updateInset(this, false);
169 }
170
171
172 void InsetFormulaBase::handleFont
173         (BufferView * bv, string const & arg, MathTextCodes t)
174 {
175         if (mathcursor->selection()) {
176                 bv->lockedInsetStoreUndo(Undo::EDIT);
177                 updateLocal(bv, true);
178         }
179         mathcursor->handleFont(t);
180         for (string::const_iterator it = arg.begin(); it != arg.end(); ++it)
181                 mathcursor->insert(*it);
182         updateLocal(bv, false);
183 }
184
185
186 void InsetFormulaBase::insetUnlock(BufferView * bv)
187 {
188         if (mathcursor) {
189                 if (mathcursor->inMacroMode()) {
190                         mathcursor->macroModeClose();
191                         updateLocal(bv, true);
192                 }
193                 delete mathcursor;
194                 mathcursor = 0;
195         }
196         bv->updateInset(this, false);
197 }
198
199
200 void InsetFormulaBase::getCursorPos(BufferView *, int & x, int & y) const
201 {
202         mathcursor->getPos(x, y);
203         //x -= xo_;
204         y -= yo_;
205         //lyxerr << "getCursorPos: " << x << " " << y << "\n";
206 }
207
208
209 void InsetFormulaBase::toggleInsetCursor(BufferView * bv)
210 {
211         if (!mathcursor)
212                 return;
213
214         if (isCursorVisible())
215                 bv->hideLockedInsetCursor();
216         else {
217                 metrics(bv);
218                 int x;
219                 int y;
220                 mathcursor->getPos(x, y);
221                 y -= yo_;
222                 int asc = 0;
223                 int des = 0;
224                 math_font_max_dim(font_, asc, des);
225                 bv->showLockedInsetCursor(x, y, asc, des);
226                 //lyxerr << "toggleInsetCursor: " << x << " " << y << "\n";
227         }
228
229         toggleCursorVisible();
230 }
231
232
233 void InsetFormulaBase::showInsetCursor(BufferView * bv, bool)
234 {
235         if (isCursorVisible())
236                 return;
237         if (mathcursor) {
238                 metrics(bv);
239                 int x;
240                 int y;
241                 mathcursor->getPos(x, y);
242                 y -= yo_;
243                 int asc = 0;
244                 int des = 0;
245                 math_font_max_dim(font_, asc, des);
246                 bv->fitLockedInsetCursor(x, y, asc, des);
247                 //lyxerr << "showInsetCursor: x: " << x << " y: " << y << " yo: " << yo_ << "\n";
248         }
249         toggleInsetCursor(bv);
250 }
251
252
253 void InsetFormulaBase::hideInsetCursor(BufferView * bv)
254 {
255         if (isCursorVisible())
256                 toggleInsetCursor(bv);
257 }
258
259
260 void InsetFormulaBase::toggleInsetSelection(BufferView * bv)
261 {
262         if (mathcursor)
263                 bv->updateInset(this, false);
264 }
265
266
267 vector<string> const InsetFormulaBase::getLabelList() const
268 {
269   return vector<string>();
270 }
271
272
273 void InsetFormulaBase::updateLocal(BufferView * bv, bool dirty)
274 {
275         metrics(bv);
276         bv->updateInset(this, dirty);
277 }
278
279
280 bool InsetFormulaBase::insetButtonRelease(BufferView * bv,
281                                           int /*x*/, int /*y*/, int button)
282 {
283         //lyxerr << "insetButtonRelease: " << x << " " << y << "\n";
284
285         if (!mathcursor)
286                 return false;
287         hideInsetCursor(bv);
288         showInsetCursor(bv);
289         bv->updateInset(this, false);
290
291         if (button == 3) {
292                 // launch math panel for right mouse button
293                 bv->owner()->getDialogs()->showMathPanel();
294                 return true;
295         }
296         return false;
297 }
298
299
300 void InsetFormulaBase::insetButtonPress(BufferView * bv,
301                                         int x, int y, int button)
302 {
303         //lyxerr << "insetButtonPress: "
304         //      << x << " " << y << " but: " << button << "\n";
305 #if 0
306         switch (button) {
307                 default:
308                 case 1:
309                         // left click
310                         delete mathcursor;
311                         mathcursor = new MathCursor(this, x == 0);
312                         metrics(bv);
313                         first_x = x;
314                         first_y = y;
315                         mathcursor->selClear();
316                         mathcursor->setPos(x + xo_, y + yo_);
317                         break;
318 /*
319                 case 2:
320                         lyxerr << "insetButtonPress: 2\n";
321                         // insert stuff
322                         if (mathcursor) {
323                                 bv->lockedInsetStoreUndo(Undo::EDIT);
324                                 MathArray ar;
325                                 mathcursor->selGet(ar);
326                                 mathcursor->setPos(x + xo_, y + yo_);
327                                 string sel =
328                                         bv->getLyXText()->selectionAsString(bv->buffer(), false);
329                                 mathed_parse_cell(ar, sel);
330                                 mathcursor->insert(ar);
331                         }
332                         break;
333 */
334                 case 3:
335                         // launch math panel for right mouse button
336                         bv->owner()->getDialogs()->showMathPanel();
337                         break;
338         }
339 #else
340         if (button == 1 || !mathcursor) {
341                 delete mathcursor;
342                 mathcursor = new MathCursor(this, x == 0);
343                 metrics(bv);
344                 first_x = x;
345                 first_y = y;
346                 mathcursor->selClear();
347                 mathcursor->setPos(x + xo_, y + yo_);
348         }
349 #if 0
350 #warning Never launch a Dialog on "Press" event ONLY on "Release" event!
351         if (button == 3) {
352                 // launch math panel for right mouse button
353                 bv->owner()->getDialogs()->showMathPanel();
354         }
355 #endif
356 #endif
357         bv->updateInset(this, false);
358 }
359
360
361 void InsetFormulaBase::insetMotionNotify(BufferView * bv,
362                                          int x, int y, int /*button*/)
363 {
364         if (!mathcursor)
365                 return;
366
367         if (abs(x - first_x) < 2 && abs(y - first_y) < 2) {
368                 //lyxerr << "insetMotionNotify: ignored\n";
369                 return;
370         }
371         first_x = x;
372         first_y = y;
373
374         if (!mathcursor->selection())
375                 mathcursor->selStart();
376
377         //lyxerr << "insetMotionNotify: " << x + xo_ << ' ' << y + yo_
378         //      << ' ' << button << "\n";
379         hideInsetCursor(bv);
380         mathcursor->setPos(x + xo_, y + yo_);
381         showInsetCursor(bv);
382         bv->updateInset(this, false);
383 }
384
385
386 void InsetFormulaBase::insetKeyPress(XKeyEvent *)
387 {
388         lyxerr[Debug::MATHED] << "Used InsetFormulaBase::InsetKeyPress." << endl;
389 }
390
391
392 UpdatableInset::RESULT
393 InsetFormulaBase::localDispatch(BufferView * bv, kb_action action,
394                             string const & arg)
395 {
396         //lyxerr << "InsetFormulaBase::localDispatch: act: " << action
397         //      << " arg: '" << arg << "' cursor: " << mathcursor << "\n";
398
399         if (!mathcursor)
400                 return UNDISPATCHED;
401
402         RESULT result      = DISPATCHED;
403         bool sel           = false;
404         bool was_macro     = mathcursor->inMacroMode();
405         bool was_selection = mathcursor->selection();
406
407         hideInsetCursor(bv);
408
409         mathcursor->normalize();
410         mathcursor->touch();
411
412         switch (action) {
413
414                 // --- Cursor Movements ---------------------------------------------
415
416         case LFUN_RIGHTSEL:
417                 sel = true; // fall through...
418
419         case LFUN_RIGHT:
420                 result = mathcursor->right(sel) ? DISPATCHED : FINISHED_RIGHT;
421                 //lyxerr << "calling scroll 20\n";
422                 //scroll(bv, 20);
423                 updateLocal(bv, false);
424                 // write something to the minibuffer
425                 //bv->owner()->message(mathcursor->info());
426                 break;
427
428
429         case LFUN_LEFTSEL:
430                 sel = true; // fall through
431
432         case LFUN_LEFT:
433                 result = mathcursor->left(sel) ? DISPATCHED : FINISHED;
434                 updateLocal(bv, false);
435                 break;
436
437
438         case LFUN_UPSEL:
439                 sel = true;
440
441         case LFUN_UP:
442                 result = mathcursor->up(sel) ? DISPATCHED : FINISHED_UP;
443                 updateLocal(bv, false);
444                 break;
445
446
447         case LFUN_DOWNSEL:
448                 sel = true;
449
450         case LFUN_DOWN:
451                 result = mathcursor->down(sel) ? DISPATCHED : FINISHED_DOWN;
452                 updateLocal(bv, false);
453                 break;
454
455         case LFUN_HOMESEL:
456                 sel = true;
457
458         case LFUN_HOME:
459                 mathcursor->home(sel);
460                 updateLocal(bv, false);
461                 break;
462
463         case LFUN_ENDSEL:
464                 sel = true;
465
466         case LFUN_END:
467                 mathcursor->end(sel);
468                 updateLocal(bv, false);
469                 break;
470
471         case LFUN_DELETE_LINE_FORWARD:
472                 bv->lockedInsetStoreUndo(Undo::DELETE);
473                 mathcursor->delLine();
474                 updateLocal(bv, true);
475                 break;
476
477         case LFUN_TAB:
478                 mathcursor->idxNext();
479                 updateLocal(bv, false);
480                 break;
481
482         case LFUN_SHIFT_TAB:
483                 mathcursor->idxPrev();
484                 updateLocal(bv, false);
485                 break;
486
487         case LFUN_TABINSERT:
488                 bv->lockedInsetStoreUndo(Undo::EDIT);
489                 mathcursor->splitCell();
490                 updateLocal(bv, true);
491                 break;
492
493         case LFUN_DELETE_WORD_BACKWARD:
494         case LFUN_BACKSPACE:
495                 bv->lockedInsetStoreUndo(Undo::DELETE);
496                 mathcursor->backspace();
497                 bv->updateInset(this, true);
498                 break;
499
500         case LFUN_DELETE_WORD_FORWARD:
501         case LFUN_DELETE:
502                 bv->lockedInsetStoreUndo(Undo::DELETE);
503                 mathcursor->erase();
504                 bv->updateInset(this, true);
505                 break;
506
507         //    case LFUN_GETXY:
508         //      sprintf(dispatch_buffer, "%d %d",);
509         //      dispatch_result = dispatch_buffer;
510         //      break;
511         case LFUN_SETXY: {
512                 lyxerr << "LFUN_SETXY broken!\n";
513                 int x = 0;
514                 int y = 0;
515                 istringstream is(arg.c_str());
516                 is >> x >> y;
517                 mathcursor->setPos(x, y);
518                 updateLocal(bv, false);
519                 break;
520         }
521
522         case LFUN_PASTE:
523                 if (was_macro)
524                         mathcursor->macroModeClose();
525                 bv->lockedInsetStoreUndo(Undo::EDIT);
526                 mathcursor->selPaste();
527                 updateLocal(bv, true);
528                 break;
529
530         case LFUN_CUT:
531                 bv->lockedInsetStoreUndo(Undo::DELETE);
532                 mathcursor->selCut();
533                 updateLocal(bv, true);
534                 break;
535
536         case LFUN_COPY:
537                 mathcursor->selCopy();
538                 break;
539
540         case LFUN_WORDRIGHTSEL:
541         case LFUN_WORDLEFTSEL:
542                 break;
543
544         // Special casing for superscript in case of LyX handling
545         // dead-keys:
546         case LFUN_CIRCUMFLEX:
547                 if (arg.empty()) {
548                         // do superscript if LyX handles
549                         // deadkeys
550                         bv->lockedInsetStoreUndo(Undo::EDIT);
551                         mathcursor->script(true);
552                         updateLocal(bv, true);
553                 }
554                 break;
555         case LFUN_UMLAUT:
556         case LFUN_ACUTE:
557         case LFUN_GRAVE:
558         case LFUN_BREVE:
559         case LFUN_DOT:
560         case LFUN_MACRON:
561         case LFUN_CARON:
562         case LFUN_TILDE:
563         case LFUN_CEDILLA:
564         case LFUN_CIRCLE:
565         case LFUN_UNDERDOT:
566         case LFUN_TIE:
567         case LFUN_OGONEK:
568         case LFUN_HUNG_UMLAUT:
569                 break;
570
571         //  Math fonts
572         case LFUN_GREEK_TOGGLE: handleFont(bv, arg, LM_TC_GREEK); break;
573         case LFUN_BOLD:         handleFont(bv, arg, LM_TC_BF); break;
574         case LFUN_SANS:         handleFont(bv, arg, LM_TC_SF); break;
575         case LFUN_EMPH:         handleFont(bv, arg, LM_TC_CAL); break;
576         case LFUN_ROMAN:        handleFont(bv, arg, LM_TC_RM); break;
577         case LFUN_CODE:         handleFont(bv, arg, LM_TC_TT); break;
578         case LFUN_FRAK:         handleFont(bv, arg, LM_TC_EUFRAK); break;
579         case LFUN_ITAL:         handleFont(bv, arg, LM_TC_IT); break;
580         case LFUN_NOUN:         handleFont(bv, arg, LM_TC_BB); break;
581         case LFUN_DEFAULT:      handleFont(bv, arg, LM_TC_VAR); break;
582         case LFUN_FREE:         handleFont(bv, arg, LM_TC_TEXTRM); break;
583
584         case LFUN_GREEK:
585                 handleFont(bv, arg, LM_TC_GREEK1);
586                 if (arg.size())
587                         mathcursor->interpret(arg);
588                 break;
589
590         case LFUN_MATH_MODE:
591 #if 1
592                 handleFont(bv, arg, LM_TC_TEXTRM);
593 #endif
594
595 #if 0
596                 mathcursor->niceInsert(MathAtom(new MathHullInset(LM_OT_SIMPLE)));
597                 updateLocal(bv, true);
598 #endif
599
600                 //bv->owner()->message(_("math text mode toggled"));
601                 break;
602
603         case LFUN_MATH_LIMITS:
604                 bv->lockedInsetStoreUndo(Undo::EDIT);
605                 if (mathcursor->toggleLimits())
606                         updateLocal(bv, true);
607                 break;
608
609         case LFUN_MATH_SIZE:
610 #if 0
611                 if (!arg.empty()) {
612                         bv->lockedInsetStoreUndo(Undo::EDIT);
613                         mathcursor->setSize(arg);
614                         updateLocal(bv, true);
615                 }
616 #endif
617                 break;
618
619         case LFUN_INSERT_MATRIX:
620                 if (!arg.empty()) {
621                         bv->lockedInsetStoreUndo(Undo::EDIT);
622                         mathcursor->interpret("matrix " + arg);
623                         updateLocal(bv, true);
624                 }
625                 break;
626
627         case LFUN_SUPERSCRIPT:
628         case LFUN_SUBSCRIPT:
629         {
630                 bv->lockedInsetStoreUndo(Undo::EDIT);
631                 mathcursor->script(action == LFUN_SUPERSCRIPT);
632                 updateLocal(bv, true);
633                 break;
634         }
635
636         case LFUN_MATH_DELIM:
637         {
638                 //lyxerr << "formulabase::LFUN_MATH_DELIM, arg: '" << arg << "'\n";
639                 string ls;
640                 string rs = split(arg, ls, ' ');
641                 // Reasonable default values
642                 if (ls.empty())
643                         ls = '(';
644                 if (rs.empty())
645                         rs = ')';
646
647                 bv->lockedInsetStoreUndo(Undo::EDIT);
648                 mathcursor->handleDelim(ls, rs);
649                 updateLocal(bv, true);
650                 break;
651         }
652
653         case LFUN_PROTECTEDSPACE:
654         case LFUN_MATH_SPACE:
655                 bv->lockedInsetStoreUndo(Undo::EDIT);
656                 mathcursor->insert(MathAtom(new MathSpaceInset(1)));
657                 updateLocal(bv, true);
658                 break;
659
660         case LFUN_UNDO:
661                 bv->owner()->message(_("Invalid action in math mode!"));
662                 break;
663
664
665         case LFUN_MATH_HALIGN:
666         case LFUN_MATH_VALIGN:
667         case LFUN_MATH_ROW_INSERT:
668         case LFUN_MATH_ROW_DELETE:
669         case LFUN_MATH_COLUMN_INSERT:
670         case LFUN_MATH_COLUMN_DELETE:
671         {
672                 MathInset::idx_type idx = 0;
673                 MathGridInset * p = mathcursor ? mathcursor->enclosingGrid(idx) : 0;
674                 if (p) {
675                         mathcursor->popToEnclosingGrid();
676                         bv->lockedInsetStoreUndo(Undo::EDIT);
677                         char align = arg.size() ? arg[0] : 'c';
678                         switch (action) {
679                                 case LFUN_MATH_HALIGN: p->halign(align, p->col(idx)); break;
680                                 case LFUN_MATH_VALIGN: p->valign(align); break;
681                                 case LFUN_MATH_ROW_INSERT: p->addRow(p->row(idx)); break;
682                                 case LFUN_MATH_ROW_DELETE: p->delRow(p->row(idx)); break;
683                                 case LFUN_MATH_COLUMN_INSERT: p->addCol(p->col(idx)); break;
684                                 case LFUN_MATH_COLUMN_DELETE: p->delCol(p->col(idx)); break;
685                                 default: ;
686                         }
687                         updateLocal(bv, true);
688                 }
689                 break;
690         }
691
692         case LFUN_EXEC_COMMAND:
693                 result = UNDISPATCHED;
694                 break;
695
696         case LFUN_BREAKPARAGRAPH:
697         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
698                 //lyxerr << "LFUN ignored\n";
699                 break;
700
701         case LFUN_INSET_ERT:
702                 // interpret this as if a backslash was typed
703                 bv->lockedInsetStoreUndo(Undo::EDIT);
704                 mathcursor->interpret('\\');
705                 updateLocal(bv, true);
706                 break;
707
708         case -1:
709         case LFUN_INSERT_MATH:
710         case LFUN_SELFINSERT:
711                 if (!arg.empty()) {
712                         bv->lockedInsetStoreUndo(Undo::EDIT);
713                         if (arg.size() == 1)
714                                 result = mathcursor->interpret(arg[0]) ? DISPATCHED : FINISHED_RIGHT;
715                         else
716                                 result = mathcursor->interpret(arg) ? DISPATCHED : FINISHED_RIGHT;
717                         updateLocal(bv, true);
718                 }
719                 break;
720
721         case LFUN_MATH_PANEL:
722                 result = UNDISPATCHED;
723                 break;
724
725         case LFUN_ESCAPE:
726                 if (mathcursor->selection())
727                         mathcursor->selClear();
728                 else
729                         result = UNDISPATCHED;
730                 break;
731
732         default:
733                 result = UNDISPATCHED;
734         }
735
736         mathcursor->normalize();
737         mathcursor->touch();
738
739         lyx::Assert(mathcursor);
740
741         if (mathcursor->selection() || was_selection)
742                 toggleInsetSelection(bv);
743
744         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE ||
745             result == UNDISPATCHED)
746                 showInsetCursor(bv);
747         else
748                 bv->unlockInset(this);
749
750         revealCodes(bv);
751
752         return result;  // original version
753 }
754
755
756 void InsetFormulaBase::revealCodes(BufferView * /*bv*/) const
757 {
758         if (!mathcursor)
759                 return;
760 #if 0
761         // write something to the minibuffer
762         // translate to latex
763         mathcursor->markInsert();
764         ostringstream os;
765         write(NULL, os);
766         string str = os.str();
767         mathcursor->markErase();
768         string::size_type pos = 0;
769         string res;
770         for (string::iterator it = str.begin(); it != str.end(); ++it) {
771                 if (*it == '\n')
772                         res += ' ';
773                 else if (*it == '\0') {
774                         res += "  -X-  ";
775                         pos = it - str.begin();
776                 }
777                 else
778                         res += *it;
779         }
780         if (pos > 30)
781                 res = res.substr(pos - 30);
782         if (res.size() > 60)
783                 res = res.substr(0, 60);
784         bv->owner()->message(res);
785 #endif
786 }
787
788
789 Inset::Code InsetFormulaBase::lyxCode() const
790 {
791         return Inset::MATH_CODE;
792 }
793
794
795 int InsetFormulaBase::ylow() const
796 {
797         return yo_ - ascent(view_, font_);
798 }
799
800
801 int InsetFormulaBase::yhigh() const
802 {
803         return yo_ + descent(view_, font_);
804 }
805
806
807 int InsetFormulaBase::xlow() const
808 {
809         return xo_;
810 }
811
812
813 int InsetFormulaBase::xhigh() const
814 {
815         return xo_ + width(view_, font_);
816 }
817
818
819 /////////////////////////////////////////////////////////////////////
820
821
822 bool InsetFormulaBase::searchForward(BufferView * bv, string const & str,
823                                      bool, bool)
824 {
825 #ifdef WITH_WARNINGS
826 #warning pretty ugly
827 #endif
828         static InsetFormulaBase * lastformula = 0;
829         static MathIterator current = MathIterator(ibegin(par().nucleus()));
830         static MathArray ar;
831         static string laststr;
832
833         if (lastformula != this || laststr != str) {
834                 //lyxerr << "reset lastformula to " << this << "\n";
835                 lastformula = this;
836                 laststr = str;
837                 current = ibegin(par().nucleus());
838                 ar.clear();
839                 mathed_parse_cell(ar, str);
840         } else {
841                 ++current;
842         }
843         //lyxerr << "searching '" << str << "' in " << this << ar << endl;
844
845         for (MathIterator it = current; it != iend(par().nucleus()); ++it) {
846                 if (it.cell().matchpart(ar, it.position().pos_)) {
847                         mathcursor->setSelection(it.cursor(), ar.size());
848                         current = it;
849                         it.jump(ar.size());
850                         // I guess some of the following can go
851                         bv->toggleSelection(true);
852                         hideInsetCursor(bv);
853                         updateLocal(bv, true);
854                         showInsetCursor(bv);
855                         metrics(bv);
856                         return true;
857                 }
858         }
859
860         //lyxerr << "not found!\n";
861         lastformula = 0;
862         // we have to unlock ourself in this function by default!
863         // don't ask me why...
864         bv->unlockInset(this);
865         return false;
866 }
867
868
869 bool InsetFormulaBase::searchBackward(BufferView * bv, string const & what,
870                                       bool a, bool b)
871 {
872         lyxerr << "searching backward not implemented in mathed" << endl;
873         return searchForward(bv, what, a, b);
874 }
875
876
877 /////////////////////////////////////////////////////////////////////
878
879
880 void mathDispatchCreation(BufferView * bv, string const & arg, bool display)
881 {
882         if (bv->available()) {
883                 // use selection if available..
884                 //string sel;
885                 //if (action == LFUN_MATH_IMPORT_SELECTION)
886                 //      sel = "";
887                 //else
888
889                 string sel = bv->getLyXText()->selectionAsString(bv->buffer(), false);
890
891                 InsetFormulaBase * f;
892                 if (sel.empty()) {
893                         f = new InsetFormula;
894                         if (openNewInset(bv, f)) {
895                                 // don't do that also for LFUN_MATH_MODE unless you want end up with
896                                 // always changing to mathrm when opening an inlined inset
897                                 // -- I really hate "LyXfunc overloading"...
898                                 if (display)
899                                         f->localDispatch(bv, LFUN_MATH_DISPLAY, string());
900                                 f->localDispatch(bv, LFUN_INSERT_MATH, arg);
901                         }
902                 } else {
903                         // create a macro if we see "\\newcommand" somewhere, and an ordinary
904                         // formula otherwise
905                         if (sel.find("\\newcommand") == string::npos &&
906                                   sel.find("\\def") == string::npos)
907                                 f = new InsetFormula(sel);
908                         else {
909                                 string name;
910                                 if (!mathed_parse_macro(name, sel))
911                                         return;
912                                 f = new InsetFormulaMacro(sel);
913                         }
914                         bv->getLyXText()->cutSelection(bv);
915                         openNewInset(bv, f);
916                 }
917         }
918         bv->owner()->getLyXFunc()->setMessage(N_("Math editor mode"));
919 }
920
921
922 void mathDispatchMathDisplay(BufferView * bv, string const & arg)
923 {
924         mathDispatchCreation(bv, arg, true);
925 }
926
927
928 void mathDispatchMathMode(BufferView * bv, string const & arg)
929 {
930         mathDispatchCreation(bv, arg, false);
931 }
932
933
934 void mathDispatchMathImportSelection(BufferView * bv, string const & arg)
935 {
936         mathDispatchCreation(bv, arg, true);
937 }
938
939
940 void mathDispatchMathMacro(BufferView * bv, string const & arg)
941 {
942         if (bv->available()) {
943                 if (arg.empty())
944                         bv->owner()->getLyXFunc()->setErrorMessage(N_("Missing argument"));
945                 else {
946                         string s = arg;
947                         string const s1 = token(s, ' ', 1);
948                         int const na = s1.empty() ? 0 : lyx::atoi(s1);
949                         openNewInset(bv, new InsetFormulaMacro(token(s, ' ', 0), na));
950                 }
951         }
952 }
953
954
955 void mathDispatchMathDelim(BufferView * bv, string const & arg)
956 {
957         if (bv->available()) {
958                 if (openNewInset(bv, new InsetFormula))
959                         bv->theLockingInset()->localDispatch(bv, LFUN_MATH_DELIM, arg);
960         }
961 }
962
963
964 void mathDispatchInsertMatrix(BufferView * bv, string const & arg)
965 {
966         if (bv->available()) {
967                 if (openNewInset(bv, new InsetFormula))
968                         bv->theLockingInset()->localDispatch(bv, LFUN_INSERT_MATRIX, arg);
969         }
970 }
971
972
973 void mathDispatchInsertMath(BufferView * bv, string const & arg)
974 {
975         if (bv->available()) {
976                 if (arg.size() && arg[0] == '\\') {
977                         InsetFormula * f = new InsetFormula(arg);
978                         if (!bv->insertInset(f))
979                                 delete f;
980                         else if (!mathcursor) // hotfix
981                                 bv->getLyXText()->cursorRight(bv);
982                 } else {
983                         mathDispatchMathMode(bv, arg);
984                 }
985         }
986 }
987
988
989 void mathDispatchGreek(BufferView * bv, string const & arg)
990 {
991         if (bv->available()) {
992                 InsetFormula * f = new InsetFormula;
993                 if (openNewInset(bv, f)) {
994                         bv->theLockingInset()->localDispatch(bv, LFUN_GREEK, arg);
995                         bv->unlockInset(f);
996                 }
997         }
998 }
999
1000
1001 void mathDispatch(BufferView *, kb_action, string const &)
1002 {}