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 int const em = fm.width('M');
52 // See drawlogo() below to understand what this does.
54 case InsetSpecialChar::PHRASE_LYX:
55 width = fm.width(from_ascii("L")) - em / 6
56 + fm.width(from_ascii("Y")) - em / 8
57 + fm.width(from_ascii("X"));
60 case InsetSpecialChar::PHRASE_TEX:
61 width = fm.width(from_ascii("T")) - em / 6
62 + fm.width(from_ascii("E")) - em / 8
63 + fm.width(from_ascii("X"));
66 case InsetSpecialChar::PHRASE_LATEX2E:
67 width = logoWidth(font, InsetSpecialChar::PHRASE_LATEX)
69 + fm.width(from_ascii("2") + char_type(0x03b5));
71 case InsetSpecialChar::PHRASE_LATEX: {
72 FontInfo smaller = font;
73 smaller.decSize().decSize();
74 width = fm.width(from_ascii("L")) - 9 * em / 25
75 + theFontMetrics(smaller).width(from_ascii("A")) - 3 * em / 20
76 + logoWidth(font, InsetSpecialChar::PHRASE_TEX);
80 LYXERR0("No information for computing width of logo " << kind);
89 void InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const
91 frontend::FontMetrics const & fm =
92 theFontMetrics(mi.base.font);
93 dim.asc = fm.maxAscent();
94 dim.des = fm.maxDescent();
102 case END_OF_SENTENCE:
106 s = from_ascii(". . .");
109 s = from_ascii(" x ");
112 dim.wid = fm.width(from_ascii("-"));
114 dim.wid -= 2; // to make it look shorter
126 dim.wid = logoWidth(mi.base.font, kind_);
130 dim.wid = fm.width(s);
132 setDimCache(mi, dim);
138 void drawLogo(PainterInfo & pi, InsetSpecialChar::Kind kind, int & x, int & y) {
139 FontInfo const & font = pi.base.font;
140 // FIXME: this definition of em is bogus, but there is a need
141 // for a big refactoring of the code around this issue anyway.
142 int const em = theFontMetrics(font).width('M');
144 case InsetSpecialChar::PHRASE_LYX:
146 * \providecommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\\@};
148 x += pi.pain.text(x, y, from_ascii("L"), font);
150 x += pi.pain.text(x, y + em / 4, from_ascii("Y"), font);
152 x += pi.pain.text(x, y, from_ascii("X"), font);
155 case InsetSpecialChar::PHRASE_TEX: {
157 * \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
159 int const ex = theFontMetrics(font).ascent('x');
160 x += pi.pain.text(x, y, from_ascii("T"), font);
162 x += pi.pain.text(x, y + ex / 2, from_ascii("E"), font);
164 x += pi.pain.text(x, y, from_ascii("X"), font);
167 case InsetSpecialChar::PHRASE_LATEX2E:
169 * \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
170 * \if b\expandafter\@car\f@series\@nil\boldmath\fi
171 * \LaTeX\kern.15em2$_{\textstyle\varepsilon}$}}
173 drawLogo(pi, InsetSpecialChar::PHRASE_LATEX, x, y);
175 x += pi.pain.text(x, y, from_ascii("2"), font);
176 x += pi.pain.text(x, y + em / 4, char_type(0x03b5), font);
179 case InsetSpecialChar::PHRASE_LATEX: {
181 * \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
183 * \vbox to\ht\z@{\hbox{\check@mathfonts
184 * \fontsize\sf@size\z@
185 * \math@fontsfalse\selectfont
192 x += pi.pain.text(x, y, from_ascii("L"), font);
194 FontInfo smaller = font;
195 smaller.decSize().decSize();
196 x += pi.pain.text(x, y - em / 5, from_ascii("A"), smaller);
198 drawLogo(pi, InsetSpecialChar::PHRASE_TEX, x, y);
202 LYXERR0("No information for drawing logo " << kind);
208 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
210 FontInfo font = pi.base.font;
215 font.setColor(Color_special);
216 pi.pain.text(x, y, char_type('-'), font);
221 font.setColor(Color_special);
222 pi.pain.text(x, y, char_type('|'), font);
225 case END_OF_SENTENCE:
227 font.setColor(Color_special);
228 pi.pain.text(x, y, char_type('.'), font);
233 font.setColor(Color_special);
234 string ell = ". . . ";
235 docstring dell(ell.begin(), ell.end());
236 pi.pain.text(x, y, dell, font);
241 frontend::FontMetrics const & fm =
242 theFontMetrics(font);
244 // A triangle the width and height of an 'x'
245 int w = fm.width(char_type('x'));
246 int ox = fm.width(char_type(' ')) + x;
247 int h = fm.ascent(char_type('x'));
250 xp[0] = ox; yp[0] = y;
251 xp[1] = ox; yp[1] = y - h;
252 xp[2] = ox + w; yp[2] = y - h/2;
253 xp[3] = ox; yp[3] = y;
255 pi.pain.lines(xp, yp, 4, Color_special);
260 font.setColor(Color_special);
261 pi.pain.text(x, y, char_type('/'), font);
266 font.setColor(Color_latex);
267 pi.pain.text(x, y, char_type('-'), font);
274 drawLogo(pi, kind_, x, y);
280 // In lyxf3 this will be just LaTeX
281 void InsetSpecialChar::write(ostream & os) const
286 command = "softhyphen";
289 command = "ligaturebreak";
291 case END_OF_SENTENCE:
292 command = "endofsentence";
298 command = "menuseparator";
301 command = "breakableslash";
304 command = "nobreakdash";
319 os << "\\SpecialChar " << command << "\n";
323 // This function will not be necessary when lyx3
324 void InsetSpecialChar::read(Lexer & lex)
327 string const command = lex.getString();
329 if (command == "softhyphen")
331 else if (command == "ligaturebreak")
332 kind_ = LIGATURE_BREAK;
333 else if (command == "endofsentence")
334 kind_ = END_OF_SENTENCE;
335 else if (command == "ldots")
337 else if (command == "menuseparator")
338 kind_ = MENU_SEPARATOR;
339 else if (command == "breakableslash")
341 else if (command == "nobreakdash")
343 else if (command == "LyX")
345 else if (command == "TeX")
347 else if (command == "LaTeX2e")
348 kind_ = PHRASE_LATEX2E;
349 else if (command == "LaTeX")
350 kind_ = PHRASE_LATEX;
352 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
356 void InsetSpecialChar::latex(otexstream & os,
357 OutputParams const & rp) const
364 os << "\\textcompwordmark{}";
366 case END_OF_SENTENCE:
373 if (rp.local_font->isRightToLeft())
374 os << "\\lyxarrow*{}";
376 os << "\\lyxarrow{}";
384 os << "\\nobreakdash-";
410 int InsetSpecialChar::plaintext(odocstringstream & os,
411 OutputParams const &, size_t) const
419 case END_OF_SENTENCE:
452 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
458 case END_OF_SENTENCE:
491 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
497 xs << XHTMLStream::ESCAPE_NONE << "‌";
499 case END_OF_SENTENCE:
503 xs << XHTMLStream::ESCAPE_NONE << "…";
506 xs << XHTMLStream::ESCAPE_NONE << "⇒";
509 xs << XHTMLStream::ESCAPE_NONE << "⁄";
512 xs << XHTMLStream::ESCAPE_NONE << "‑";
521 xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε";
531 void InsetSpecialChar::toString(odocstream & os) const
535 // Do not output ZERO WIDTH NON JOINER here
536 // Spell checker would choke on it.
541 odocstringstream ods;
542 plaintext(ods, OutputParams(0));
547 void InsetSpecialChar::forOutliner(docstring & os, size_t) const
549 odocstringstream ods;
550 plaintext(ods, OutputParams(0));
555 void InsetSpecialChar::validate(LaTeXFeatures & features) const
557 if (kind_ == MENU_SEPARATOR)
558 features.require("lyxarrow");
559 if (kind_ == NOBREAKDASH)
560 features.require("amsmath");
561 if (kind_ == PHRASE_LYX)
562 features.require("LyX");
566 bool InsetSpecialChar::isLetter() const
568 return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
569 || kind_ == NOBREAKDASH;
573 bool InsetSpecialChar::isLineSeparator() const
576 // this would be nice, but it does not work, since
577 // Paragraph::stripLeadingSpaces nukes the characters which
578 // have this property. I leave the code here, since it should
579 // eventually be made to work. (JMarc 20020327)
580 return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR