]> git.lyx.org Git - lyx.git/blob - src/mathed/math_parinset.C
fix "make dist" target
[lyx.git] / src / mathed / math_parinset.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "math_parinset.h"
8 #include "math_iter.h"
9 #include "array.h"
10 #include "math_xiter.h"
11 #include "math_parser.h"
12 #include "LColor.h"
13 #include "mathed/support.h"
14 #include "Painter.h"
15 #include "math_rowst.h"
16 #include "math_parinset.h"
17 #include "debug.h"
18
19 using std::endl;
20
21 extern int number_of_newlines;
22
23
24 MathedRowContainer & MathParInset::getRowSt()
25 {
26         return row_;
27 }
28
29
30 string MathParInset::label() const
31 {
32         if (row_.size() == 0) {
33                 lyxerr << "Warning: Empty rowst when accessing label!\n";
34                 return string();
35         }
36         return row_.back().getLabel();
37 }
38
39
40 MathParInset::MathParInset(short st, string const & nm, short ot)
41         : MathedInset(nm, ot, st)
42 {
43         ascent  = 8;
44         width   = 4;
45         descent = 0;
46         flag    = 1;
47         if (objtype == LM_OT_SCRIPT)
48                 flag |= LMPF_SCRIPT;
49 }
50
51
52 MathedInset * MathParInset::Clone()
53 {
54         return new MathParInset(*this);
55 }
56
57
58 void MathParInset::substitute(MathMacro * m)
59 {
60         //lyxerr << "called: MathParInset::substitute, m: " << m << endl;
61         array.substitute(m);
62 }
63
64
65
66 void MathParInset::setData(MathedArray const & a)
67 {
68         array = a;
69         
70         // A standard paragraph shouldn't have any tabs nor CRs.
71         MathedIter it(&array);
72         while (it.OK()) {
73                 char c = it.GetChar();
74                 if (c == LM_TC_TAB || c == LM_TC_CR) 
75                         it.Delete();
76                 else
77                         it.Next();
78         }
79 }
80
81
82 void MathParInset::draw(Painter & pain, int x, int y)
83 {
84         byte cxp = 0;
85         int xp   = 0;
86         int asc  = df_asc;
87         int des  = 0;
88         bool limits = false;
89         
90         xo_ = x;
91         yo_ = y;
92         MathedXIter data(this);
93         if (array.empty()) {
94                 data.GetPos(x, y);
95                 pain.rectangle(x, y - df_asc, df_width, df_asc,
96                                LColor::mathline);
97                 return;
98         }
99
100         data.GoBegin();
101         while (data.OK()) {
102                 data.GetPos(x, y);
103                 byte const cx = data.GetChar();
104                 if (cx >= ' ') {
105                         string const s = data.GetString();
106                         drawStr(pain, data.fcode(), size(), x, y, s);
107                         mathed_char_height(LM_TC_CONST, size(), 'y', asc, des);
108                         limits = false;
109                 } else if (cx == 0) {
110                         break;
111                 } else if (MathIsInset(cx)) {
112                         int yy = y;
113                         MathedInset * p = data.GetInset();
114                         if (cx == LM_TC_UP) {
115                                 if (limits) {
116                                         x -= (xp > p->Width()) ?
117                                                 p->Width() + (xp - p->Width()) / 2 : xp;  
118                                         yy -= (asc + p->Descent() + 4);
119                                 } else
120                                         yy -= (p->Descent() > asc) ?
121                                                 p->Descent() + 4 : asc;
122                         } else if (cx == LM_TC_DOWN) {
123                                 if (limits) {
124                                         x -= (xp > p->Width()) ?
125                                                 p->Width() + (xp - p->Width()) / 2 : xp;
126                                         yy += des + p->Ascent() + 2;
127                                 } else
128                                         yy += des + p->Ascent() / 2;
129                         } else {
130                                 asc = p->Ascent();
131                                 des = p->Descent();
132                         }
133                         p->draw(pain, x, yy);
134                         if (cx != LM_TC_UP && cx != LM_TC_DOWN) {
135                                 limits = p->GetLimits();
136                                 if (limits)
137                                         xp = p->Width();
138                         }
139                         data.Next();
140                 } else if (cx == LM_TC_TAB) {
141                         if (cxp == cx
142                             || cxp == LM_TC_CR || data.IsFirst()) {
143                                 pain.rectangle(x, y - df_asc,
144                                                df_width, df_asc,
145                                                LColor::mathline);
146                         }
147                         data.Next();
148                         limits = false;
149                 } else if (cx == LM_TC_CR) {
150                         if (cxp == LM_TC_TAB
151                             || cxp == LM_TC_CR || data.IsFirst()) {
152                                 pain.rectangle(x, y - df_asc,
153                                                df_width, df_asc,
154                                                LColor::mathline);
155                         }
156                         data.Next();
157                         limits = false;
158                 } else {         
159                         lyxerr << "GMathed Error: Unrecognized code[" << cx << "]" << endl;
160                         break;
161                 }
162         
163                 cxp = cx;
164         }
165         if (cxp == LM_TC_TAB || cxp == LM_TC_CR) { 
166                 data.GetPos(x, y);
167                 pain.rectangle(x, y - df_asc, df_width, df_asc,
168                                LColor::mathline);
169         }
170 }
171
172
173 void MathParInset::Metrics()
174 {
175         byte cx;
176         byte cxp = 0;
177         int ls;
178         int asc = df_asc;
179         int des = 0;
180         int tb  = 0;
181         int tab = 0;
182         
183         bool limits = false;
184         
185         ascent = df_asc;//mathed_char_height(LM_TC_VAR, size, 'I', asc, des); 
186         width  = df_width;
187         descent = 0;
188         if (array.empty())
189                 return;
190         
191         ascent = 0;
192         MathedXIter data(this);
193         data.GoBegin();
194         while (data.OK()) {
195                 cx = data.GetChar();      
196                 if (cx >= ' ') {
197                         string const s = data.GetString();
198                         mathed_string_height(data.fcode(),
199                                              size(), s, asc, des);
200                         if (asc > ascent)
201                                 ascent = asc;
202                         if (des > descent)
203                                 descent = des;
204                         limits = false;
205                         mathed_char_height(LM_TC_CONST, size(), 'y', asc, des);
206                 } else if (MathIsInset(cx)) {
207                         MathedInset * p = data.GetInset();
208                         p->SetStyle(size());   
209                         p->Metrics();
210                         if (cx == LM_TC_UP) {
211                                 asc += (limits) ? p->Height() + 4: p->Ascent() + 
212                                         ((p->Descent()>asc) ? p->Descent() - asc + 4: 0);
213                         } else if (cx == LM_TC_DOWN) {
214                                 des += (limits ? p->Height() + 4 : p->Height() - p->Ascent() / 2);
215                         } else {
216                                 asc = p->Ascent();
217                                 des = p->Descent();
218                         }
219                         if (asc > ascent)
220                                 ascent = asc;
221                         if (des > descent)
222                                 descent = des;
223                         if (cx!= LM_TC_UP && cx!= LM_TC_DOWN)
224                                 limits = p->GetLimits();
225                         data.Next();
226                 } else  if (cx == LM_TC_TAB) {
227                         int x;
228                         int y;
229                         data.GetIncPos(x, y);
230                         if (data.IsFirst() || cxp == LM_TC_TAB || cxp == LM_TC_CR) {
231                                 if (ascent < df_asc)
232                                         ascent = df_asc;
233                                 tb = x;
234                         }
235                         data.setTab(x - tb, tab);
236                         tb = x;
237                         ++tab;
238                         limits = false;                   
239                         data.Next();
240                 } else if (cx == LM_TC_CR) {
241                         if (tb > 0) {
242                                 int x;
243                                 int y;
244                                 data.GetIncPos(x, y);
245                                 if (data.IsFirst() || cxp == LM_TC_TAB || cxp == LM_TC_CR) {
246                                         if (ascent < df_asc)
247                                                 ascent = df_asc;
248                                         tb = x;
249                                 } 
250                                 data.setTab(x - tb, tab);
251                         } else //if (GetColumns() == 1) 
252                                 {
253                                         int x;
254                                         int y;
255                                         data.GetIncPos(x, y);
256                                         data.setTab(x, tab);
257                                         if (ascent < df_asc)
258                                                 ascent = df_asc;
259                                 } 
260                         tb = tab = 0;
261                         data.subMetrics(ascent, descent);
262                         ascent = df_asc;
263                         descent = 0;
264                         data.Next();
265                 } else {
266                         lyxerr << "Mathed Error: Unrecognized code[" << cx
267                                << "]" << endl;
268                         break;
269                 }       
270                 cxp = cx;
271         }
272         data.GetIncPos(width, ls);
273         
274         // No matter how simple is a matrix, it is NOT a subparagraph
275         if (isMatrix()) {
276                 if (cxp == LM_TC_TAB) {
277                         if (ascent < df_asc)
278                                 ascent = df_asc;
279                         data.setTab(0, tab);
280                 } else {
281                         data.setTab(width - tb, tab);
282                 }
283         }
284         
285         data.subMetrics(ascent, descent);
286 }
287
288
289
290 void MathParInset::Write(ostream & os, bool fragile)
291 {
292         if (array.empty())
293                 return;
294
295         int brace = 0;
296         latexkeys const * l;
297         MathedIter data(&array);
298         // hack
299         MathedRowContainer::iterator crow = getRowSt().begin();   
300         data.Reset();
301         
302         if (!Permit(LMPF_FIXED_SIZE)) { 
303                 l = lm_get_key_by_id(size(), LM_TK_STY);
304                 if (l)
305                         os << '\\' << l->name << ' ';
306         }
307         while (data.OK()) {
308                 byte cx = data.GetChar();
309                 if (cx >= ' ') {
310                         string str = data.GetString();
311                         
312                         if (data.fcode() >= LM_TC_RM && data.fcode() <= LM_TC_TEXTRM) {
313                                 os << '\\' << math_font_name[data.fcode()-LM_TC_RM] << '{';
314                         }
315                         for (string::const_iterator s = str.begin();
316                              s != str.end(); ++s) {
317                                 byte c = *s;
318                                 if (MathIsSymbol(data.fcode())) {
319                                         l = lm_get_key_by_id(c, (data.fcode() == LM_TC_BSYM) ?
320                                                              LM_TK_BIGSYM : LM_TK_SYM);
321                                         if (l) {
322                                                 os << '\\' << l->name << ' ';
323                                         } else {
324 #ifdef WITH_WARNINGS
325 #warning this does not compile on gcc 2.97
326 #endif
327                                                 //lyxerr << "Illegal symbol code[" << c
328                                                 //   << " " << str.end() - s << " " << data.fcode() << "]";
329                                         }
330                                 } else {
331                                         // Is there a standard logical XOR?
332                                         if ((data.fcode() == LM_TC_TEX && c != '{' && c != '}') ||
333                                             (data.fcode() == LM_TC_SPECIAL))
334                                                 os << '\\';
335                                         else {
336                                                 if (c == '{')
337                                                         ++brace;
338                                                 if (c == '}')
339                                                         --brace;
340                                         }
341                                         if (c == '}' && data.fcode() == LM_TC_TEX && brace < 0) 
342                                                 lyxerr <<"Math warning: Unexpected closing brace."
343                                                        << endl;
344                                         else           
345                                                 os << char(c);
346                                 }
347                         }
348                         if (data.fcode()>= LM_TC_RM && data.fcode()<= LM_TC_TEXTRM)
349                                 os << '}';
350                 } else {
351                         if (MathIsInset(cx)) {
352                                 MathedInset * p = data.GetInset();
353                                 if (cx == LM_TC_UP)
354                                         os << "^{";
355                                 if (cx == LM_TC_DOWN)
356                                         os << "_{";
357                                 p->Write(os, fragile);
358                                 if (cx == LM_TC_UP || cx == LM_TC_DOWN)
359                                         os << '}';
360                                 data.Next();
361                         } else {
362                                 switch (cx) {
363                                 case LM_TC_TAB:
364                                 {
365                                         os << " & ";
366                                         data.Next();
367                                         break;
368                                 }
369                                 case LM_TC_CR:
370                                 {
371                                         if (crow) {
372                                                 if (!crow->isNumbered()) {  
373                                                         os << "\\nonumber ";
374                                                 }
375                                                 if (!crow->getLabel().empty()) {
376                                                         os << "\\label{"
377                                                            << crow->getLabel()
378                                                            << "} ";
379                                                 }
380                                                 ++crow;
381                                         }
382                                         if (fragile)
383                                                 os << "\\protect";
384                                         os << "\\\\\n";
385                                         ++number_of_newlines;
386                                         data.Next();
387                                         break;
388                                 }
389                                 default:
390                                         lyxerr << "WMath Error: unrecognized code[" << cx << "]";
391                                         return;
392                                 }     
393                         }
394                 }
395         }
396         
397         if (crow) {
398                 if (!crow->isNumbered()) {
399                         os << "\\nonumber ";
400                 }
401                 if (!crow->getLabel().empty()) {
402                         os << "\\label{"
403                            << crow->getLabel()
404                            << "} ";
405                 }
406         }
407
408         if (brace > 0)
409                 os << string(brace, '}');
410 }
411
412
413 void MathParInset::WriteNormal(ostream & os)
414 {
415         if (array.empty()) {
416                 os << "[par] ";
417                 return;
418         }
419
420         os << "[par ";
421
422         int brace = 0;
423         latexkeys const * l;
424         MathedIter data(&array);
425         // hack
426         MathedRowContainer::iterator crow = getRowSt().begin();   
427         data.Reset();
428         
429         if (!Permit(LMPF_FIXED_SIZE)) { 
430                 l = lm_get_key_by_id(size(), LM_TK_STY);
431                 if (l)
432                         os << l->name << ' ';
433         }
434         while (data.OK()) {
435                 byte cx = data.GetChar();
436                 if (cx >= ' ') {
437                         string str = data.GetString();
438                         
439                         if (data.fcode() >= LM_TC_RM && data.fcode() <= LM_TC_TEXTRM) {
440                                 os << "[font " << math_font_name[data.fcode()-LM_TC_RM] << " [";
441                         }
442                         for (string::const_iterator s = str.begin();
443                              s != str.end(); ++s) {
444                                 byte c = *s;
445                                 if (MathIsSymbol(data.fcode())) {
446                                         l = lm_get_key_by_id(c, (data.fcode() == LM_TC_BSYM) ?
447                                                              LM_TK_BIGSYM : LM_TK_SYM);
448                                         if (l) {
449                                                 os << " [" << l->name << "] ";
450                                         } else {
451 #ifdef WITH_WARNINGS
452 #warning this does not compile on gcc 2.97
453 #endif
454                                                 //lyxerr << "Illegal symbol code[" << c
455                                                 //   << " " << str.end() - s << " " << data.fcode() << "]";
456                                         }
457                                 } else {
458                                         // Is there a standard logical XOR?
459                                         if ((data.fcode() == LM_TC_TEX && c != '{' && c != '}') ||
460                                             (data.fcode() == LM_TC_SPECIAL))
461                                                 os << "[";
462                                         else {
463                                                 if (c == '{')
464                                                         ++brace;
465                                                 if (c == '}')
466                                                         --brace;
467                                         }
468                                         if (c == '}' && data.fcode() == LM_TC_TEX && brace < 0) 
469                                                 lyxerr <<"Math warning: Unexpected closing brace."
470                                                        << endl;
471                                         else           
472                                                 os << char(c);
473                                 }
474                         }
475                         if (data.fcode()>= LM_TC_RM && data.fcode()<= LM_TC_TEXTRM)
476                                 os << "] ";
477                 } else {
478                         if (MathIsInset(cx)) {
479                                 MathedInset * p = data.GetInset();
480                                 if (cx == LM_TC_UP)
481                                         os << "[superscript ";
482                                 if (cx == LM_TC_DOWN)
483                                         os << "[subscript ";
484                                 p->WriteNormal(os);
485                                 if (cx == LM_TC_UP || cx == LM_TC_DOWN)
486                                         os << "] ";
487                                 data.Next();
488                         } else {
489                                 switch (cx) {
490                                 case LM_TC_TAB:
491                                 {
492                                         os << "] [";
493                                         data.Next();
494                                         break;
495                                 }
496                                 case LM_TC_CR:
497                                 {
498                                         os << "] ] ";
499                                         data.Next();
500                                         break;
501                                 }
502                                 default:
503                                         lyxerr << "WMath Error: unrecognized code[" << cx << "]";
504                                         return;
505                                 }     
506                         }
507                 }
508         }
509         
510         if (brace > 0)
511                 os << string(brace, '}');
512
513         os << "] ";
514 }
515
516
517 void MathParInset::clear()
518 {
519         array.clear();
520 }
521
522 bool MathParInset::Inside(int x, int y) 
523 {
524   return (x >= xo() && x <= xo() + width
525           && y <= yo() + descent && y >= yo() - ascent);
526 }
527
528
529 void MathParInset::GetXY(int & x, int & y) const
530 {
531    x = xo();
532    y = yo();
533 }
534
535
536 void MathParInset::UserSetSize(short sz)
537 {
538         if (sz >= 0) {
539                 size(sz);      
540                 flag = flag & ~LMPF_FIXED_SIZE;
541         }
542 }
543
544
545 void MathParInset::SetStyle(short sz) 
546 {
547         if (Permit(LMPF_FIXED_SIZE)) {
548                 if (Permit(LMPF_SCRIPT)) 
549                         sz = (sz < LM_ST_SCRIPT) ? LM_ST_SCRIPT: LM_ST_SCRIPTSCRIPT;
550                 if (Permit(LMPF_SMALLER) && sz < LM_ST_SCRIPTSCRIPT) 
551                         ++sz;
552                 MathedInset::SetStyle(sz);
553         }
554 }
555
556
557 bool MathParInset::Permit(short f) const
558 {
559         return bool(f & flag);
560 }
561
562
563 MathedArray & MathParInset::GetData()
564 {
565         return array;
566 }
567
568 void MathParInset::push_back(MathedInset * inset, int t)
569 {
570         array.push_back(inset, t);
571 }
572
573
574 MathedArray const & MathParInset::GetData() const
575 {
576         return array;
577 }
578
579
580 void MathParInset::setXY(int x, int y)
581 {
582         xo_ = x;
583         yo_ = y;
584 }