]> git.lyx.org Git - lyx.git/blob - src/insets/insetlatexaccent.C
dd97fcf5859d4d0d434f9e5ac758b9fd4705edb5
[lyx.git] / src / insets / insetlatexaccent.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
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "insetlatexaccent.h"
18 #include "debug.h"
19 #include "lyxrc.h"
20 #include "lyxdraw.h"
21 #include "support/lstrings.h"
22 #include "Painter.h"
23
24 extern LyXRC * lyxrc;
25
26 /* LatexAccent. Proper handling of accented characters */
27 /* This part is done by Ivan Schreter, schreter@ccsun.tuke.sk */
28 /* Later modified by Lars G. Bjønnes, larsbj@lyx.org */
29
30 InsetLatexAccent::InsetLatexAccent()
31 {
32         candisp = false;
33 }
34
35
36 InsetLatexAccent::InsetLatexAccent(string const & string)
37         : contents(string)
38 {
39         checkContents();
40 }
41
42
43 void InsetLatexAccent::checkContents()
44         // check, if we know the modifier and can display it ok on screen
45 {
46         candisp = false;
47
48         if (contents.empty() || contents.length() < 2) return;
49
50         // REMOVE IN 0.13
51         // Dirty Hack for backward compability. remove in 0.13 (Lgb)
52         contents = frontStrip(strip(contents));
53         if (!contains(contents, "{") && !contains(contents, "}")) {
54                 if (contents.length() == 2) {
55                         string tmp;
56                         tmp += contents[0];
57                         tmp += contents[1];
58                         tmp += "{}";
59                         contents = tmp;
60                 } else if (contents.length() == 3) {
61                         string tmp;
62                         tmp += contents[0];
63                         tmp += contents[1];
64                         tmp += '{';
65                         tmp += contents[2];
66                         tmp += '}';
67                         contents = tmp;
68                 } else if (contents.length() == 4 && contents[2] == ' ') {
69                         string tmp;
70                         tmp += contents[0];
71                         tmp += contents[1];
72                         tmp += '{';
73                         tmp += contents[3];
74                         tmp += '}';
75                         contents = tmp;
76                 } else if  (contents.length() == 4 && contents[2] == '\\'
77                             && (contents[3] == 'i' || contents[3] == 'j')) {
78                         string tmp;
79                         tmp += contents[0];
80                         tmp += contents[1];
81                         tmp += '{';
82                         tmp += contents[2];
83                         tmp += contents[3];
84                         tmp += '}';
85                         contents = tmp;
86                 }
87         }
88         if (contents[0] != '\\') return; // demand that first char is a '\\'
89
90         lyxerr[Debug::KEY] << "Decode: " << contents << endl;
91
92         remdot = false; plusasc = false; plusdesc = false;
93
94         switch (contents[1]) { // second char should be one of these
95         case '\'':  // acute
96                 modtype = ACUTE;    // acute
97                 plusasc = true;    // at the top of character
98                 break;
99         case '`':   // grave
100                 modtype = GRAVE;    // grave
101                 plusasc = true;    // at the top
102                 break;
103         case '=':   // macron
104                 modtype = MACRON;    // macron
105                 plusasc = true;    // at the top
106                 break;
107         case '~':   // tilde
108                 modtype = TILDE;    // tilde
109                 plusasc = true;    // at the top
110                 break;
111         case 'b':   // underbar
112                 modtype = UNDERBAR;    // underbar
113                 plusdesc = true;   // at the bottom
114                 break;
115         case 'c':   // cedilla
116                 modtype = CEDILLA;    // cedilla
117                 plusdesc = true;   // at the bottom
118                 break;
119         case 'd':   // underdot
120                 modtype = UNDERDOT;    // underdot
121                 plusdesc = true;   // at the bottom
122                 break;
123         case 'r':   // circle
124                 modtype = CIRCLE;    // circle
125                 plusasc = true;    // at the top
126                 break;
127         case 't':   // tie
128                 modtype = TIE;    // tie
129                 plusasc = true;    // at the top
130                 break;
131         case 'u':   // breve
132                 modtype = BREVE;    // breve
133                 plusasc = true;    // at the top
134                 break;
135         case 'v':   // caron
136                 modtype = CARON;   // caron
137                 plusasc = true;    // at the top
138                 break;
139         case 'q':   // special caron
140                 modtype = SPECIAL_CARON;   // special caron
141                 plusasc = true;    // at the top
142                 break;
143         case 'H':   // hungarian umlaut
144                 modtype = HUNGARIAN_UMLAUT;   // hungarian umlaut
145                 plusasc = true;    // at the top
146                 break;
147         case '"':   // umlaut
148                 modtype = UMLAUT;   // umlaut
149                 plusasc = true;    // at the top
150                 break;
151         case '.':   // dot
152                 modtype = DOT;   // dot
153                 plusasc = true;    // at the top
154                 break;
155         case '^':   // circumflex
156                 modtype = CIRCUMFLEX;   // circumflex
157                 plusasc = true;    // at the top
158                 break;
159         case 'k':   // ogonek
160                 modtype = OGONEK;  // ogonek
161                 plusdesc = true;
162                 break;
163         case 'i': // dot-less-i
164                 modtype = DOT_LESS_I;  // dot-less-i
165                 plusasc = true; // at the top (not really needed)
166                 remdot = true;
167                 break;
168         case 'j': // dot-less-j
169                 modtype = DOT_LESS_J; // dot-less-j
170                 plusasc = true; // at the top (not really needed)
171                 remdot = true;
172                 break;
173         case 'l': // lslash
174                 modtype = lSLASH;
175                 plusasc = true; // at the top (not really needed)
176                 break;
177         case 'L': // lslash
178                 modtype = LSLASH;
179                 plusasc = true; // at the top (not really needed)
180                 break;
181         default:
182                 printf ("Default\n");
183                 // unknow accent (or something else)
184                 return;
185         }
186
187         // we demand that third char is a '{' (Lgb)
188         if (contents[2] != '{') return;
189
190         // special clause for \i{}, \j{} \l{} and \L{}
191         if ((modtype == DOT_LESS_I || modtype == DOT_LESS_J
192              || modtype == lSLASH || modtype == LSLASH)
193             && contents[3] == '}' ) {
194                 switch (modtype) {
195                 case DOT_LESS_I: ic = 'i'; break;
196                 case DOT_LESS_J: ic = 'j'; break;
197                 case lSLASH:     ic = 'l'; break;
198                 case LSLASH:     ic = 'L'; break;
199                 default:
200                         // if this happens something is really wrong
201                         lyxerr << "InsetLaTexAccent: weird error." << endl;
202                         break;
203                 }
204                 //ic = (modtype == DOT_LESS_J ? 'j' : 'i');
205                 lyxerr[Debug::KEY] << "Contents: [" << contents << "]"
206                                    << ", ic: " << ic 
207                                    << ", top: " << plusasc 
208                                    << ", bot: " << plusdesc 
209                                    << ", dot: " << remdot 
210                                    << ", mod: " << modtype << endl;
211                 // Special case for space
212         } else if (contents[3] == '}') {
213                 ic = ' ';
214         } else {
215                 int i = 3;
216                 
217                 // now get the char
218                 ic = contents[3]; // i will always be 3 here
219
220                 // ic should now be a alfa-char or '\\'
221                 if (ic == '\\') {
222                         ic = contents[++i]; // will only allow \<foo>{\i} and \<foo>{\j}
223                         if (ic == 'i' || ic == 'j')
224                                 remdot = true;
225                         else
226                                 return;
227                 } else if ( (ic == 'i'|| ic == 'j') && contents[4] == '}') {
228                         // Do a rewrite: \<foo>{i} --> \<foo>{\i}
229                         string temp = contents;
230                         temp.erase(3, string::npos);
231                         temp += '\\';
232                         temp += char(ic);
233                         for(string::size_type j = 4;
234                             j < contents.length(); ++j)
235                                 temp+= contents[j];
236                         contents= temp;
237                         ++i;
238                         remdot = true;
239                 }    
240
241                 // demand a '}' at the end
242                 if (contents[++i] != '}' && contents[++i]) return;
243                                            
244                 // fine, the char is properly decoded now (hopefully)
245                 lyxerr[Debug::KEY] << "Contents: [" << contents << "]"
246                                    << ", ic: " << ic
247                                    << ", top: " << plusasc 
248                                    << ", bot: " << plusdesc 
249                                    << ", dot: " << remdot
250                                    << ", mod: " << modtype << endl;
251         }
252         candisp = true;
253 }
254
255
256 #ifdef USE_PAINTER
257 int InsetLatexAccent::ascent(Painter &, LyXFont const & font) const
258 {
259         // This function is a bit too simplistix and is just a
260         // "try to make a fit for all accents" approach, to
261         // make it better we need to know what kind of accent is
262         // used and add to max based on that.
263         int max;
264         if (candisp) {
265                 if (ic == ' ')
266                         max = font.ascent('a');
267                 else
268                         max = font.ascent(ic);
269                 if (plusasc) 
270                         max += (font.maxAscent() + 3) / 3;
271         } else
272                 max = font.maxAscent() + 4;
273         return max;
274 }
275 #else
276 int InsetLatexAccent::Ascent(LyXFont const & font) const
277 {
278         // This function is a bit too simplistix and is just a
279         // "try to make a fit for all accents" approach, to
280         // make it better we need to know what kind of accent is
281         // used and add to max based on that.
282         int max;
283         if (candisp) {
284                 if (ic == ' ')
285                         max = font.ascent('a');
286                 else
287                         max = font.ascent(ic);
288                 if (plusasc) 
289                         max += (font.maxAscent() + 3) / 3;
290         } else
291                 max = font.maxAscent() + 4;
292         return max;
293 }
294 #endif
295
296
297 #ifdef USE_PAINTER
298 int InsetLatexAccent::descent(Painter &, LyXFont const & font) const
299 {
300         int max;
301         if (candisp) {
302                 if (ic == ' ') 
303                         max = font.descent('a');
304                 else
305                         max = font.descent(ic);
306                 if (plusdesc)
307                         max += 3;
308         } else
309                 max = font.maxDescent() + 4;
310         return max;
311 }
312 #else
313 int InsetLatexAccent::Descent(LyXFont const & font) const
314 {
315         int max;
316         if (candisp) {
317                 if (ic == ' ') 
318                         max = font.descent('a');
319                 else
320                         max = font.descent(ic);
321                 if (plusdesc)
322                         max += 3;
323         } else
324                 max = font.maxDescent() + 4;
325         return max;
326 }
327 #endif
328
329
330 #ifdef USE_PAINTER
331 int InsetLatexAccent::width(Painter &, LyXFont const & font) const
332 {
333         if (candisp)
334                 return font.textWidth(&ic, 1);
335         else
336                 return font.stringWidth(contents) + 4;
337 }
338 #else
339 int InsetLatexAccent::Width(LyXFont const & font) const
340 {
341         if (candisp)
342                 return font.textWidth(&ic, 1);
343         else
344                 return font.stringWidth(contents) + 4;
345 }
346 #endif
347
348
349 int InsetLatexAccent::Lbearing(LyXFont const & font) const
350 {
351         return font.lbearing(ic);
352 }
353
354
355 int InsetLatexAccent::Rbearing(LyXFont const & font) const
356 {
357         return font.rbearing(ic);
358 }
359
360
361 #ifdef USE_PAINTER
362 bool InsetLatexAccent::DisplayISO8859_9(Painter & pain, LyXFont const & font,
363                                         int baseline, 
364                                         float & x) const
365 {
366         unsigned char tmpic = ic;
367         
368         switch (modtype) {
369         case CEDILLA:
370         {
371                 if (ic == 'c') tmpic = 0xe7;
372                 if (ic == 'C') tmpic = 0xc7;
373                 if (ic == 's') tmpic = 0xfe;
374                 if (ic == 'S') tmpic = 0xde;
375                 break;
376         }
377         case BREVE:
378         {       if (ic == 'g') tmpic = 0xf0;
379         if (ic == 'G') tmpic = 0xd0;
380         break;
381         }
382         case UMLAUT:
383         {
384                 if (ic == 'o') tmpic = 0xf6;
385                 if (ic == 'O') tmpic = 0xd6;
386                 if (ic == 'u') tmpic = 0xfc;
387                 if (ic == 'U') tmpic = 0xdc;
388                 break;
389         }
390         case DOT:        if (ic == 'I') tmpic = 0xdd; break;
391         case DOT_LESS_I: tmpic = 0xfd; break;
392         default:         return false;
393         }
394         if (tmpic != ic) {
395                 char ch = char(tmpic);
396                 pain.text(x, baseline, ch, font);
397                 x += width(pain, font);
398                 return true;
399         }
400         else
401                 return false;
402 }
403 #else
404 bool InsetLatexAccent::DisplayISO8859_9(LyXFont font,
405                                         LyXScreen & scr,
406                                         int baseline, 
407                                         float & x)
408 {
409         unsigned char tmpic = ic;
410         
411         switch (modtype) {
412         case CEDILLA:
413         {
414                 if (ic == 'c') tmpic = 0xe7;
415                 if (ic == 'C') tmpic = 0xc7;
416                 if (ic == 's') tmpic = 0xfe;
417                 if (ic == 'S') tmpic = 0xde;
418                 break;
419         }
420         case BREVE:
421         {       if (ic == 'g') tmpic = 0xf0;
422         if (ic == 'G') tmpic = 0xd0;
423         break;
424         }
425         case UMLAUT:
426         {
427                 if (ic == 'o') tmpic = 0xf6;
428                 if (ic == 'O') tmpic = 0xd6;
429                 if (ic == 'u') tmpic = 0xfc;
430                 if (ic == 'U') tmpic = 0xdc;
431                 break;
432         }
433         case DOT:        if (ic == 'I') tmpic = 0xdd; break;
434         case DOT_LESS_I: tmpic = 0xfd; break;
435         default:         return false;
436         }
437         if (tmpic != ic) {
438                 char ch = char(tmpic);
439                 scr.drawText(font, &ch, 1, baseline, int(x));
440                 x += Width (font);
441                 return true;
442         }
443         else
444                 return false;
445 }
446 #endif
447
448
449 #ifdef USE_PAINTER
450 void InsetLatexAccent::draw(Painter & pain, LyXFont const & font,
451                             int baseline, float & x) const
452 {
453         if (lyxrc->font_norm == "iso8859-9")
454                 if (DisplayISO8859_9(pain, font, baseline, x))  
455                         return;
456         
457         /* draw it! */ 
458         // All the manually drawn accents in this function could use an
459         // overhaul. Different ways of drawing (what metrics to use)
460         // should also be considered.
461         
462         if (candisp) {
463                 int asc = ascent(pain, font);
464                 int desc = descent(pain, font);
465                 int wid = width(pain, font);
466                 float x2 = x + (Rbearing(font) - Lbearing(font)) / 2.0;
467                 float hg;
468                 int y;
469                 if (plusasc) {
470                         // mark at the top
471                         hg = font.maxDescent();
472                         y = baseline - asc;
473
474                         if (font.shape() == LyXFont::ITALIC_SHAPE)
475                                 x2 += (4.0 * hg) / 5.0; // italic
476                 } else {
477                         // at the bottom
478                         hg = desc;
479                         y = baseline;
480                 }
481
482                 float hg35 = float(hg * 3.0) / 5.0;
483
484                 // display with proper accent mark
485                 // first the letter
486                 pain.text(int(x), baseline, ic, font);
487
488 #if 0
489                 GC pgc = GetAccentGC(font, int((hg + 3.0) / 5.0));
490 #endif
491
492                 if (remdot) {
493                         int tmpvar = baseline - font.ascent('i');
494                         float tmpx = 0;
495                         if (font.shape() == LyXFont::ITALIC_SHAPE)
496                                 tmpx += (8.0 * hg) / 10.0; // italic
497                         lyxerr[Debug::KEY] << "Removing dot." << endl;
498                         // remove the dot first
499                         pain.fillRectangle(int(x + tmpx), tmpvar, wid,
500                                            font.ascent('i') -
501                                            font.ascent('x') - 1,
502                                            LColor::background);
503                         // the five lines below is a simple hack to
504                         // make the display of accent 'i' and 'j'
505                         // better. It makes the accent be written
506                         // closer to the top of the dot-less 'i' or 'j'.
507                         char tmpic = ic; // store the ic when we
508                         ic = 'x';        // calculates the ascent of
509                         asc = ascent(pain, font); // the dot-less version (here: 'x')
510                         ic = tmpic;      // set the orig ic back
511                         y = baseline - asc; // update to new y coord.
512                 }
513                 // now the rest - draw within (x, y, x+wid, y+hg)
514                 switch (modtype) {
515                 case ACUTE:     // acute
516                 {
517                         pain.line(int(x2), int(y + hg),
518                                   int(x2 + hg35), y + hg35);
519                         break;
520                 }
521                 case GRAVE:     // grave
522                 {
523                         pain.line(int(x2), int(y + hg),
524                                   int(x2 - hg35), y + hg35);
525                         break;
526                 }
527                 case MACRON:     // macron
528                 {
529                         pain.line(int(x2 - wid * 0.4),
530                                   int(y + hg),
531                                   int(x2 + wid * 0.4),
532                                   int(y + hg));
533                         break;
534                 }
535                 case TILDE:     // tilde
536                 {
537                         if (hg35 > 2.0) hg35 -= 1.0;
538                         x2 += (hg35 / 2.0);
539                         int xp[4], yp[4];
540                         
541                         xp[0] = int(x2 - 2.0 * hg35);
542                         yp[0] = int(y + hg);
543                         
544                         xp[1] = int(x2 - hg35);
545                         yp[1] = int(y + hg35);
546                         
547                         xp[2] = int(x2);
548                         yp[2] = int(y + hg);
549                         
550                         xp[3] = int(x2 + hg35);
551                         yp[3] = int(y + hg35);
552                         
553                         pain.lines(xp, yp, 4);
554                         break;
555                 }
556                 case UNDERBAR:     // underbar
557                 {
558                         pain.line(int(x2 - wid * 0.4),
559                                   y + hg / 2.0,
560                                   int(x2 + wid * 0.4),
561                                   y + hg / 2.0);
562                         break;
563                 }
564                 case CEDILLA:     // cedilla
565                 {
566                         int xp[4], yp[4];
567                         
568                         xp[0] = int(x2);
569                         yp[0] = y;
570                         
571                         xp[1] = int(x2);
572                         yp[1] = y + int(hg / 3.0);
573                         
574                         xp[2] = int(x2 + (hg / 3.0));
575                         yp[2] = y + int(hg / 2.0);
576                         
577                         xp[3] = int(x2 - (hg / 4.0));
578                         yp[3] = y + int(hg);
579
580                         pain.lines(xp, yp, 4);
581                         break;
582                 }
583                 case UNDERDOT:     // underdot
584                 {
585                         pain.arc(int(x2), y + hg35,
586                                      3, 3, 0, 360 * 64);
587                         break;
588                 }
589
590                 case DOT:    // dot
591                 {
592                         pain.arc(int(x2), y + hg * 0.5,
593                                      (hg + 3.0)/5.0,
594                                      (hg + 3.0)/5.0,
595                                      0, 360 * 64);
596                         break;
597                 }
598
599                 case CIRCLE:     // circle
600                 {
601                         pain.arc(int(x2 - (hg / 2.0)),
602                                  y + (hg / 2.0), hg, hg , 0,
603                                  360 * 64);
604                         break;
605                 }
606                 case TIE:     // tie
607                 {
608                         pain.arc(int(x2 + hg35), y + hg / 2.0,
609                                  2 * hg, hg, 0, 360 * 32);
610                         break;
611                 }
612                 case BREVE:     // breve
613                 {
614                         pain.arc(int(x2 - (hg / 2.0)), y,
615                                  hg, hg, 0, -360*32);
616                         break;
617                 }
618                 case CARON:    // caron
619                 {
620                         int xp[3], yp[3];
621                         
622                         xp[0] = int(x2 - hg35); yp[0] = int(y + hg35);
623                         xp[1] = int(x2);        yp[1] = int(y + hg);
624                         xp[2] = int(x2 + hg35); yp[2] = int(y + hg35);
625                         pain.lines(xp, yp, 3);
626                         break;
627                 }
628                 case SPECIAL_CARON:    // special caron
629                 {
630                         switch (ic) {
631                         case 'L': wid = int(4.0 * wid / 5.0); break;
632                         case 't': y -= int(hg35 / 2.0); break;
633                         }
634                         int xp[3], yp[3];
635                         xp[0] = int(x + wid);
636                         yp[0] = int(y + hg35 + hg);
637                         
638                         xp[1] = int(x + wid + (hg35 / 2.0));
639                         yp[1] = int(y + hg + (hg35 / 2.0));
640                         
641                         xp[2] = int(x + wid + (hg35 / 2.0));
642                         yp[2] = y + int(hg);
643
644                         pain.lines(xp, yp, 3);
645                         break;
646                 }
647                 case HUNGARIAN_UMLAUT:    // hung. umlaut
648                 {
649                         int xs1[2], xs2[2], ys1[2], ys2[2];
650                         
651                         xs1[0] = int(x2 - (hg / 2.0));
652                         ys1[0] = int(y + hg);
653                         
654                         xs2[0] = int(x2 + hg35 - (hg / 2.0));
655                         ys2[0] = int(y + hg35);
656                         
657                         xs1[1] = int(x2 + (hg / 2.0));
658                         ys1[1] = int(y + hg);
659                         
660                         xs2[1] = int(x2 + hg35 + (hg / 2.0));
661                         ys2[1] = int(y + hg35);
662
663                         pain.segments(xs1, ys1, xs2, ys2, 2);
664                         break;
665                 }
666                 case UMLAUT:    // umlaut
667                 {
668                         float rad = hg / 2.0;
669                         if (rad <= 1.0) {
670                                 pain.point(int(x2 - 4.0 * hg / 7.0),
671                                            y + hg35);
672                                 pain.point(int(x2 + 4.0 * hg / 7.0),
673                                            y + hg35);
674                         } else {
675                                 rad += .5; // this ensures that f.ex. 1.5 will
676                                 // not be rounded down to .5 and then
677                                 // converted to int = 0
678                                 pain.arc(int(x2 - 2.0 * hg / 4.0),
679                                              y + hg35,
680                                              rad, rad,
681                                              0, 360 * 64);
682                                 pain.arc(int(x2 + 2.0 * hg / 4.0),
683                                             y + hg35,
684                                             rad, rad, 0, 360*64);
685                         }
686                         break;
687                 }
688                 case CIRCUMFLEX:    // circumflex
689                 {
690                         int xp[3], yp[3];
691                         
692                         xp[0] = int(x2 - hg35); yp[0] = y + int(hg);
693                         xp[1] = int(x2);        yp[1] = int(y + hg35);
694                         xp[2] = int(x2 + hg35); yp[2] = y + int(hg);
695                         pain.lines(xp, yp, 3);
696                         break;
697                 }
698                 case OGONEK:    // ogonek
699                 {
700                         // this does probably not look like an ogonek, so
701                         // it should certainly be refined
702                         int xp[4], yp[4];
703                         
704                         xp[0] = int(x2);
705                         yp[0] = y;
706                         
707                         xp[1] = int(x2);
708                         yp[1] = y + int(hg35);
709                         
710                         xp[2] = int(x2 - hg35);
711                         yp[2] = y + int(hg / 2.0);
712                         
713                         xp[3] = int(x2 + hg / 4.0);
714                         yp[3] = y + int(hg);
715
716                         pain.lines(xp, yp, 4);
717                         break;
718                 }
719                 case lSLASH:
720                 case LSLASH:
721                 {
722                         int xp[2], yp[2];
723                         
724                         xp[0] = int(x);
725                         yp[0] = y + int(3.0 * hg);
726                         
727                         xp[1] = int(x + float(wid) * 0.75);
728                         yp[1] = y + int(hg);
729                         
730                         pain.lines(xp, yp, 2);
731                         break;
732                 }
733                 case DOT_LESS_I: // dotless-i
734                 case DOT_LESS_J: // dotless-j
735                 {
736                         // nothing to do for these
737                         break;
738                 }
739                 }
740         } else {
741                 pain.fillRectangle(int(x + 1),
742                                    baseline - ascent(pain, font) + 1,
743                                    width(pain, font) - 2,
744                                    ascent(pain, font)
745                                    + descent(pain, font) - 2);
746                 pain.rectangle(int(x + 1), baseline - ascent(pain, font) + 1,
747                                width(pain, font) - 2,
748                                ascent(pain, font) + descent(pain, font) - 2);
749                 pain.text(int(x + 2), baseline, contents, font);
750         }
751         x +=  width(pain, font);
752 }
753 #else
754 void InsetLatexAccent::Draw(LyXFont font,
755                             LyXScreen & scr,
756                             int baseline, 
757                             float & x)
758 {
759         if (lyxrc->font_norm == "iso8859-9")
760                 if (DisplayISO8859_9 (font, scr, baseline, x))  
761                         return;
762         
763         /* draw it! */ 
764         // All the manually drawn accents in this function could use an
765         // overhaul. Different ways of drawing (what metrics to use)
766         // should also be considered.
767         
768         if (candisp) {
769                 int asc = Ascent(font);
770                 int desc = Descent(font);
771                 int wid = Width(font);
772                 float x2 = x + (Rbearing(font) - Lbearing(font)) / 2.0;
773                 float hg;
774                 int y;
775                 if (plusasc) {
776                         // mark at the top
777                         hg = font.maxDescent();
778                         y = baseline - asc;
779
780                         if (font.shape() == LyXFont::ITALIC_SHAPE)
781                                 x2 += (4.0 * hg) / 5.0; // italic
782                 } else {
783                         // at the bottom
784                         hg = desc;
785                         y = baseline;
786                 }
787
788                 float hg35 = float(hg * 3.0) / 5.0;
789
790                 // display with proper accent mark
791                 // first the letter
792                 scr.drawText(font, &ic, 1, baseline, int(x));
793
794                 GC pgc = GetAccentGC(font, int((hg + 3.0) / 5.0));
795
796                 if (remdot) {
797                         int tmpvar = baseline - font.ascent('i');
798                         float tmpx = 0;
799                         if (font.shape() == LyXFont::ITALIC_SHAPE)
800                                 tmpx += (8.0 * hg) / 10.0; // italic
801                         lyxerr[Debug::KEY] << "Removing dot." << endl;
802                         // remove the dot first
803                         scr.fillRectangle(gc_clear, int(x + tmpx),
804                                           tmpvar, wid,
805                                           font.ascent('i') -
806                                           font.ascent('x') - 1);
807                         // the five lines below is a simple hack to
808                         // make the display of accent 'i' and 'j'
809                         // better. It makes the accent be written
810                         // closer to the top of the dot-less 'i' or 'j'.
811                         char tmpic = ic; // store the ic when we
812                         ic = 'x';        // calculates the ascent of
813                         asc = Ascent(font); // the dot-less version (here: 'x')
814                         ic = tmpic;      // set the orig ic back
815                         y = baseline - asc; // update to new y coord.
816                 }
817                 // now the rest - draw within (x, y, x+wid, y+hg)
818                 switch (modtype) {
819                 case ACUTE:     // acute
820                 {
821                         scr.drawLine(pgc, int(x2), int(y + hg),
822                                      int(x2 + hg35), y + hg35);
823                         break;
824                 }
825                 case GRAVE:     // grave
826                 {
827                         scr.drawLine(pgc, int(x2), int(y + hg),
828                                      int(x2 - hg35), y + hg35); 
829                         break;
830                 }
831                 case MACRON:     // macron
832                 {
833                         scr.drawLine(pgc,
834                                      int(x2 - wid * 0.4),
835                                      int(y + hg),
836                                      int(x2 + wid * 0.4),
837                                      int(y + hg));
838                         break;
839                 }
840                 case TILDE:     // tilde
841                 {
842                         if (hg35 > 2.0) hg35 -= 1.0;
843                         x2 += (hg35 / 2.0);
844                         XPoint p[4];
845                         p[0].x = int(x2 - 2.0 * hg35); p[0].y = int(y + hg);
846                         p[1].x = int(x2 - hg35);   p[1].y = int(y + hg35);
847                         p[2].x = int(x2);          p[2].y = int(y + hg);
848                         p[3].x = int(x2 + hg35);   p[3].y = int(y + hg35);
849                         scr.drawLines(pgc, p, 4);
850                         break;
851                 }
852                 case UNDERBAR:     // underbar
853                 {
854                         scr.drawLine(pgc,
855                                      int(x2 - wid * 0.4),
856                                      y + (hg / 2.0),
857                                      int(x2 + wid * 0.4),
858                                      y + (hg / 2.0));
859                         break;
860                 }
861                 case CEDILLA:     // cedilla
862                 {
863                         XPoint p[4];
864                         p[0].x = int(x2);          p[0].y = y;
865                         p[1].x = int(x2);          p[1].y = y + int(hg / 3.0);
866                         p[2].x = int(x2 + (hg / 3.0));
867                         p[2].y = y + int(hg / 2.0);
868                         p[3].x = int(x2 - (hg / 4.0)); p[3].y = y + int(hg);
869                         scr.drawLines(pgc, p, 4);
870                         break;
871                 }
872                 case UNDERDOT:     // underdot
873                 {
874                         scr.fillArc(pgc, int(x2), y + hg35,
875                                     3, 3, 0, 360*64);
876                         break;
877                 }
878
879                 case DOT:    // dot
880                 {
881                         scr.fillArc(pgc, int(x2), y + hg * 0.5,
882                                     (hg + 3.0)/5.0,
883                                     (hg + 3.0)/5.0, 0, 360*64);
884                         break;
885                 }
886
887                 case CIRCLE:     // circle
888                 {
889                         scr.drawArc(pgc, int(x2 - (hg / 2.0)),
890                                     y + (hg / 2.0), hg, hg, 0,
891                                     360*64);
892                         break;
893                 }
894                 case TIE:     // tie
895                 {
896                         scr.drawArc(pgc,
897                                     int(x2 + hg35), y + (hg / 2.0),
898                                     2 * hg, hg, 0, 360*32);
899                         break;
900                 }
901                 case BREVE:     // breve
902                 {
903                         scr.drawArc(pgc,
904                                     int(x2 - (hg / 2.0)), y,
905                                     hg, hg, 0, -360*32);
906                         break;
907                 }
908                 case CARON:    // caron
909                 {
910                         XPoint p[3];
911                         p[0].x = int(x2 - hg35); p[0].y = int(y + hg35);
912                         p[1].x = int(x2);        p[1].y = int(y + hg);
913                         p[2].x = int(x2 + hg35); p[2].y = int(y + hg35);
914                         scr.drawLines(pgc, p, 3);
915                         break;
916                 }
917                 case SPECIAL_CARON:    // special caron
918                 {
919                         switch (ic) {
920                         case 'L': wid = int(4.0 * wid / 5.0); break;
921                         case 't': y -= int(hg35 / 2.0); break;
922                         }
923                         XPoint p[3];
924                         p[0].x = int(x + wid);   p[0].y = int(y + hg35 + hg);
925                         p[1].x = int(x + wid + (hg35 / 2.0));
926                         p[1].y = int(y + hg + (hg35 / 2.0));
927                         p[2].x = int(x + wid + (hg35 / 2.0));
928                         p[2].y = y + int(hg);
929                         scr.drawLines(pgc, p, 3);
930                         break;
931                 }
932                 case HUNGARIAN_UMLAUT:    // hung. umlaut
933                 {
934                         XSegment s[2];
935                         s[0].x1= int(x2 - (hg / 2.0));     s[0].y1 = int(y + hg);
936                         s[0].x2 = int(x2 + hg35 - (hg / 2.0));
937                         s[0].y2 = int(y + hg35);
938                         s[1].x1 = int(x2 + (hg / 2.0));
939                         s[1].y1 = int(y + hg);
940                         s[1].x2 = int(x2 + hg35 + (hg / 2.0));
941                         s[1].y2 = int(y + hg35);
942
943                         scr.drawSegments(pgc, s, 2);
944                         break;
945                 }
946                 case UMLAUT:    // umlaut
947                 {
948                         float rad = hg / 2.0;
949                         if (rad <= 1.0) {
950                                 scr.drawPoint(pgc,
951                                               int(x2 - ((4.0 * hg) / 7.0)),
952                                               y + hg35);
953                                 scr.drawPoint(pgc,
954                                               int(x2 + ((4.0 * hg) / 7.0)),
955                                               y + hg35);
956                         } else {
957                                 rad += .5; // this ensures that f.ex. 1.5 will
958                                 // not be rounded down to .5 and then
959                                 // converted to int = 0
960                                 scr.fillArc(pgc, int(x2 - ((2.0 * hg) / 4.0)),
961                                             y + hg35,
962                                             rad, rad, 0, 360*64);
963                                 scr.fillArc(pgc, int(x2 + ((2.0 * hg) / 4.0)),
964                                             y + hg35,
965                                             rad, rad, 0, 360*64);
966                         }
967                         //scr.drawText(font, "¨", 1, y + hg, x2);
968                         break;
969                 }
970                 case CIRCUMFLEX:    // circumflex
971                 {
972                         XPoint p[3];
973                         p[0].x = int(x2 - hg35); p[0].y = y + int(hg);
974                         p[1].x = int(x2);        p[1].y = int(y + hg35);
975                         p[2].x = int(x2 + hg35); p[2].y = y + int(hg);
976                         scr.drawLines(pgc, p, 3);
977                         break;
978                 }
979                 case OGONEK:    // ogonek
980                 {
981                         // this does probably not look like an ogonek, so
982                         // it should certainly be refined
983                         XPoint p[4];
984                         p[0].x = int(x2);          p[0].y = y;
985                         p[1].x = int(x2);          p[1].y = y + int(hg35);
986                         p[2].x = int(x2 - hg35);
987                         p[2].y = y + int(hg / 2.0);
988                         p[3].x = int(x2 + (hg / 4.0)); p[3].y = y + int(hg);
989                         scr.drawLines(pgc, p, 4);
990                         break;
991                 }
992                 case lSLASH:
993                 case LSLASH:
994                 {
995                         XPoint p[2];
996                         p[0].x = int(x);
997                         p[0].y = y + int(3.0 * hg);
998                         p[1].x = int(x + float(wid) * 0.75);
999                         p[1].y = y + int(hg);
1000                         scr.drawLines(pgc, p, 2);
1001                         break;
1002                 }
1003                 case DOT_LESS_I: // dotless-i
1004                 case DOT_LESS_J: // dotless-j
1005                 {
1006                         // nothing to do for these
1007                         break;
1008                 }
1009                 }
1010         } else {
1011                 scr.fillRectangle(gc_lighted,
1012                                   int(x + 1), baseline - Ascent(font) + 1,
1013                                   Width(font) - 2,
1014                                   Ascent(font) + Descent(font) - 2);
1015                 
1016                 scr.drawRectangle(gc_lighted,
1017                                   int(x), baseline - Ascent(font),
1018                                   Width(font) - 1,
1019                                   Ascent(font) + Descent(font) - 1);
1020                 scr.drawString(font, contents, baseline, int(x + 2));
1021         }
1022         x +=  Width(font);
1023 }
1024 #endif
1025
1026
1027 void InsetLatexAccent::Write(ostream & os)
1028 {
1029         os << "\\i " << contents << "\n";
1030 }
1031
1032
1033 void InsetLatexAccent::Read(LyXLex & lex)
1034 {
1035         lex.EatLine();
1036         contents = lex.GetString();
1037         checkContents();
1038 }
1039
1040
1041 int InsetLatexAccent::Latex(ostream & os, signed char /*fragile*/)
1042 {
1043         os << contents;
1044         return 0;
1045 }
1046
1047
1048 int InsetLatexAccent::Latex(string & file, signed char /*fragile*/)
1049 {
1050         file += contents;
1051         return 0;
1052 }
1053
1054
1055 int InsetLatexAccent::Linuxdoc(string & file)
1056 {
1057         file += contents;
1058         return 0;
1059 }
1060
1061
1062 int InsetLatexAccent::DocBook(string & file)
1063 {
1064         file += contents;
1065         return 0;
1066 }
1067
1068
1069 bool InsetLatexAccent::Deletable() const
1070 {
1071         return true;
1072 }
1073
1074
1075 bool InsetLatexAccent::DirectWrite() const
1076 {
1077         return true;
1078 }
1079
1080
1081 Inset * InsetLatexAccent::Clone() const
1082 {
1083         return new InsetLatexAccent(contents);
1084 }
1085
1086
1087 Inset::Code InsetLatexAccent::LyxCode() const
1088 {
1089         return Inset::ACCENT_CODE;
1090 }
1091
1092
1093 ostream & operator<<(ostream & o, InsetLatexAccent::ACCENT_TYPES at)
1094 {
1095         return o << int(at);
1096 }