]> git.lyx.org Git - lyx.git/blob - src/mathed/math_macro.C
some small updates to Painter, and make the new painter the default.
[lyx.git] / src / mathed / math_macro.C
1 // -*- C++ -*-
2 /*
3  *  File:        math_macro.C
4  *  Purpose:     Implementation of macro class for mathed 
5  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
6  *  Created:     November 1996
7  *  Description: WYSIWYG math macros
8  *
9  *  Dependencies: Mathed
10  *
11  *  Copyright: (c) 1996, 1997 Alejandro Aguilar Sierra
12  *
13  *  Version: 0.2, Mathed & Lyx project.
14  *
15  *  This code is under the GNU General Public Licence version 2 or later.
16  */
17
18 #include <config.h>
19 #include FORMS_H_LOCATION
20
21 #ifdef __GNUG__
22 #pragma implementation "math_macro.h"
23 #pragma implementation "math_defs.h"
24 #endif
25
26 #include "LString.h"
27 #include "math_macro.h"
28 #include "math_iter.h"
29 #include "math_inset.h"
30 #include "support/lstrings.h"
31 #include "debug.h"
32
33
34 ostream & operator<<(ostream & o, MathedTextCodes mtc)
35 {
36         return o << int(mtc);
37 }
38
39 enum MathedMacroFlag {
40     MMF_Env= 1,
41     MMF_Exp= 2,
42     MMF_Edit= 4
43 };
44
45 ostream & operator<<(ostream & o, MathedMacroFlag mmf)
46 {
47         return o << int(mmf);
48 }
49
50 #ifndef USE_PAINTER
51 extern GC mathGC, mathFrameGC, latexGC;
52 #endif
53 extern int mathed_string_width(short type, int style, byte const* s, int ls);
54 extern int mathed_string_height(short, int, byte const*, int, int&, int&);
55
56
57 MathMacro::MathMacro(MathMacroTemplate* t): 
58     MathParInset(LM_ST_TEXT, "", LM_OT_MACRO), tmplate(t)
59 {
60     nargs = tmplate->getNoArgs();
61     tcode = tmplate->getTCode();
62     args = new MacroArgumentBase[nargs];
63     for (int i = 0; i < nargs; ++i) {
64 //      if (tmplate->getMacroPar(i)->Permit(LMPF_ALLOW_CR))
65 //        args[i].row = new MathedRowSt(tmplate->getMacroPar(i)->GetColumns());
66 //      else 
67           args[i].row = 0;
68 /*      int k = tmplate->getMacroPar(i)->GetColumns();
69         if (k>0) {
70             args[i].array = new LyxArrayBase;
71             for (int j= 0; j<k-1; ++j) args[i].array->Insert(j, LM_TC_TAB);
72         }*/
73     }
74     idx = 0;
75     SetName(tmplate->GetName());
76 }
77
78
79 MathMacro::MathMacro(MathMacro * m): 
80     MathParInset(LM_ST_TEXT, m->GetName(), LM_OT_MACRO)
81 {
82     tmplate = m->tmplate;
83     nargs = tmplate->getNoArgs();
84     tcode = tmplate->getTCode();
85     args = new MacroArgumentBase[nargs];
86     idx = 0;
87     SetName(tmplate->GetName());
88     for (int i = 0; i < tmplate->nargs; ++i) {
89         m->setArgumentIdx(i);
90         MathedIter it(m->GetData());
91         args[i].row = m->args[i].row;
92         args[i].array = it.Copy();
93     }
94 }
95
96 MathMacro::~MathMacro()
97 {
98     for (idx = 0; idx < nargs; ++idx) {
99         MathedIter it(args[idx].array);
100         it. Clear();
101         delete args[idx].row;
102     }
103     delete[] args;
104 }
105
106
107 MathedInset * MathMacro::Clone()
108 {
109     return new MathMacro(this);
110 }
111
112
113 void MathMacro::Metrics()
114 {
115     if (nargs > 0)
116       tmplate->update(this);
117     tmplate->Metrics();
118     width = tmplate->Width();
119     ascent = tmplate->Ascent();
120     descent = tmplate->Descent();
121 }
122
123
124 #ifdef USE_PAINTER
125 void MathMacro::draw(Painter & pain, int x, int y)
126 {
127     xo = x;  yo = y;
128     Metrics();
129     tmplate->update(this);
130     tmplate->SetStyle(size);
131     //mathGC = latexGC;
132     tmplate->draw(pain, x, y);
133     for (int i = 0; i < nargs; ++i)
134       tmplate->GetMacroXY(i, args[i].x, args[i].y);
135 }
136 #else
137 void MathMacro::Draw(int x, int y)
138 {
139     xo = x;  yo = y;
140     Metrics();
141     tmplate->update(this);
142     tmplate->SetStyle(size);
143     mathGC = latexGC;
144     tmplate->Draw(x, y);
145     for (int i = 0; i < nargs; ++i)
146       tmplate->GetMacroXY(i, args[i].x, args[i].y);
147 }
148 #endif
149
150
151 int MathMacro::GetColumns()
152 {
153     return tmplate->getMacroPar(idx)->GetColumns();
154 }
155
156
157 void MathMacro::GetXY(int & x, int & y) const
158 {
159     x = args[idx].x;  y = args[idx].y;
160 }
161
162
163 bool MathMacro::Permit(short f)
164 {
165     return (nargs > 0) ?
166             tmplate->getMacroPar(idx)->Permit(f) : MathParInset::Permit(f);
167 }
168
169
170 void MathMacro::SetFocus(int x, int y)
171 {
172     tmplate->update(this);
173     tmplate->SetMacroFocus(idx, x, y);
174 }
175
176
177 void MathMacro::Write(ostream & os)
178 {
179    string output;
180    MathMacro::Write(output);
181    os << output;
182 }
183
184
185 void MathMacro::Write(string &file)
186 {
187     if (tmplate->flags & MMF_Exp) {
188             lyxerr[Debug::MATHED] << "Expand " << tmplate->flags
189                                   << ' ' << MMF_Exp << endl; 
190         tmplate->update(this);
191         tmplate->Write(file);
192     } else {
193         if (tmplate->flags & MMF_Env) {
194           file += "\\begin{";
195           file += name;
196           file += "} ";
197         } else {
198           file += '\\';
199           file += name;
200         }
201 //      if (options) { 
202 //        file += '[';
203 //        file += options;
204 //        file += ']';
205 //      }
206         
207         if (!(tmplate->flags & MMF_Env) && nargs > 0) 
208           file += '{';
209         
210         for (int i = 0; i < nargs; ++i) {
211             array = args[i].array;
212             MathParInset::Write(file);
213             if (i < nargs - 1)  
214               file += "}{";
215         }   
216         if (tmplate->flags & MMF_Env) {
217             file += "\\end{";
218             file += name;
219             file += '}';
220         } else {
221             if (nargs > 0) 
222                 file += '}';
223             else
224                 file += ' ';
225         }
226     }
227 }
228
229
230
231 /*---------------  Macro argument -----------------------------------*/
232
233 MathMacroArgument::MathMacroArgument(int n)
234 {
235     number = n;
236     expnd_mode = false;
237     SetType(LM_OT_MACRO_ARG);
238 }
239
240
241 #ifdef USE_PAINTER
242 void MathMacroArgument::draw(Painter & pain, int x, int baseline)
243 {
244     if (expnd_mode) {
245         MathParInset::draw(pain, x, baseline);
246     } else {
247         unsigned char s[3];
248         sprintf(reinterpret_cast<char*>(s), "#%d", number);
249         drawStr(pain, LM_TC_TEX, size, x, baseline, &s[0], 2);
250     }
251 }
252 #else
253 void MathMacroArgument::Draw(int x, int baseline)
254 {
255     if (expnd_mode) {
256         MathParInset::Draw(x, baseline);
257     } else {
258         unsigned char s[3];
259         sprintf(reinterpret_cast<char*>(s), "#%d", number);
260         drawStr(LM_TC_TEX, size, x, baseline, &s[0], 2);
261     }
262 }
263 #endif
264
265
266 void MathMacroArgument::Metrics()
267 {
268     if (expnd_mode) {
269         MathParInset::Metrics();
270     } else {
271         unsigned char s[3];
272         sprintf(reinterpret_cast<char*>(s), "#%d", number);
273         width = mathed_string_width(LM_TC_TEX, size, &s[0], 2);
274         mathed_string_height(LM_TC_TEX, size, &s[0], 2, ascent, descent);
275     }
276 }
277
278
279 void MathMacroArgument::Write(ostream & os)
280 {
281    string output;
282    MathMacroArgument::Write(output);
283    os << output;
284 }
285
286
287 void MathMacroArgument::Write(string & file)
288 {
289     if (expnd_mode) {
290         MathParInset::Write(file);
291     } else {
292         file += '#';
293         file += tostr(number);
294         file += ' ';
295     }
296 }
297
298
299 /* --------------------- MathMacroTemplate ---------------------------*/
300
301 MathMacroTemplate::MathMacroTemplate(char const * nm, int na, int flg):
302     MathParInset(LM_ST_TEXT, nm, LM_OT_MACRO), 
303     flags(flg), nargs(na)
304 {
305     if (nargs > 0) {
306         tcode = LM_TC_ACTIVE_INSET;
307         args = new MathMacroArgument[nargs];
308         for (int i = 0; i < nargs; ++i) {
309             args[i].setNumber(i + 1);
310         }
311     } else 
312       tcode = LM_TC_INSET;
313 }
314
315
316 MathMacroTemplate::~MathMacroTemplate()
317 {
318     // prevent to delete already deleted objects
319     for (int i = 0; i < nargs; ++i) {
320         args[i].SetData(0);
321     }
322     delete[] args;
323 }
324
325
326 void MathMacroTemplate::setEditMode(bool ed)
327 {
328     if (ed) {
329         flags |= MMF_Edit;
330         for (int i = 0; i < nargs; ++i) {
331             args[i].setExpand(false);
332         }
333     } else {
334         flags &= ~MMF_Edit;
335         for (int i = 0; i < nargs; ++i) {
336             args[i].setExpand(true);
337         }
338     }
339 }
340
341
342 #ifdef USE_PAINTER
343 void MathMacroTemplate::draw(Painter & pain, int x, int y)
344 {
345     int x2, y2;
346     bool expnd = (nargs > 0) ? args[0].getExpand(): false;
347     if (flags & MMF_Edit) {
348         for (int i = 0; i < nargs; ++i) {
349             args[i].setExpand(false);
350         }
351       x2 = x; y2 = y;
352     } else {
353         for (int i = 0; i < nargs; ++i) {
354             args[i].setExpand(true);
355         }
356       x2 = xo; y2 = yo;
357     }
358     MathParInset::draw(pain, x, y);
359     xo = x2; yo = y2;
360     
361     for (int i = 0; i < nargs; ++i) {
362         args[i].setExpand(expnd);
363     }
364 }
365 #else
366 void MathMacroTemplate::Draw(int x, int y)
367 {
368     int x2, y2;
369     bool expnd = (nargs>0) ? args[0].getExpand(): false;
370     if (flags & MMF_Edit) {
371         for (int i = 0; i < nargs; ++i) {
372             args[i].setExpand(false);
373         }
374       x2 = x; y2 = y;
375     } else {
376         for (int i = 0; i < nargs; ++i) {
377             args[i].setExpand(true);
378         }
379       x2 = xo; y2 = yo;
380     }
381     MathParInset::Draw(x, y);
382     xo = x2; yo = y2;
383     
384     for (int i = 0; i < nargs; ++i) {
385         args[i].setExpand(expnd);
386     }
387 }
388 #endif
389
390
391 void MathMacroTemplate::Metrics()
392 {
393     bool expnd = (nargs>0) ? args[0].getExpand(): false;
394     
395     if (flags & MMF_Edit) {
396         for (int i = 0; i < nargs; ++i) {
397             args[i].setExpand(false);
398         }
399     } else {
400         for (int i = 0; i < nargs; ++i) {
401             args[i].setExpand(true);
402         }
403     }
404     MathParInset::Metrics();
405     
406     for (int i = 0; i < nargs; ++i) {
407         args[i].setExpand(expnd);
408     }
409 }
410
411
412 void MathMacroTemplate::update(MathMacro * macro)
413 {
414     int idx = (macro) ? macro->getArgumentIdx(): 0;
415     for (int i = 0; i < nargs; ++i) {
416         if (macro) {
417             macro->setArgumentIdx(i);
418             args[i].SetData(macro->GetData());
419             MathedRowSt *row = macro->getRowSt();
420             args[i].setRowSt(row);
421         }
422     }   
423     if (macro)
424       macro->setArgumentIdx(idx);
425 }
426     
427
428 void MathMacroTemplate::WriteDef(ostream & os)
429 {
430         os << "\n\\newcommand{\\" << name << "}";
431       
432     if (nargs > 0 ) 
433             os << "[" << nargs << "]";
434     
435     os << "{";
436     
437     for (int i = 0; i < nargs; ++i) {
438         args[i].setExpand(false);
439     }    
440     Write(os); 
441     os << "}\n";
442 }
443
444
445 void MathMacroTemplate::WriteDef(string &file)
446 {
447     file += "\n\\newcommand{\\";
448     file += name;
449     file += '}';
450       
451     if (nargs > 0 ) {
452       file += '[';
453       file += tostr(nargs);
454       file += ']';
455     }
456     
457     file += '{';
458     
459     for (int i = 0; i < nargs; ++i) {
460         args[i].setExpand(false);
461     }    
462     Write(file); 
463     file += "}\n";
464 }
465
466
467 void MathMacroTemplate::setArgument(LyxArrayBase * a, int i)
468 {
469     args[i].SetData(a);
470 }
471
472
473 void MathMacroTemplate::GetMacroXY(int i, int & x, int & y) const
474 {
475     args[i].GetXY(x, y);
476 }
477
478
479 MathParInset * MathMacroTemplate::getMacroPar(int i) const
480 {
481     return (i >= 0 && i < nargs) ? static_cast<MathParInset*>(&args[i]) : 0;
482 }
483
484
485 void MathMacroTemplate::SetMacroFocus(int &idx, int x, int y)
486 {
487     for (int i = 0; i < nargs; ++i) {
488         if (args[i].Inside(x, y)) {
489             idx = i;
490             break;
491         }
492     }
493 }
494
495
496 /* -------------------------- MathMacroTable -----------------------*/
497
498 MathMacroTable::MathMacroTable(int n): max_macros(n)
499 {
500     macro_table = new MathMacroTemplateP[max_macros];
501     num_macros = 0;
502 }
503
504
505 MathMacroTable::~MathMacroTable()
506 {
507     delete[] macro_table;
508 }
509
510
511 // The search is currently linear but will be binary or hash, later.
512 MathMacroTemplate * MathMacroTable::getTemplate(char const * name) const
513 {
514     for (int i = 0; i < num_macros; ++i) {
515       if (strcmp(name, macro_table[i]->GetName()) == 0) 
516         return macro_table[i];
517     }
518     
519     return 0;
520 }
521
522 void MathMacroTable::addTemplate(MathMacroTemplate * m)
523 {
524     if (num_macros < max_macros)
525       macro_table[num_macros++] = m;
526     else
527             lyxerr << "Error (MathMacroTable::addTemplate): "
528                     "Macro table exhausted!" << endl;
529 }
530
531
532 // All this stuff aparently leaks because it's created here and is not 
533 // deleted never, but it have to live all the LyX sesion. OK, would not
534 // so hard to do it in the MacroTable destructor, but this doesn't harm
535 // seriously, so don't bother me with purify results here.   ;-)
536
537 void MathMacroTable::builtinMacros()
538 {
539     MathedIter iter;
540     MathParInset * inset;// *arg;
541     LyxArrayBase * array2;
542     
543     built = true;
544     
545     lyxerr[Debug::MATHED] << "Building macros" << endl;
546     
547     // This macro doesn't have arguments
548     MathMacroTemplate * m = new MathMacroTemplate("notin");  // this leaks
549     addTemplate(m);
550     LyxArrayBase * array = new LyxArrayBase; // this leaks
551     iter.SetData(array);
552     iter.Insert(new MathAccentInset(LM_in, LM_TC_BOPS, LM_not)); // this leaks
553     m->SetData(array);
554     
555     // These two are only while we are still with LyX 2.x
556     m = new MathMacroTemplate("emptyset"); // this leaks
557     addTemplate(m);
558     array = new LyxArrayBase; // this leaks
559     iter.SetData(array);
560     iter.Insert(new MathAccentInset('O', LM_TC_RM, LM_not)); // this leaks
561     m->SetData(array);
562     
563     m = new MathMacroTemplate("perp"); // this leaks
564     addTemplate(m);
565     array = new LyxArrayBase; // this leaks
566     iter.SetData(array);
567     iter.Insert(LM_bot, LM_TC_BOP);
568     m->SetData(array);
569
570     // binom has two arguments
571     m = new MathMacroTemplate("binom", 2);
572     addTemplate(m);
573     array = new LyxArrayBase; 
574     m->SetData(array);
575     iter.SetData(array);
576     inset = new MathDelimInset('(', ')');
577     iter.Insert(inset, LM_TC_ACTIVE_INSET);
578     array = new LyxArrayBase; 
579     iter.SetData(array);
580     MathFracInset *frac = new MathFracInset(LM_OT_ATOP);
581     iter.Insert(frac, LM_TC_ACTIVE_INSET);
582     inset->SetData(array);
583     array = new LyxArrayBase;
584     array2 = new LyxArrayBase;  
585     iter.SetData(array);
586     iter.Insert(m->getMacroPar(0));
587     iter.SetData(array2);
588     iter.Insert(m->getMacroPar(1));
589     frac->SetData(array, array2);
590
591 /*
592     // Cases has 1 argument
593     m = new MathMacroTemplate("cases", 1, MMF_Env); // this leaks
594     addTemplate(m);
595     array = new LyxArrayBase; // this leaks
596     iter.SetData(array);
597     arg = new MathMatrixInset(2, 1); // this leaks
598
599     m->setArgument(arg);
600     arg->SetAlign('c', "ll");
601     iter.Insert(arg, LM_TC_ACTIVE_INSET);
602     inset = new MathDelimInset('{', '.'); // this leaks
603     inset->SetData(array);
604     array = new LyxArrayBase; // this leaks
605     iter.SetData(array);
606     iter.Insert(inset, LM_TC_ACTIVE_INSET);
607     m->SetData(array);
608   
609
610     // the environment substack has 1 argument
611     m = new MathMacroTemplate("substack", 1, MMF_Env); // this leaks
612     addTemplate(m);     
613     arg = new MathMatrixInset(1, 1); // this leaks
614     m->setArgument(arg);
615     arg->SetType(LM_OT_MACRO);
616     array = new LyxArrayBase; // this leaks
617     iter.SetData(array);
618     iter.Insert(arg, LM_TC_ACTIVE_INSET);
619     m->SetData(array);*/
620 }
621
622
623 MathMacroTable MathMacroTable::mathMTable(255);
624 bool MathMacroTable::built = false;