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