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