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