]> git.lyx.org Git - lyx.git/blob - src/mathed/math_macro.C
change to use ostreams instead of string when writing files. fiddling with insettext...
[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 int mathed_string_width(short type, int style, byte const* s, int ls);
51 extern int mathed_string_height(short, int, byte const*, int, int&, int&);
52
53
54 MathMacro::MathMacro(MathMacroTemplate* t): 
55     MathParInset(LM_ST_TEXT, "", LM_OT_MACRO), tmplate(t)
56 {
57     nargs = tmplate->getNoArgs();
58     tcode = tmplate->getTCode();
59     args = new MacroArgumentBase[nargs];
60     for (int i = 0; i < nargs; ++i) {
61 //      if (tmplate->getMacroPar(i)->Permit(LMPF_ALLOW_CR))
62 //        args[i].row = new MathedRowSt(tmplate->getMacroPar(i)->GetColumns());
63 //      else 
64           args[i].row = 0;
65 /*      int k = tmplate->getMacroPar(i)->GetColumns();
66         if (k>0) {
67             args[i].array = new LyxArrayBase;
68             for (int j= 0; j<k-1; ++j) args[i].array->Insert(j, LM_TC_TAB);
69         }*/
70     }
71     idx = 0;
72     SetName(tmplate->GetName());
73 }
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     return new MathMacro(this);
107 }
108
109
110 void MathMacro::Metrics()
111 {
112     if (nargs > 0)
113       tmplate->update(this);
114     tmplate->Metrics();
115     width = tmplate->Width();
116     ascent = tmplate->Ascent();
117     descent = tmplate->Descent();
118 }
119
120
121 void MathMacro::draw(Painter & pain, int x, int y)
122 {
123     xo = x;  yo = y;
124     Metrics();
125     tmplate->update(this);
126     tmplate->SetStyle(size);
127     tmplate->draw(pain, x, y);
128     for (int i = 0; i < nargs; ++i)
129       tmplate->GetMacroXY(i, args[i].x, args[i].y);
130 }
131
132
133 int MathMacro::GetColumns()
134 {
135     return tmplate->getMacroPar(idx)->GetColumns();
136 }
137
138
139 void MathMacro::GetXY(int & x, int & y) const
140 {
141     x = args[idx].x;  y = args[idx].y;
142 }
143
144
145 bool MathMacro::Permit(short f)
146 {
147     return (nargs > 0) ?
148             tmplate->getMacroPar(idx)->Permit(f) : MathParInset::Permit(f);
149 }
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(ostream & os)
160 {
161    string output;
162    MathMacro::Write(output);
163    os << output;
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
223 void MathMacroArgument::draw(Painter & pain, int x, int baseline)
224 {
225     if (expnd_mode) {
226         MathParInset::draw(pain, x, baseline);
227     } else {
228         unsigned char s[3];
229         sprintf(reinterpret_cast<char*>(s), "#%d", number);
230         drawStr(pain, LM_TC_TEX, size, x, baseline, &s[0], 2);
231     }
232 }
233
234
235 void MathMacroArgument::Metrics()
236 {
237     if (expnd_mode) {
238         MathParInset::Metrics();
239     } else {
240         unsigned char s[3];
241         sprintf(reinterpret_cast<char*>(s), "#%d", number);
242         width = mathed_string_width(LM_TC_TEX, size, &s[0], 2);
243         mathed_string_height(LM_TC_TEX, size, &s[0], 2, ascent, descent);
244     }
245 }
246
247
248 void MathMacroArgument::Write(ostream & os)
249 {
250    string output;
251    MathMacroArgument::Write(output);
252    os << output;
253 }
254
255
256 void MathMacroArgument::Write(string & file)
257 {
258     if (expnd_mode) {
259         MathParInset::Write(file);
260     } else {
261         file += '#';
262         file += tostr(number);
263         file += ' ';
264     }
265 }
266
267
268 /* --------------------- MathMacroTemplate ---------------------------*/
269
270 MathMacroTemplate::MathMacroTemplate(char const * nm, int na, int flg):
271     MathParInset(LM_ST_TEXT, nm, LM_OT_MACRO), 
272     flags(flg), nargs(na)
273 {
274     if (nargs > 0) {
275         tcode = LM_TC_ACTIVE_INSET;
276         args = new MathMacroArgument[nargs];
277         for (int i = 0; i < nargs; ++i) {
278             args[i].setNumber(i + 1);
279         }
280     } else 
281       tcode = LM_TC_INSET;
282 }
283
284
285 MathMacroTemplate::~MathMacroTemplate()
286 {
287     // prevent to delete already deleted objects
288     for (int i = 0; i < nargs; ++i) {
289         args[i].SetData(0);
290     }
291     delete[] args;
292 }
293
294
295 void MathMacroTemplate::setEditMode(bool ed)
296 {
297     if (ed) {
298         flags |= MMF_Edit;
299         for (int i = 0; i < nargs; ++i) {
300             args[i].setExpand(false);
301         }
302     } else {
303         flags &= ~MMF_Edit;
304         for (int i = 0; i < nargs; ++i) {
305             args[i].setExpand(true);
306         }
307     }
308 }
309
310
311 void MathMacroTemplate::draw(Painter & pain, int x, int y)
312 {
313     int x2, y2;
314     bool expnd = (nargs > 0) ? args[0].getExpand(): false;
315     if (flags & MMF_Edit) {
316         for (int i = 0; i < nargs; ++i) {
317             args[i].setExpand(false);
318         }
319       x2 = x; y2 = y;
320     } else {
321         for (int i = 0; i < nargs; ++i) {
322             args[i].setExpand(true);
323         }
324       x2 = xo; y2 = yo;
325     }
326     MathParInset::draw(pain, x, y);
327     xo = x2; yo = y2;
328     
329     for (int i = 0; i < nargs; ++i) {
330         args[i].setExpand(expnd);
331     }
332 }
333
334
335 void MathMacroTemplate::Metrics()
336 {
337     bool expnd = (nargs>0) ? args[0].getExpand(): false;
338     
339     if (flags & MMF_Edit) {
340         for (int i = 0; i < nargs; ++i) {
341             args[i].setExpand(false);
342         }
343     } else {
344         for (int i = 0; i < nargs; ++i) {
345             args[i].setExpand(true);
346         }
347     }
348     MathParInset::Metrics();
349     
350     for (int i = 0; i < nargs; ++i) {
351         args[i].setExpand(expnd);
352     }
353 }
354
355
356 void MathMacroTemplate::update(MathMacro * macro)
357 {
358     int idx = (macro) ? macro->getArgumentIdx(): 0;
359     for (int i = 0; i < nargs; ++i) {
360         if (macro) {
361             macro->setArgumentIdx(i);
362             args[i].SetData(macro->GetData());
363             MathedRowSt *row = macro->getRowSt();
364             args[i].setRowSt(row);
365         }
366     }   
367     if (macro)
368       macro->setArgumentIdx(idx);
369 }
370     
371
372 void MathMacroTemplate::WriteDef(ostream & os)
373 {
374         os << "\n\\newcommand{\\" << name << "}";
375       
376     if (nargs > 0 ) 
377             os << "[" << nargs << "]";
378     
379     os << "{";
380     
381     for (int i = 0; i < nargs; ++i) {
382         args[i].setExpand(false);
383     }    
384     Write(os); 
385     os << "}\n";
386 }
387
388
389 void MathMacroTemplate::WriteDef(string & file)
390 {
391     file += "\n\\newcommand{\\";
392     file += name;
393     file += '}';
394       
395     if (nargs > 0 ) {
396       file += '[';
397       file += tostr(nargs);
398       file += ']';
399     }
400     
401     file += '{';
402     
403     for (int i = 0; i < nargs; ++i) {
404         args[i].setExpand(false);
405     }    
406     Write(file); 
407     file += "}\n";
408 }
409
410
411 void MathMacroTemplate::setArgument(LyxArrayBase * a, int i)
412 {
413     args[i].SetData(a);
414 }
415
416
417 void MathMacroTemplate::GetMacroXY(int i, int & x, int & y) const
418 {
419     args[i].GetXY(x, y);
420 }
421
422
423 MathParInset * MathMacroTemplate::getMacroPar(int i) const
424 {
425     return (i >= 0 && i < nargs) ? static_cast<MathParInset*>(&args[i]) : 0;
426 }
427
428
429 void MathMacroTemplate::SetMacroFocus(int &idx, int x, int y)
430 {
431     for (int i = 0; i < nargs; ++i) {
432         if (args[i].Inside(x, y)) {
433             idx = i;
434             break;
435         }
436     }
437 }
438
439
440 /* -------------------------- MathMacroTable -----------------------*/
441
442 MathMacroTable::MathMacroTable(int n): max_macros(n)
443 {
444     macro_table = new MathMacroTemplateP[max_macros];
445     num_macros = 0;
446 }
447
448
449 MathMacroTable::~MathMacroTable()
450 {
451     delete[] macro_table;
452 }
453
454
455 // The search is currently linear but will be binary or hash, later.
456 MathMacroTemplate * MathMacroTable::getTemplate(char const * name) const
457 {
458     for (int i = 0; i < num_macros; ++i) {
459       if (strcmp(name, macro_table[i]->GetName()) == 0) 
460         return macro_table[i];
461     }
462     
463     return 0;
464 }
465
466 void MathMacroTable::addTemplate(MathMacroTemplate * m)
467 {
468     if (num_macros < max_macros)
469       macro_table[num_macros++] = m;
470     else
471             lyxerr << "Error (MathMacroTable::addTemplate): "
472                     "Macro table exhausted!" << endl;
473 }
474
475
476 // All this stuff aparently leaks because it's created here and is not 
477 // deleted never, but it have to live all the LyX sesion. OK, would not
478 // so hard to do it in the MacroTable destructor, but this doesn't harm
479 // seriously, so don't bother me with purify results here.   ;-)
480
481 void MathMacroTable::builtinMacros()
482 {
483     MathedIter iter;
484     MathParInset * inset;// *arg;
485     LyxArrayBase * array2;
486     
487     built = true;
488     
489     lyxerr[Debug::MATHED] << "Building macros" << endl;
490     
491     // This macro doesn't have arguments
492     MathMacroTemplate * m = new MathMacroTemplate("notin");  // this leaks
493     addTemplate(m);
494     LyxArrayBase * array = new LyxArrayBase; // this leaks
495     iter.SetData(array);
496     iter.Insert(new MathAccentInset(LM_in, LM_TC_BOPS, LM_not)); // this leaks
497     m->SetData(array);
498     
499     // These two are only while we are still with LyX 2.x
500     m = new MathMacroTemplate("emptyset"); // this leaks
501     addTemplate(m);
502     array = new LyxArrayBase; // this leaks
503     iter.SetData(array);
504     iter.Insert(new MathAccentInset('O', LM_TC_RM, LM_not)); // this leaks
505     m->SetData(array);
506     
507     m = new MathMacroTemplate("perp"); // this leaks
508     addTemplate(m);
509     array = new LyxArrayBase; // this leaks
510     iter.SetData(array);
511     iter.Insert(LM_bot, LM_TC_BOP);
512     m->SetData(array);
513
514     // binom has two arguments
515     m = new MathMacroTemplate("binom", 2);
516     addTemplate(m);
517     array = new LyxArrayBase; 
518     m->SetData(array);
519     iter.SetData(array);
520     inset = new MathDelimInset('(', ')');
521     iter.Insert(inset, LM_TC_ACTIVE_INSET);
522     array = new LyxArrayBase; 
523     iter.SetData(array);
524     MathFracInset *frac = new MathFracInset(LM_OT_ATOP);
525     iter.Insert(frac, LM_TC_ACTIVE_INSET);
526     inset->SetData(array);
527     array = new LyxArrayBase;
528     array2 = new LyxArrayBase;  
529     iter.SetData(array);
530     iter.Insert(m->getMacroPar(0));
531     iter.SetData(array2);
532     iter.Insert(m->getMacroPar(1));
533     frac->SetData(array, array2);
534
535 /*
536     // Cases has 1 argument
537     m = new MathMacroTemplate("cases", 1, MMF_Env); // this leaks
538     addTemplate(m);
539     array = new LyxArrayBase; // this leaks
540     iter.SetData(array);
541     arg = new MathMatrixInset(2, 1); // this leaks
542
543     m->setArgument(arg);
544     arg->SetAlign('c', "ll");
545     iter.Insert(arg, LM_TC_ACTIVE_INSET);
546     inset = new MathDelimInset('{', '.'); // this leaks
547     inset->SetData(array);
548     array = new LyxArrayBase; // this leaks
549     iter.SetData(array);
550     iter.Insert(inset, LM_TC_ACTIVE_INSET);
551     m->SetData(array);
552   
553
554     // the environment substack has 1 argument
555     m = new MathMacroTemplate("substack", 1, MMF_Env); // this leaks
556     addTemplate(m);     
557     arg = new MathMatrixInset(1, 1); // this leaks
558     m->setArgument(arg);
559     arg->SetType(LM_OT_MACRO);
560     array = new LyxArrayBase; // this leaks
561     iter.SetData(array);
562     iter.Insert(arg, LM_TC_ACTIVE_INSET);
563     m->SetData(array);*/
564 }
565
566
567 MathMacroTable MathMacroTable::mathMTable(255);
568 bool MathMacroTable::built = false;