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