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