]> git.lyx.org Git - lyx.git/blob - src/lyxfont.C
7e67c81f0028e0de912629d0e343455b70938b7a
[lyx.git] / src / lyxfont.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-1999 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12 #include <clocale>
13
14 #ifdef __GNUG__
15 #pragma implementation "lyxfont.h"
16 #endif
17
18 #include <cctype>
19
20 #include "gettext.h"
21 #include "lyxfont.h"
22 #include "debug.h"
23 #include "lyxrc.h"
24 #include "lyxlex.h"
25 #include "FontLoader.h"
26 #include "support/lstrings.h"
27
28 extern LyXRC * lyxrc;
29
30 // The global fontloader
31 FontLoader fontloader;
32
33 //
34 // Names for the GUI
35 //
36
37 string const GUIFamilyNames[6] = 
38 { N_("Roman"), N_("Sans serif"), N_("Typewriter"), N_("Symbol"), N_("Inherit"),
39   N_("Ignore") };
40   
41 string const GUISeriesNames[4] = 
42 { N_("Medium"), N_("Bold"), N_("Inherit"), N_("Ignore") };
43
44 string const GUIShapeNames[6] = 
45 { N_("Upright"), N_("Italic"), N_("Slanted"), N_("Smallcaps"), N_("Inherit"),
46   N_("Ignore") };
47
48 string const GUISizeNames[14] = 
49 { N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"),
50   N_("Larger"), N_("Largest"), N_("Huge"), N_("Huger"), N_("Increase"), N_("Decrease"), 
51   N_("Inherit"), N_("Ignore") };
52  
53 string const lGUISizeNames[15] = 
54 { N_("tiny"), N_("smallest"), N_("smaller"), N_("small"), N_("normal"), N_("large"),
55   N_("larger"), N_("largest"), N_("huge"), N_("huger"), N_("increase"), N_("decrease"),
56   N_("inherit"), N_("ignore"), string() };
57  
58 string const GUIMiscNames[5] = 
59 { N_("Off"), N_("On"), N_("Toggle"), N_("Inherit"), N_("Ignore") };
60
61 string const GUIDirectionNames[5] = 
62 { N_("LTR"), N_("RTL"), N_("Toggle"), N_("Inherit"), N_("Ignore") };
63
64
65 //
66 // Strings used to read and write .lyx format files
67 //
68 string const LyXFamilyNames[6] = 
69 { "roman", "sans", "typewriter", "symbol", "default", "error" };
70  
71 string const LyXSeriesNames[4] = 
72 { "medium", "bold", "default", "error" };
73  
74 string const LyXShapeNames[6] = 
75 { "up", "italic", "slanted", "smallcaps", "default", "error" };
76  
77 string const LyXSizeNames[14] = 
78 { "tiny", "scriptsize", "footnotesize", "small", "normal", "large",
79   "larger", "largest", "huge", "giant", 
80   "increase-error", "decrease-error", "default", "error" };
81
82 string const LyXMiscNames[12] = 
83 { "off", "on", "toggle", "default", "error" };
84
85 //
86 // Strings used to write LaTeX files
87 //
88
89 string const LaTeXFamilyNames[6] = 
90 { "textrm", "textsf", "texttt", "error1", "error2", "error3" };
91  
92 string const LaTeXSeriesNames[4] = 
93 { "textmd", "textbf", "error4", "error5" };
94  
95 string const LaTeXShapeNames[6] = 
96 { "textup", "textit", "textsl", "textsc", "error6", "error7" };
97  
98 string const LaTeXSizeNames[14] = 
99 { "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
100   "Large", "LARGE", "huge", "Huge", "error8", "error9", "error10", "error11" };
101
102 #ifdef NEW_BITS
103 LyXFont::FontBits LyXFont::sane = { ROMAN_FAMILY,
104                   MEDIUM_SERIES,
105                   UP_SHAPE,
106                   SIZE_NORMAL,
107                   LColor::none,
108                   OFF,
109                   OFF,
110                   OFF,
111                   OFF,
112                   LTR_DIR };
113
114 LyXFont::FontBits LyXFont::inherit = { INHERIT_FAMILY, 
115                       INHERIT_SERIES, 
116                       INHERIT_SHAPE, 
117                       INHERIT_SIZE,
118                       LColor::inherit,
119                       INHERIT,
120                       INHERIT,
121                       INHERIT,
122                       INHERIT,
123                       INHERIT_DIR };
124
125 LyXFont::FontBits LyXFont::ignore = { IGNORE_FAMILY,
126                      IGNORE_SERIES,
127                      IGNORE_SHAPE,
128                      IGNORE_SIZE,
129                      LColor::ignore,
130                      IGNORE,
131                      IGNORE,
132                      IGNORE,
133                      IGNORE,
134                      IGNORE_DIR };
135 #endif
136
137 /// Decreases font size by one
138 LyXFont & LyXFont::decSize() 
139 {
140         switch (size()) {
141         case SIZE_HUGER:        setSize(SIZE_HUGE);     break;
142         case SIZE_HUGE:         setSize(SIZE_LARGEST);  break;
143         case SIZE_LARGEST:      setSize(SIZE_LARGER);   break;
144         case SIZE_LARGER:       setSize(SIZE_LARGE);    break;
145         case SIZE_LARGE:        setSize(SIZE_NORMAL);   break;
146         case SIZE_NORMAL:       setSize(SIZE_SMALL);    break;
147         case SIZE_SMALL:        setSize(SIZE_FOOTNOTE); break;
148         case SIZE_FOOTNOTE:     setSize(SIZE_SCRIPT);   break;
149         case SIZE_SCRIPT:       setSize(SIZE_TINY);     break;
150         case SIZE_TINY:         break;
151         case INCREASE_SIZE:
152                 lyxerr << "Can't LyXFont::decSize on INCREASE_SIZE" << endl;
153                 break;
154         case DECREASE_SIZE:
155                 lyxerr <<"Can't LyXFont::decSize on DECREASE_SIZE" << endl;
156                 break;
157         case INHERIT_SIZE:
158                 lyxerr <<"Can't LyXFont::decSize on INHERIT_SIZE" << endl;
159                 break;
160         case IGNORE_SIZE:
161                 lyxerr <<"Can't LyXFont::decSize on IGNORE_SIZE" << endl;
162                 break;
163         }
164         return *this;
165 }
166
167
168 /// Increases font size by one
169 LyXFont & LyXFont::incSize() 
170 {
171         switch(size()) {
172         case SIZE_HUGER:        break;
173         case SIZE_HUGE:         setSize(SIZE_HUGER);    break;
174         case SIZE_LARGEST:      setSize(SIZE_HUGE);     break;
175         case SIZE_LARGER:       setSize(SIZE_LARGEST);  break;
176         case SIZE_LARGE:        setSize(SIZE_LARGER);   break;
177         case SIZE_NORMAL:       setSize(SIZE_LARGE);    break;
178         case SIZE_SMALL:        setSize(SIZE_NORMAL);   break;
179         case SIZE_FOOTNOTE:     setSize(SIZE_SMALL);    break;
180         case SIZE_SCRIPT:       setSize(SIZE_FOOTNOTE); break;
181         case SIZE_TINY:         setSize(SIZE_SCRIPT);   break;
182         case INCREASE_SIZE:
183                 lyxerr <<"Can't LyXFont::incSize on INCREASE_SIZE" << endl;
184                 break;
185         case DECREASE_SIZE:
186                 lyxerr <<"Can't LyXFont::incSize on DECREASE_SIZE" << endl;
187                 break;
188         case INHERIT_SIZE:
189                 lyxerr <<"Can't LyXFont::incSize on INHERIT_SIZE" << endl;
190                 break;
191         case IGNORE_SIZE:
192                 lyxerr <<"Can't LyXFont::incSize on IGNORE_SIZE" << endl;
193                 break;
194         }
195         return *this;
196 }
197
198
199 /// Updates a misc setting according to request
200 LyXFont::FONT_MISC_STATE LyXFont::setMisc(FONT_MISC_STATE newfont, 
201                                           FONT_MISC_STATE org)
202 {
203         if (newfont == TOGGLE) {
204                 if (org == ON)
205                         return OFF;
206                 else if (org == OFF)
207                         return ON;
208                 else {
209                         lyxerr <<"LyXFont::setMisc: Need state"
210                                 " ON or OFF to toggle. Setting to ON" << endl;
211                         return ON;
212                 }
213         } else if (newfont == IGNORE)
214                 return org;
215         else 
216                 return newfont;
217 }
218
219
220 /// Updates font settings according to request
221 void LyXFont::update(LyXFont const & newfont, bool toggleall)
222 {
223         if(newfont.family() == family() && toggleall)
224                 setFamily(INHERIT_FAMILY); // toggle 'back'
225         else if (newfont.family() != IGNORE_FAMILY)
226                 setFamily(newfont.family());
227         // else it's IGNORE_SHAPE
228
229         // "Old" behaviour: "Setting" bold will toggle bold on/off.
230         switch (newfont.series()) {
231         case BOLD_SERIES:
232                 // We toggle...
233                 if (series() == BOLD_SERIES && toggleall)
234                         setSeries(MEDIUM_SERIES);
235                 else
236                         setSeries(BOLD_SERIES);
237                 break;
238         case MEDIUM_SERIES:
239         case INHERIT_SERIES:
240                 setSeries(newfont.series());
241                 break;
242         case IGNORE_SERIES: 
243                 break;
244         }
245
246         if(newfont.shape() == shape() && toggleall)
247                 setShape(INHERIT_SHAPE); // toggle 'back'
248         else if (newfont.shape() != IGNORE_SHAPE)
249                 setShape(newfont.shape());
250         // else it's IGNORE_SHAPE
251
252         if (newfont.size() != IGNORE_SIZE) {
253                 if (newfont.size() == INCREASE_SIZE)
254                         incSize();
255                 else if (newfont.size() == DECREASE_SIZE)
256                         decSize();
257                 else if (newfont.size() == size() && toggleall)
258                         setSize(INHERIT_SIZE); // toggle 'back'
259                 else
260                         setSize(newfont.size());
261         }
262
263         setEmph(setMisc(newfont.emph(), emph()));
264         setUnderbar(setMisc(newfont.underbar(), underbar()));
265         setNoun(setMisc(newfont.noun(), noun()));
266         setLatex(setMisc(newfont.latex(), latex()));
267
268         switch(newfont.direction()) {
269         case TOGGLE_DIR:
270                 if (direction() == LTR_DIR)
271                         setDirection(RTL_DIR);
272                 else
273                         setDirection(LTR_DIR);
274                 break;
275         case IGNORE_DIR:
276                 break;
277         default:
278                 setDirection(newfont.direction());
279         }
280
281         if(newfont.color() == color() && toggleall)
282                 setColor(LColor::inherit); // toggle 'back'
283         else if (newfont.color() != LColor::ignore)
284                 setColor(newfont.color());
285 }
286
287
288 /// Reduce font to fall back to template where possible
289 void LyXFont::reduce(LyXFont const & tmplt)
290 {
291         if (family() == tmplt.family())
292                 setFamily(INHERIT_FAMILY);
293         if (series() == tmplt.series())
294                 setSeries(INHERIT_SERIES);
295         if (shape() == tmplt.shape())
296                 setShape(INHERIT_SHAPE);
297         if (size() == tmplt.size())
298                 setSize(INHERIT_SIZE);
299         if (emph() == tmplt.emph())
300                 setEmph(INHERIT);
301         if (underbar() == tmplt.underbar())
302                 setUnderbar(INHERIT);
303         if (noun() == tmplt.noun())
304                 setNoun(INHERIT);
305         if (latex() == tmplt.latex())
306                 setLatex(INHERIT);
307         if (color() == tmplt.color())
308                 setColor(LColor::inherit);
309         if (direction() == tmplt.direction())
310                 setDirection(INHERIT_DIR);
311 }
312
313
314 /// Realize font from a template
315 // This one is not pretty, but it's extremely fast (Asger)
316 #ifdef NEW_BITS
317 LyXFont & LyXFont::realize(LyXFont const & tmplt)
318 {
319         if (bits == inherit) {
320                 bits = tmplt.bits;
321                 return *this;
322         }
323         
324         if (bits.family == INHERIT_FAMILY) {
325                 bits.family = tmplt.bits.family;
326         }
327         if (bits.series == INHERIT_SERIES) {
328                 bits.series = tmplt.bits.series;
329         }
330         if (bits.shape == INHERIT_SHAPE) {
331                 bits.shape = tmplt.bits.shape;
332         }
333         if (bits.size == INHERIT_SIZE) {
334                 bits.size = tmplt.bits.size;
335         }
336         if (bits.emph == INHERIT) {
337                 bits.emph = tmplt.bits.emph;
338         }
339         if (bits.underbar == INHERIT) {
340                 bits.underbar = tmplt.bits.underbar;
341         }
342         if (bits.noun == INHERIT) {
343                 bits.noun = tmplt.bits.noun;
344         }
345         if (bits.latex == INHERIT) {
346                 bits.latex = tmplt.bits.latex;
347         }
348         if (bits.color == LColor::inherit) {
349                 bits.color = tmplt.bits.color;
350         }
351         if (bits.direction == INHERIT_DIR) {
352                 bits.direction = tmplt.bits.direction;
353         }
354
355         return *this;
356 }
357 #else
358 LyXFont & LyXFont::realize(LyXFont const & tmplt)
359 {
360         if (bits == inherit) {
361                 bits = tmplt.bits;
362                 return *this;
363         }
364
365         if ((bits & (Fam_Mask<<Fam_Pos)) == (ui32(INHERIT_FAMILY)<<Fam_Pos))
366                 {
367                         bits &= ~(Fam_Mask << Fam_Pos);
368                         bits |= (tmplt.bits & Fam_Mask << Fam_Pos);
369                 }
370         if ((bits & (Ser_Mask<<Ser_Pos)) == (ui32(INHERIT_SERIES)<<Ser_Pos))
371                 {
372                         bits &= ~(Ser_Mask << Ser_Pos);
373                         bits |= (tmplt.bits & Ser_Mask << Ser_Pos);
374                 }
375         if ((bits & (Sha_Mask << Sha_Pos)) == ui32(INHERIT_SHAPE) << Sha_Pos)
376                 {
377                         bits &= ~(Sha_Mask << Sha_Pos);
378                         bits |= (tmplt.bits & Sha_Mask << Sha_Pos);
379                 }
380         if ((bits & (Siz_Mask << Siz_Pos)) == ui32(INHERIT_SIZE) << Siz_Pos)
381                 {
382                         bits &= ~(Siz_Mask << Siz_Pos);
383                         bits |= (tmplt.bits & Siz_Mask << Siz_Pos);
384                 }
385         if ((bits & (Misc_Mask << Emp_Pos)) == ui32(INHERIT) << Emp_Pos)
386                 {
387                         bits &= ~(Misc_Mask << Emp_Pos);
388                         bits |= (tmplt.bits & Misc_Mask << Emp_Pos);
389                 }
390         if ((bits & (Misc_Mask << Und_Pos)) == ui32(INHERIT) << Und_Pos)
391                 {
392                         bits &= ~(Misc_Mask << Und_Pos);
393                         bits |= (tmplt.bits & Misc_Mask << Und_Pos);
394                 }
395         if ((bits & (Misc_Mask << Nou_Pos)) == ui32(INHERIT) << Nou_Pos)
396                 {
397                         bits &= ~(Misc_Mask << Nou_Pos);
398                         bits |= (tmplt.bits & Misc_Mask << Nou_Pos);
399                 }
400         if ((bits & (Misc_Mask << Lat_Pos)) == ui32(INHERIT) << Lat_Pos)
401                 {
402                         bits &= ~(Misc_Mask << Lat_Pos);
403                         bits |= (tmplt.bits & Misc_Mask << Lat_Pos);
404                 }
405         if ((bits & (Col_Mask << Col_Pos)) == ui32(LColor::inherit) << Col_Pos)
406                 {
407                         bits &= ~(Col_Mask << Col_Pos);
408                         bits |= (tmplt.bits & Col_Mask << Col_Pos);
409                 }
410         if ((bits & (Dir_Mask << Dir_Pos)) == ui32(INHERIT_DIR) << Dir_Pos)
411                 {
412                         bits &= ~(Dir_Mask << Dir_Pos);
413                         bits |= (tmplt.bits & Dir_Mask << Dir_Pos);
414                 }
415
416         return *this;
417 }
418 #endif
419
420
421 /// Is font resolved?
422 bool LyXFont::resolved() const
423 {
424         return (family() != INHERIT_FAMILY && series() != INHERIT_SERIES &&
425                 shape() != INHERIT_SHAPE && size() != INHERIT_SIZE &&
426                 emph() != INHERIT && underbar() != INHERIT && 
427                 noun() != INHERIT && latex() != INHERIT && 
428                 color() != LColor::inherit &&
429                 direction() != INHERIT_DIR);
430 }
431
432
433 /// Build GUI description of font state
434 string LyXFont::stateText() const
435 {
436         string buf;
437         if (family() != INHERIT_FAMILY)
438                 buf += string(_(GUIFamilyNames[family()].c_str())) + ", ";
439         if (series() != INHERIT_SERIES)
440                 buf += string(_(GUISeriesNames[series()].c_str())) + ", ";
441         if (shape() != INHERIT_SHAPE)
442                 buf += string(_(GUIShapeNames[shape()].c_str())) + ", ";
443         if (size() != INHERIT_SIZE)
444                 buf += string(_(GUISizeNames[size()].c_str())) + ", ";
445         if (color() != LColor::inherit)
446                 buf += lcolor.getGUIName(color()) + ", ";
447         if (emph() != INHERIT)
448                 buf += string(_("Emphasis ")) + _(GUIMiscNames[emph()].c_str()) + ", ";
449         if (underbar() != INHERIT)
450                 buf += string(_("Underline ")) + _(GUIMiscNames[underbar()].c_str()) + ", ";
451         if (noun() != INHERIT)
452                 buf += string(_("Noun ")) + _(GUIMiscNames[noun()].c_str()) + ", ";
453         if (latex() != INHERIT)
454                 buf += string(_("Latex ")) + _(GUIMiscNames[latex()].c_str()) + ", ";
455         if (direction() != INHERIT_DIR)
456                 buf += string(_("Direction ")) + _(GUIDirectionNames[direction()].c_str()) + ", ";
457         if (buf.empty())
458                 buf = _("Default");
459         buf = strip(buf, ' ');
460         buf = strip(buf, ',');
461         return buf;
462 }
463
464
465 // Set family according to lyx format string
466 LyXFont & LyXFont::setLyXFamily(string const & fam)
467 {
468         string s = lowercase(fam);
469
470         int i = 0;
471         while (s != LyXFamilyNames[i] && LyXFamilyNames[i] != "error") ++i;
472         if (s == LyXFamilyNames[i]) {
473                 setFamily(LyXFont::FONT_FAMILY(i));
474         } else
475                 lyxerr << "LyXFont::setLyXFamily: Unknown family `"
476                        << s << '\'' << endl;
477         return *this;
478 }
479
480
481 // Set series according to lyx format string
482 LyXFont & LyXFont::setLyXSeries(string const & ser)
483 {
484         string s = lowercase(ser);
485
486         int i = 0;
487         while (s != LyXSeriesNames[i] && LyXSeriesNames[i] != "error") ++i;
488         if (s == LyXSeriesNames[i]) {
489                 setSeries(LyXFont::FONT_SERIES(i));
490         } else
491                 lyxerr << "LyXFont::setLyXSeries: Unknown series `"
492                        << s << '\'' << endl;
493         return *this;
494 }
495
496
497 // Set shape according to lyx format string
498 LyXFont & LyXFont::setLyXShape(string const & sha)
499 {
500         string s = lowercase(sha);
501
502         int i = 0;
503         while (s != LyXShapeNames[i] && LyXShapeNames[i] != "error") ++i;
504         if (s == LyXShapeNames[i]) {
505                 setShape(LyXFont::FONT_SHAPE(i));
506         } else
507                 lyxerr << "LyXFont::setLyXShape: Unknown shape `"
508                        << s << '\'' << endl;
509         return *this;
510 }
511
512
513 // Set size according to lyx format string
514 LyXFont & LyXFont::setLyXSize(string const & siz)
515 {
516         string s = lowercase(siz);
517         int i = 0;
518         while (s != LyXSizeNames[i] && LyXSizeNames[i] != "error") ++i;
519         if (s == LyXSizeNames[i]) {
520                 setSize(LyXFont::FONT_SIZE(i));
521         } else
522                 lyxerr << "LyXFont::setLyXSize: Unknown size `"
523                        << s << '\'' << endl;
524         return *this;
525 }
526
527 // Set size according to lyx format string
528 LyXFont::FONT_MISC_STATE LyXFont::setLyXMisc(string const & siz)
529 {
530         string s = lowercase(siz);
531         int i= 0;
532         while (s != LyXMiscNames[i] && LyXMiscNames[i] != "error") ++i;
533         if (s == LyXMiscNames[i])
534                 return FONT_MISC_STATE(i);
535         lyxerr << "LyXFont::setLyXMisc: Unknown misc flag `"
536                << s << '\'' << endl;
537         return OFF;
538 }
539
540 /// Sets color after LyX text format
541 LyXFont & LyXFont::setLyXColor(string const & col)
542 {
543         setColor(lcolor.getFromLyXName(col));
544         return *this;
545 }
546
547
548 /// Sets size after GUI name
549 LyXFont & LyXFont::setGUISize(string const & siz)
550 {
551 #warning this might be wrong.
552         /// ??????
553         // this is how it was how it was done in the lyx repository...
554         // but this does not make sense.
555         setColor(lcolor.getFromGUIName(siz));
556         return *this;
557 }
558
559
560 // Returns size in latex format
561 string LyXFont::latexSize() const
562 {
563         return LaTeXSizeNames[size()];
564 }
565
566
567 // Read a font definition from given file in lyx format
568 // Used for layouts
569 LyXFont & LyXFont::lyxRead(LyXLex & lex)
570 {
571         bool error = false;
572         bool finished = false;
573         while (!finished && lex.IsOK() && !error) {
574                 lex.next();
575                 string tok = lowercase(lex.GetString());
576
577                 if (tok.empty()) {
578                         continue;
579                 } else if (tok == "endfont") {
580                         finished = true;
581                 } else if (tok == "family") {
582                         lex.next();
583                         string tok = lex.GetString();
584                         setLyXFamily(tok);
585                 } else if (tok == "series") {
586                         lex.next();
587                         string tok = lex.GetString();
588                         setLyXSeries(tok);
589                 } else if (tok == "shape") {
590                         lex.next();
591                         string tok = lex.GetString();
592                         setLyXShape(tok);
593                 } else if (tok == "size") {
594                         lex.next();
595                         string tok = lex.GetString();
596                         setLyXSize(tok);
597                 } else if (tok == "latex") {
598                         lex.next();
599                         string tok = lowercase(lex.GetString());
600
601                         if (tok == "no_latex") {
602                                 setLatex(OFF);
603                         } else if (tok == "latex") {
604                                 setLatex(ON);
605                         } else {
606                                 lex.printError("Illegal LaTeX type`$$Token'");
607                         }
608                 } else if (tok == "misc") {
609                         lex.next();
610                         string tok = lowercase(lex.GetString());
611
612                         if (tok == "no_bar") {
613                                 setUnderbar(OFF);
614                         } else if (tok == "no_emph") {
615                                 setEmph(OFF);
616                         } else if (tok == "no_noun") {
617                                 setNoun(OFF);
618                         } else if (tok == "emph") {
619                                 setEmph(ON);
620                         } else if (tok == "underbar") {
621                                 setUnderbar(ON);
622                         } else if (tok == "noun") {
623                                 setNoun(ON);
624                         } else {
625                                 lex.printError("Illegal misc type `$$Token´");
626                         }
627                 } else if (tok == "color") {
628                         lex.next();
629                         string tok = lex.GetString();
630                         setLyXColor(tok);
631                 } else if (tok == "direction") {
632                         lex.next();
633                         string tok = lowercase(lex.GetString());
634
635                         if (tok == "ltr") {
636                                 setDirection(LTR_DIR);
637                         } else if (tok == "rtl") {
638                                 setDirection(RTL_DIR);
639                         } else {
640                                 lex.printError("Illegal type`$$Token'");
641                         }
642                 } else {
643                         lex.printError("Unknown tag `$$Token'");
644                         error = true;
645                 }
646         }
647         return *this;
648 }
649
650
651 /// Writes the changes from this font to orgfont in .lyx format in file
652 void LyXFont::lyxWriteChanges(LyXFont const & orgfont, ostream & os) const
653 {
654         os << "\n";
655         if (orgfont.family() != family()) {
656                 os << "\\family " << LyXFamilyNames[family()] << " \n";
657         }
658         if (orgfont.series() != series()) {
659                 os << "\\series " << LyXSeriesNames[series()] << " \n";
660         }
661         if (orgfont.shape() != shape()) {
662                 os << "\\shape " << LyXShapeNames[shape()] << " \n";
663         }
664         if (orgfont.size() != size()) {
665                 os << "\\size " << LyXSizeNames[size()] << " \n";
666         }
667         if (orgfont.emph() != emph()) {
668                 os << "\\emph " << LyXMiscNames[emph()] << " \n";
669         }
670         if (orgfont.underbar() != underbar()) {
671                 // This is only for backwards compatibility
672                 switch (underbar()) {
673                 case OFF:       os << "\\bar no \n"; break;
674                 case ON:        os << "\\bar under \n"; break;
675                 case TOGGLE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
676                                         "TOGGLE should not appear here!"
677                                        << endl;
678                 break;
679                 case INHERIT:   os << "\\bar default \n"; break;
680                 case IGNORE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
681                                         "IGNORE should not appear here!"
682                                        << endl;
683                 break;
684                 }
685         }
686         if (orgfont.noun() != noun()) {
687                 os << "\\noun " << LyXMiscNames[noun()] << " \n";
688         }
689         if (orgfont.latex() != latex()) {
690                 // This is only for backwards compatibility
691                 switch (latex()) {
692                 case OFF:       os << "\\latex no_latex \n"; break;
693                 case ON:        os << "\\latex latex \n"; break;
694                 case TOGGLE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
695                                         "TOGGLE should not appear here!"
696                                        << endl;
697                 break;
698                 case INHERIT:   os << "\\latex default \n"; break;
699                 case IGNORE:    lyxerr << "LyXFont::lyxWriteFontChanges: "
700                                         "IGNORE should not appear here!"
701                                        << endl;
702                 break;
703                 }
704         }
705         if (orgfont.color() != color()) {
706                 os << "\\color " << lcolor.getLyXName(color()) << "\n";
707         }
708         if (orgfont.direction() != direction()) {
709                 switch (direction()) {
710                 case RTL_DIR:   os << "\\direction rtl \n"; break;
711                 case LTR_DIR:   os << "\\direction ltr\n"; break;
712                 case TOGGLE_DIR:   lyxerr << "LyXFont::lyxWriteFontChanges: "
713                                         "TOGGLE should not appear here!"
714                                        << endl;
715                 case INHERIT_DIR:   os << "\\direction default \n"; break;
716                 case IGNORE_DIR:    lyxerr << "LyXFont::lyxWriteFontChanges: "
717                                         "IGNORE should not appear here!"
718                                        << endl;
719                 break;
720                 }
721         }
722 }
723
724
725 /// Writes the head of the LaTeX needed to impose this font
726 // Returns number of chars written.
727 int LyXFont::latexWriteStartChanges(string & file, LyXFont const & base,
728                                     LyXFont const & prev) const
729 {
730         LyXFont f = *this;
731         f.reduce(base);
732         
733         if (f.bits == inherit)
734                 return 0;
735         
736         int count = 0;
737         bool env = false;
738
739         FONT_DIRECTION direction = f.direction();
740         if (direction != prev.direction()) {
741                 if (direction == LTR_DIR) {
742                         file += "\\L{";
743                         count += 3;
744                         env = true; //We have opened a new environment
745                 }
746                 if (direction == RTL_DIR) {
747                         file += "\\R{";
748                         count += 3;
749                         env = true; //We have opened a new environment
750                 }
751         }
752
753         if (f.family() != INHERIT_FAMILY) {
754                 file += '\\';
755                 file += LaTeXFamilyNames[f.family()];
756                 file += '{';
757                 count += LaTeXFamilyNames[f.family()].length() + 2;
758                 env = true; //We have opened a new environment
759         }
760         if (f.series() != INHERIT_SERIES) {
761                 file += '\\';
762                 file += LaTeXSeriesNames[f.series()];
763                 file += '{';
764                 count += LaTeXSeriesNames[f.series()].length() + 2;
765                 env = true; //We have opened a new environment
766         }
767         if (f.shape() != INHERIT_SHAPE) {
768                 file += '\\';
769                 file += LaTeXShapeNames[f.shape()];
770                 file += '{';
771                 count += LaTeXShapeNames[f.shape()].length() + 2;
772                 env = true; //We have opened a new environment
773         }
774         if (f.color() != LColor::inherit) {
775                 file += "\\textcolor{";
776                 file += lcolor.getLaTeXName(f.color());
777                 file += "}{";
778                 count += lcolor.getLaTeXName(f.color()).length() + 13;
779                 env = true; //We have opened a new environment
780         }
781         if (f.emph() == ON) {
782                 file += "\\emph{";
783                 count += 6;
784                 env = true; //We have opened a new environment
785         }
786         if (f.underbar() == ON) {
787                 file += "\\underbar{";
788                 count += 10;
789                 env = true; //We have opened a new environment
790         }
791         // \noun{} is a LyX special macro
792         if (f.noun() == ON) {
793                 file += "\\noun{";
794                 count += 8;
795                 env = true; //We have opened a new environment
796         }
797         if (f.size() != INHERIT_SIZE) {
798                 // If we didn't open an environment above, we open one here
799                 if (!env) {
800                         file += '{';
801                         ++count;
802                 }
803                 file += '\\';
804                 file += LaTeXSizeNames[f.size()];
805                 file += ' ';
806                 count += LaTeXSizeNames[f.size()].length() + 2;
807         }
808         return count;
809 }
810
811
812 /// Writes ending block of LaTeX needed to close use of this font
813 // Returns number of chars written
814 // This one corresponds to latexWriteStartChanges(). (Asger)
815 int LyXFont::latexWriteEndChanges(string & file, LyXFont const & base,
816                                   LyXFont const & next) const
817 {
818         LyXFont f = *this; // why do you need this?
819         f.reduce(base); // why isn't this just "reduce(base);" (Lgb)
820         // Because this function is const. Everything breaks if this
821         // method changes the font it represents. There is no speed penalty
822         // by using the temporary. (Asger)
823
824         if (f.bits == inherit)
825                 return 0;
826         
827         int count = 0;
828         bool env = false;
829
830         FONT_DIRECTION direction = f.direction();
831         if ( direction != next.direction()
832             && (direction == RTL_DIR || direction == LTR_DIR) ) {
833                 file += '}';
834                 ++count;
835                 env = true; // Size change need not bother about closing env.
836         }
837
838         if (f.family() != INHERIT_FAMILY) {
839                 file += '}';
840                 ++count;
841                 env = true; // Size change need not bother about closing env.
842         }
843         if (f.series() != INHERIT_SERIES) {
844                 file += '}';
845                 ++count;
846                 env = true; // Size change need not bother about closing env.
847         }
848         if (f.shape() != INHERIT_SHAPE) {
849                 file += '}';
850                 ++count;
851                 env = true; // Size change need not bother about closing env.
852         }
853         if (f.color() != LColor::inherit) {
854                 file += '}';
855                 ++count;
856                 env = true; // Size change need not bother about closing env.
857         }
858         if (f.emph() == ON) {
859                 file += '}';
860                 ++count;
861                 env = true; // Size change need not bother about closing env.
862         }
863         if (f.underbar() == ON) {
864                 file += '}';
865                 ++count;
866                 env = true; // Size change need not bother about closing env.
867         }
868         if (f.noun() == ON) {
869                 file += '}';
870                 ++count;
871                 env = true; // Size change need not bother about closing env.
872         }
873         if (f.size() != INHERIT_SIZE) {
874                 // We only have to close if only size changed
875                 if (!env) {
876                         file += '}';
877                         ++count;
878                 }
879         }
880         
881         return count;
882 }
883
884
885 LColor::color LyXFont::realColor() const
886 {
887         if (latex() == ON)
888                 return LColor::latex;
889         if (color() == LColor::none)
890                 return LColor::foreground;
891         return color();
892 }
893
894
895 // Convert logical attributes to concrete shape attribute
896 LyXFont::FONT_SHAPE LyXFont::realShape() const
897 {
898         register FONT_SHAPE s = shape();
899
900         if (emph() == ON) {
901                 if (s == UP_SHAPE)
902                         s = ITALIC_SHAPE;
903                 else
904                         s = UP_SHAPE;
905         }
906         if (noun() == ON)
907                 s = SMALLCAPS_SHAPE;
908         return s;
909 }
910
911
912 XFontStruct * LyXFont::getXFontstruct() const
913 {
914         return fontloader.load(family(), series(), realShape(), size());
915 }
916
917
918 int LyXFont::maxAscent() const
919 {
920         return getXFontstruct()->ascent;
921 }
922
923
924 int LyXFont::maxDescent() const
925 {
926         return getXFontstruct()->descent;
927 }
928
929
930 int LyXFont::ascent(char c) const
931 {
932         XFontStruct * finfo = getXFontstruct();
933         unsigned int uc = static_cast<unsigned char>(c);
934         if (finfo->per_char
935             && uc >= finfo->min_char_or_byte2
936             && uc <= finfo->max_char_or_byte2) 
937                 return finfo->per_char[uc - finfo->min_char_or_byte2].ascent;
938         else
939                 return finfo->ascent;
940 }
941
942
943 int LyXFont::descent(char c) const
944 {
945         XFontStruct * finfo = getXFontstruct();
946         unsigned int uc = static_cast<unsigned char>(c);
947         if (finfo->per_char
948             && uc >= finfo->min_char_or_byte2
949             && uc <= finfo->max_char_or_byte2) 
950                 return finfo->per_char[uc - finfo->min_char_or_byte2].descent;
951         else
952                 return finfo->descent;
953 }
954
955
956 // Specialized after profiling. (Asger)
957 int LyXFont::width(char c) const
958 {
959         if (realShape() != LyXFont::SMALLCAPS_SHAPE){
960                 return XTextWidth(getXFontstruct(), &c, 1);
961         } else {
962                 return textWidth(&c, 1);
963         }
964 }
965
966
967 int LyXFont::lbearing(char c) const
968 {
969         XFontStruct * finfo = getXFontstruct();
970         unsigned int uc = static_cast<unsigned char>(c);
971         if (finfo->per_char
972             && uc >= finfo->min_char_or_byte2
973             && uc <= finfo->max_char_or_byte2) 
974                 return finfo->per_char[uc - finfo->min_char_or_byte2].lbearing;
975         else
976                 return 0;
977 }
978
979
980 int LyXFont::rbearing(char c) const
981 {
982         XFontStruct * finfo = getXFontstruct();
983         unsigned int uc = static_cast<unsigned char>(c);
984         if (finfo->per_char
985             && uc >= finfo->min_char_or_byte2
986             && uc <= finfo->max_char_or_byte2) 
987                 return finfo->per_char[uc - finfo->min_char_or_byte2].rbearing;
988         else
989                 return width(c);
990 }
991
992
993 int LyXFont::textWidth(char const * s, int n) const
994 {
995         if (realShape() != LyXFont::SMALLCAPS_SHAPE){
996                 return XTextWidth(getXFontstruct(), s, n);
997         } else {
998                 // emulate smallcaps since X doesn't support this
999                 unsigned int result = 0;
1000                 char c;
1001                 LyXFont smallfont = *this;
1002                 smallfont.decSize();
1003                 smallfont.decSize();
1004                 smallfont.setShape(LyXFont::UP_SHAPE);
1005                 for (int i = 0; i < n; ++i) {
1006                         c = s[i];
1007                         // when islower is a macro, the cast is needed (JMarc)
1008                         if (islower(static_cast<unsigned char>(c))){
1009                                 c = toupper(c);
1010                                 result += XTextWidth(smallfont.getXFontstruct(), &c, 1);
1011                         } else {
1012                                 result += XTextWidth(getXFontstruct(), &c, 1);
1013                         }
1014                 }
1015                 return result;
1016         }
1017 }
1018
1019
1020 int LyXFont::stringWidth(string const & s) const
1021 {
1022         if (s.empty()) return 0;
1023         return textWidth(s.c_str(), s.length());
1024 }
1025
1026
1027 int LyXFont::signedStringWidth(string const & s) const
1028 {
1029         if (s.empty()) return 0;
1030         if (s.c_str()[0] == '-')
1031                 return -textWidth(s.c_str()+1, s.length()-1);
1032         else
1033                 return textWidth(s.c_str(), s.length());
1034 }
1035
1036
1037 int LyXFont::drawText(char const * s, int n, Pixmap, 
1038                       int, int x) const
1039 {
1040         if (realShape() != LyXFont::SMALLCAPS_SHAPE) {
1041                 /* XDrawString(fl_display,
1042                    pm,
1043                    getGC(),
1044                    x, baseline,
1045                    s, n);
1046                    XFlush(fl_display); */
1047                 return XTextWidth(getXFontstruct(), s, n);
1048
1049         } else {
1050                 // emulate smallcaps since X doesn't support this
1051                 char c;
1052                 int sx = x;
1053                 LyXFont smallfont = *this;
1054                 smallfont.decSize();
1055                 smallfont.decSize();
1056                 smallfont.setShape(LyXFont::UP_SHAPE);
1057                 for (int i = 0; i < n; ++i) {
1058                         c = s[i];
1059                         if (islower(static_cast<unsigned char>(c))){
1060                                 c = toupper(c);
1061                                 /* XDrawString(fl_display,
1062                                    pm,
1063                                    smallfont.getGC(),
1064                                    x, baseline,
1065                                    &c, 1); */
1066                                 x += XTextWidth(smallfont.getXFontstruct(),
1067                                                 &c, 1);
1068                                 //XFlush(fl_display);
1069                         } else {
1070                                 /* XDrawString(fl_display,
1071                                    pm,
1072                                    getGC(),
1073                                    x, baseline,
1074                                    &c, 1);*/
1075                                 x += XTextWidth(getXFontstruct(), &c, 1);
1076                                 //XFlush(fl_display);
1077                         }
1078                 }
1079                 return x - sx;
1080         }
1081 }
1082
1083
1084 int LyXFont::drawString(string const & s, Pixmap pm, int baseline, int x) const
1085 {
1086         return drawText(s.c_str(), s.length(), pm, baseline, x);
1087 }
1088
1089
1090 bool LyXFont::equalExceptLatex(LyXFont const & f) const 
1091 {
1092         LyXFont f1 = *this;
1093         f1.setLatex(f.latex());
1094         return f1 == f;
1095 }
1096
1097
1098 LyXDirection LyXFont::getFontDirection() const
1099 {
1100         if (lyxrc->rtl_support 
1101             && direction() == LyXFont::RTL_DIR
1102             && latex() != LyXFont::ON)
1103                 return LYX_DIR_RIGHT_TO_LEFT;
1104         else
1105                 return LYX_DIR_LEFT_TO_RIGHT;
1106 }
1107
1108
1109 ostream & operator<<(ostream & o, LyXFont::FONT_MISC_STATE fms)
1110 {
1111         return o << int(fms);
1112 }