1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright (C) 1995 Matthias Ettrich
7 * Copyright (C) 1995-1998 The LyX Team.
9 *======================================================*/
14 #pragma implementation
17 #include "insetlatexaccent.h"
24 // $Id: insetlatexaccent.C,v 1.1 1999/09/27 18:44:39 larsbj Exp $
26 #if !defined(lint) && !defined(WITH_WARNINGS)
27 static char vcid[] = "$Id: insetlatexaccent.C,v 1.1 1999/09/27 18:44:39 larsbj Exp $";
30 /* LatexAccent. Proper handling of accented characters */
31 /* This part is done by Ivan Schreter, schreter@ccsun.tuke.sk */
32 /* Later modified by Lars G. Bjonnes, larsbj@ifi.uio.no */
34 InsetLatexAccent::InsetLatexAccent()
40 InsetLatexAccent::InsetLatexAccent(InsetLatexAccent const & other)
41 :contents(other.contents),
42 candisp(other.candisp),
43 modtype(other.modtype),
45 plusasc(other.plusasc),
46 plusdesc(other.plusdesc),
51 InsetLatexAccent::InsetLatexAccent(LString const & string)
58 InsetLatexAccent::~InsetLatexAccent()
63 void InsetLatexAccent::checkContents()
64 // check, if we know the modifier and can display it ok on screen
68 if (contents.empty() || contents.length()<2) return;
71 // Dirty Hack for backward compability. remove in 0.13 (Lgb)
73 contents.frontStrip();
74 if (!contents.contains("{") && !contents.contains("}")) {
75 if (contents.length() == 2) {
81 } else if (contents.length() == 3) {
89 } else if (contents.length()==4 && contents[2] == ' ') {
97 } else if (contents.length()==4 && contents[2] == '\\'
98 && (contents[3]== 'i' || contents[3]== 'j')) {
109 if (contents[0] != '\\') return; // demand that first char is a '\\'
111 lyxerr.debug("Decode: " + contents);
113 remdot = false; plusasc = false; plusdesc = false;
115 switch (contents[1]) { // second char should be one of these
117 modtype = ACUTE; // acute
118 plusasc = true; // at the top of character
121 modtype = GRAVE; // grave
122 plusasc = true; // at the top
125 modtype = MACRON; // macron
126 plusasc = true; // at the top
129 modtype = TILDE; // tilde
130 plusasc = true; // at the top
132 case 'b': // underbar
133 modtype = UNDERBAR; // underbar
134 plusdesc = true; // at the bottom
137 modtype = CEDILLA; // cedilla
138 plusdesc = true; // at the bottom
140 case 'd': // underdot
141 modtype = UNDERDOT; // underdot
142 plusdesc = true; // at the bottom
145 modtype = CIRCLE; // circle
146 plusasc = true; // at the top
149 modtype = TIE; // tie
150 plusasc = true; // at the top
153 modtype = BREVE; // breve
154 plusasc = true; // at the top
157 modtype = CARON; // caron
158 plusasc = true; // at the top
160 case 'q': // special caron
161 modtype = SPECIAL_CARON; // special caron
162 plusasc = true; // at the top
164 case 'H': // hungarian umlaut
165 modtype = HUNGARIAN_UMLAUT; // hungarian umlaut
166 plusasc = true; // at the top
169 modtype = UMLAUT; // umlaut
170 plusasc = true; // at the top
173 modtype = DOT; // dot
174 plusasc = true; // at the top
176 case '^': // circumflex
177 modtype = CIRCUMFLEX; // circumflex
178 plusasc = true; // at the top
181 modtype = OGONEK; // ogonek
184 case 'i': // dot-less-i
185 modtype = DOT_LESS_I; // dot-less-i
186 plusasc = true; // at the top (not really needed)
189 case 'j': // dot-less-j
190 modtype = DOT_LESS_J; // dot-less-j
191 plusasc = true; // at the top (not really needed)
196 plusasc = true; // at the top (not really needed)
200 plusasc = true; // at the top (not really needed)
203 printf ("Default\n");
204 // unknow accent (or something else)
208 // we demand that third char is a '{' (Lgb)
209 if (contents[2] != '{') return;
211 // special clause for \i{}, \j{} \l{} and \L{}
212 if ((modtype == DOT_LESS_I || modtype == DOT_LESS_J
213 || modtype == lSLASH || modtype == LSLASH)
214 && contents[3] == '}' ) {
216 case DOT_LESS_I: ic = 'i'; break;
217 case DOT_LESS_J: ic = 'j'; break;
218 case lSLASH: ic = 'l'; break;
219 case LSLASH: ic = 'L'; break;
221 // if this happens something is really wrong
222 lyxerr.print("InsetLaTexAccent: weird error.");
225 //ic = (modtype == DOT_LESS_J ? 'j' : 'i');
226 lyxerr.debug("Contents: [" + contents + "], ic: " + ic
227 + ", top: " + long(plusasc)
228 + ", bot: " + long(plusdesc)
229 + ", dot: " + long(remdot)
230 + ", mod: " + long(modtype));
231 // Special case for space
232 } else if (contents[3] == '}') {
238 ic = contents[3]; // i will always be 3 here
240 // ic should now be a alfa-char or '\\'
242 ic = contents[++i]; // will only allow \<foo>{\i} and \<foo>{\j}
243 if (ic == 'i' || ic == 'j')
247 } else if ( (ic=='i'|| ic=='j') && contents[4]=='}') {
248 // Do a rewrite: \<foo>{i} --> \<foo>{\i}
249 LString temp=contents;
253 for(int j=4;j<contents.length();j++)
260 // demand a '}' at the end
261 if (contents[++i] != '}' && contents[++i]) return;
263 // fine, the char is properly decoded now (hopefully)
264 lyxerr.debug("Contents: [" + contents + "], ic: " + ic
265 + ", top: " + long(plusasc)
266 + ", bot: " + long(plusdesc)
267 + ", dot: " + long(remdot)
268 + ", mod: " + long(modtype));
274 int InsetLatexAccent::Ascent(LyXFont const &font) const
279 max = font.ascent('a');
281 max = font.ascent(ic);
283 max += (font.maxAscent()+3) / 3;
285 max = font.maxAscent()+4;
290 int InsetLatexAccent::Descent(LyXFont const &font) const
295 max = font.descent('a');
297 max = font.descent(ic);
301 max = font.maxDescent() + 4;
306 int InsetLatexAccent::Width(LyXFont const &font) const
309 return font.textWidth(&ic, 1);
311 return font.stringWidth(contents) + 4;
316 bool InsetLatexAccent::DisplayISO8859_9(LyXFont font,
321 unsigned char tmpic = ic;
326 if (ic == 'c') tmpic = 0xe7;
327 if (ic == 'C') tmpic = 0xc7;
328 if (ic == 's') tmpic = 0xfe;
329 if (ic == 'S') tmpic = 0xde;
333 { if (ic == 'g') tmpic = 0xf0;
334 if (ic == 'G') tmpic = 0xd0;
339 if (ic == 'o') tmpic = 0xf6;
340 if (ic == 'O') tmpic = 0xd6;
341 if (ic == 'u') tmpic = 0xfc;
342 if (ic == 'U') tmpic = 0xdc;
345 case DOT: if (ic == 'I') tmpic = 0xdd; break;
346 case DOT_LESS_I: tmpic = 0xfd; break;
347 default: return false;
350 char ch = char(tmpic);
351 scr.drawText(font, &ch, 1, baseline, int(x));
360 void InsetLatexAccent::Draw(LyXFont font,
365 if (lyxrc->font_norm=="iso8859-9")
366 if (DisplayISO8859_9 (font, scr, baseline, x))
372 int asc = Ascent(font);
373 int desc = Descent(font);
374 int wid = Width(font);
375 float x2 = x+(float(wid)/2);
380 hg = font.maxDescent();
383 if (font.shape() == LyXFont::ITALIC_SHAPE) x2 += (4*hg)/5; // italic
390 hg35 = float(hg*3)/5;
392 // display with proper accent mark
394 scr.drawText(font, &ic, 1, baseline, int(x));
396 GC pgc = GetAccentGC(font, (hg+3)/5);
399 int tmpvar = baseline - font.ascent('i');
401 if (font.shape() == LyXFont::ITALIC_SHAPE) tmpx += (8*hg)/10; // italic
402 lyxerr.debug("Removing dot.", Error::ANY);
403 // remove the dot first
404 scr.fillRectangle(gc_clear, int(x + tmpx),
410 // now the rest - draw within (x,y, x+wid, y+hg)
414 scr.drawLine(pgc, int(x2), int(y+hg35),
420 scr.drawLine(pgc,int(x2), int(y+hg35),
424 case MACRON: // macron
427 int(x2-(3*wid/7)), int(y+(hg/2) + hg35),
428 int(x2+(3*wid/7)), int(y+(hg/2) + hg35));
433 if (hg35 > 2) --hg35;
436 p[0].x = int(x2 - 2*hg35); p[0].y = int(y + hg);
437 p[1].x = int(x2 - hg35); p[1].y = int(y + hg35);
438 p[2].x = int(x2); p[2].y = int(y + hg);
439 p[3].x = int(x2 + hg35); p[3].y = int(y + hg35);
440 scr.drawLines(pgc, p, 4);
443 case UNDERBAR: // underbar
446 int(x2-(3*wid/7)), y+(hg/2),
447 int(x2+(3*wid/7)), y+(hg/2));
450 case CEDILLA: // cedilla
453 p[0].x = int(x2); p[0].y = y;
454 p[1].x = int(x2); p[1].y = y + (hg/3);
455 p[2].x = int(x2 + (hg/3)); p[2].y = y + (hg/2);
456 p[3].x = int(x2 - (hg/4)); p[3].y = y + hg;
457 scr.drawLines(pgc, p, 4);
460 case UNDERDOT: // underdot
463 scr.drawArc(pgc,int(x2), y+(hg/2),
467 case CIRCLE: // circle
469 scr.drawArc(pgc, int(x2-(hg/2)), y, hg, hg, 0,
483 int(x2-(hg/2)), y-(hg/4),
490 p[0].x = int(x2 - hg35); p[0].y = y;
491 p[1].x = int(x2); p[1].y = int(y+hg35);
492 p[2].x = int(x2 + hg35); p[2].y = y;
493 scr.drawLines(pgc, p, 3);
496 case SPECIAL_CARON: // special caron
499 case 'L': wid = 4*wid/5; break;
500 case 't': y -= int(hg35/2); break;
503 p[0].x = int(x+wid); p[0].y = int(y+hg35+hg);
504 p[1].x = int(x+wid+(hg35/2)); p[1].y = int(y+ hg+(hg35/2));
505 p[2].x = int(x+wid+(hg35/2)); p[2].y = y + hg;
506 scr.drawLines(pgc, p, 3);
509 case HUNGARIAN_UMLAUT: // hung. umlaut
512 s[0].x1= int(x2-(hg/2)); s[0].y1 = int(y + hg35);
513 s[0].x2= int(x2+hg35-(hg/2)); s[0].y2 = y;
514 s[1].x1= int(x2+(hg/2)); s[1].y1 = int(y + hg35);
515 s[1].x2= int(x2+hg35+(hg/2)); s[1].y2 = y;
517 scr.drawSegments(pgc, s, 2);
520 case UMLAUT: // umlaut
523 tmpadd += (remdot) ? ((19*hg)/10) : ((20*hg)/27); // if (remdot) -> i or j
524 int rad = ((hg*4)/8);
526 scr.drawPoint(pgc, int(x2-((4*hg)/7)), tmpadd);
527 scr.drawPoint(pgc, int(x2+((4*hg)/7)), tmpadd);
529 scr.drawArc(pgc, int(x2-((2*hg)/4)), tmpadd,
530 rad-1, rad-1, 0, 360*64);
531 scr.drawArc(pgc, int(x2+((2*hg)/4)), tmpadd,
532 rad-1, rad-1, 0, 360*64);
536 case CIRCUMFLEX: // circumflex
539 p[0].x = int(x2 - hg35); p[0].y = y + hg;
540 p[1].x = int(x2); p[1].y = int(y + hg35);
541 p[2].x = int(x2 + hg35); p[2].y = y + hg;
542 scr.drawLines(pgc, p, 3);
545 case OGONEK: // ogonek
547 // this does probably not look like an ogonek, so
548 // it should certainly be refined
550 p[0].x = int(x2); p[0].y = y;
551 p[1].x = int(x2); p[1].y = y + (hg/3);
552 p[2].x = int(x2 - (hg/3)); p[2].y = y + (hg/2);
553 p[3].x = int(x2 + (hg/4)); p[3].y = y + hg;
554 scr.drawLines(pgc, p, 4);
561 p[0].x = int(x); p[0].y = y+3*hg;
562 p[1].x = int(x+float(wid)*.75); p[1].y = y+hg;
563 scr.drawLines(pgc, p, 2);
566 case DOT_LESS_I: // dotless-i
567 case DOT_LESS_J: // dotless-j
569 // nothing to do for these
574 //scr.drawFilledRectangle(int(x+1), baseline - Ascent(font)+1,
576 // Ascent(font)+Descent(font)-2,
578 scr.fillRectangle(gc_lighted,
579 int(x+1), baseline - Ascent(font)+1,
581 Ascent(font)+Descent(font)-2);
583 //scr.drawRectangle(int(x), baseline - Ascent(font),
585 // Ascent(font)+Descent(font)-1,
587 scr.drawRectangle(gc_lighted,
588 int(x), baseline - Ascent(font),
590 Ascent(font)+Descent(font)-1);
591 scr.drawString(font, contents, baseline, int(x+2));
597 void InsetLatexAccent::Write(FILE *file)
599 fprintf(file, "\\i %s\n", contents.c_str());
603 void InsetLatexAccent::Read(LyXLex &lex)
606 contents = lex.GetString();
611 int InsetLatexAccent::Latex(FILE *file, signed char /*fragile*/)
613 fprintf(file, "%s", contents.c_str());
618 int InsetLatexAccent::Latex(LString &file, signed char /*fragile*/)
625 int InsetLatexAccent::Linuxdoc(LString &file)
632 int InsetLatexAccent::DocBook(LString &file)
639 bool InsetLatexAccent::Deletable() const
645 bool InsetLatexAccent::DirectWrite() const
651 Inset* InsetLatexAccent::Clone()
653 InsetLatexAccent *result = new InsetLatexAccent(contents);
658 Inset::Code InsetLatexAccent::LyxCode() const
660 return Inset::ACCENT_CODE;
664 bool InsetLatexAccent::IsEqual(Inset* other)
666 if (other && other->LyxCode() == Inset::ACCENT_CODE){
667 InsetLatexAccent* otheraccent = (InsetLatexAccent*) other;
668 return (contents == otheraccent->contents);