]> git.lyx.org Git - lyx.git/blob - src/mathed/math_macro.C
apply the ostream changes to mathed, some other small related things
[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 #ifdef USE_OSTREAM_ONLY
162     if (tmplate->flags & MMF_Exp) {
163             lyxerr[Debug::MATHED] << "Expand " << tmplate->flags
164                                   << ' ' << MMF_Exp << endl; 
165         tmplate->update(this);
166         tmplate->Write(os);
167     } else {
168         if (tmplate->flags & MMF_Env) {
169                 os << "\\begin{"
170                    << name
171                    << "} ";
172         } else {
173                 os << '\\' << name;
174         }
175 //      if (options) { 
176 //        file += '[';
177 //        file += options;
178 //        file += ']';
179 //      }
180         
181         if (!(tmplate->flags & MMF_Env) && nargs > 0) 
182                 os << '{';
183         
184         for (int i = 0; i < nargs; ++i) {
185             array = args[i].array;
186             MathParInset::Write(os);
187             if (i < nargs - 1)  
188                     os << "}{";
189         }   
190         if (tmplate->flags & MMF_Env) {
191                 os << "\\end{"
192                    << name
193                    << '}';
194         } else {
195             if (nargs > 0) 
196                     os << '}';
197             else
198                     os << ' ';
199         }
200     }
201 #else
202    string output;
203    MathMacro::Write(output);
204    os << output;
205 #endif
206 }
207
208
209 #ifndef USE_OSTREAM_ONLY
210 void MathMacro::Write(string &file)
211 {
212     if (tmplate->flags & MMF_Exp) {
213             lyxerr[Debug::MATHED] << "Expand " << tmplate->flags
214                                   << ' ' << MMF_Exp << endl; 
215         tmplate->update(this);
216         tmplate->Write(file);
217     } else {
218         if (tmplate->flags & MMF_Env) {
219           file += "\\begin{";
220           file += name;
221           file += "} ";
222         } else {
223           file += '\\';
224           file += name;
225         }
226 //      if (options) { 
227 //        file += '[';
228 //        file += options;
229 //        file += ']';
230 //      }
231         
232         if (!(tmplate->flags & MMF_Env) && nargs > 0) 
233           file += '{';
234         
235         for (int i = 0; i < nargs; ++i) {
236             array = args[i].array;
237             MathParInset::Write(file);
238             if (i < nargs - 1)  
239               file += "}{";
240         }   
241         if (tmplate->flags & MMF_Env) {
242             file += "\\end{";
243             file += name;
244             file += '}';
245         } else {
246             if (nargs > 0) 
247                 file += '}';
248             else
249                 file += ' ';
250         }
251     }
252 }
253 #endif
254
255
256 /*---------------  Macro argument -----------------------------------*/
257
258 MathMacroArgument::MathMacroArgument(int n)
259 {
260     number = n;
261     expnd_mode = false;
262     SetType(LM_OT_MACRO_ARG);
263 }
264
265
266 void MathMacroArgument::draw(Painter & pain, int x, int baseline)
267 {
268     if (expnd_mode) {
269         MathParInset::draw(pain, x, baseline);
270     } else {
271         unsigned char s[3];
272         sprintf(reinterpret_cast<char*>(s), "#%d", number);
273         drawStr(pain, LM_TC_TEX, size, x, baseline, &s[0], 2);
274     }
275 }
276
277
278 void MathMacroArgument::Metrics()
279 {
280     if (expnd_mode) {
281         MathParInset::Metrics();
282     } else {
283         unsigned char s[3];
284         sprintf(reinterpret_cast<char*>(s), "#%d", number);
285         width = mathed_string_width(LM_TC_TEX, size, &s[0], 2);
286         mathed_string_height(LM_TC_TEX, size, &s[0], 2, ascent, descent);
287     }
288 }
289
290
291 void MathMacroArgument::Write(ostream & os)
292 {
293 #ifdef USE_OSTREAM_ONLY
294     if (expnd_mode) {
295         MathParInset::Write(os);
296     } else {
297             os << '#' << number << ' ';
298     }
299 #else
300    string output;
301    MathMacroArgument::Write(output);
302    os << output;
303 #endif
304 }
305
306
307 #ifndef USE_OSTREAM_ONLY
308 void MathMacroArgument::Write(string & file)
309 {
310     if (expnd_mode) {
311         MathParInset::Write(file);
312     } else {
313         file += '#';
314         file += tostr(number);
315         file += ' ';
316     }
317 }
318 #endif
319
320
321 /* --------------------- MathMacroTemplate ---------------------------*/
322
323 MathMacroTemplate::MathMacroTemplate(char const * nm, int na, int flg):
324     MathParInset(LM_ST_TEXT, nm, LM_OT_MACRO), 
325     flags(flg), nargs(na)
326 {
327     if (nargs > 0) {
328         tcode = LM_TC_ACTIVE_INSET;
329         args = new MathMacroArgument[nargs];
330         for (int i = 0; i < nargs; ++i) {
331             args[i].setNumber(i + 1);
332         }
333     } else 
334       tcode = LM_TC_INSET;
335 }
336
337
338 MathMacroTemplate::~MathMacroTemplate()
339 {
340     // prevent to delete already deleted objects
341     for (int i = 0; i < nargs; ++i) {
342         args[i].SetData(0);
343     }
344     delete[] args;
345 }
346
347
348 void MathMacroTemplate::setEditMode(bool ed)
349 {
350     if (ed) {
351         flags |= MMF_Edit;
352         for (int i = 0; i < nargs; ++i) {
353             args[i].setExpand(false);
354         }
355     } else {
356         flags &= ~MMF_Edit;
357         for (int i = 0; i < nargs; ++i) {
358             args[i].setExpand(true);
359         }
360     }
361 }
362
363
364 void MathMacroTemplate::draw(Painter & pain, 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(pain, x, y);
380     xo = x2; yo = y2;
381     
382     for (int i = 0; i < nargs; ++i) {
383         args[i].setExpand(expnd);
384     }
385 }
386
387
388 void MathMacroTemplate::Metrics()
389 {
390     bool expnd = (nargs>0) ? args[0].getExpand(): false;
391     
392     if (flags & MMF_Edit) {
393         for (int i = 0; i < nargs; ++i) {
394             args[i].setExpand(false);
395         }
396     } else {
397         for (int i = 0; i < nargs; ++i) {
398             args[i].setExpand(true);
399         }
400     }
401     MathParInset::Metrics();
402     
403     for (int i = 0; i < nargs; ++i) {
404         args[i].setExpand(expnd);
405     }
406 }
407
408
409 void MathMacroTemplate::update(MathMacro * macro)
410 {
411     int idx = (macro) ? macro->getArgumentIdx(): 0;
412     for (int i = 0; i < nargs; ++i) {
413         if (macro) {
414             macro->setArgumentIdx(i);
415             args[i].SetData(macro->GetData());
416             MathedRowSt *row = macro->getRowSt();
417             args[i].setRowSt(row);
418         }
419     }   
420     if (macro)
421       macro->setArgumentIdx(idx);
422 }
423     
424
425 void MathMacroTemplate::WriteDef(ostream & os)
426 {
427         os << "\n\\newcommand{\\" << name << "}";
428       
429     if (nargs > 0 ) 
430             os << "[" << nargs << "]";
431     
432     os << "{";
433     
434     for (int i = 0; i < nargs; ++i) {
435         args[i].setExpand(false);
436     }    
437     Write(os); 
438     os << "}\n";
439 }
440
441
442 #ifndef USE_OSTREAM_ONLY
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 #endif
464
465
466 void MathMacroTemplate::setArgument(LyxArrayBase * a, int i)
467 {
468     args[i].SetData(a);
469 }
470
471
472 void MathMacroTemplate::GetMacroXY(int i, int & x, int & y) const
473 {
474     args[i].GetXY(x, y);
475 }
476
477
478 MathParInset * MathMacroTemplate::getMacroPar(int i) const
479 {
480     return (i >= 0 && i < nargs) ? static_cast<MathParInset*>(&args[i]) : 0;
481 }
482
483
484 void MathMacroTemplate::SetMacroFocus(int &idx, int x, int y)
485 {
486     for (int i = 0; i < nargs; ++i) {
487         if (args[i].Inside(x, y)) {
488             idx = i;
489             break;
490         }
491     }
492 }
493
494
495 /* -------------------------- MathMacroTable -----------------------*/
496
497 MathMacroTable::MathMacroTable(int n) : max_macros(n)
498 {
499     macro_table = new MathMacroTemplateP[max_macros];
500     num_macros = 0;
501 }
502
503
504 MathMacroTable::~MathMacroTable()
505 {
506     delete[] macro_table;
507 }
508
509
510 // The search is currently linear but will be binary or hash, later.
511 MathMacroTemplate * MathMacroTable::getTemplate(char const * name) const
512 {
513     for (int i = 0; i < num_macros; ++i) {
514       if (strcmp(name, macro_table[i]->GetName()) == 0) 
515         return macro_table[i];
516     }
517     
518     return 0;
519 }
520
521 void MathMacroTable::addTemplate(MathMacroTemplate * m)
522 {
523     if (num_macros < max_macros)
524       macro_table[num_macros++] = m;
525     else
526             lyxerr << "Error (MathMacroTable::addTemplate): "
527                     "Macro table exhausted!" << endl;
528 }
529
530
531 // All this stuff aparently leaks because it's created here and is not 
532 // deleted never, but it have to live all the LyX sesion. OK, would not
533 // so hard to do it in the MacroTable destructor, but this doesn't harm
534 // seriously, so don't bother me with purify results here.   ;-)
535
536 void MathMacroTable::builtinMacros()
537 {
538     MathedIter iter;
539     MathParInset * inset;// *arg;
540     LyxArrayBase * array2;
541     
542     built = true;
543     
544     lyxerr[Debug::MATHED] << "Building macros" << endl;
545     
546     // This macro doesn't have arguments
547     MathMacroTemplate * m = new MathMacroTemplate("notin");  // this leaks
548     addTemplate(m);
549     LyxArrayBase * array = new LyxArrayBase; // this leaks
550     iter.SetData(array);
551     iter.Insert(new MathAccentInset(LM_in, LM_TC_BOPS, LM_not)); // this leaks
552     m->SetData(array);
553     
554     // These two are only while we are still with LyX 2.x
555     m = new MathMacroTemplate("emptyset"); // this leaks
556     addTemplate(m);
557     array = new LyxArrayBase; // this leaks
558     iter.SetData(array);
559     iter.Insert(new MathAccentInset('O', LM_TC_RM, LM_not)); // this leaks
560     m->SetData(array);
561     
562     m = new MathMacroTemplate("perp"); // this leaks
563     addTemplate(m);
564     array = new LyxArrayBase; // this leaks
565     iter.SetData(array);
566     iter.Insert(LM_bot, LM_TC_BOP);
567     m->SetData(array);
568
569     // binom has two arguments
570     m = new MathMacroTemplate("binom", 2);
571     addTemplate(m);
572     array = new LyxArrayBase; 
573     m->SetData(array);
574     iter.SetData(array);
575     inset = new MathDelimInset('(', ')');
576     iter.Insert(inset, LM_TC_ACTIVE_INSET);
577     array = new LyxArrayBase; 
578     iter.SetData(array);
579     MathFracInset *frac = new MathFracInset(LM_OT_ATOP);
580     iter.Insert(frac, LM_TC_ACTIVE_INSET);
581     inset->SetData(array);
582     array = new LyxArrayBase;
583     array2 = new LyxArrayBase;  
584     iter.SetData(array);
585     iter.Insert(m->getMacroPar(0));
586     iter.SetData(array2);
587     iter.Insert(m->getMacroPar(1));
588     frac->SetData(array, array2);
589
590 /*
591     // Cases has 1 argument
592     m = new MathMacroTemplate("cases", 1, MMF_Env); // this leaks
593     addTemplate(m);
594     array = new LyxArrayBase; // this leaks
595     iter.SetData(array);
596     arg = new MathMatrixInset(2, 1); // this leaks
597
598     m->setArgument(arg);
599     arg->SetAlign('c', "ll");
600     iter.Insert(arg, LM_TC_ACTIVE_INSET);
601     inset = new MathDelimInset('{', '.'); // this leaks
602     inset->SetData(array);
603     array = new LyxArrayBase; // this leaks
604     iter.SetData(array);
605     iter.Insert(inset, LM_TC_ACTIVE_INSET);
606     m->SetData(array);
607   
608
609     // the environment substack has 1 argument
610     m = new MathMacroTemplate("substack", 1, MMF_Env); // this leaks
611     addTemplate(m);     
612     arg = new MathMatrixInset(1, 1); // this leaks
613     m->setArgument(arg);
614     arg->SetType(LM_OT_MACRO);
615     array = new LyxArrayBase; // this leaks
616     iter.SetData(array);
617     iter.Insert(arg, LM_TC_ACTIVE_INSET);
618     m->SetData(array);*/
619 }
620
621
622 MathMacroTable MathMacroTable::mathMTable(255);
623 bool MathMacroTable::built = false;