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