2 * \file InsetSpecialChar.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup Nielsen
7 * \author Jean-Marc Lasgouttes
8 * \author Lars Gullik Bjønnes
10 * Full author contact details are available in file CREDITS.
15 #include "InsetSpecialChar.h"
17 #include "Dimension.h"
19 #include "LaTeXFeatures.h"
21 #include "MetricsInfo.h"
22 #include "output_xhtml.h"
24 #include "frontends/FontMetrics.h"
25 #include "frontends/Painter.h"
27 #include "support/debug.h"
28 #include "support/docstream.h"
35 InsetSpecialChar::InsetSpecialChar(Kind k)
40 InsetSpecialChar::Kind InsetSpecialChar::kind() const
48 int logoWidth(FontInfo const & font, InsetSpecialChar::Kind kind) {
49 frontend::FontMetrics const & fm = theFontMetrics(font);
50 double const em = fm.width('M');
53 case InsetSpecialChar::PHRASE_LYX:
54 width = fm.width(from_ascii("L")) - 0.16667 * em
55 + fm.width(from_ascii("Y")) - 0.125 * em
56 + fm.width(from_ascii("X"));
59 case InsetSpecialChar::PHRASE_TEX:
60 width = fm.width(from_ascii("T")) - 0.16667 * em
61 + fm.width(from_ascii("E")) - 0.125 * em
62 + fm.width(from_ascii("X"));
65 case InsetSpecialChar::PHRASE_LATEX2E:
66 width = logoWidth(font, InsetSpecialChar::PHRASE_LATEX)
67 + fm.width(from_ascii("2") + char_type(0x03b5));
69 case InsetSpecialChar::PHRASE_LATEX: {
70 FontInfo smaller = font;
71 smaller.decSize().decSize();
72 width = fm.width(from_ascii("L")) - 0.36 * em
73 + theFontMetrics(smaller).width(from_ascii("A")) - 0.15 * em
74 + logoWidth(font, InsetSpecialChar::PHRASE_TEX);
78 LYXERR0("No information for computing width of logo " << kind);
87 void InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const
89 frontend::FontMetrics const & fm =
90 theFontMetrics(mi.base.font);
91 dim.asc = fm.maxAscent();
92 dim.des = fm.maxDescent();
100 case END_OF_SENTENCE:
104 s = from_ascii(". . .");
107 s = from_ascii(" x ");
110 dim.wid = fm.width(from_ascii("-"));
112 dim.wid -= 2; // to make it look shorter
124 dim.wid = logoWidth(mi.base.font, kind_);
128 dim.wid = fm.width(s);
130 setDimCache(mi, dim);
136 void drawLogo(PainterInfo & pi, InsetSpecialChar::Kind kind, int & x, int & y) {
137 FontInfo const & font = pi.base.font;
138 // FIXME: this definition of em is bogus, but there is a need
139 // for a big refactoring of the code around this issue anyway.
140 double const em = theFontMetrics(font).width('M');
142 case InsetSpecialChar::PHRASE_LYX:
143 x += pi.pain.text(x, y, from_ascii("L"), font);
145 x += pi.pain.text(x, y + 0.25 * em, from_ascii("Y"), font);
147 x += pi.pain.text(x, y, from_ascii("X"), font);
150 case InsetSpecialChar::PHRASE_TEX:
151 x += pi.pain.text(x, y, from_ascii("T"), font);
153 x += pi.pain.text(x, y + 0.25 * em, from_ascii("E"), font);
155 x += pi.pain.text(x, y, from_ascii("X"), font);
158 case InsetSpecialChar::PHRASE_LATEX2E:
159 drawLogo(pi, InsetSpecialChar::PHRASE_LATEX, x, y);
160 x += pi.pain.text(x, y, from_ascii("2"), font);
161 x += pi.pain.text(x, y + 0.25 * em, char_type(0x03b5), font);
164 case InsetSpecialChar::PHRASE_LATEX: {
165 x += pi.pain.text(x, y, from_ascii("L"), font);
167 FontInfo smaller = font;
168 smaller.decSize().decSize();
169 x += pi.pain.text(x, y - 0.2 * em, from_ascii("A"), smaller);
171 drawLogo(pi, InsetSpecialChar::PHRASE_TEX, x, y);
175 LYXERR0("No information for drawing logo " << kind);
181 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
183 FontInfo font = pi.base.font;
188 font.setColor(Color_special);
189 pi.pain.text(x, y, char_type('-'), font);
194 font.setColor(Color_special);
195 pi.pain.text(x, y, char_type('|'), font);
198 case END_OF_SENTENCE:
200 font.setColor(Color_special);
201 pi.pain.text(x, y, char_type('.'), font);
206 font.setColor(Color_special);
207 string ell = ". . . ";
208 docstring dell(ell.begin(), ell.end());
209 pi.pain.text(x, y, dell, font);
214 frontend::FontMetrics const & fm =
215 theFontMetrics(font);
217 // A triangle the width and height of an 'x'
218 int w = fm.width(char_type('x'));
219 int ox = fm.width(char_type(' ')) + x;
220 int h = fm.ascent(char_type('x'));
223 xp[0] = ox; yp[0] = y;
224 xp[1] = ox; yp[1] = y - h;
225 xp[2] = ox + w; yp[2] = y - h/2;
226 xp[3] = ox; yp[3] = y;
228 pi.pain.lines(xp, yp, 4, Color_special);
233 font.setColor(Color_special);
234 pi.pain.text(x, y, char_type('/'), font);
239 font.setColor(Color_latex);
240 pi.pain.text(x, y, char_type('-'), font);
247 drawLogo(pi, kind_, x, y);
253 // In lyxf3 this will be just LaTeX
254 void InsetSpecialChar::write(ostream & os) const
262 command = "\\textcompwordmark{}";
264 case END_OF_SENTENCE:
268 command = "\\ldots{}";
271 command = "\\menuseparator";
274 command = "\\slash{}";
277 command = "\\nobreakdash-";
286 command = "\\LaTeX2e";
292 os << "\\SpecialChar " << command << "\n";
296 // This function will not be necessary when lyx3
297 void InsetSpecialChar::read(Lexer & lex)
300 string const command = lex.getString();
302 if (command == "\\-")
304 else if (command == "\\textcompwordmark{}")
305 kind_ = LIGATURE_BREAK;
306 else if (command == "\\@.")
307 kind_ = END_OF_SENTENCE;
308 else if (command == "\\ldots{}")
310 else if (command == "\\menuseparator")
311 kind_ = MENU_SEPARATOR;
312 else if (command == "\\slash{}")
314 else if (command == "\\nobreakdash-")
316 else if (command == "\\LyX")
318 else if (command == "\\TeX")
320 else if (command == "\\LaTeX2e")
321 kind_ = PHRASE_LATEX2E;
322 else if (command == "\\LaTeX")
323 kind_ = PHRASE_LATEX;
325 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
329 void InsetSpecialChar::latex(otexstream & os,
330 OutputParams const & rp) const
337 os << "\\textcompwordmark{}";
339 case END_OF_SENTENCE:
346 if (rp.local_font->isRightToLeft())
347 os << "\\lyxarrow*{}";
349 os << "\\lyxarrow{}";
357 os << "\\nobreakdash-";
383 int InsetSpecialChar::plaintext(odocstringstream & os,
384 OutputParams const &, size_t) const
392 case END_OF_SENTENCE:
425 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
431 case END_OF_SENTENCE:
464 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
470 xs << XHTMLStream::ESCAPE_NONE << "‌";
472 case END_OF_SENTENCE:
476 xs << XHTMLStream::ESCAPE_NONE << "…";
479 xs << XHTMLStream::ESCAPE_NONE << "⇒";
482 xs << XHTMLStream::ESCAPE_NONE << "⁄";
485 xs << XHTMLStream::ESCAPE_NONE << "‑";
494 xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε";
504 void InsetSpecialChar::toString(odocstream & os) const
508 // Do not output ZERO WIDTH NON JOINER here
509 // Spell checker would choke on it.
514 odocstringstream ods;
515 plaintext(ods, OutputParams(0));
520 void InsetSpecialChar::forOutliner(docstring & os, size_t) const
522 odocstringstream ods;
523 plaintext(ods, OutputParams(0));
528 void InsetSpecialChar::validate(LaTeXFeatures & features) const
530 if (kind_ == MENU_SEPARATOR)
531 features.require("lyxarrow");
532 if (kind_ == NOBREAKDASH)
533 features.require("amsmath");
534 if (kind_ == PHRASE_LYX)
535 features.require("LyX");
539 bool InsetSpecialChar::isLetter() const
541 return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
542 || kind_ == NOBREAKDASH;
546 bool InsetSpecialChar::isLineSeparator() const
549 // this would be nice, but it does not work, since
550 // Paragraph::stripLeadingSpaces nukes the characters which
551 // have this property. I leave the code here, since it should
552 // eventually be made to work. (JMarc 20020327)
553 return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR