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 // helper function: draw text and update x.
139 void drawChar(PainterInfo & pi, int & x, int const y, char_type ch)
141 pi.pain.text(x, y, ch, pi.base.font);
142 x += theFontMetrics(pi.base.font).width(ch);
146 void drawLogo(PainterInfo & pi, int & x, int const y, InsetSpecialChar::Kind kind)
148 FontInfo const & font = pi.base.font;
149 int const em = theFontMetrics(font).em();
151 case InsetSpecialChar::PHRASE_LYX:
153 * \providecommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\\@};
155 drawChar(pi, x, y, 'L');
157 drawChar(pi, x, y + em / 4, 'Y');
159 drawChar(pi, x, y, 'X');
162 case InsetSpecialChar::PHRASE_TEX: {
164 * \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
166 int const ex = theFontMetrics(font).ascent('x');
167 drawChar(pi, x, y, 'T');
169 drawChar(pi, x, y + ex / 2, 'E');
171 drawChar(pi, x, y, 'X');
174 case InsetSpecialChar::PHRASE_LATEX2E:
176 * \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
177 * \if b\expandafter\@car\f@series\@nil\boldmath\fi
178 * \LaTeX\kern.15em2$_{\textstyle\varepsilon}$}}
180 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_LATEX);
182 drawChar(pi, x, y, '2');
183 drawChar(pi, x, y + em / 4, char_type(0x03b5));
186 case InsetSpecialChar::PHRASE_LATEX: {
188 * \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
190 * \vbox to\ht\z@{\hbox{\check@mathfonts
191 * \fontsize\sf@size\z@
192 * \math@fontsfalse\selectfont
199 drawChar(pi, x, y, 'L');
201 PainterInfo pi2 = pi;
202 pi2.base.font.decSize().decSize();
203 drawChar(pi2, x, y - em / 5, 'A');
205 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_TEX);
209 LYXERR0("No information for drawing logo " << kind);
215 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
217 FontInfo font = pi.base.font;
222 font.setColor(Color_special);
223 pi.pain.text(x, y, char_type('-'), font);
228 font.setColor(Color_special);
229 pi.pain.text(x, y, char_type('|'), font);
232 case END_OF_SENTENCE:
234 font.setColor(Color_special);
235 pi.pain.text(x, y, char_type('.'), font);
240 font.setColor(Color_special);
241 string ell = ". . . ";
242 docstring dell(ell.begin(), ell.end());
243 pi.pain.text(x, y, dell, font);
248 frontend::FontMetrics const & fm =
249 theFontMetrics(font);
251 // A triangle the width and height of an 'x'
252 int w = fm.width(char_type('x'));
253 int ox = fm.width(char_type(' ')) + x;
254 int h = fm.ascent(char_type('x'));
257 xp[0] = ox; yp[0] = y;
258 xp[1] = ox; yp[1] = y - h;
259 xp[2] = ox + w; yp[2] = y - h/2;
260 xp[3] = ox; yp[3] = y;
262 pi.pain.lines(xp, yp, 4, Color_special);
267 font.setColor(Color_special);
268 pi.pain.text(x, y, char_type('/'), font);
273 font.setColor(Color_latex);
274 pi.pain.text(x, y, char_type('-'), font);
281 drawLogo(pi, x, y, kind_);
287 // In lyxf3 this will be just LaTeX
288 void InsetSpecialChar::write(ostream & os) const
293 command = "softhyphen";
296 command = "ligaturebreak";
298 case END_OF_SENTENCE:
299 command = "endofsentence";
305 command = "menuseparator";
308 command = "breakableslash";
311 command = "nobreakdash";
326 os << "\\SpecialChar " << command << "\n";
330 // This function will not be necessary when lyx3
331 void InsetSpecialChar::read(Lexer & lex)
334 string const command = lex.getString();
336 if (command == "softhyphen")
338 else if (command == "ligaturebreak")
339 kind_ = LIGATURE_BREAK;
340 else if (command == "endofsentence")
341 kind_ = END_OF_SENTENCE;
342 else if (command == "ldots")
344 else if (command == "menuseparator")
345 kind_ = MENU_SEPARATOR;
346 else if (command == "breakableslash")
348 else if (command == "nobreakdash")
350 else if (command == "LyX")
352 else if (command == "TeX")
354 else if (command == "LaTeX2e")
355 kind_ = PHRASE_LATEX2E;
356 else if (command == "LaTeX")
357 kind_ = PHRASE_LATEX;
359 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
363 void InsetSpecialChar::latex(otexstream & os,
364 OutputParams const & rp) const
371 os << "\\textcompwordmark{}";
373 case END_OF_SENTENCE:
380 if (rp.local_font->isRightToLeft())
381 os << "\\lyxarrow*{}";
383 os << "\\lyxarrow{}";
391 os << "\\nobreakdash-";
417 int InsetSpecialChar::plaintext(odocstringstream & os,
418 OutputParams const &, size_t) const
426 case END_OF_SENTENCE:
459 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
465 case END_OF_SENTENCE:
498 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
504 xs << XHTMLStream::ESCAPE_NONE << "‌";
506 case END_OF_SENTENCE:
510 xs << XHTMLStream::ESCAPE_NONE << "…";
513 xs << XHTMLStream::ESCAPE_NONE << "⇒";
516 xs << XHTMLStream::ESCAPE_NONE << "⁄";
519 xs << XHTMLStream::ESCAPE_NONE << "‑";
528 xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε";
538 void InsetSpecialChar::toString(odocstream & os) const
542 // Do not output ZERO WIDTH NON JOINER here
543 // Spell checker would choke on it.
548 odocstringstream ods;
549 plaintext(ods, OutputParams(0));
554 void InsetSpecialChar::forOutliner(docstring & os, size_t const,
557 odocstringstream ods;
558 plaintext(ods, OutputParams(0));
563 void InsetSpecialChar::validate(LaTeXFeatures & features) const
565 if (kind_ == MENU_SEPARATOR)
566 features.require("lyxarrow");
567 if (kind_ == NOBREAKDASH)
568 features.require("amsmath");
569 if (kind_ == PHRASE_LYX)
570 features.require("LyX");
574 bool InsetSpecialChar::isLetter() const
576 return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
577 || kind_ == NOBREAKDASH;
581 bool InsetSpecialChar::isLineSeparator() const
584 // this would be nice, but it does not work, since
585 // Paragraph::stripLeadingSpaces nukes the characters which
586 // have this property. I leave the code here, since it should
587 // eventually be made to work. (JMarc 20020327)
588 return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR