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"
23 #include "texstream.h"
25 #include "frontends/FontMetrics.h"
26 #include "frontends/Painter.h"
28 #include "support/debug.h"
29 #include "support/docstream.h"
36 InsetSpecialChar::InsetSpecialChar(Kind k)
41 InsetSpecialChar::Kind InsetSpecialChar::kind() const
49 int logoWidth(FontInfo const & font, InsetSpecialChar::Kind kind) {
50 frontend::FontMetrics const & fm = theFontMetrics(font);
51 int const em = fm.em();
53 // See drawlogo() below to understand what this does.
55 case InsetSpecialChar::PHRASE_LYX:
56 width = fm.width(from_ascii("L")) - em / 6
57 + fm.width(from_ascii("Y")) - em / 8
58 + fm.width(from_ascii("X"));
61 case InsetSpecialChar::PHRASE_TEX:
62 width = fm.width(from_ascii("T")) - em / 6
63 + fm.width(from_ascii("E")) - em / 8
64 + fm.width(from_ascii("X"));
67 case InsetSpecialChar::PHRASE_LATEX2E:
68 width = logoWidth(font, InsetSpecialChar::PHRASE_LATEX)
70 + fm.width(from_ascii("2") + char_type(0x03b5));
72 case InsetSpecialChar::PHRASE_LATEX: {
73 FontInfo smaller = font;
74 smaller.decSize().decSize();
75 width = fm.width(from_ascii("L")) - 9 * em / 25
76 + theFontMetrics(smaller).width(from_ascii("A")) - 3 * em / 20
77 + logoWidth(font, InsetSpecialChar::PHRASE_TEX);
81 LYXERR0("No information for computing width of logo " << kind);
90 void InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const
92 frontend::FontMetrics const & fm =
93 theFontMetrics(mi.base.font);
94 dim.asc = fm.maxAscent();
95 dim.des = fm.maxDescent();
103 case END_OF_SENTENCE:
107 s = from_ascii(". . .");
110 s = from_ascii(" x ");
113 dim.wid = fm.width(from_ascii("-"));
115 dim.wid -= 2; // to make it look shorter
127 dim.wid = logoWidth(mi.base.font, kind_);
131 dim.wid = fm.width(s);
137 // helper function: draw text and update x.
138 void drawChar(PainterInfo & pi, int & x, int const y, char_type ch)
140 FontInfo font = pi.base.font;
141 font.setPaintColor(pi.textColor(font.realColor()));
142 pi.pain.text(x, y, ch, font);
143 x += theFontMetrics(font).width(ch);
147 void drawLogo(PainterInfo & pi, int & x, int const y, InsetSpecialChar::Kind kind)
149 FontInfo const & font = pi.base.font;
150 int const em = theFontMetrics(font).em();
152 case InsetSpecialChar::PHRASE_LYX:
154 * \providecommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\\@};
156 drawChar(pi, x, y, 'L');
158 drawChar(pi, x, y + em / 4, 'Y');
160 drawChar(pi, x, y, 'X');
163 case InsetSpecialChar::PHRASE_TEX: {
165 * \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
167 int const ex = theFontMetrics(font).ascent('x');
168 drawChar(pi, x, y, 'T');
170 drawChar(pi, x, y + ex / 2, 'E');
172 drawChar(pi, x, y, 'X');
175 case InsetSpecialChar::PHRASE_LATEX2E:
177 * \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
178 * \if b\expandafter\@car\f@series\@nil\boldmath\fi
179 * \LaTeX\kern.15em2$_{\textstyle\varepsilon}$}}
181 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_LATEX);
183 drawChar(pi, x, y, '2');
184 drawChar(pi, x, y + em / 4, char_type(0x03b5));
187 case InsetSpecialChar::PHRASE_LATEX: {
189 * \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
191 * \vbox to\ht\z@{\hbox{\check@mathfonts
192 * \fontsize\sf@size\z@
193 * \math@fontsfalse\selectfont
200 drawChar(pi, x, y, 'L');
202 PainterInfo pi2 = pi;
203 pi2.base.font.decSize().decSize();
204 drawChar(pi2, x, y - em / 5, 'A');
206 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_TEX);
210 LYXERR0("No information for drawing logo " << kind);
216 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
218 FontInfo font = pi.base.font;
223 font.setColor(Color_special);
224 pi.pain.text(x, y, char_type('-'), font);
229 font.setColor(Color_special);
230 pi.pain.text(x, y, char_type('|'), font);
233 case END_OF_SENTENCE:
235 font.setColor(Color_special);
236 pi.pain.text(x, y, char_type('.'), font);
241 font.setColor(Color_special);
242 string ell = ". . . ";
243 docstring dell(ell.begin(), ell.end());
244 pi.pain.text(x, y, dell, font);
249 frontend::FontMetrics const & fm =
250 theFontMetrics(font);
252 // A triangle the width and height of an 'x'
253 int w = fm.width(char_type('x'));
254 int ox = fm.width(char_type(' ')) + x;
255 int h = fm.ascent(char_type('x'));
258 xp[0] = ox; yp[0] = y;
259 xp[1] = ox; yp[1] = y - h;
260 xp[2] = ox + w; yp[2] = y - h/2;
261 xp[3] = ox; yp[3] = y;
263 pi.pain.lines(xp, yp, 4, Color_special);
268 font.setColor(Color_special);
269 pi.pain.text(x, y, char_type('/'), font);
274 font.setColor(Color_latex);
275 pi.pain.text(x, y, char_type('-'), font);
282 drawLogo(pi, x, y, kind_);
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 void InsetSpecialChar::read(Lexer & lex)
333 string const command = lex.getString();
335 if (command == "softhyphen")
337 else if (command == "ligaturebreak")
338 kind_ = LIGATURE_BREAK;
339 else if (command == "endofsentence")
340 kind_ = END_OF_SENTENCE;
341 else if (command == "ldots")
343 else if (command == "menuseparator")
344 kind_ = MENU_SEPARATOR;
345 else if (command == "breakableslash")
347 else if (command == "nobreakdash")
349 else if (command == "LyX")
351 else if (command == "TeX")
353 else if (command == "LaTeX2e")
354 kind_ = PHRASE_LATEX2E;
355 else if (command == "LaTeX")
356 kind_ = PHRASE_LATEX;
358 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
362 void InsetSpecialChar::latex(otexstream & os,
363 OutputParams const & rp) const
370 os << "\\textcompwordmark" << termcmd;
372 case END_OF_SENTENCE:
376 os << "\\ldots" << termcmd;
379 if (rp.local_font->isRightToLeft())
386 os << "\\slash" << termcmd;
391 os << "\\nobreakdash-";
396 os << "\\LyX" << termcmd;
401 os << "\\TeX" << termcmd;
406 os << "\\LaTeXe" << termcmd;
411 os << "\\LaTeX" << termcmd;
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::isChar() const
576 return kind_ != HYPHENATION && kind_ != LIGATURE_BREAK;
580 bool InsetSpecialChar::isLetter() const
582 return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
583 || kind_ == NOBREAKDASH;
587 bool InsetSpecialChar::isLineSeparator() const
590 // this would be nice, but it does not work, since
591 // Paragraph::stripLeadingSpaces nukes the characters which
592 // have this property. I leave the code here, since it should
593 // eventually be made to work. (JMarc 20020327)
594 return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR