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;
311 bool InsetLatexAccent::DisplayISO8859_9(LyXFont font,
316 unsigned char tmpic = ic;
321 if (ic == 'c') tmpic = 0xe7;
322 if (ic == 'C') tmpic = 0xc7;
323 if (ic == 's') tmpic = 0xfe;
324 if (ic == 'S') tmpic = 0xde;
328 { if (ic == 'g') tmpic = 0xf0;
329 if (ic == 'G') tmpic = 0xd0;
334 if (ic == 'o') tmpic = 0xf6;
335 if (ic == 'O') tmpic = 0xd6;
336 if (ic == 'u') tmpic = 0xfc;
337 if (ic == 'U') tmpic = 0xdc;
340 case DOT: if (ic == 'I') tmpic = 0xdd; break;
341 case DOT_LESS_I: tmpic = 0xfd; break;
342 default: return false;
345 char ch = char(tmpic);
346 scr.drawText(font, &ch, 1, baseline, int(x));
355 void InsetLatexAccent::Draw(LyXFont font,
360 if (lyxrc->font_norm=="iso8859-9")
361 if (DisplayISO8859_9 (font, scr, baseline, x))
367 int asc = Ascent(font);
368 int desc = Descent(font);
369 int wid = Width(font);
370 float x2 = x + float(wid/2);
375 hg = font.maxDescent();
378 if (font.shape() == LyXFont::ITALIC_SHAPE) x2 += (4*hg)/5; // italic
385 hg35 = float(hg*3)/5;
387 // display with proper accent mark
389 scr.drawText(font, &ic, 1, baseline, int(x));
391 GC pgc = GetAccentGC(font, (hg+3)/5);
394 int tmpvar = baseline - font.ascent('i');
396 if (font.shape() == LyXFont::ITALIC_SHAPE) tmpx += (8*hg)/10; // italic
397 lyxerr.debug() << "Removing dot." << endl;
398 // remove the dot first
399 scr.fillRectangle(gc_clear, int(x + tmpx),
405 // now the rest - draw within (x,y, x+wid, y+hg)
409 scr.drawLine(pgc, int(x2), int(y+hg35),
415 scr.drawLine(pgc,int(x2), int(y+hg35),
419 case MACRON: // macron
422 int(x2-(3*wid/7)), int(y+(hg/2) + hg35),
423 int(x2+(3*wid/7)), int(y+(hg/2) + hg35));
428 if (hg35 > 2) --hg35;
431 p[0].x = int(x2 - 2*hg35); p[0].y = int(y + hg);
432 p[1].x = int(x2 - hg35); p[1].y = int(y + hg35);
433 p[2].x = int(x2); p[2].y = int(y + hg);
434 p[3].x = int(x2 + hg35); p[3].y = int(y + hg35);
435 scr.drawLines(pgc, p, 4);
438 case UNDERBAR: // underbar
441 int(x2-(3*wid/7)), y+(hg/2),
442 int(x2+(3*wid/7)), y+(hg/2));
445 case CEDILLA: // cedilla
448 p[0].x = int(x2); p[0].y = y;
449 p[1].x = int(x2); p[1].y = y + (hg/3);
450 p[2].x = int(x2 + (hg/3)); p[2].y = y + (hg/2);
451 p[3].x = int(x2 - (hg/4)); p[3].y = y + hg;
452 scr.drawLines(pgc, p, 4);
455 case UNDERDOT: // underdot
458 scr.drawArc(pgc,int(x2), y+(hg/2),
462 case CIRCLE: // circle
464 scr.drawArc(pgc, int(x2-(hg/2)), y, hg, hg, 0,
478 int(x2-(hg/2)), y-(hg/4),
485 p[0].x = int(x2 - hg35); p[0].y = y;
486 p[1].x = int(x2); p[1].y = int(y+hg35);
487 p[2].x = int(x2 + hg35); p[2].y = y;
488 scr.drawLines(pgc, p, 3);
491 case SPECIAL_CARON: // special caron
494 case 'L': wid = 4*wid/5; break;
495 case 't': y -= int(hg35/2); break;
498 p[0].x = int(x+wid); p[0].y = int(y+hg35+hg);
499 p[1].x = int(x+wid+(hg35/2)); p[1].y = int(y+ hg+(hg35/2));
500 p[2].x = int(x+wid+(hg35/2)); p[2].y = y + hg;
501 scr.drawLines(pgc, p, 3);
504 case HUNGARIAN_UMLAUT: // hung. umlaut
507 s[0].x1= int(x2-(hg/2)); s[0].y1 = int(y + hg35);
508 s[0].x2= int(x2+hg35-(hg/2)); s[0].y2 = y;
509 s[1].x1= int(x2+(hg/2)); s[1].y1 = int(y + hg35);
510 s[1].x2= int(x2+hg35+(hg/2)); s[1].y2 = y;
512 scr.drawSegments(pgc, s, 2);
515 case UMLAUT: // umlaut
518 tmpadd += (remdot) ? ((19*hg)/10) : ((20*hg)/27); // if (remdot) -> i or j
519 int rad = ((hg*4)/8);
521 scr.drawPoint(pgc, int(x2-((4*hg)/7)), tmpadd);
522 scr.drawPoint(pgc, int(x2+((4*hg)/7)), tmpadd);
524 scr.drawArc(pgc, int(x2-((2*hg)/4)), tmpadd,
525 rad-1, rad-1, 0, 360*64);
526 scr.drawArc(pgc, int(x2+((2*hg)/4)), tmpadd,
527 rad-1, rad-1, 0, 360*64);
531 case CIRCUMFLEX: // circumflex
534 p[0].x = int(x2 - hg35); p[0].y = y + hg;
535 p[1].x = int(x2); p[1].y = int(y + hg35);
536 p[2].x = int(x2 + hg35); p[2].y = y + hg;
537 scr.drawLines(pgc, p, 3);
540 case OGONEK: // ogonek
542 // this does probably not look like an ogonek, so
543 // it should certainly be refined
545 p[0].x = int(x2); p[0].y = y;
546 p[1].x = int(x2); p[1].y = y + (hg/3);
547 p[2].x = int(x2 - (hg/3)); p[2].y = y + (hg/2);
548 p[3].x = int(x2 + (hg/4)); p[3].y = y + hg;
549 scr.drawLines(pgc, p, 4);
556 p[0].x = int(x); p[0].y = y+3*hg;
557 p[1].x = int(x+float(wid)*.75); p[1].y = y+hg;
558 scr.drawLines(pgc, p, 2);
561 case DOT_LESS_I: // dotless-i
562 case DOT_LESS_J: // dotless-j
564 // nothing to do for these
569 scr.fillRectangle(gc_lighted,
570 int(x+1), baseline - Ascent(font)+1,
572 Ascent(font)+Descent(font)-2);
574 scr.drawRectangle(gc_lighted,
575 int(x), baseline - Ascent(font),
577 Ascent(font)+Descent(font)-1);
578 scr.drawString(font, contents, baseline, int(x+2));
584 void InsetLatexAccent::Write(FILE * file)
586 fprintf(file, "\\i %s\n", contents.c_str());
590 void InsetLatexAccent::Read(LyXLex & lex)
593 contents = lex.GetString();
598 int InsetLatexAccent::Latex(FILE * file, signed char /*fragile*/)
600 fprintf(file, "%s", contents.c_str());
605 int InsetLatexAccent::Latex(string & file, signed char /*fragile*/)
612 int InsetLatexAccent::Linuxdoc(string & file)
619 int InsetLatexAccent::DocBook(string & file)
626 bool InsetLatexAccent::Deletable() const
632 bool InsetLatexAccent::DirectWrite() const
638 Inset* InsetLatexAccent::Clone()
640 InsetLatexAccent * result = new InsetLatexAccent(contents);
645 Inset::Code InsetLatexAccent::LyxCode() const
647 return Inset::ACCENT_CODE;
651 bool InsetLatexAccent::IsEqual(Inset * other)
653 if (other && other->LyxCode() == Inset::ACCENT_CODE){
654 InsetLatexAccent* otheraccent = (InsetLatexAccent*) other;
655 return (contents == otheraccent->contents);
660 ostream & operator<<(ostream & o, InsetLatexAccent::ACCENT_TYPES at)