]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parinset.C
2ca3d14a092101296a04a7769d87f2810c1350d0
[lyx.git] / src / mathed / math_parinset.C
1 #include <config.h>
2
3 #include "math_parinset.h"
4 #include "math_iter.h"
5 #include "array.h"
6 #include "math_xiter.h"
7 #include "LColor.h"
8 #include "mathed/support.h"
9 #include "Painter.h"
10 #include "math_parser.h"
11 #include "math_rowst.h"
12 #include "math_parinset.h"
13 #include "debug.h"
14
15 using std::endl;
16
17 extern int number_of_newlines;
18
19
20 MathedRowSt * MathParInset::getRowSt() const
21 {
22         return 0;
23 }
24
25
26 MathParInset::MathParInset(short st, string const & nm, short ot)
27         : MathedInset(nm, ot, st)
28 {
29         ascent = 8;
30         width = 4;
31         descent = 0;
32         flag = 1;
33         if (objtype == LM_OT_SCRIPT)
34                 flag |= LMPF_SCRIPT;
35 }
36
37
38 MathParInset::MathParInset(MathParInset * p)
39         : MathedInset(p)
40 {
41         flag = p->flag;
42         p->setArgumentIdx(0);
43         MathedIter it(p->GetData());
44         setData(it.Copy());
45 }
46
47
48 MathParInset::~MathParInset()
49 {
50 }
51
52
53 MathedInset * MathParInset::Clone()
54 {
55         return new MathParInset(this);
56 }
57
58
59 void MathParInset::setData(MathedArray * a)
60 {
61         array = *a;
62         
63         // A standard paragraph shouldn't have any tabs nor CRs.
64         MathedIter it(&array);
65         while (it.OK()) {
66                 char c = it.GetChar();
67                 if (c == LM_TC_TAB || c == LM_TC_CR) 
68                         it.Delete();
69                 else
70                         it.Next();
71         }
72 }
73
74
75 void 
76 MathParInset::draw(Painter & pain, int x, int y)
77 {
78         byte cxp = 0;
79         int xp = 0;
80         int asc = df_asc;
81         int des = 0;
82         bool limits = false;
83         
84         xo_ = x;
85         yo_ = y; 
86         if (array.empty()) {
87                 MathedXIter data(this);
88                 data.GetPos(x, y);
89                 pain.rectangle(x, y - df_asc, df_width, df_asc, LColor::mathline);
90                 return;
91         }  
92         MathedXIter data(this);
93         data.GoBegin();
94         while (data.OK()) {
95                 data.GetPos(x, y);
96                 byte cx = data.GetChar();
97                 if (cx >= ' ') {
98                         string s = data.GetString();
99                         drawStr(pain, data.fcode(), size(), x, y, s);
100                         mathed_char_height(LM_TC_CONST, size(), 'y', asc, des);
101                         limits = false;
102                 }
103                 else {
104                         if (cx == 0)
105                                 break;
106                         if (MathIsInset(cx)) {
107                                 int yy = y;
108                                 MathedInset * p = data.GetInset();
109                                 if (cx == LM_TC_UP) {
110                                         if (limits) {
111                                                 x -= (xp>p->Width()) ? p->Width()+(xp-p->Width())/2: xp;  
112                                                 yy -= (asc + p->Descent()+4);
113                                         }       
114                                         else
115                                                 yy -= (p->Descent()>asc) ? p->Descent()+4: asc;
116                                 }
117                                 else if (cx == LM_TC_DOWN) {
118                                         if (limits) {
119                                                 x -= (xp>p->Width()) ? p->Width()+(xp-p->Width())/2: xp;
120                                                 yy += des + p->Ascent() + 2;
121                                         } else
122                                                 yy += des + p->Ascent()/2;
123                                 }
124                                 else {
125                                         asc = p->Ascent();
126                                         des = p->Descent();
127                                 }
128                                 p->draw(pain, x, yy);
129                                 if (cx!= LM_TC_UP && cx!= LM_TC_DOWN) {
130                                         limits = p->GetLimits();
131                                         if (limits)
132                                                 xp = p->Width();
133                                 }
134                                 data.Next();
135                         }
136                         else if (cx == LM_TC_TAB) {
137                                 if (cxp == cx || cxp == LM_TC_CR || data.IsFirst()) {
138                                         pain.rectangle(x, y - df_asc, df_width, df_asc, LColor::mathline);
139                                 }
140                                 data.Next();
141                                 limits = false;
142                         }
143                         else if (cx == LM_TC_CR) {
144                                 if (cxp == LM_TC_TAB || cxp == LM_TC_CR || data.IsFirst()) {
145                                         pain.rectangle(x, y - df_asc, df_width, df_asc, LColor::mathline);
146                                 }
147                                 data.Next();
148                                 limits = false;
149                         }
150                         else {   
151                                 lyxerr << "GMathed Error: Unrecognized code[" << cx << "]" << endl;
152                                 break;
153                         }
154                 }
155                 cxp = cx;
156         }
157         if (cxp == LM_TC_TAB || cxp == LM_TC_CR) { 
158                 data.GetPos(x, y);
159                 pain.rectangle(x, y - df_asc, df_width, df_asc, LColor::mathline);
160         }
161 }
162
163
164 void 
165 MathParInset::Metrics()
166 {
167         byte cx;
168         byte cxp = 0;
169         int ls;
170         int asc = df_asc;
171         int des = 0;
172         int tb = 0;
173         int tab = 0;
174         
175         bool limits = false;
176         
177         ascent = df_asc;//mathed_char_height(LM_TC_VAR, size, 'I', asc, des); 
178         width = df_width;
179         descent = 0;
180         if (array.empty()) return;
181         
182         ascent = 0;
183         MathedXIter data(this);
184         data.GoBegin();
185         while (data.OK()) {
186                 cx = data.GetChar();      
187                 if (cx >= ' ') {
188                         string s = data.GetString();
189                         mathed_string_height(data.fcode(),
190                                              size(), s, asc, des);
191                         if (asc > ascent) ascent = asc;
192                         if (des > descent) descent = des;
193                         limits = false;
194                         mathed_char_height(LM_TC_CONST, size(), 'y', asc, des);
195                 } else
196                         if (MathIsInset(cx)) {
197                                 MathedInset * p = data.GetInset();
198                                 p->SetStyle(size());   
199                                 p->Metrics();
200                                 if (cx == LM_TC_UP) {
201                                         asc += (limits) ? p->Height() + 4: p->Ascent() + 
202                                                 ((p->Descent()>asc) ? p->Descent() - asc + 4: 0);
203                                 } else
204                                         if (cx == LM_TC_DOWN) {
205                                                 des += ((limits) ? p->Height() + 4: p->Height() - p->Ascent() / 2);
206                                         } else {
207                                                 asc = p->Ascent();
208                                                 des = p->Descent();
209                                         }
210                                 if (asc > ascent) ascent = asc;
211                                 if (des > descent) descent = des;
212                                 if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
213                                         limits = p->GetLimits();
214                                 data.Next();
215                         } else 
216                                 if (cx == LM_TC_TAB) {
217                                         int x, y;
218                                         data.GetIncPos(x, y);
219                                         if (data.IsFirst() || cxp == LM_TC_TAB || cxp == LM_TC_CR) {
220                                                 if (ascent<df_asc) ascent = df_asc;
221                                                 tb = x;
222                                         }
223                                         data.setTab(x-tb, tab);
224                                         tb = x;
225                                         ++tab;
226                                         limits = false;                   
227                                         data.Next();
228                                 } else
229                                         if (cx == LM_TC_CR) {
230                                                 if (tb > 0) {
231                                                         int x, y;
232                                                         data.GetIncPos(x, y);
233                                                         if (data.IsFirst() || cxp == LM_TC_TAB || cxp == LM_TC_CR) {
234                                                                 if (ascent<df_asc) ascent = df_asc;
235                                                                 tb = x;
236                                                         } 
237                                                         data.setTab(x - tb, tab);
238                                                 } else //if (GetColumns() == 1) 
239                                                         {
240                                                                 int x, y;
241                                                                 data.GetIncPos(x, y);
242                                                                 data.setTab(x, tab);
243                                                                 if (ascent<df_asc) ascent = df_asc;
244                                                         } 
245                                                 tb = tab = 0;
246                                                 data.subMetrics(ascent, descent);
247                                                 ascent = df_asc;   
248                                                 descent = 0;
249                                                 data.Next();
250                                         } else {
251                                                 lyxerr << "Mathed Error: Unrecognized code[" << cx
252                                                        << "]" << endl;
253                                                 break;
254                                         }       
255                 cxp = cx;
256         }
257         data.GetIncPos(width, ls);
258         
259         // No matter how simple is a matrix, it is NOT a subparagraph
260         if (isMatrix()) {
261                 if (cxp == LM_TC_TAB) {
262                         if (ascent<df_asc) ascent = df_asc;
263                         data.setTab(0, tab);
264                 } else {
265                         data.setTab(width - tb, tab);
266                 }
267         }
268         
269         data.subMetrics(ascent, descent);
270 }
271
272
273
274 void MathParInset::Write(ostream & os, bool fragile)
275 {
276         if (array.empty()) return;
277         int brace = 0;
278         latexkeys const * l;
279         MathedIter data(&array);
280         // hack
281         MathedRowSt const * crow = getRowSt();   
282         data.Reset();
283         
284         if (!Permit(LMPF_FIXED_SIZE)) { 
285                 l = lm_get_key_by_id(size(), LM_TK_STY);
286                 if (l) {
287                         os << '\\' << l->name << ' ';
288                 }
289         }
290         while (data.OK()) {
291                 byte cx = data.GetChar();
292                 if (cx >= ' ') {
293                         string str = data.GetString();
294                         
295                         if (data.fcode() >= LM_TC_RM && data.fcode() <= LM_TC_TEXTRM) {
296                                 os << '\\' << math_font_name[data.fcode()-LM_TC_RM] << '{';
297                         }
298                         for (string::const_iterator s = str.begin();
299                              s != str.end(); ++s) {
300                                 byte c = *s;
301                                 if (MathIsSymbol(data.fcode())) {
302                                         l = lm_get_key_by_id(c, (data.fcode() == LM_TC_BSYM) ?
303                                                              LM_TK_BIGSYM : LM_TK_SYM);
304                                         if (l) {
305                                                 os << '\\' << l->name << ' ';
306                                         } else {
307 #warning this does not compile on gcc 2.97
308                                                 //lyxerr << "Illegal symbol code[" << c
309                                                 //   << " " << str.end() - s << " " << data.fcode() << "]";
310                                         }
311                                 } else {
312                                         // Is there a standard logical XOR?
313                                         if ((data.fcode() == LM_TC_TEX && c != '{' && c != '}') ||
314                                             (data.fcode() == LM_TC_SPECIAL))
315                                                 os << '\\';
316                                         else {
317                                                 if (c == '{') ++brace;
318                                                 if (c == '}') --brace;
319                                         }
320                                         if (c == '}' && data.fcode() == LM_TC_TEX && brace < 0) 
321                                                 lyxerr <<"Math warning: Unexpected closing brace."
322                                                        << endl;
323                                         else           
324                                                 os << char(c);
325                                 }
326                         }
327                         if (data.fcode()>= LM_TC_RM && data.fcode()<= LM_TC_TEXTRM)
328                                 os << '}';
329                 } else     
330                         if (MathIsInset(cx)) {
331                                 MathedInset * p = data.GetInset();
332                                 if (cx == LM_TC_UP)
333                                         os << "^{";
334                                 if (cx == LM_TC_DOWN)
335                                         os << "_{";
336                                 p->Write(os, fragile);
337                                 if (cx == LM_TC_UP || cx == LM_TC_DOWN)
338                                         os << '}';
339                                 data.Next();
340                         } else
341                                 switch (cx) {
342                                 case LM_TC_TAB:
343                                 {
344                                         os << " & ";
345                                         data.Next();
346                                         break;
347                                 }
348                                 case LM_TC_CR:
349                                 {
350                                         if (crow) {
351                                                 if (!crow->isNumbered()) {  
352                                                         os << "\\nonumber ";
353                                                 }
354                                                 if (!crow->getLabel().empty()) {
355                                                         os << "\\label{"
356                                                            << crow->getLabel()
357                                                            << "} ";
358                                                 }
359                                                 crow = crow->getNext();
360                                         }
361                                         if (fragile)
362                                                 os << "\\protect";
363                                         os << "\\\\\n";
364                                         ++number_of_newlines;
365                                         data.Next();
366                                         break;
367                                 }
368                                 default:
369                                         lyxerr << "WMath Error: unrecognized code[" << cx << "]";
370                                         return;
371                                 }     
372         }
373         
374         if (crow) {
375                 if (!crow->isNumbered()) {
376                         os << "\\nonumber ";
377                 }
378                 if (!crow->getLabel().empty()) {
379                         os << "\\label{"
380                            << crow->getLabel()
381                            << "} ";
382                 }
383         }
384
385         if (brace > 0)
386                 os << string(brace, '}');
387 }
388
389
390 bool MathParInset::Inside(int x, int y) 
391 {
392   return (x >= xo() && x <= xo() + width
393           && y <= yo() + descent && y >= yo() - ascent);
394 }
395
396
397 void MathParInset::GetXY(int & x, int & y) const
398 {
399    x = xo();
400    y = yo();
401 }
402
403
404 void MathParInset::UserSetSize(short sz)
405 {
406    if (sz >= 0) {
407        size(sz);      
408        flag = flag & ~LMPF_FIXED_SIZE;
409    }
410 }
411
412
413 void MathParInset::SetStyle(short sz) 
414 {
415     if (Permit(LMPF_FIXED_SIZE)) {
416         if (Permit(LMPF_SCRIPT)) 
417           sz = (sz < LM_ST_SCRIPT) ? LM_ST_SCRIPT: LM_ST_SCRIPTSCRIPT;
418         if (Permit(LMPF_SMALLER) && sz < LM_ST_SCRIPTSCRIPT) {
419             ++sz;
420         } 
421         MathedInset::SetStyle(sz);
422     }
423 }
424
425
426 bool MathParInset::Permit(short f) const
427 {
428         return bool(f & flag);
429 }
430
431
432 MathedArray * MathParInset::GetData()
433 {
434         return &array;
435 }
436
437
438 void MathParInset::setXY(int x, int y)
439 {
440         xo_ = x;
441         yo_ = y;
442 }