]> git.lyx.org Git - features.git/blob - src/mathed/formula.C
mathed64.diff
[features.git] / src / mathed / formula.C
1 /*
2 *  File:        formula.C
3 *  Purpose:     Implementation of formula inset
4 *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5 *  Created:     January 1996
6 *  Description: Allows the edition of math paragraphs inside Lyx.
7 *
8 *  Copyright: 1996-1998 Alejandro Aguilar Sierra
9 *
10 *  Version: 0.4, Lyx project.
11 *
12 *   You are free to use and modify this code under the terms of
13 *   the GNU General Public Licence version 2 or later.
14 */
15
16 #include <config.h>
17
18 #include "Lsstream.h"
19
20 #ifdef __GNUG__
21 #pragma implementation
22 #endif
23
24 #include "formula.h"
25 #include "commandtags.h"
26 #include "math_cursor.h"
27 #include "math_parser.h"
28 #include "lyx_main.h"
29 #include "BufferView.h"
30 #include "lyxtext.h"
31 #include "gettext.h"
32 #include "LaTeXFeatures.h"
33 #include "debug.h"
34 #include "lyx_gui_misc.h"
35 #include "support/LOstream.h"
36 #include "LyXView.h"
37 #include "Painter.h"
38 #include "font.h"
39 #include "support/lyxlib.h"
40 #include "lyxrc.h"
41 #include "math_inset.h"
42 #include "math_parinset.h"
43 #include "math_matrixinset.h"
44 #include "math_rowst.h"
45 #include "math_spaceinset.h"
46 #include "math_deliminset.h"
47 #include "mathed/support.h"
48 #include "lyxfunc.h"
49
50 using std::ostream;
51 using std::istream;
52 using std::pair;
53 using std::endl;
54 using std::vector;
55 using std::max;
56
57 extern string mathed_label;
58
59 extern char const * latex_special_chars;
60
61 int greek_kb_flag = 0;
62 extern char const * latex_mathenv[];
63
64 // this is only used by Whichfont and mathed_init_fonts (Lgb)
65 LyXFont * Math_Fonts = 0;
66
67
68 MathedCursor * mathcursor = 0;
69
70
71 namespace {
72
73 LyXFont::FONT_SIZE lfont_size = LyXFont::SIZE_NORMAL;
74
75 // local global
76 int sel_x;
77 int sel_y;
78 bool sel_flag;
79
80 int mathed_write(MathParInset *, std::ostream &, bool fragile,
81                  string const & label = string());
82
83 void mathed_init_fonts();
84
85 void mathedValidate(LaTeXFeatures & features, MathParInset * par);
86
87 } // namespaces
88
89
90
91 LyXFont WhichFont(short type, int size)
92 {
93         LyXFont f;
94         
95         if (!Math_Fonts)
96                 mathed_init_fonts();
97
98         switch (type) {
99         case LM_TC_SYMB:        
100                 f = Math_Fonts[2];
101                 break;
102
103         case LM_TC_BSYM:        
104                 f = Math_Fonts[2];
105                 break;
106
107         case LM_TC_VAR:
108         case LM_TC_IT:
109                 f = Math_Fonts[0];
110                 break;
111
112         case LM_TC_BF:
113                 f = Math_Fonts[3];
114                 break;
115
116         case LM_TC_SF:
117                 f = Math_Fonts[7];
118                 break;
119
120         case LM_TC_CAL:
121                 f = Math_Fonts[4];
122                 break;
123
124         case LM_TC_TT:
125                 f = Math_Fonts[5];
126                 break;
127
128         case LM_TC_SPECIAL: //f = Math_Fonts[0]; break;
129         case LM_TC_TEXTRM:
130         case LM_TC_RM:
131                 f = Math_Fonts[6];
132                 break;
133
134         default:
135                 f = Math_Fonts[1];
136                 break;
137         }
138
139         f.setSize(lfont_size);
140
141         switch (size) {
142         case LM_ST_DISPLAY:
143                 if (type == LM_TC_BSYM) {
144                         f.incSize();
145                         f.incSize();
146                 }
147                 break;
148
149         case LM_ST_TEXT:
150                 break;
151
152         case LM_ST_SCRIPT:
153                 f.decSize();
154                 break;
155
156         case LM_ST_SCRIPTSCRIPT:
157                 f.decSize();
158                 f.decSize();
159                 break;
160
161         default:
162                 lyxerr << "Mathed Error: wrong font size: " << size << endl;
163                 break;
164         }
165
166         if (type != LM_TC_TEXTRM)
167                 f.setColor(LColor::math);
168
169         return f;
170 }
171
172
173 namespace {
174
175 void mathed_init_fonts() //removed 'static' because DEC cxx does not
176 //like it (JMarc)
177 // Probably because this func is declared as a friend in math_defs.h
178 // Lgb
179 {
180         Math_Fonts = new LyXFont[8]; //DEC cxx cannot initialize all fonts
181         //at once (JMarc) rc
182
183         for (int i = 0 ; i < 8 ; ++i) {
184                 Math_Fonts[i] = LyXFont(LyXFont::ALL_SANE);
185         }
186
187         Math_Fonts[0].setShape(LyXFont::ITALIC_SHAPE);
188
189         Math_Fonts[1].setFamily(LyXFont::SYMBOL_FAMILY);
190
191         Math_Fonts[2].setFamily(LyXFont::SYMBOL_FAMILY);
192         Math_Fonts[2].setShape(LyXFont::ITALIC_SHAPE);
193
194         Math_Fonts[3].setSeries(LyXFont::BOLD_SERIES);
195
196         Math_Fonts[4].setFamily(LyXFont::SANS_FAMILY);
197         Math_Fonts[4].setShape(LyXFont::ITALIC_SHAPE);
198
199         Math_Fonts[5].setFamily(LyXFont::TYPEWRITER_FAMILY);
200
201         Math_Fonts[6].setFamily(LyXFont::ROMAN_FAMILY);
202
203         Math_Fonts[7].setFamily(LyXFont::SANS_FAMILY);
204
205         LyXFont f = WhichFont(LM_TC_VAR, LM_ST_TEXT);
206         MathedInset::defaultAscent(lyxfont::maxAscent(f));
207         MathedInset::defaultDescent(lyxfont::maxDescent(f));
208         MathedInset::defaultWidth(lyxfont::width('I', f));
209 }
210
211 } // namespace anon
212
213
214 // quite a hack i know. Should be done with return values...
215 int number_of_newlines = 0;
216
217
218 InsetFormula::InsetFormula(bool display)
219 {
220         par = new MathParInset; // this leaks
221         //  mathcursor = 0;
222         disp_flag_ = display;
223         if (disp_flag_) {
224                 par->SetType(LM_OT_PAR);
225                 par->SetStyle(LM_ST_DISPLAY);
226         }
227 }
228
229
230 InsetFormula::InsetFormula(MathParInset * p)
231 {
232         if (is_matrix_type(p->GetType()))
233                 lyxerr << "InsetFormula::InsetFormula: This shouldn't happen" << endl;
234
235         par = is_multiline(p->GetType()) ?
236                 new MathMatrixInset(*static_cast<MathMatrixInset*>(p)):
237                 new MathParInset(*p);
238         //   mathcursor = 0;
239
240         disp_flag_ = par->GetType() > 0;
241 }
242
243
244 InsetFormula::~InsetFormula()
245 {
246 #ifdef WITH_WARNINGS
247 #warning leak this for a while...
248 #endif
249         //delete par;
250 }
251
252
253 Inset * InsetFormula::Clone(Buffer const &) const
254 {
255         return new InsetFormula(par);
256 }
257
258
259 void InsetFormula::Write(Buffer const * buf, ostream & os) const
260 {
261         os << "Formula ";
262         Latex(buf, os, false, false);
263 }
264
265
266 int InsetFormula::Latex(Buffer const *, ostream & os, bool fragile, bool) const
267 {
268         return mathed_write(par, os, fragile, par->label()); 
269 }
270
271
272 int InsetFormula::Ascii(Buffer const *, ostream & os, int) const
273 {
274         par->Write(os, false);
275         return 0;
276 }
277
278
279 int InsetFormula::Linuxdoc(Buffer const * buf, ostream & os) const
280 {
281         return Ascii(buf, os, 0);
282 }
283
284
285 int InsetFormula::DocBook(Buffer const * buf, ostream & os) const
286 {
287         return Ascii(buf, os, 0);
288 }
289
290
291 // Check if uses AMS macros
292 void InsetFormula::Validate(LaTeXFeatures & features) const
293 {
294         if (is_ams(par->GetType()))
295                 features.amsstyle = true;
296
297         // Validation is necessary only if not using AMS math.
298         // To be safe, we will always run mathedValidate.
299         //if (!features.amsstyle)
300         mathedValidate(features, par);
301 }
302
303
304 void InsetFormula::Read(Buffer const *buffer, LyXLex & lex)
305 {
306         istream & is = lex.getStream();
307
308         mathed_parser_file(is, lex.GetLineNo());
309
310         MathedArray ar;
311         mathed_parse(ar, par, 0);
312         if (par->isMatrix()) {
313                 //lyxerr << "################## InsetFormula::Read: IsMatrix\n";
314                 static_cast<MathMatrixInset*>(par)->setData(ar);
315         }
316         else {
317                 par->setData(ar);
318                 //lyxerr << "################## InsetFormula::Read: keine Matrix\n";
319         }
320
321         //lyxerr << "InsetFormula::Read: par: " << par << " " << par->GetData() << endl;
322
323         par->Metrics();
324         disp_flag_ = (par->GetType() > 0);
325
326         // Update line number
327         lex.setLineNo(mathed_parser_lineno());
328
329         // reading of end_inset in the inset!!!
330         while (lex.IsOK()) {
331                 lex.nextToken();
332                 if (lex.GetString() == "\\end_inset")
333                         break;
334                 lyxerr << "InsetFormula::Read: Garbage before \\end_inset,"
335                         " or missing \\end_inset!" << endl;
336         }
337
338         if (lyxerr.debugging(Debug::MATHED))
339                 Write(buffer, lyxerr);
340 }
341
342
343 int InsetFormula::ascent(BufferView *, LyXFont const &) const
344 {
345         return par->Ascent() + (disp_flag_ ? 8 : 1);
346 }
347
348
349 int InsetFormula::descent(BufferView *, LyXFont const &) const
350 {
351         return par->Descent() + (disp_flag_ ? 8 : 1);
352 }
353
354
355 int InsetFormula::width(BufferView * bv, LyXFont const & f) const
356 {
357         MathedInset::workWidth = bv->workWidth();
358         lfont_size = f.size();
359         par->Metrics();
360         return par->Width(); //+2;
361 }
362
363
364 void InsetFormula::draw(BufferView * bv, LyXFont const & f,
365                         int baseline, float & x, bool) const
366 {
367         MathedInset::workWidth = bv->workWidth();
368         Painter & pain = bv->painter();
369         // Seems commenting out solves a problem.
370         LyXFont font = mathed_get_font(LM_TC_TEXTRM, LM_ST_TEXT);
371         font.setSize(f.size());
372         lfont_size = font.size();
373         /// Let's try to wait a bit with this... (Lgb)
374         //UpdatableInset::draw(pain, font, baseline, x);
375
376         // otherwise a segfault could occur
377         // in some XDrawRectangles (i.e. matrix) (Matthias)
378         if (mathcursor && mathcursor->GetPar() == par) {
379                 if (mathcursor->Selection()) {
380                         int n;
381                         int * xp = 0;
382                         int * yp = 0;
383                         mathcursor->SelGetArea(&xp, &yp, n);
384                         pain.fillPolygon(xp, yp, n, LColor::selection);
385                 }
386                 mathcursor->draw(pain, int(x), baseline);
387         } else {
388                 par->draw(pain, int(x), baseline);
389         }
390         x += float(width(bv, font));
391
392         if (is_numbered(par->GetType())) {
393                 LyXFont wfont = WhichFont(LM_TC_BF, par->size());
394                 wfont.setLatex(LyXFont::OFF);
395
396                 if (is_singlely_numbered(par->GetType())) {
397                         string str;
398                         if (!par->label().empty())
399                                 str = string("(") + par->label() + ")";
400                         else
401                                 str = string("(#)");
402                         pain.text(int(x + 20), baseline, str, wfont);
403                 } else {
404                         MathedRowContainer::iterator crow = par->getRowSt().begin();
405                         while (crow) {
406                                 int const y = baseline + crow->getBaseline();
407                                 if (crow->isNumbered()) {
408                                         string str;
409                                         if (!crow->getLabel().empty())
410                                                 str = string("(") + crow->getLabel() + ")";
411                                         else
412                                                 str = "(#)";
413                                         pain.text(int(x + 20), y, str, wfont);
414                                 }
415                                 ++crow;
416                         }
417                 }
418         }
419         setCursorVisible(false);
420 }
421
422
423 string const InsetFormula::EditMessage() const
424 {
425         return _("Math editor mode");
426 }
427
428
429 void InsetFormula::Edit(BufferView * bv, int x, int y, unsigned int)
430 {
431         mathcursor = new MathedCursor(par);
432
433         if (!bv->lockInset(this))
434                 lyxerr[Debug::MATHED] << "Cannot lock inset!!!" << endl;
435
436         par->Metrics();
437         bv->updateInset(this, false);
438         x += par->xo();
439         y += par->yo();
440         mathcursor->SetPos(x, y);
441         sel_x = 0;
442         sel_y = 0;
443         sel_flag = false;
444 }
445
446
447 void InsetFormula::InsetUnlock(BufferView * bv)
448 {
449         if (mathcursor) {
450                 if (mathcursor->InMacroMode()) {
451                         mathcursor->MacroModeClose();
452                         UpdateLocal(bv);
453                 }
454                 delete mathcursor;
455         }
456         mathcursor = 0;
457         bv->updateInset(this, false);
458 }
459
460
461 // Now a symbol can be inserted only if the inset is locked
462 void InsetFormula::InsertSymbol(BufferView *, string const & s)
463 {
464         if (s.empty() || !mathcursor)
465                 return;
466         mathcursor->Interpret(s);
467         // Andre: UpdateLocal(bv);
468 }
469
470
471 void InsetFormula::GetCursorPos(BufferView *, int & x, int & y) const
472 {
473         mathcursor->GetPos(x, y);
474         x -= par->xo();
475         y -= par->yo();
476 }
477
478
479 void InsetFormula::ToggleInsetCursor(BufferView * bv)
480 {
481         if (!mathcursor)
482                 return;
483
484         int x;
485         int y;
486         mathcursor->GetPos(x, y);
487         //  x -= par->xo;
488         y -= par->yo();
489         LyXFont font = WhichFont(LM_TC_TEXTRM, LM_ST_TEXT);
490         int const asc = lyxfont::maxAscent(font);
491         int const desc = lyxfont::maxDescent(font);
492
493         if (isCursorVisible())
494                 bv->hideLockedInsetCursor();
495         else
496                 bv->showLockedInsetCursor(x, y, asc, desc);
497
498         toggleCursorVisible();
499 }
500
501
502 void InsetFormula::ShowInsetCursor(BufferView * bv, bool)
503 {
504         if (!isCursorVisible()) {
505                 if (mathcursor) {
506                         int x;
507                         int y;
508                         mathcursor->GetPos(x, y);
509                         //  x -= par->xo;
510                         y -= par->yo();
511                         LyXFont font = WhichFont(LM_TC_TEXTRM, LM_ST_TEXT);
512                         int const asc = lyxfont::maxAscent(font);
513                         int const desc = lyxfont::maxDescent(font);
514                         bv->fitLockedInsetCursor(x, y, asc, desc);
515                 }
516                 ToggleInsetCursor(bv);
517         }
518 }
519
520
521 void InsetFormula::HideInsetCursor(BufferView * bv)
522 {
523         if (isCursorVisible())
524                 ToggleInsetCursor(bv);
525 }
526
527
528 void InsetFormula::ToggleInsetSelection(BufferView * bv)
529 {
530         if (!mathcursor)
531                 return;
532
533         bv->updateInset(this, false);
534 }
535
536
537 void InsetFormula::display(bool dspf)
538 {
539         if (dspf != disp_flag_) {
540                 if (dspf) {
541                         par->SetType(LM_OT_PAR);
542                         par->SetStyle(LM_ST_DISPLAY);
543                 } else {
544                         if (is_multiline(par->GetType())) {
545                                 if (mathcursor)
546                                         mathcursor->SetPar(par);
547                         }
548                         par->SetType(LM_OT_MIN);
549                         par->SetStyle(LM_ST_TEXT);
550 #ifdef WITH_WARNINGS
551 #warning Labels
552 #endif
553 /*
554                         if (!label_.empty()) {
555                                 label_.erase();
556                         }
557 */
558                 }
559                 disp_flag_ = dspf;
560         }
561 }
562
563
564 vector<string> const InsetFormula::getLabelList() const
565 {
566         vector<string> label_list;
567         MathedRowContainer::iterator crow = par->getRowSt().begin();
568         for ( ; crow; ++crow)
569                 label_list.push_back(crow->getLabel());
570
571         return label_list;
572 }
573
574
575 void InsetFormula::UpdateLocal(BufferView * bv)
576 {
577         par->Metrics();  // To inform lyx kernel the exact size
578         // (there were problems with arrays).
579         bv->updateInset(this, true);
580 }
581
582
583 void InsetFormula::InsetButtonRelease(BufferView * bv,
584                                       int x, int y, int /*button*/)
585 {
586         if (mathcursor) {
587                 HideInsetCursor(bv);
588                 x += par->xo();
589                 y += par->yo();
590                 mathcursor->SetPos(x, y);
591                 ShowInsetCursor(bv);
592                 if (sel_flag) {
593                         sel_flag = false;
594                         sel_x = sel_y = 0;
595                         bv->updateInset(this, false);
596                 }
597         }
598 }
599
600
601 void InsetFormula::InsetButtonPress(BufferView * bv, int x, int y,
602                                     int /*button*/)
603 {
604         sel_flag = false;
605         sel_x = x;
606         sel_y = y;
607         if (mathcursor && mathcursor->Selection()) {
608                 mathcursor->SelClear();
609                 bv->updateInset(this, false);
610         }
611 }
612
613
614 void InsetFormula::InsetMotionNotify(BufferView * bv,
615                                      int x, int y, int /*button*/)
616 {
617         if (sel_x && sel_y && abs(x-sel_x) > 4 && !sel_flag) {
618                 sel_flag = true;
619                 HideInsetCursor(bv);
620                 mathcursor->SetPos(sel_x + par->xo(), sel_y + par->yo());
621                 mathcursor->SelStart();
622                 ShowInsetCursor(bv);
623                 mathcursor->GetPos(sel_x, sel_y);
624         } else if (sel_flag) {
625                 HideInsetCursor(bv);
626                 x += par->xo();
627                 y += par->yo();
628                 mathcursor->SetPos(x, y);
629                 ShowInsetCursor(bv);
630                 mathcursor->GetPos(x, y);
631                 if (sel_x != x || sel_y != y)
632                         bv->updateInset(this, false);
633                 sel_x = x;
634                 sel_y = y;
635         }
636 }
637
638
639 void InsetFormula::InsetKeyPress(XKeyEvent *)
640 {
641         lyxerr[Debug::MATHED] << "Used InsetFormula::InsetKeyPress." << endl;
642 }
643
644
645 // Special Mathed functions
646 bool InsetFormula::SetNumber(bool numbf)
647 {
648         if (disp_flag_) {
649                 short type = par->GetType();
650                 bool const oldf = is_numbered(type);
651                 if (numbf && !oldf)
652                         ++type;
653                 if (!numbf && oldf)
654                         --type;
655                 par->SetType(type);
656                 return oldf;
657         } else
658                 return false;
659 }
660
661
662 UpdatableInset::RESULT
663 InsetFormula::LocalDispatch(BufferView * bv, kb_action action,
664                             string const & arg)
665 {
666         //lyxerr << "InsetFormula::LocalDispatch: act: " << action
667         //      << " arg: '" << arg << "' cursor: " << mathcursor << "\n";
668         //   extern char *dispatch_result;
669
670         if (!mathcursor) {
671                 return UNDISPATCHED;
672         }
673
674         MathedTextCodes varcode = LM_TC_MIN;
675         bool was_macro = mathcursor->InMacroMode();
676         bool sel = false;
677         bool space_on = false;
678         bool was_selection = mathcursor->Selection();
679         RESULT result = DISPATCHED;
680         static MathSpaceInset * sp= 0;
681
682         HideInsetCursor(bv);
683
684         if (mathcursor->getLastCode() == LM_TC_TEX) {
685                 varcode = LM_TC_TEX;
686         }
687
688         switch (action) {
689                 // --- Cursor Movements ---------------------------------------------
690         case LFUN_RIGHTSEL:
691                 sel = true; // fall through...
692
693         case LFUN_RIGHT:
694                 result = DISPATCH_RESULT(mathcursor->Right(sel));
695                 if (!sel && (result == DISPATCHED))
696                         result = DISPATCHED_NOUPDATE;
697                 UpdateLocal(bv);
698                 break;
699
700
701         case LFUN_LEFTSEL:
702                 sel = true; // fall through
703
704         case LFUN_LEFT:
705                 result = DISPATCH_RESULT(mathcursor->Left(sel));
706                 if (!sel && (result == DISPATCHED))
707                         result = DISPATCHED_NOUPDATE;
708                 UpdateLocal(bv);
709                 break;
710
711
712         case LFUN_UPSEL:
713                 sel = true;
714
715         case LFUN_UP:
716                 result = DISPATCH_RESULT(mathcursor->Up(sel));
717                 if (!sel && (result == DISPATCHED))
718                         result = DISPATCHED_NOUPDATE;
719                 UpdateLocal(bv);
720                 break;
721
722
723         case LFUN_DOWNSEL:
724                 sel = true;
725
726         case LFUN_DOWN:
727                 result = DISPATCH_RESULT(mathcursor->Down(sel));
728                 if (!sel && (result == DISPATCHED))
729                         result = DISPATCHED_NOUPDATE;
730                 UpdateLocal(bv);
731                 break;
732
733
734         case LFUN_HOME:
735                 mathcursor->Home();
736                 result = DISPATCHED_NOUPDATE;
737                 break;
738
739         case LFUN_END:
740                 mathcursor->End();
741                 result = DISPATCHED_NOUPDATE;
742                 break;
743
744         case LFUN_DELETE_LINE_FORWARD:
745                 bv->lockedInsetStoreUndo(Undo::DELETE);
746                 mathcursor->DelLine();
747                 // Andre:
748                 UpdateLocal(bv);
749                 break;
750
751         case LFUN_BREAKLINE: 
752         {
753                 bv->lockedInsetStoreUndo(Undo::INSERT);
754                 byte c = arg.empty() ? '1' : arg[0];
755                 mathcursor->Insert(c, LM_TC_CR);
756 #ifdef WITH_WARNINGS
757 #warning Labels
758 #endif
759 /*
760                 if (!par->label().empty()) {
761                         mathcursor->setLabel(label_);
762                         label_.erase();
763                 }
764 */
765                 par = mathcursor->GetPar();
766                 // Andre:
767                 UpdateLocal(bv);
768         }
769         break;
770
771         case LFUN_TAB:
772                 bv->lockedInsetStoreUndo(Undo::INSERT);
773                 mathcursor->Insert(0, LM_TC_TAB);
774                 //UpdateInset(this);
775                 break;
776
777         case LFUN_TABINSERT:
778                 bv->lockedInsetStoreUndo(Undo::INSERT);
779                 mathcursor->Insert('T', LM_TC_TAB);
780                 // Andre:
781                 UpdateLocal(bv);
782                 break;
783
784         case LFUN_BACKSPACE:
785                 if (!mathcursor->Left())
786                         break;
787
788                 if (!mathcursor->InMacroMode() && mathcursor->pullArg()) {
789                         bv->updateInset(this, true);
790                         break;
791                 }
792                 // fall through...
793
794         case LFUN_DELETE:
795                 bv->lockedInsetStoreUndo(Undo::DELETE);
796                 mathcursor->Delete();
797                 bv->updateInset(this, true);
798                 break;
799
800                 //    case LFUN_GETXY:
801                 //      sprintf(dispatch_buffer, "%d %d",);
802                 //      dispatch_result = dispatch_buffer;
803                 //      break;
804         case LFUN_SETXY:
805         {
806                 int x;
807                 int y;
808                 int x1;
809                 int y1;
810                 istringstream ist(arg.c_str());
811                 ist >> x >> y;
812                 par->GetXY(x1, y1);
813                 mathcursor->SetPos(x1 + x, y1 + y);
814         }
815         break;
816
817                 /* cursor selection ---------------------------- */
818
819         case LFUN_PASTE:
820                 if (was_macro)
821                         mathcursor->MacroModeClose();
822                 bv->lockedInsetStoreUndo(Undo::INSERT);
823                 mathcursor->SelPaste();
824                 // Andre:
825                 UpdateLocal(bv);
826                 break;
827
828         case LFUN_CUT:
829                 bv->lockedInsetStoreUndo(Undo::DELETE);
830                 mathcursor->SelCut();
831                 // Andre:
832                 UpdateLocal(bv);
833                 break;
834
835         case LFUN_COPY:
836                 mathcursor->SelCopy();
837                 break;
838
839         case LFUN_HOMESEL:
840         case LFUN_ENDSEL:
841         case LFUN_WORDRIGHTSEL:
842         case LFUN_WORDLEFTSEL:
843                 break;
844
845                 // --- accented characters ------------------------------
846
847         case LFUN_UMLAUT:     mathcursor->setAccent(LM_ddot); break;
848         case LFUN_CIRCUMFLEX: mathcursor->setAccent(LM_hat); break;
849         case LFUN_GRAVE:      mathcursor->setAccent(LM_grave); break;
850         case LFUN_ACUTE:      mathcursor->setAccent(LM_acute); break;
851         case LFUN_TILDE:      mathcursor->setAccent(LM_tilde); break;
852         case LFUN_MACRON:     mathcursor->setAccent(LM_bar); break;
853         case LFUN_DOT:        mathcursor->setAccent(LM_dot); break;
854         case LFUN_CARON:      mathcursor->setAccent(LM_check); break;
855         case LFUN_BREVE:      mathcursor->setAccent(LM_breve); break;
856         case LFUN_VECTOR:     mathcursor->setAccent(LM_vec); break;
857
858                 // Greek mode
859         case LFUN_GREEK:
860                 if (!greek_kb_flag) {
861                         greek_kb_flag = 1;
862                         bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Math greek mode on"));
863                 } else
864                         greek_kb_flag = 0;
865                 break;
866
867                 // Greek keyboard
868         case LFUN_GREEK_TOGGLE:
869                 greek_kb_flag = (greek_kb_flag) ? 0 : 2;
870                 if (greek_kb_flag)
871                         bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Math greek keyboard on"));
872                 else
873                         bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Math greek keyboard off"));
874                 break;
875
876                 //  Math fonts
877         case LFUN_BOLD:  mathcursor->toggleLastCode(LM_TC_BF); break;
878         case LFUN_SANS:  mathcursor->toggleLastCode(LM_TC_SF); break;
879         case LFUN_EMPH:  mathcursor->toggleLastCode(LM_TC_CAL); break;
880         case LFUN_ROMAN: mathcursor->toggleLastCode(LM_TC_RM); break;
881         case LFUN_CODE:  mathcursor->toggleLastCode(LM_TC_TT); break;
882         case LFUN_DEFAULT:  mathcursor->setLastCode(LM_TC_VAR); break;
883
884         case LFUN_TEX:
885                 // varcode = LM_TC_TEX;
886                 mathcursor->setLastCode(LM_TC_TEX);
887                 bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("TeX mode"));
888                 break;
889
890         case LFUN_MATH_NUMBER:
891                 bv->lockedInsetStoreUndo(Undo::INSERT);
892                 if (disp_flag_) {
893                         short type = par->GetType();
894                         if (is_numbered(type)) {
895                                 --type;
896 #ifdef WITH_WARNINGS
897 #warning Labels
898 #endif
899 /*
900                                 if (!label_.empty()) {
901                                         label_.erase();
902                                 }
903 */
904                                 bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("No number"));
905                         } else {
906                                 ++type;
907                                 bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("Number"));
908                         }
909                         par->SetType(type);
910                         // Andre:
911                         UpdateLocal(bv);
912                 }
913                 break;
914
915         case LFUN_MATH_NONUMBER:
916                 if (is_multi_numbered(par->GetType())) {
917                                 //BUG
918                                 //         par->SetNumbered(!par->IsNumbered());
919
920 #ifdef WITH_WARNINGS
921 #warning This is a terrible hack! We should find a better solution.
922 #endif
923                         while (mathcursor->getLabel() == MathedXIter::error_label) {
924                                 if (LocalDispatch(bv, LFUN_LEFT, string()) == FINISHED)
925                                         return DISPATCHED;
926                         }
927                         mathcursor->setNumbered();
928                         // Andre:
929                         UpdateLocal(bv);
930                 }
931                 break;
932
933         case LFUN_MATH_LIMITS:
934                 bv->lockedInsetStoreUndo(Undo::INSERT);
935                 if (mathcursor->Limits())
936                         // Andre:
937                         UpdateLocal(bv);
938                 // fall through!
939
940         case LFUN_MATH_SIZE:
941                 if (!arg.empty()) {
942                         latexkeys const * l = in_word_set(arg);
943                         int const sz = l ? l->id : -1;
944                         mathcursor->SetSize(sz);
945                         // Andre:
946                         UpdateLocal(bv);
947                         break;
948                 }
949                 // possible fall through?
950
951         case LFUN_INSERT_MATH:
952                 bv->lockedInsetStoreUndo(Undo::INSERT);
953                 InsertSymbol(bv, arg);
954                 break;
955
956
957         case LFUN_INSERT_MATRIX:
958         {
959                 bv->lockedInsetStoreUndo(Undo::INSERT);
960                 char s[80];
961                 char arg2[80];
962                 // This is just so that too long args won't ooze out of s.
963                 strncpy(arg2, arg.c_str(), 80);
964                 arg2[79]= '\0';
965                 int m;
966                 int n;
967                 int const k = sscanf(arg2, "%d %d %s", &m, &n, s);
968                 s[79] = '\0';
969
970                 if (k < 1) {
971                         m = n = 1;
972                 } else if (k == 1) {
973                         n = 1;
974                 }
975
976                 if (mathcursor) {
977                         MathMatrixInset * p = new MathMatrixInset(m, n);
978                         if (k > 2 && int(strlen(s)) > m)
979                                 p->SetAlign(s[0], &s[1]);
980                         mathcursor->insertInset(p, LM_TC_ACTIVE_INSET);
981                         // Andre:
982                         UpdateLocal(bv);
983                 }
984                 break;
985         }
986
987         case LFUN_MATH_DELIM:
988         {
989                 bv->lockedInsetStoreUndo(Undo::INSERT);
990                 char lf[40];
991                 char rg[40];
992                 char arg2[40];
993                 int ilf = '(';
994                 int irg = '.';
995                 latexkeys const * l;
996                 string vdelim("(){}[]./|");
997
998                 if (arg.empty())
999                         break;
1000                 ::strncpy(arg2, arg.c_str(), 40);
1001                 arg2[39]= '\0';
1002                 int const n = sscanf(arg2, "%s %s", lf, rg);
1003                 lf[39] = '\0';
1004                 rg[39] = '\0';
1005
1006                 if (n > 0) {
1007                         if (isdigit(lf[0]))
1008                                 ilf = lyx::atoi(lf);
1009                         else
1010                                 if (lf[1]) {
1011                                         l = in_word_set(lf, strlen(lf));
1012                                         // Long words will cause l == 0; so check.
1013                                         if (l)
1014                                                 ilf = l->id;
1015                                 } else if (vdelim.find(lf[0]) != string::npos)
1016                                         ilf = lf[0];
1017
1018                         if (n > 1) {
1019                                 if (isdigit(rg[0]))
1020                                         irg = lyx::atoi(rg);
1021                                 else
1022                                         if (rg[1]) {
1023                                                 l = in_word_set(rg, strlen(rg));
1024                                                 if (l)
1025                                                         irg = l->id;
1026                                         } else if (vdelim.find(rg[0]) != string::npos)
1027                                                 irg = rg[0];
1028                         }
1029                 }
1030
1031                 MathDelimInset * p = new MathDelimInset(ilf, irg);
1032                 mathcursor->insertInset(p, LM_TC_ACTIVE_INSET);
1033                 // Andre:
1034                 UpdateLocal(bv);
1035                 break;
1036         }
1037
1038         case LFUN_PROTECTEDSPACE:
1039                 bv->lockedInsetStoreUndo(Undo::INSERT);
1040                 sp = new MathSpaceInset(1);
1041                 mathcursor->insertInset(sp, LM_TC_INSET);
1042                 space_on = true;
1043                 // Andre:
1044                 UpdateLocal(bv);
1045                 break;
1046
1047         case LFUN_INSERT_LABEL:
1048         {
1049                 bv->lockedInsetStoreUndo(Undo::INSERT);
1050                 if (par->GetType() < LM_OT_PAR)
1051                         break;
1052
1053                 string old_label = is_multiline(par->GetType())
1054                         ? mathcursor->getLabel() : par->label();
1055
1056 #ifdef WITH_WARNINGS
1057 #warning This is a terrible hack! We should find a better solution.
1058 #endif
1059                 // This is needed because in some positions
1060                 // mathcursor->cursor->crow is equal to 0, and therefore
1061                 // the label cannot be inserted.
1062                 // So we move the cursor left until
1063                 // mathcursor->cursor->crow != 0.
1064                 while (old_label == MathedXIter::error_label) {
1065                         if (LocalDispatch(bv, LFUN_LEFT, string()) == FINISHED)
1066                                 return DISPATCHED;
1067                         old_label = mathcursor->getLabel();
1068                 }
1069
1070                 string new_label = arg;
1071                 if (new_label.empty()) {
1072                         string const default_label =
1073                                 (lyxrc.label_init_length >= 0) ? "eq:" : "";
1074                         pair<bool, string> const res = old_label.empty()
1075                                 ? askForText(_("Enter new label to insert:"),
1076                                              default_label)
1077                                 : askForText(_("Enter label:"), old_label);
1078                         if (!res.first)
1079                                 break;
1080                         new_label = frontStrip(strip(res.second));
1081                 }
1082
1083                 if (new_label == old_label)
1084                         break;  // Nothing to do
1085
1086                 if (!new_label.empty())
1087                         SetNumber(true);
1088
1089                 if (!new_label.empty() && bv->ChangeRefsIfUnique(old_label, new_label))
1090                         bv->redraw();
1091
1092 #ifdef WITH_WARNINGS
1093 #warning Labels
1094 #endif
1095 /*
1096                 if (is_multi_numbered(par->GetType())) {
1097                         mathcursor->setLabel(new_label);
1098                         // par->SetLabel(new_label);
1099                 } else
1100                         label_ = new_label;
1101 */
1102
1103                 // Andre:
1104                 UpdateLocal(bv);
1105                 break;
1106         }
1107
1108         case LFUN_MATH_DISPLAY:
1109                 bv->lockedInsetStoreUndo(Undo::EDIT);
1110                 display(!disp_flag_);
1111                 // Andre:
1112                 UpdateLocal(bv);
1113                 break;
1114
1115                 // Invalid actions under math mode
1116         case LFUN_MATH_MODE:
1117                 if (mathcursor->getLastCode()!= LM_TC_TEXTRM) {
1118                         bv->owner()->getLyXFunc()
1119                                 ->Dispatch(LFUN_MESSAGE, _("math text mode"));
1120                         varcode = LM_TC_TEXTRM;
1121                 } else {
1122                         varcode = LM_TC_VAR;
1123                 }
1124                 mathcursor->setLastCode(varcode);
1125                 break;
1126
1127         case LFUN_UNDO:
1128                 bv->owner()->getLyXFunc()
1129                         ->Dispatch(LFUN_MESSAGE,
1130                                    _("Invalid action in math mode!"));
1131                 break;
1132
1133                 //------- dummy actions
1134 #ifdef WITH_WARNINGS
1135 #warning Is this needed here? Shouldnt the main dispatch handle this? (Lgb)
1136 #endif
1137                 //case LFUN_EXEC_COMMAND:
1138                 //bv->owner()->getMiniBuffer()->PrepareForCommand();
1139                 //break;
1140
1141         default:
1142                 if ((action == -1  || action == LFUN_SELFINSERT)
1143                     && !arg.empty())  {
1144                         unsigned char c = arg[0];
1145                         bv->lockedInsetStoreUndo(Undo::INSERT);
1146
1147                         if (c == ' ' && mathcursor->getAccent() == LM_hat) {
1148                                 c = '^';
1149                                 mathcursor->setAccent(0);
1150                         }
1151
1152                         if (c == 0) {      // Dead key, do nothing
1153                                 //lyxerr << "deadkey" << endl;
1154                                 break;
1155                         }
1156
1157                         if (isalpha(c)) {
1158                                 if (mathcursor->getLastCode() == LM_TC_TEX) {
1159                                         mathcursor->MacroModeOpen();
1160                                         mathcursor->clearLastCode();
1161                                         varcode = LM_TC_MIN;
1162                                 } else if (!varcode) {          
1163                                         short f = (mathcursor->getLastCode()) ?
1164                                                 mathcursor->getLastCode() :
1165                                                 static_cast<MathedTextCodes>(mathcursor->GetFCode());
1166                                         varcode = MathIsAlphaFont(f) ?
1167                                                 static_cast<MathedTextCodes>(f) :
1168                                                 LM_TC_VAR;
1169                                 }
1170                                 
1171                                 //           lyxerr << "Varcode << vardoce;
1172                                 MathedTextCodes char_code = varcode;
1173                                 if (greek_kb_flag) {
1174                                         char greek[26] =
1175                                         {'A', 'B', 'X',  0 , 'E',  0 ,  0 , 'H', 'I',  0 ,
1176                                          'K',  0 , 'M', 'N', 'O',  0 ,  0 , 'P',  0 , 'T',
1177                                          'Y',  0,   0,   0,   0 , 'Z' };
1178                                         
1179                                         if ('A' <= c && c <= 'Z' && greek[c - 'A']) {
1180                                                 char_code = LM_TC_RM;
1181                                                 c = greek[c - 'A'];
1182                                         } else
1183                                                 char_code = LM_TC_SYMB;
1184                                 }
1185                                 
1186                                 mathcursor->Insert(c, char_code);
1187                                 
1188                                 if (greek_kb_flag && char_code == LM_TC_RM )
1189                                         mathcursor->setLastCode(LM_TC_VAR);
1190                                 
1191                                 varcode = LM_TC_MIN;
1192                                 
1193                                 if (greek_kb_flag < 2)
1194                                         greek_kb_flag = 0;
1195                                 
1196                         } else if (strchr("!,:;{}", c) && (varcode == LM_TC_TEX||was_macro)) {
1197                                 mathcursor->Insert(c, LM_TC_TEX);
1198                                 if (c == '{') {
1199                                         mathcursor->Insert('}', LM_TC_TEX);
1200                                         mathcursor->Left();
1201                                 }
1202                                 mathcursor->clearLastCode();
1203                                 //             varcode = LM_TC_MIN;
1204                         } else if (c == '_' && varcode == LM_TC_TEX) {
1205                                 mathcursor->Insert(c, LM_TC_SPECIAL);
1206                                 mathcursor->clearLastCode();
1207                                 //             varcode = LM_TC_MIN;
1208                         } else if (('0'<= c && c<= '9') && (varcode == LM_TC_TEX||was_macro)) {
1209                                 mathcursor->MacroModeOpen();
1210                                 mathcursor->clearLastCode();
1211                                 mathcursor->Insert(c, LM_TC_MIN);
1212                         } else if (('0'<= c && c<= '9') || strchr(";:!|[]().,?", c)) {
1213                                 mathcursor->Insert(c, LM_TC_CONST);
1214                         } else if (strchr("+/-*<>=", c)) {
1215                                 mathcursor->Insert(c, LM_TC_BOP);
1216                         } else if (strchr(latex_special_chars, c) && c!= '_') {
1217                                 mathcursor->Insert(c, LM_TC_SPECIAL);
1218                         } else if (c == '_' || c == '^') {
1219                                 char s[2];
1220                                 s[0] = c;
1221                                 s[1] = 0;
1222                                 mathcursor->Interpret(s);
1223                         } else if (c == ' ') {  
1224                                 if (!varcode) { 
1225                                         short f = (mathcursor->getLastCode()) ?
1226                                                 mathcursor->getLastCode() :
1227                                                 static_cast<MathedTextCodes>(mathcursor->GetFCode());
1228                                         varcode = MathIsAlphaFont(f) ?
1229                                                 static_cast<MathedTextCodes>(f) :
1230                                                 LM_TC_VAR;
1231                                 }
1232                                 
1233                                 if (varcode == LM_TC_TEXTRM) {
1234                                         mathcursor->Insert(c, LM_TC_TEXTRM);
1235                                 } else if (was_macro) {
1236                                         mathcursor->MacroModeClose();
1237                                 } else if (sp) {
1238                                         int isp = (sp->GetSpace()<5) ? sp->GetSpace()+1: 0;
1239                                         sp->SetSpace(isp);
1240                                         space_on = true;
1241                                 } else if (!mathcursor->Pop() && mathcursor->IsEnd())
1242                                         result = FINISHED;
1243                         } else if (c == '\'' || c == '@') {
1244                                 mathcursor->Insert (c, LM_TC_VAR);
1245                         } else if (c == '\\') {
1246                                 if (was_macro)
1247                                         mathcursor->MacroModeClose();
1248                                 // This line nukes the mathcursor. Why?
1249                                 //bv->owner()->getLyXFunc()->Dispatch(LFUN_MESSAGE, _("TeX mode"));
1250                                 mathcursor->setLastCode(LM_TC_TEX);
1251                         }
1252                         // Andre:
1253                         UpdateLocal(bv);
1254                 } else if (action == LFUN_MATH_PANEL) {
1255                         result = UNDISPATCHED;
1256                 } else {
1257                         // lyxerr << "Closed by action " << action << endl;
1258                         result =  FINISHED;
1259                 }
1260         }
1261         
1262         //UpdateLocal(bv);
1263         
1264         // Andre:
1265         if ((mathcursor && was_macro != mathcursor->InMacroMode())
1266             && action >= 0
1267             && action != LFUN_BACKSPACE) 
1268                 UpdateLocal(bv);
1269
1270         if (sp && !space_on)
1271                 sp = 0;
1272
1273         if (mathcursor && (mathcursor->Selection() || was_selection))
1274                 ToggleInsetSelection(bv);
1275
1276         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE ||
1277             result == UNDISPATCHED)
1278                 ShowInsetCursor(bv);
1279         else
1280                 bv->unlockInset(this);
1281
1282         return result;  // original version
1283 }
1284
1285
1286 namespace {
1287
1288 void mathedValidate(LaTeXFeatures & features, MathParInset * par)
1289 {
1290         MathedIter it(&par->GetData());
1291
1292         while (it.OK() && !(features.binom && features.boldsymbol)) {
1293                 if (it.IsInset()) {
1294                         if (it.IsActive()) {
1295                                 MathParInset * p = it.GetActiveInset();
1296                                 if (!features.binom && p->GetType() == LM_OT_MACRO &&
1297                                     p->GetName() == "binom") {
1298                                         features.binom = true;
1299                                 } else {
1300                                         for (int i = 0; i <= p->getMaxArgumentIdx(); ++i) {
1301                                                 p->setArgumentIdx(i);
1302                                                 mathedValidate(features, p);
1303                                         }
1304                                 }
1305                         } else {
1306                                 MathedInset * p = it.GetInset();
1307                                 if (!features.boldsymbol && p->GetName() == "boldsymbol") {
1308                                         features.boldsymbol = true;
1309                                 }
1310                         }
1311                 }
1312                 it.Next();
1313         }
1314 }
1315
1316
1317 int mathed_write(MathParInset * p, ostream & os,
1318                  bool fragile, string const & label)
1319 {
1320         number_of_newlines = 0;
1321         short mathed_env = p->GetType();
1322         
1323         if (mathed_env == LM_OT_MIN) {
1324                 if (fragile) os << "\\protect";
1325                 os << "\\( "; // changed from " \\( " (Albrecht Dress)
1326         } else {
1327                 if (mathed_env == LM_OT_PAR){
1328                         os << "\\[\n";
1329                 } else {
1330                         os << "\\begin{"
1331                            << latex_mathenv[mathed_env]
1332                            << "}";
1333                         if (is_multicolumn(mathed_env)) {
1334                                 if (mathed_env != LM_OT_ALIGNAT
1335                                     && mathed_env != LM_OT_ALIGNATN)
1336                                         os << "%";
1337                                 os << "{" << p->GetColumns()/2 << "}";
1338                         }
1339                         os << "\n";
1340                 }
1341                 ++number_of_newlines;
1342         }
1343         
1344         if (!label.empty() && label[0] > ' '
1345             && is_singlely_numbered(mathed_env)) {
1346                 os << "\\label{"
1347                    << label
1348                    << "}\n";
1349                 ++number_of_newlines;
1350         }
1351         
1352         p->Write(os, fragile);
1353         
1354         if (mathed_env == LM_OT_MIN){
1355                 if (fragile) os << "\\protect";
1356                 os << " \\)";
1357         } else if (mathed_env == LM_OT_PAR) {
1358                 os << "\\]\n";
1359                 ++number_of_newlines;
1360         } else {
1361                 os << "\n\\end{"
1362                    << latex_mathenv[mathed_env]
1363                    << "}\n";
1364                 number_of_newlines += 2;
1365         }
1366         return number_of_newlines;
1367 }
1368
1369 } // namespace anon
1370
1371
1372 /* FIXME: math-greek-toggle seems to work OK, but math-greek doesn't turn
1373  * on greek mode */
1374 bool math_insert_greek(BufferView * bv, char c)
1375 {
1376         if (bv->available() &&
1377             (('A' <= c && c <= 'Z') ||
1378              ('a'<= c && c<= 'z')))   {
1379                 string tmp;
1380                 tmp = c;
1381                 if (!bv->theLockingInset() || bv->theLockingInset()->IsTextInset()) {
1382                         int greek_kb_flag_save = greek_kb_flag;
1383                         InsetFormula * new_inset = new InsetFormula();
1384                         bv->beforeChange(bv->text);
1385                         if (!bv->insertInset(new_inset)) {
1386                                 delete new_inset;
1387                                 return false;
1388                         }
1389 //       Update(1);//BUG
1390                         new_inset->Edit(bv, 0, 0, 0);
1391                         new_inset->LocalDispatch(bv, LFUN_SELFINSERT, tmp);
1392                         if (greek_kb_flag_save < 2) {
1393                                 bv->unlockInset(new_inset); // bv->theLockingInset());
1394                                 bv->text->CursorRight(bv, true);
1395                         }
1396                 } else
1397                         if (bv->theLockingInset()->LyxCode() == Inset::MATH_CODE ||
1398                             bv->theLockingInset()->LyxCode() == Inset::MATHMACRO_CODE)
1399                                 static_cast<InsetFormula*>(bv->theLockingInset())->LocalDispatch(bv, LFUN_SELFINSERT, tmp);
1400                         else
1401                                 lyxerr << "Math error: attempt to write on a wrong "
1402                                         "class of inset." << endl;
1403                 return true;
1404         }
1405         return false;
1406 }