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