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