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