]> git.lyx.org Git - lyx.git/blob - src/mathed/math_macro.C
some inline fix + mathed16.diff
[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
23 #endif
24
25 #include "LString.h"
26 #include "math_macro.h"
27 #include "array.h"
28 #include "math_iter.h"
29 #include "math_inset.h"
30 #include "math_accentinset.h"
31 #include "math_deliminset.h"
32 #include "math_fracinset.h"
33 #include "math_rowst.h"
34 #include "support/lstrings.h"
35 #include "debug.h"
36
37 using std::ostream;
38 using std::endl;
39
40 ostream & operator<<(ostream & o, MathedTextCodes mtc)
41 {
42         return o << int(mtc);
43 }
44
45 enum MathedMacroFlag {
46     MMF_Env= 1,
47     MMF_Exp= 2,
48     MMF_Edit= 4
49 };
50
51 ostream & operator<<(ostream & o, MathedMacroFlag mmf)
52 {
53         return o << int(mmf);
54 }
55
56 extern int mathed_string_width(short type, int style, string const & s);
57 extern int mathed_string_height(short, int, string const &, int &, int &);
58
59
60 MathMacro::MathMacro(MathMacroTemplate* t): 
61     MathParInset(LM_ST_TEXT, "", LM_OT_MACRO), tmplate(t)
62 {
63         nargs = tmplate->getNoArgs();
64         tcode = tmplate->getTCode();
65         args_.resize(nargs);
66         for (int i = 0; i < nargs; ++i) {
67                 args_[i].row = 0;
68         }
69         idx = 0;
70         SetName(tmplate->GetName());
71 }
72
73
74 MathMacro::MathMacro(MathMacro * m): 
75     MathParInset(LM_ST_TEXT, m->GetName(), LM_OT_MACRO)
76 {
77         tmplate = m->tmplate;
78         nargs = tmplate->getNoArgs();
79         tcode = tmplate->getTCode();
80         args_.resize(nargs);
81         idx = 0;
82         SetName(tmplate->GetName());
83         for (int i = 0; i < tmplate->nargs; ++i) {
84                 m->setArgumentIdx(i);
85                 MathedIter it(m->GetData());
86                 args_[i].row   = m->args_[i].row;
87                 args_[i].array = it.Copy();
88         }
89 }
90
91 MathMacro::~MathMacro()
92 {
93         for (idx = 0; idx < nargs; ++idx) {
94                 MathedIter it(args_[idx].array);
95                 it.Clear();
96                 delete args_[idx].row;
97         }
98 }
99
100
101 MathedInset * MathMacro::Clone()
102 {
103     return new MathMacro(this);
104 }
105
106
107 void MathMacro::Metrics()
108 {
109     if (nargs > 0)
110       tmplate->update(this);
111     tmplate->SetStyle(size);
112     tmplate->Metrics();
113     width = tmplate->Width();
114     ascent = tmplate->Ascent();
115     descent = tmplate->Descent();
116 }
117
118
119 void MathMacro::draw(Painter & pain, int x, int y)
120 {
121     xo = x;  yo = y;
122     Metrics();
123     tmplate->update(this);
124     tmplate->SetStyle(size);
125     tmplate->draw(pain, x, y);
126     for (int i = 0; i < nargs; ++i) {
127             tmplate->GetMacroXY(i, args_[i].x, args_[i].y);
128     }
129 }
130
131
132 int MathMacro::GetColumns() const
133 {
134     return tmplate->getMacroPar(idx)->GetColumns();
135 }
136
137
138 void MathMacro::GetXY(int & x, int & y) const
139 {
140     x = args_[idx].x;  y = args_[idx].y;
141 }
142
143
144 bool MathMacro::Permit(short f) const
145 {
146     return (nargs > 0) ?
147             tmplate->getMacroPar(idx)->Permit(f) : MathParInset::Permit(f);
148 }
149
150
151 void MathMacro::SetFocus(int x, int y)
152 {
153     tmplate->update(this);
154     tmplate->SetMacroFocus(idx, x, y);
155 }
156
157
158 void MathMacro::Write(ostream & os, bool fragile)
159 {
160     if (tmplate->flags & MMF_Exp) {
161             lyxerr[Debug::MATHED] << "Expand " << tmplate->flags
162                                   << ' ' << MMF_Exp << endl; 
163         tmplate->update(this);
164         tmplate->Write(os, fragile);
165     } else {
166         if (tmplate->flags & MMF_Env) {
167                 os << "\\begin{"
168                    << name
169                    << "} ";
170         } else {
171                 os << '\\' << name;
172         }
173 //      if (options) { 
174 //        file += '[';
175 //        file += options;
176 //        file += ']';
177 //      }
178         
179         if (!(tmplate->flags & MMF_Env) && nargs > 0) 
180                 os << '{';
181         
182         for (int i = 0; i < nargs; ++i) {
183             array = args_[i].array;
184             MathParInset::Write(os, fragile);
185             if (i < nargs - 1)  
186                     os << "}{";
187         }   
188         if (tmplate->flags & MMF_Env) {
189                 os << "\\end{"
190                    << name
191                    << '}';
192         } else {
193             if (nargs > 0) 
194                     os << '}';
195             else
196                     os << ' ';
197         }
198     }
199 }
200
201
202 /*---------------  Macro argument -----------------------------------*/
203
204 MathMacroArgument::MathMacroArgument(int n)
205 {
206     number = n;
207     expnd_mode = false;
208     SetType(LM_OT_MACRO_ARG);
209 }
210
211
212 void MathMacroArgument::draw(Painter & pain, int x, int baseline)
213 {
214         if (expnd_mode) {
215                 MathParInset::draw(pain, x, baseline);
216         }
217         else {
218                 std::ostringstream ost;
219                 ost << '#' << number;
220                 drawStr(pain, LM_TC_TEX, size, x, baseline, ost.str().c_str());
221         }
222 }
223
224
225 void MathMacroArgument::Metrics()
226 {
227         if (expnd_mode) {
228                 MathParInset::Metrics();
229         }
230         else {
231                 std::ostringstream ost;
232                 ost << '#' << number;
233                 width = mathed_string_width(LM_TC_TEX, size, ost.str().c_str());
234                 mathed_string_height(LM_TC_TEX, size, ost.str().c_str(),
235                                      ascent, descent);
236         }
237 }
238
239
240 void MathMacroArgument::Write(ostream & os, bool fragile)
241 {
242     if (expnd_mode) {
243         MathParInset::Write(os, fragile);
244     } else {
245             os << '#' << number << ' ';
246     }
247 }
248
249
250 /* --------------------- MathMacroTemplate ---------------------------*/
251
252 MathMacroTemplate::MathMacroTemplate(string const & nm, int na, int flg):
253     MathParInset(LM_ST_TEXT, nm, LM_OT_MACRO), 
254     flags(flg), nargs(na)
255 {
256         if (nargs > 0) {
257                 tcode = LM_TC_ACTIVE_INSET;
258                 args_.resize(nargs);
259                 for (int i = 0; i < nargs; ++i) {
260                         args_[i].setNumber(i + 1);
261                 }
262         } else {
263                 tcode = LM_TC_INSET;
264                 // Here is  nargs != args_.size()
265                 //args = 0;
266         }
267 }
268
269
270 MathMacroTemplate::~MathMacroTemplate()
271 {
272         // prevent to delete already deleted objects
273         for (int i = 0; i < nargs; ++i) {
274                 args_[i].SetData(0);
275         }
276 }
277
278
279 void MathMacroTemplate::setEditMode(bool ed)
280 {
281         if (ed) {
282                 flags |= MMF_Edit;
283                 for (int i = 0; i < nargs; ++i) {
284                         args_[i].setExpand(false);
285                 }
286         }
287         else {
288                 flags &= ~MMF_Edit;
289                 for (int i = 0; i < nargs; ++i) {
290                         args_[i].setExpand(true);
291                 }
292         }
293 }
294
295
296 void MathMacroTemplate::draw(Painter & pain, int x, int y)
297 {
298         int x2, y2;
299         bool expnd = (nargs > 0) ? args_[0].getExpand(): false;
300         if (flags & MMF_Edit) {
301                 for (int i = 0; i < nargs; ++i) {
302                         args_[i].setExpand(false);
303                 }
304                 x2 = x; y2 = y;
305         } else {
306                 for (int i = 0; i < nargs; ++i) {
307                         args_[i].setExpand(true);
308                 }
309                 x2 = xo; y2 = yo;
310         }
311         MathParInset::draw(pain, x, y);
312         xo = x2; yo = y2;
313
314         for (int i = 0; i < nargs; ++i) {
315                 args_[i].setExpand(expnd);
316         }
317 }
318
319
320 void MathMacroTemplate::Metrics()
321 {
322     bool expnd = (nargs > 0) ? args_[0].getExpand(): false;
323     
324     if (flags & MMF_Edit) {
325         for (int i = 0; i < nargs; ++i) {
326             args_[i].setExpand(false);
327         }
328     } else {
329         for (int i = 0; i < nargs; ++i) {
330             args_[i].setExpand(true);
331         }
332     }
333     MathParInset::Metrics();
334     
335     for (int i = 0; i < nargs; ++i) {
336         args_[i].setExpand(expnd);
337     }
338 }
339
340
341 void MathMacroTemplate::update(MathMacro * macro)
342 {
343     int idx = (macro) ? macro->getArgumentIdx() : 0;
344     for (int i = 0; i < nargs; ++i) {
345         if (macro) {
346             macro->setArgumentIdx(i);
347             args_[i].SetData(macro->GetData());
348             MathedRowSt * row = macro->getRowSt();
349             args_[i].setRowSt(row);
350         }
351     }   
352     if (macro)
353       macro->setArgumentIdx(idx);
354 }
355     
356
357 void MathMacroTemplate::WriteDef(ostream & os, bool fragile)
358 {
359         os << "\n\\newcommand{\\" << name << "}";
360
361         if (nargs > 0 ) 
362                 os << "[" << nargs << "]";
363
364         os << "{";
365
366         for (int i = 0; i < nargs; ++i) {
367                 args_[i].setExpand(false);
368         }        
369         Write(os, fragile); 
370         os << "}\n";
371 }
372
373
374 void MathMacroTemplate::setArgument(MathedArray * a, int i)
375 {
376     args_[i].SetData(a);
377 }
378
379
380 void MathMacroTemplate::GetMacroXY(int i, int & x, int & y) const
381 {
382     args_[i].GetXY(x, y);
383 }
384
385
386 MathParInset * MathMacroTemplate::getMacroPar(int i) const
387 {
388         if (i >= 0 && i < nargs) 
389                 return const_cast<MathParInset *>
390                         (static_cast<MathParInset const *>(&args_[i]));
391         else 
392                 return 0;
393 }
394
395
396 void MathMacroTemplate::SetMacroFocus(int &idx, int x, int y)
397 {
398         for (int i = 0; i < nargs; ++i) {
399                 if (args_[i].Inside(x, y)) {
400                         idx = i;
401                         break;
402                 }
403         }
404 }
405
406
407 /* -------------------------- MathMacroTable -----------------------*/
408
409 // The search is currently linear but will be binary or hash, later.
410 MathMacroTemplate * MathMacroTable::getTemplate(string const & name) const
411 {
412         for (size_type i = 0; i < macro_table.size(); ++i) {
413                 if (name == macro_table[i]->GetName()) 
414                         return macro_table[i];
415         }
416
417         return 0;
418 }
419
420 void MathMacroTable::addTemplate(MathMacroTemplate * m)
421 {
422         macro_table.push_back(m);
423 }
424
425
426 // All this stuff aparently leaks because it's created here and is not 
427 // deleted never, but it have to live all the LyX sesion. OK, would not
428 // so hard to do it in the MacroTable destructor, but this doesn't harm
429 // seriously, so don't bother me with purify results here.   ;-)
430
431 void MathMacroTable::builtinMacros()
432 {
433     MathedIter iter;
434     MathParInset * inset;// *arg;
435     MathedArray * array2;
436     
437     built = true;
438     
439     lyxerr[Debug::MATHED] << "Building macros" << endl;
440     
441     // This macro doesn't have arguments
442     MathMacroTemplate * m = new MathMacroTemplate("notin");  // this leaks
443     addTemplate(m);
444     MathedArray * array = new MathedArray; // this leaks
445     iter.SetData(array);
446     iter.Insert(new MathAccentInset(LM_in, LM_TC_BOPS, LM_not)); // this leaks
447     m->SetData(array);
448     
449     // These two are only while we are still with LyX 2.x
450     m = new MathMacroTemplate("emptyset"); // this leaks
451     addTemplate(m);
452     array = new MathedArray; // this leaks
453     iter.SetData(array);
454     iter.Insert(new MathAccentInset('O', LM_TC_RM, LM_not)); // this leaks
455     m->SetData(array);
456     
457     m = new MathMacroTemplate("perp"); // this leaks
458     addTemplate(m);
459     array = new MathedArray; // this leaks
460     iter.SetData(array);
461     iter.Insert(LM_bot, LM_TC_BOP);
462     m->SetData(array);
463
464     // binom has two arguments
465     m = new MathMacroTemplate("binom", 2);
466     addTemplate(m);
467     array = new MathedArray; 
468     m->SetData(array);
469     iter.SetData(array);
470     inset = new MathDelimInset('(', ')');
471     iter.Insert(inset, LM_TC_ACTIVE_INSET);
472     array = new MathedArray; 
473     iter.SetData(array);
474     MathFracInset * frac = new MathFracInset(LM_OT_ATOP);
475     iter.Insert(frac, LM_TC_ACTIVE_INSET);
476     inset->SetData(array);
477     array = new MathedArray;
478     array2 = new MathedArray;  
479     iter.SetData(array);
480     iter.Insert(m->getMacroPar(0));
481     iter.SetData(array2);
482     iter.Insert(m->getMacroPar(1));
483     frac->SetData(array, array2);
484
485 /*
486     // Cases has 1 argument
487     m = new MathMacroTemplate("cases", 1, MMF_Env); // this leaks
488     addTemplate(m);
489     array = new MathedArray; // this leaks
490     iter.SetData(array);
491     arg = new MathMatrixInset(2, 1); // this leaks
492
493     m->setArgument(arg);
494     arg->SetAlign('c', "ll");
495     iter.Insert(arg, LM_TC_ACTIVE_INSET);
496     inset = new MathDelimInset('{', '.'); // this leaks
497     inset->SetData(array);
498     array = new MathedArray; // this leaks
499     iter.SetData(array);
500     iter.Insert(inset, LM_TC_ACTIVE_INSET);
501     m->SetData(array);
502   
503
504     // the environment substack has 1 argument
505     m = new MathMacroTemplate("substack", 1, MMF_Env); // this leaks
506     addTemplate(m);     
507     arg = new MathMatrixInset(1, 1); // this leaks
508     m->setArgument(arg);
509     arg->SetType(LM_OT_MACRO);
510     array = new MathedArray; // this leaks
511     iter.SetData(array);
512     iter.Insert(arg, LM_TC_ACTIVE_INSET);
513     m->SetData(array);*/
514 }
515
516
517 MathMacroTable MathMacroTable::mathMTable;
518 bool MathMacroTable::built = false;