]> git.lyx.org Git - lyx.git/blob - src/mathed/math_macro.C
A bit of cxx warniong hunting; update to rpm spec file.
[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: 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 #ifdef HAVE_SSTREAM
272             ostringstream ost;
273             ost << '#' << number;
274             drawStr(pain, LM_TC_TEX, size, x, baseline, 
275                     reinterpret_cast<byte const *>(ost.str().c_str()), 2);
276 #else
277             char s[3];
278             ostrstream ost(s, 3);
279             ost << '#' << number << '\0';
280             drawStr(pain, LM_TC_TEX, size, x, baseline,
281                     reinterpret_cast<byte *>(ost.str()), 2);
282 #endif
283     }
284 }
285
286
287 void MathMacroArgument::Metrics()
288 {
289     if (expnd_mode) {
290         MathParInset::Metrics();
291     } else {
292 #ifdef HAVE_SSTREAM
293             ostringstream ost;
294             ost << '#' << number;
295             width = mathed_string_width(LM_TC_TEX, size, 
296                                         reinterpret_cast<byte const *>(ost.str().c_str()), 2);
297             mathed_string_height(LM_TC_TEX, size,
298                                  reinterpret_cast<byte const *>(ost.str().c_str()), 
299                                  2, ascent, descent);
300 #else
301         char s[3];
302         ostrstream ost(s, 3);
303         ost << '#' << number << '\0';
304         width = mathed_string_width(LM_TC_TEX, size,
305                                     reinterpret_cast<byte *>
306                                     (ost.str()), 2);
307         mathed_string_height(LM_TC_TEX, size,
308                              reinterpret_cast<byte *>(ost.str()),
309                              2, ascent, descent);
310 #endif
311     }
312 }
313
314
315 void MathMacroArgument::Write(ostream & os)
316 {
317 #ifdef USE_OSTREAM_ONLY
318     if (expnd_mode) {
319         MathParInset::Write(os);
320     } else {
321             os << '#' << number << ' ';
322     }
323 #else
324    string output;
325    MathMacroArgument::Write(output);
326    os << output;
327 #endif
328 }
329
330
331 #ifndef USE_OSTREAM_ONLY
332 void MathMacroArgument::Write(string & file)
333 {
334     if (expnd_mode) {
335         MathParInset::Write(file);
336     } else {
337         file += '#';
338         file += tostr(number);
339         file += ' ';
340     }
341 }
342 #endif
343
344
345 /* --------------------- MathMacroTemplate ---------------------------*/
346
347 MathMacroTemplate::MathMacroTemplate(char const * nm, int na, int flg):
348     MathParInset(LM_ST_TEXT, nm, LM_OT_MACRO), 
349     flags(flg), nargs(na)
350 {
351     if (nargs > 0) {
352         tcode = LM_TC_ACTIVE_INSET;
353         args = new MathMacroArgument[nargs];
354         for (int i = 0; i < nargs; ++i) {
355             args[i].setNumber(i + 1);
356         }
357     } else 
358       tcode = LM_TC_INSET;
359 }
360
361
362 MathMacroTemplate::~MathMacroTemplate()
363 {
364     // prevent to delete already deleted objects
365     for (int i = 0; i < nargs; ++i) {
366         args[i].SetData(0);
367     }
368     delete[] args;
369 }
370
371
372 void MathMacroTemplate::setEditMode(bool ed)
373 {
374     if (ed) {
375         flags |= MMF_Edit;
376         for (int i = 0; i < nargs; ++i) {
377             args[i].setExpand(false);
378         }
379     } else {
380         flags &= ~MMF_Edit;
381         for (int i = 0; i < nargs; ++i) {
382             args[i].setExpand(true);
383         }
384     }
385 }
386
387
388 void MathMacroTemplate::draw(Painter & pain, int x, int y)
389 {
390     int x2, y2;
391     bool expnd = (nargs > 0) ? args[0].getExpand(): false;
392     if (flags & MMF_Edit) {
393         for (int i = 0; i < nargs; ++i) {
394             args[i].setExpand(false);
395         }
396       x2 = x; y2 = y;
397     } else {
398         for (int i = 0; i < nargs; ++i) {
399             args[i].setExpand(true);
400         }
401       x2 = xo; y2 = yo;
402     }
403     MathParInset::draw(pain, x, y);
404     xo = x2; yo = y2;
405     
406     for (int i = 0; i < nargs; ++i) {
407         args[i].setExpand(expnd);
408     }
409 }
410
411
412 void MathMacroTemplate::Metrics()
413 {
414     bool expnd = (nargs>0) ? args[0].getExpand(): false;
415     
416     if (flags & MMF_Edit) {
417         for (int i = 0; i < nargs; ++i) {
418             args[i].setExpand(false);
419         }
420     } else {
421         for (int i = 0; i < nargs; ++i) {
422             args[i].setExpand(true);
423         }
424     }
425     MathParInset::Metrics();
426     
427     for (int i = 0; i < nargs; ++i) {
428         args[i].setExpand(expnd);
429     }
430 }
431
432
433 void MathMacroTemplate::update(MathMacro * macro)
434 {
435     int idx = (macro) ? macro->getArgumentIdx(): 0;
436     for (int i = 0; i < nargs; ++i) {
437         if (macro) {
438             macro->setArgumentIdx(i);
439             args[i].SetData(macro->GetData());
440             MathedRowSt *row = macro->getRowSt();
441             args[i].setRowSt(row);
442         }
443     }   
444     if (macro)
445       macro->setArgumentIdx(idx);
446 }
447     
448
449 void MathMacroTemplate::WriteDef(ostream & os)
450 {
451         os << "\n\\newcommand{\\" << name << "}";
452       
453     if (nargs > 0 ) 
454             os << "[" << nargs << "]";
455     
456     os << "{";
457     
458     for (int i = 0; i < nargs; ++i) {
459         args[i].setExpand(false);
460     }    
461     Write(os); 
462     os << "}\n";
463 }
464
465
466 #ifndef USE_OSTREAM_ONLY
467 void MathMacroTemplate::WriteDef(string & file)
468 {
469     file += "\n\\newcommand{\\";
470     file += name;
471     file += '}';
472       
473     if (nargs > 0 ) {
474       file += '[';
475       file += tostr(nargs);
476       file += ']';
477     }
478     
479     file += '{';
480     
481     for (int i = 0; i < nargs; ++i) {
482         args[i].setExpand(false);
483     }    
484     Write(file); 
485     file += "}\n";
486 }
487 #endif
488
489
490 void MathMacroTemplate::setArgument(LyxArrayBase * a, int i)
491 {
492     args[i].SetData(a);
493 }
494
495
496 void MathMacroTemplate::GetMacroXY(int i, int & x, int & y) const
497 {
498     args[i].GetXY(x, y);
499 }
500
501
502 MathParInset * MathMacroTemplate::getMacroPar(int i) const
503 {
504     return (i >= 0 && i < nargs) ? static_cast<MathParInset*>(&args[i]) : 0;
505 }
506
507
508 void MathMacroTemplate::SetMacroFocus(int &idx, int x, int y)
509 {
510     for (int i = 0; i < nargs; ++i) {
511         if (args[i].Inside(x, y)) {
512             idx = i;
513             break;
514         }
515     }
516 }
517
518
519 /* -------------------------- MathMacroTable -----------------------*/
520
521 MathMacroTable::MathMacroTable(int n) : max_macros(n)
522 {
523     macro_table = new MathMacroTemplateP[max_macros];
524     num_macros = 0;
525 }
526
527
528 MathMacroTable::~MathMacroTable()
529 {
530     delete[] macro_table;
531 }
532
533
534 // The search is currently linear but will be binary or hash, later.
535 MathMacroTemplate * MathMacroTable::getTemplate(char const * name) const
536 {
537     for (int i = 0; i < num_macros; ++i) {
538       if (strcmp(name, macro_table[i]->GetName()) == 0) 
539         return macro_table[i];
540     }
541     
542     return 0;
543 }
544
545 void MathMacroTable::addTemplate(MathMacroTemplate * m)
546 {
547     if (num_macros < max_macros)
548       macro_table[num_macros++] = m;
549     else
550             lyxerr << "Error (MathMacroTable::addTemplate): "
551                     "Macro table exhausted!" << endl;
552 }
553
554
555 // All this stuff aparently leaks because it's created here and is not 
556 // deleted never, but it have to live all the LyX sesion. OK, would not
557 // so hard to do it in the MacroTable destructor, but this doesn't harm
558 // seriously, so don't bother me with purify results here.   ;-)
559
560 void MathMacroTable::builtinMacros()
561 {
562     MathedIter iter;
563     MathParInset * inset;// *arg;
564     LyxArrayBase * array2;
565     
566     built = true;
567     
568     lyxerr[Debug::MATHED] << "Building macros" << endl;
569     
570     // This macro doesn't have arguments
571     MathMacroTemplate * m = new MathMacroTemplate("notin");  // this leaks
572     addTemplate(m);
573     LyxArrayBase * array = new LyxArrayBase; // this leaks
574     iter.SetData(array);
575     iter.Insert(new MathAccentInset(LM_in, LM_TC_BOPS, LM_not)); // this leaks
576     m->SetData(array);
577     
578     // These two are only while we are still with LyX 2.x
579     m = new MathMacroTemplate("emptyset"); // this leaks
580     addTemplate(m);
581     array = new LyxArrayBase; // this leaks
582     iter.SetData(array);
583     iter.Insert(new MathAccentInset('O', LM_TC_RM, LM_not)); // this leaks
584     m->SetData(array);
585     
586     m = new MathMacroTemplate("perp"); // this leaks
587     addTemplate(m);
588     array = new LyxArrayBase; // this leaks
589     iter.SetData(array);
590     iter.Insert(LM_bot, LM_TC_BOP);
591     m->SetData(array);
592
593     // binom has two arguments
594     m = new MathMacroTemplate("binom", 2);
595     addTemplate(m);
596     array = new LyxArrayBase; 
597     m->SetData(array);
598     iter.SetData(array);
599     inset = new MathDelimInset('(', ')');
600     iter.Insert(inset, LM_TC_ACTIVE_INSET);
601     array = new LyxArrayBase; 
602     iter.SetData(array);
603     MathFracInset *frac = new MathFracInset(LM_OT_ATOP);
604     iter.Insert(frac, LM_TC_ACTIVE_INSET);
605     inset->SetData(array);
606     array = new LyxArrayBase;
607     array2 = new LyxArrayBase;  
608     iter.SetData(array);
609     iter.Insert(m->getMacroPar(0));
610     iter.SetData(array2);
611     iter.Insert(m->getMacroPar(1));
612     frac->SetData(array, array2);
613
614 /*
615     // Cases has 1 argument
616     m = new MathMacroTemplate("cases", 1, MMF_Env); // this leaks
617     addTemplate(m);
618     array = new LyxArrayBase; // this leaks
619     iter.SetData(array);
620     arg = new MathMatrixInset(2, 1); // this leaks
621
622     m->setArgument(arg);
623     arg->SetAlign('c', "ll");
624     iter.Insert(arg, LM_TC_ACTIVE_INSET);
625     inset = new MathDelimInset('{', '.'); // this leaks
626     inset->SetData(array);
627     array = new LyxArrayBase; // this leaks
628     iter.SetData(array);
629     iter.Insert(inset, LM_TC_ACTIVE_INSET);
630     m->SetData(array);
631   
632
633     // the environment substack has 1 argument
634     m = new MathMacroTemplate("substack", 1, MMF_Env); // this leaks
635     addTemplate(m);     
636     arg = new MathMatrixInset(1, 1); // this leaks
637     m->setArgument(arg);
638     arg->SetType(LM_OT_MACRO);
639     array = new LyxArrayBase; // this leaks
640     iter.SetData(array);
641     iter.Insert(arg, LM_TC_ACTIVE_INSET);
642     m->SetData(array);*/
643 }
644
645
646 MathMacroTable MathMacroTable::mathMTable(255);
647 bool MathMacroTable::built = false;