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