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);
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.print("InsetLaTexAccent: weird error.");
219 //ic = (modtype == DOT_LESS_J ? 'j' : 'i');
220 lyxerr.debug("Contents: [" + contents + "], ic: " + ic
221 + ", top: " + tostr(plusasc)
222 + ", bot: " + tostr(plusdesc)
223 + ", dot: " + tostr(remdot)
224 + ", mod: " + tostr(modtype));
225 // Special case for space
226 } else if (contents[3] == '}') {
232 ic = contents[3]; // i will always be 3 here
234 // ic should now be a alfa-char or '\\'
236 ic = contents[++i]; // will only allow \<foo>{\i} and \<foo>{\j}
237 if (ic == 'i' || ic == 'j')
241 } else if ( (ic=='i'|| ic=='j') && contents[4]=='}') {
242 // Do a rewrite: \<foo>{i} --> \<foo>{\i}
243 string temp=contents;
244 temp.erase(3, string::npos);
247 for(string::size_type j = 4; j < contents.length(); ++j)
254 // demand a '}' at the end
255 if (contents[++i] != '}' && contents[++i]) return;
257 // fine, the char is properly decoded now (hopefully)
258 lyxerr.debug("Contents: [" + contents + "], ic: " + ic
259 + ", top: " + tostr(plusasc)
260 + ", bot: " + tostr(plusdesc)
261 + ", dot: " + tostr(remdot)
262 + ", mod: " + tostr(modtype));
268 int InsetLatexAccent::Ascent(LyXFont const &font) const
273 max = font.ascent('a');
275 max = font.ascent(ic);
277 max += (font.maxAscent()+3) / 3;
279 max = font.maxAscent()+4;
284 int InsetLatexAccent::Descent(LyXFont const &font) const
289 max = font.descent('a');
291 max = font.descent(ic);
295 max = font.maxDescent() + 4;
300 int InsetLatexAccent::Width(LyXFont const &font) const
303 return font.textWidth(&ic, 1);
305 return font.stringWidth(contents) + 4;
310 bool InsetLatexAccent::DisplayISO8859_9(LyXFont font,
315 unsigned char tmpic = ic;
320 if (ic == 'c') tmpic = 0xe7;
321 if (ic == 'C') tmpic = 0xc7;
322 if (ic == 's') tmpic = 0xfe;
323 if (ic == 'S') tmpic = 0xde;
327 { if (ic == 'g') tmpic = 0xf0;
328 if (ic == 'G') tmpic = 0xd0;
333 if (ic == 'o') tmpic = 0xf6;
334 if (ic == 'O') tmpic = 0xd6;
335 if (ic == 'u') tmpic = 0xfc;
336 if (ic == 'U') tmpic = 0xdc;
339 case DOT: if (ic == 'I') tmpic = 0xdd; break;
340 case DOT_LESS_I: tmpic = 0xfd; break;
341 default: return false;
344 char ch = char(tmpic);
345 scr.drawText(font, &ch, 1, baseline, int(x));
354 void InsetLatexAccent::Draw(LyXFont font,
359 if (lyxrc->font_norm=="iso8859-9")
360 if (DisplayISO8859_9 (font, scr, baseline, x))
366 int asc = Ascent(font);
367 int desc = Descent(font);
368 int wid = Width(font);
369 float x2 = x+(float(wid)/2);
374 hg = font.maxDescent();
377 if (font.shape() == LyXFont::ITALIC_SHAPE) x2 += (4*hg)/5; // italic
384 hg35 = float(hg*3)/5;
386 // display with proper accent mark
388 scr.drawText(font, &ic, 1, baseline, int(x));
390 GC pgc = GetAccentGC(font, (hg+3)/5);
393 int tmpvar = baseline - font.ascent('i');
395 if (font.shape() == LyXFont::ITALIC_SHAPE) tmpx += (8*hg)/10; // italic
396 lyxerr.debug("Removing dot.", Error::ANY);
397 // remove the dot first
398 scr.fillRectangle(gc_clear, int(x + tmpx),
404 // now the rest - draw within (x,y, x+wid, y+hg)
408 scr.drawLine(pgc, int(x2), int(y+hg35),
414 scr.drawLine(pgc,int(x2), int(y+hg35),
418 case MACRON: // macron
421 int(x2-(3*wid/7)), int(y+(hg/2) + hg35),
422 int(x2+(3*wid/7)), int(y+(hg/2) + hg35));
427 if (hg35 > 2) --hg35;
430 p[0].x = int(x2 - 2*hg35); p[0].y = int(y + hg);
431 p[1].x = int(x2 - hg35); p[1].y = int(y + hg35);
432 p[2].x = int(x2); p[2].y = int(y + hg);
433 p[3].x = int(x2 + hg35); p[3].y = int(y + hg35);
434 scr.drawLines(pgc, p, 4);
437 case UNDERBAR: // underbar
440 int(x2-(3*wid/7)), y+(hg/2),
441 int(x2+(3*wid/7)), y+(hg/2));
444 case CEDILLA: // cedilla
447 p[0].x = int(x2); p[0].y = y;
448 p[1].x = int(x2); p[1].y = y + (hg/3);
449 p[2].x = int(x2 + (hg/3)); p[2].y = y + (hg/2);
450 p[3].x = int(x2 - (hg/4)); p[3].y = y + hg;
451 scr.drawLines(pgc, p, 4);
454 case UNDERDOT: // underdot
457 scr.drawArc(pgc,int(x2), y+(hg/2),
461 case CIRCLE: // circle
463 scr.drawArc(pgc, int(x2-(hg/2)), y, hg, hg, 0,
477 int(x2-(hg/2)), y-(hg/4),
484 p[0].x = int(x2 - hg35); p[0].y = y;
485 p[1].x = int(x2); p[1].y = int(y+hg35);
486 p[2].x = int(x2 + hg35); p[2].y = y;
487 scr.drawLines(pgc, p, 3);
490 case SPECIAL_CARON: // special caron
493 case 'L': wid = 4*wid/5; break;
494 case 't': y -= int(hg35/2); break;
497 p[0].x = int(x+wid); p[0].y = int(y+hg35+hg);
498 p[1].x = int(x+wid+(hg35/2)); p[1].y = int(y+ hg+(hg35/2));
499 p[2].x = int(x+wid+(hg35/2)); p[2].y = y + hg;
500 scr.drawLines(pgc, p, 3);
503 case HUNGARIAN_UMLAUT: // hung. umlaut
506 s[0].x1= int(x2-(hg/2)); s[0].y1 = int(y + hg35);
507 s[0].x2= int(x2+hg35-(hg/2)); s[0].y2 = y;
508 s[1].x1= int(x2+(hg/2)); s[1].y1 = int(y + hg35);
509 s[1].x2= int(x2+hg35+(hg/2)); s[1].y2 = y;
511 scr.drawSegments(pgc, s, 2);
514 case UMLAUT: // umlaut
517 tmpadd += (remdot) ? ((19*hg)/10) : ((20*hg)/27); // if (remdot) -> i or j
518 int rad = ((hg*4)/8);
520 scr.drawPoint(pgc, int(x2-((4*hg)/7)), tmpadd);
521 scr.drawPoint(pgc, int(x2+((4*hg)/7)), tmpadd);
523 scr.drawArc(pgc, int(x2-((2*hg)/4)), tmpadd,
524 rad-1, rad-1, 0, 360*64);
525 scr.drawArc(pgc, int(x2+((2*hg)/4)), tmpadd,
526 rad-1, rad-1, 0, 360*64);
530 case CIRCUMFLEX: // circumflex
533 p[0].x = int(x2 - hg35); p[0].y = y + hg;
534 p[1].x = int(x2); p[1].y = int(y + hg35);
535 p[2].x = int(x2 + hg35); p[2].y = y + hg;
536 scr.drawLines(pgc, p, 3);
539 case OGONEK: // ogonek
541 // this does probably not look like an ogonek, so
542 // it should certainly be refined
544 p[0].x = int(x2); p[0].y = y;
545 p[1].x = int(x2); p[1].y = y + (hg/3);
546 p[2].x = int(x2 - (hg/3)); p[2].y = y + (hg/2);
547 p[3].x = int(x2 + (hg/4)); p[3].y = y + hg;
548 scr.drawLines(pgc, p, 4);
555 p[0].x = int(x); p[0].y = y+3*hg;
556 p[1].x = int(x+float(wid)*.75); p[1].y = y+hg;
557 scr.drawLines(pgc, p, 2);
560 case DOT_LESS_I: // dotless-i
561 case DOT_LESS_J: // dotless-j
563 // nothing to do for these
568 //scr.drawFilledRectangle(int(x+1), baseline - Ascent(font)+1,
570 // Ascent(font)+Descent(font)-2,
572 scr.fillRectangle(gc_lighted,
573 int(x+1), baseline - Ascent(font)+1,
575 Ascent(font)+Descent(font)-2);
577 //scr.drawRectangle(int(x), baseline - Ascent(font),
579 // Ascent(font)+Descent(font)-1,
581 scr.drawRectangle(gc_lighted,
582 int(x), baseline - Ascent(font),
584 Ascent(font)+Descent(font)-1);
585 scr.drawString(font, contents, baseline, int(x+2));
591 void InsetLatexAccent::Write(FILE *file)
593 fprintf(file, "\\i %s\n", contents.c_str());
597 void InsetLatexAccent::Read(LyXLex &lex)
600 contents = lex.GetString();
605 int InsetLatexAccent::Latex(FILE *file, signed char /*fragile*/)
607 fprintf(file, "%s", contents.c_str());
612 int InsetLatexAccent::Latex(string &file, signed char /*fragile*/)
619 int InsetLatexAccent::Linuxdoc(string &file)
626 int InsetLatexAccent::DocBook(string &file)
633 bool InsetLatexAccent::Deletable() const
639 bool InsetLatexAccent::DirectWrite() const
645 Inset* InsetLatexAccent::Clone()
647 InsetLatexAccent *result = new InsetLatexAccent(contents);
652 Inset::Code InsetLatexAccent::LyxCode() const
654 return Inset::ACCENT_CODE;
658 bool InsetLatexAccent::IsEqual(Inset* other)
660 if (other && other->LyxCode() == Inset::ACCENT_CODE){
661 InsetLatexAccent* otheraccent = (InsetLatexAccent*) other;
662 return (contents == otheraccent->contents);