1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-1999 The LyX Team.
9 * ======================================================*/
14 #pragma implementation
17 #include "insetlatexaccent.h"
21 #include "support/lstrings.h"
25 /* LatexAccent. Proper handling of accented characters */
26 /* This part is done by Ivan Schreter, schreter@ccsun.tuke.sk */
27 /* Later modified by Lars G. Bjonnes, larsbj@ifi.uio.no */
29 InsetLatexAccent::InsetLatexAccent()
35 InsetLatexAccent::InsetLatexAccent(InsetLatexAccent const & other)
36 :contents(other.contents),
37 candisp(other.candisp),
38 modtype(other.modtype),
40 plusasc(other.plusasc),
41 plusdesc(other.plusdesc),
46 InsetLatexAccent::InsetLatexAccent(string const & string)
53 InsetLatexAccent::~InsetLatexAccent()
58 void InsetLatexAccent::checkContents()
59 // check, if we know the modifier and can display it ok on screen
63 if (contents.empty() || contents.length()<2) return;
66 // Dirty Hack for backward compability. remove in 0.13 (Lgb)
67 contents = frontStrip(strip(contents));
68 if (!contains(contents, "{") && !contains(contents, "}")) {
69 if (contents.length() == 2) {
75 } else if (contents.length() == 3) {
83 } else if (contents.length()==4 && contents[2] == ' ') {
91 } else if (contents.length()==4 && contents[2] == '\\'
92 && (contents[3]== 'i' || contents[3]== 'j')) {
103 if (contents[0] != '\\') return; // demand that first char is a '\\'
105 lyxerr.debug() << "Decode: " << contents << endl;
107 remdot = false; plusasc = false; plusdesc = false;
109 switch (contents[1]) { // second char should be one of these
111 modtype = ACUTE; // acute
112 plusasc = true; // at the top of character
115 modtype = GRAVE; // grave
116 plusasc = true; // at the top
119 modtype = MACRON; // macron
120 plusasc = true; // at the top
123 modtype = TILDE; // tilde
124 plusasc = true; // at the top
126 case 'b': // underbar
127 modtype = UNDERBAR; // underbar
128 plusdesc = true; // at the bottom
131 modtype = CEDILLA; // cedilla
132 plusdesc = true; // at the bottom
134 case 'd': // underdot
135 modtype = UNDERDOT; // underdot
136 plusdesc = true; // at the bottom
139 modtype = CIRCLE; // circle
140 plusasc = true; // at the top
143 modtype = TIE; // tie
144 plusasc = true; // at the top
147 modtype = BREVE; // breve
148 plusasc = true; // at the top
151 modtype = CARON; // caron
152 plusasc = true; // at the top
154 case 'q': // special caron
155 modtype = SPECIAL_CARON; // special caron
156 plusasc = true; // at the top
158 case 'H': // hungarian umlaut
159 modtype = HUNGARIAN_UMLAUT; // hungarian umlaut
160 plusasc = true; // at the top
163 modtype = UMLAUT; // umlaut
164 plusasc = true; // at the top
167 modtype = DOT; // dot
168 plusasc = true; // at the top
170 case '^': // circumflex
171 modtype = CIRCUMFLEX; // circumflex
172 plusasc = true; // at the top
175 modtype = OGONEK; // ogonek
178 case 'i': // dot-less-i
179 modtype = DOT_LESS_I; // dot-less-i
180 plusasc = true; // at the top (not really needed)
183 case 'j': // dot-less-j
184 modtype = DOT_LESS_J; // dot-less-j
185 plusasc = true; // at the top (not really needed)
190 plusasc = true; // at the top (not really needed)
194 plusasc = true; // at the top (not really needed)
197 printf ("Default\n");
198 // unknow accent (or something else)
202 // we demand that third char is a '{' (Lgb)
203 if (contents[2] != '{') return;
205 // special clause for \i{}, \j{} \l{} and \L{}
206 if ((modtype == DOT_LESS_I || modtype == DOT_LESS_J
207 || modtype == lSLASH || modtype == LSLASH)
208 && contents[3] == '}' ) {
210 case DOT_LESS_I: ic = 'i'; break;
211 case DOT_LESS_J: ic = 'j'; break;
212 case lSLASH: ic = 'l'; break;
213 case LSLASH: ic = 'L'; break;
215 // if this happens something is really wrong
216 lyxerr << "InsetLaTexAccent: weird error." << endl;
219 //ic = (modtype == DOT_LESS_J ? 'j' : 'i');
220 lyxerr.debug() << "Contents: [" << contents << "]"
222 << ", top: " << plusasc
223 << ", bot: " << plusdesc
224 << ", dot: " << remdot
225 << ", mod: " << modtype << endl;
226 // Special case for space
227 } else if (contents[3] == '}') {
233 ic = contents[3]; // i will always be 3 here
235 // ic should now be a alfa-char or '\\'
237 ic = contents[++i]; // will only allow \<foo>{\i} and \<foo>{\j}
238 if (ic == 'i' || ic == 'j')
242 } else if ( (ic=='i'|| ic=='j') && contents[4]=='}') {
243 // Do a rewrite: \<foo>{i} --> \<foo>{\i}
244 string temp=contents;
245 temp.erase(3, string::npos);
248 for(string::size_type j = 4; j < contents.length(); ++j)
255 // demand a '}' at the end
256 if (contents[++i] != '}' && contents[++i]) return;
258 // fine, the char is properly decoded now (hopefully)
259 lyxerr.debug() << "Contents: [" << contents << "]"
261 << ", top: " << plusasc
262 << ", bot: " << plusdesc
263 << ", dot: " << remdot
264 << ", mod: " << modtype << endl;
270 int InsetLatexAccent::Ascent(LyXFont const &font) const
275 max = font.ascent('a');
277 max = font.ascent(ic);
279 max += (font.maxAscent()+3) / 3;
281 max = font.maxAscent()+4;
286 int InsetLatexAccent::Descent(LyXFont const &font) const
291 max = font.descent('a');
293 max = font.descent(ic);
297 max = font.maxDescent() + 4;
302 int InsetLatexAccent::Width(LyXFont const &font) const
305 return font.textWidth(&ic, 1);
307 return font.stringWidth(contents) + 4;
312 bool InsetLatexAccent::DisplayISO8859_9(LyXFont font,
317 unsigned char tmpic = ic;
322 if (ic == 'c') tmpic = 0xe7;
323 if (ic == 'C') tmpic = 0xc7;
324 if (ic == 's') tmpic = 0xfe;
325 if (ic == 'S') tmpic = 0xde;
329 { if (ic == 'g') tmpic = 0xf0;
330 if (ic == 'G') tmpic = 0xd0;
335 if (ic == 'o') tmpic = 0xf6;
336 if (ic == 'O') tmpic = 0xd6;
337 if (ic == 'u') tmpic = 0xfc;
338 if (ic == 'U') tmpic = 0xdc;
341 case DOT: if (ic == 'I') tmpic = 0xdd; break;
342 case DOT_LESS_I: tmpic = 0xfd; break;
343 default: return false;
346 char ch = char(tmpic);
347 scr.drawText(font, &ch, 1, baseline, int(x));
356 void InsetLatexAccent::Draw(LyXFont font,
361 if (lyxrc->font_norm=="iso8859-9")
362 if (DisplayISO8859_9 (font, scr, baseline, x))
368 int asc = Ascent(font);
369 int desc = Descent(font);
370 int wid = Width(font);
371 float x2 = x+(float(wid)/2);
376 hg = font.maxDescent();
379 if (font.shape() == LyXFont::ITALIC_SHAPE) x2 += (4*hg)/5; // italic
386 hg35 = float(hg*3)/5;
388 // display with proper accent mark
390 scr.drawText(font, &ic, 1, baseline, int(x));
392 GC pgc = GetAccentGC(font, (hg+3)/5);
395 int tmpvar = baseline - font.ascent('i');
397 if (font.shape() == LyXFont::ITALIC_SHAPE) tmpx += (8*hg)/10; // italic
398 lyxerr.debug() << "Removing dot." << endl;
399 // remove the dot first
400 scr.fillRectangle(gc_clear, int(x + tmpx),
406 // now the rest - draw within (x,y, x+wid, y+hg)
410 scr.drawLine(pgc, int(x2), int(y+hg35),
416 scr.drawLine(pgc,int(x2), int(y+hg35),
420 case MACRON: // macron
423 int(x2-(3*wid/7)), int(y+(hg/2) + hg35),
424 int(x2+(3*wid/7)), int(y+(hg/2) + hg35));
429 if (hg35 > 2) --hg35;
432 p[0].x = int(x2 - 2*hg35); p[0].y = int(y + hg);
433 p[1].x = int(x2 - hg35); p[1].y = int(y + hg35);
434 p[2].x = int(x2); p[2].y = int(y + hg);
435 p[3].x = int(x2 + hg35); p[3].y = int(y + hg35);
436 scr.drawLines(pgc, p, 4);
439 case UNDERBAR: // underbar
442 int(x2-(3*wid/7)), y+(hg/2),
443 int(x2+(3*wid/7)), y+(hg/2));
446 case CEDILLA: // cedilla
449 p[0].x = int(x2); p[0].y = y;
450 p[1].x = int(x2); p[1].y = y + (hg/3);
451 p[2].x = int(x2 + (hg/3)); p[2].y = y + (hg/2);
452 p[3].x = int(x2 - (hg/4)); p[3].y = y + hg;
453 scr.drawLines(pgc, p, 4);
456 case UNDERDOT: // underdot
459 scr.drawArc(pgc,int(x2), y+(hg/2),
463 case CIRCLE: // circle
465 scr.drawArc(pgc, int(x2-(hg/2)), y, hg, hg, 0,
479 int(x2-(hg/2)), y-(hg/4),
486 p[0].x = int(x2 - hg35); p[0].y = y;
487 p[1].x = int(x2); p[1].y = int(y+hg35);
488 p[2].x = int(x2 + hg35); p[2].y = y;
489 scr.drawLines(pgc, p, 3);
492 case SPECIAL_CARON: // special caron
495 case 'L': wid = 4*wid/5; break;
496 case 't': y -= int(hg35/2); break;
499 p[0].x = int(x+wid); p[0].y = int(y+hg35+hg);
500 p[1].x = int(x+wid+(hg35/2)); p[1].y = int(y+ hg+(hg35/2));
501 p[2].x = int(x+wid+(hg35/2)); p[2].y = y + hg;
502 scr.drawLines(pgc, p, 3);
505 case HUNGARIAN_UMLAUT: // hung. umlaut
508 s[0].x1= int(x2-(hg/2)); s[0].y1 = int(y + hg35);
509 s[0].x2= int(x2+hg35-(hg/2)); s[0].y2 = y;
510 s[1].x1= int(x2+(hg/2)); s[1].y1 = int(y + hg35);
511 s[1].x2= int(x2+hg35+(hg/2)); s[1].y2 = y;
513 scr.drawSegments(pgc, s, 2);
516 case UMLAUT: // umlaut
519 tmpadd += (remdot) ? ((19*hg)/10) : ((20*hg)/27); // if (remdot) -> i or j
520 int rad = ((hg*4)/8);
522 scr.drawPoint(pgc, int(x2-((4*hg)/7)), tmpadd);
523 scr.drawPoint(pgc, int(x2+((4*hg)/7)), tmpadd);
525 scr.drawArc(pgc, int(x2-((2*hg)/4)), tmpadd,
526 rad-1, rad-1, 0, 360*64);
527 scr.drawArc(pgc, int(x2+((2*hg)/4)), tmpadd,
528 rad-1, rad-1, 0, 360*64);
532 case CIRCUMFLEX: // circumflex
535 p[0].x = int(x2 - hg35); p[0].y = y + hg;
536 p[1].x = int(x2); p[1].y = int(y + hg35);
537 p[2].x = int(x2 + hg35); p[2].y = y + hg;
538 scr.drawLines(pgc, p, 3);
541 case OGONEK: // ogonek
543 // this does probably not look like an ogonek, so
544 // it should certainly be refined
546 p[0].x = int(x2); p[0].y = y;
547 p[1].x = int(x2); p[1].y = y + (hg/3);
548 p[2].x = int(x2 - (hg/3)); p[2].y = y + (hg/2);
549 p[3].x = int(x2 + (hg/4)); p[3].y = y + hg;
550 scr.drawLines(pgc, p, 4);
557 p[0].x = int(x); p[0].y = y+3*hg;
558 p[1].x = int(x+float(wid)*.75); p[1].y = y+hg;
559 scr.drawLines(pgc, p, 2);
562 case DOT_LESS_I: // dotless-i
563 case DOT_LESS_J: // dotless-j
565 // nothing to do for these
570 //scr.drawFilledRectangle(int(x+1), baseline - Ascent(font)+1,
572 // Ascent(font)+Descent(font)-2,
574 scr.fillRectangle(gc_lighted,
575 int(x+1), baseline - Ascent(font)+1,
577 Ascent(font)+Descent(font)-2);
579 //scr.drawRectangle(int(x), baseline - Ascent(font),
581 // Ascent(font)+Descent(font)-1,
583 scr.drawRectangle(gc_lighted,
584 int(x), baseline - Ascent(font),
586 Ascent(font)+Descent(font)-1);
587 scr.drawString(font, contents, baseline, int(x+2));
593 void InsetLatexAccent::Write(FILE *file)
595 fprintf(file, "\\i %s\n", contents.c_str());
599 void InsetLatexAccent::Read(LyXLex &lex)
602 contents = lex.GetString();
607 int InsetLatexAccent::Latex(FILE *file, signed char /*fragile*/)
609 fprintf(file, "%s", contents.c_str());
614 int InsetLatexAccent::Latex(string &file, signed char /*fragile*/)
621 int InsetLatexAccent::Linuxdoc(string &file)
628 int InsetLatexAccent::DocBook(string &file)
635 bool InsetLatexAccent::Deletable() const
641 bool InsetLatexAccent::DirectWrite() const
647 Inset* InsetLatexAccent::Clone()
649 InsetLatexAccent *result = new InsetLatexAccent(contents);
654 Inset::Code InsetLatexAccent::LyxCode() const
656 return Inset::ACCENT_CODE;
660 bool InsetLatexAccent::IsEqual(Inset* other)
662 if (other && other->LyxCode() == Inset::ACCENT_CODE){
663 InsetLatexAccent* otheraccent = (InsetLatexAccent*) other;
664 return (contents == otheraccent->contents);
669 ostream & operator<<(ostream & o, InsetLatexAccent::ACCENT_TYPES at)