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.em();
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 int const em = theFontMetrics(font).em();
142 case InsetSpecialChar::PHRASE_LYX:
144 * \providecommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\\@};
146 x += pi.pain.text(x, y, from_ascii("L"), font);
148 x += pi.pain.text(x, y + em / 4, from_ascii("Y"), font);
150 x += pi.pain.text(x, y, from_ascii("X"), font);
153 case InsetSpecialChar::PHRASE_TEX: {
155 * \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
157 int const ex = theFontMetrics(font).ascent('x');
158 x += pi.pain.text(x, y, from_ascii("T"), font);
160 x += pi.pain.text(x, y + ex / 2, from_ascii("E"), font);
162 x += pi.pain.text(x, y, from_ascii("X"), font);
165 case InsetSpecialChar::PHRASE_LATEX2E:
167 * \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
168 * \if b\expandafter\@car\f@series\@nil\boldmath\fi
169 * \LaTeX\kern.15em2$_{\textstyle\varepsilon}$}}
171 drawLogo(pi, InsetSpecialChar::PHRASE_LATEX, x, y);
173 x += pi.pain.text(x, y, from_ascii("2"), font);
174 x += pi.pain.text(x, y + em / 4, char_type(0x03b5), font);
177 case InsetSpecialChar::PHRASE_LATEX: {
179 * \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
181 * \vbox to\ht\z@{\hbox{\check@mathfonts
182 * \fontsize\sf@size\z@
183 * \math@fontsfalse\selectfont
190 x += pi.pain.text(x, y, from_ascii("L"), font);
192 FontInfo smaller = font;
193 smaller.decSize().decSize();
194 x += pi.pain.text(x, y - em / 5, from_ascii("A"), smaller);
196 drawLogo(pi, InsetSpecialChar::PHRASE_TEX, x, y);
200 LYXERR0("No information for drawing logo " << kind);
206 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
208 FontInfo font = pi.base.font;
213 font.setColor(Color_special);
214 pi.pain.text(x, y, char_type('-'), font);
219 font.setColor(Color_special);
220 pi.pain.text(x, y, char_type('|'), font);
223 case END_OF_SENTENCE:
225 font.setColor(Color_special);
226 pi.pain.text(x, y, char_type('.'), font);
231 font.setColor(Color_special);
232 string ell = ". . . ";
233 docstring dell(ell.begin(), ell.end());
234 pi.pain.text(x, y, dell, font);
239 frontend::FontMetrics const & fm =
240 theFontMetrics(font);
242 // A triangle the width and height of an 'x'
243 int w = fm.width(char_type('x'));
244 int ox = fm.width(char_type(' ')) + x;
245 int h = fm.ascent(char_type('x'));
248 xp[0] = ox; yp[0] = y;
249 xp[1] = ox; yp[1] = y - h;
250 xp[2] = ox + w; yp[2] = y - h/2;
251 xp[3] = ox; yp[3] = y;
253 pi.pain.lines(xp, yp, 4, Color_special);
258 font.setColor(Color_special);
259 pi.pain.text(x, y, char_type('/'), font);
264 font.setColor(Color_latex);
265 pi.pain.text(x, y, char_type('-'), font);
272 drawLogo(pi, kind_, x, y);
278 // In lyxf3 this will be just LaTeX
279 void InsetSpecialChar::write(ostream & os) const
284 command = "softhyphen";
287 command = "ligaturebreak";
289 case END_OF_SENTENCE:
290 command = "endofsentence";
296 command = "menuseparator";
299 command = "breakableslash";
302 command = "nobreakdash";
317 os << "\\SpecialChar " << command << "\n";
321 // This function will not be necessary when lyx3
322 void InsetSpecialChar::read(Lexer & lex)
325 string const command = lex.getString();
327 if (command == "softhyphen")
329 else if (command == "ligaturebreak")
330 kind_ = LIGATURE_BREAK;
331 else if (command == "endofsentence")
332 kind_ = END_OF_SENTENCE;
333 else if (command == "ldots")
335 else if (command == "menuseparator")
336 kind_ = MENU_SEPARATOR;
337 else if (command == "breakableslash")
339 else if (command == "nobreakdash")
341 else if (command == "LyX")
343 else if (command == "TeX")
345 else if (command == "LaTeX2e")
346 kind_ = PHRASE_LATEX2E;
347 else if (command == "LaTeX")
348 kind_ = PHRASE_LATEX;
350 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
354 void InsetSpecialChar::latex(otexstream & os,
355 OutputParams const & rp) const
362 os << "\\textcompwordmark{}";
364 case END_OF_SENTENCE:
371 if (rp.local_font->isRightToLeft())
372 os << "\\lyxarrow*{}";
374 os << "\\lyxarrow{}";
382 os << "\\nobreakdash-";
408 int InsetSpecialChar::plaintext(odocstringstream & os,
409 OutputParams const &, size_t) const
417 case END_OF_SENTENCE:
450 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
456 case END_OF_SENTENCE:
489 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
495 xs << XHTMLStream::ESCAPE_NONE << "‌";
497 case END_OF_SENTENCE:
501 xs << XHTMLStream::ESCAPE_NONE << "…";
504 xs << XHTMLStream::ESCAPE_NONE << "⇒";
507 xs << XHTMLStream::ESCAPE_NONE << "⁄";
510 xs << XHTMLStream::ESCAPE_NONE << "‑";
519 xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε";
529 void InsetSpecialChar::toString(odocstream & os) const
533 // Do not output ZERO WIDTH NON JOINER here
534 // Spell checker would choke on it.
539 odocstringstream ods;
540 plaintext(ods, OutputParams(0));
545 void InsetSpecialChar::forOutliner(docstring & os, size_t const,
548 odocstringstream ods;
549 plaintext(ods, OutputParams(0));
554 void InsetSpecialChar::validate(LaTeXFeatures & features) const
556 if (kind_ == MENU_SEPARATOR)
557 features.require("lyxarrow");
558 if (kind_ == NOBREAKDASH)
559 features.require("amsmath");
560 if (kind_ == PHRASE_LYX)
561 features.require("LyX");
565 bool InsetSpecialChar::isLetter() const
567 return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
568 || kind_ == NOBREAKDASH;
572 bool InsetSpecialChar::isLineSeparator() const
575 // this would be nice, but it does not work, since
576 // Paragraph::stripLeadingSpaces nukes the characters which
577 // have this property. I leave the code here, since it should
578 // eventually be made to work. (JMarc 20020327)
579 return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR