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);
133 setDimCache(mi, dim);
137 void InsetSpecialChar::drawBackground(PainterInfo & pi, int x, int y) const
141 Dimension const dim = dimension(*pi.base.bv);
142 pi.pain.fillRectangle(x, y - dim.asc, dim.wid, dim.asc + dim.des,
143 pi.backgroundColor(this));
149 // helper function: draw text and update x.
150 void drawChar(PainterInfo & pi, int & x, int const y, char_type ch)
152 pi.pain.text(x, y, ch, pi.base.font);
153 x += theFontMetrics(pi.base.font).width(ch);
157 void drawLogo(PainterInfo & pi, int & x, int const y, InsetSpecialChar::Kind kind)
159 FontInfo const & font = pi.base.font;
160 int const em = theFontMetrics(font).em();
162 case InsetSpecialChar::PHRASE_LYX:
164 * \providecommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\\@};
166 drawChar(pi, x, y, 'L');
168 drawChar(pi, x, y + em / 4, 'Y');
170 drawChar(pi, x, y, 'X');
173 case InsetSpecialChar::PHRASE_TEX: {
175 * \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
177 int const ex = theFontMetrics(font).ascent('x');
178 drawChar(pi, x, y, 'T');
180 drawChar(pi, x, y + ex / 2, 'E');
182 drawChar(pi, x, y, 'X');
185 case InsetSpecialChar::PHRASE_LATEX2E:
187 * \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
188 * \if b\expandafter\@car\f@series\@nil\boldmath\fi
189 * \LaTeX\kern.15em2$_{\textstyle\varepsilon}$}}
191 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_LATEX);
193 drawChar(pi, x, y, '2');
194 drawChar(pi, x, y + em / 4, char_type(0x03b5));
197 case InsetSpecialChar::PHRASE_LATEX: {
199 * \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
201 * \vbox to\ht\z@{\hbox{\check@mathfonts
202 * \fontsize\sf@size\z@
203 * \math@fontsfalse\selectfont
210 drawChar(pi, x, y, 'L');
212 PainterInfo pi2 = pi;
213 pi2.base.font.decSize().decSize();
214 drawChar(pi2, x, y - em / 5, 'A');
216 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_TEX);
220 LYXERR0("No information for drawing logo " << kind);
226 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
228 FontInfo font = pi.base.font;
233 font.setColor(Color_special);
234 pi.pain.text(x, y, char_type('-'), font);
239 font.setColor(Color_special);
240 pi.pain.text(x, y, char_type('|'), font);
243 case END_OF_SENTENCE:
245 font.setColor(Color_special);
246 pi.pain.text(x, y, char_type('.'), font);
251 font.setColor(Color_special);
252 string ell = ". . . ";
253 docstring dell(ell.begin(), ell.end());
254 pi.pain.text(x, y, dell, font);
259 frontend::FontMetrics const & fm =
260 theFontMetrics(font);
262 // A triangle the width and height of an 'x'
263 int w = fm.width(char_type('x'));
264 int ox = fm.width(char_type(' ')) + x;
265 int h = fm.ascent(char_type('x'));
268 xp[0] = ox; yp[0] = y;
269 xp[1] = ox; yp[1] = y - h;
270 xp[2] = ox + w; yp[2] = y - h/2;
271 xp[3] = ox; yp[3] = y;
273 pi.pain.lines(xp, yp, 4, Color_special);
278 font.setColor(Color_special);
279 pi.pain.text(x, y, char_type('/'), font);
284 font.setColor(Color_latex);
285 pi.pain.text(x, y, char_type('-'), font);
292 drawLogo(pi, x, y, kind_);
298 // In lyxf3 this will be just LaTeX
299 void InsetSpecialChar::write(ostream & os) const
304 command = "softhyphen";
307 command = "ligaturebreak";
309 case END_OF_SENTENCE:
310 command = "endofsentence";
316 command = "menuseparator";
319 command = "breakableslash";
322 command = "nobreakdash";
337 os << "\\SpecialChar " << command << "\n";
341 // This function will not be necessary when lyx3
342 void InsetSpecialChar::read(Lexer & lex)
345 string const command = lex.getString();
347 if (command == "softhyphen")
349 else if (command == "ligaturebreak")
350 kind_ = LIGATURE_BREAK;
351 else if (command == "endofsentence")
352 kind_ = END_OF_SENTENCE;
353 else if (command == "ldots")
355 else if (command == "menuseparator")
356 kind_ = MENU_SEPARATOR;
357 else if (command == "breakableslash")
359 else if (command == "nobreakdash")
361 else if (command == "LyX")
363 else if (command == "TeX")
365 else if (command == "LaTeX2e")
366 kind_ = PHRASE_LATEX2E;
367 else if (command == "LaTeX")
368 kind_ = PHRASE_LATEX;
370 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
374 void InsetSpecialChar::latex(otexstream & os,
375 OutputParams const & rp) const
382 os << "\\textcompwordmark{}";
384 case END_OF_SENTENCE:
391 if (rp.local_font->isRightToLeft())
392 os << "\\lyxarrow*{}";
394 os << "\\lyxarrow{}";
402 os << "\\nobreakdash-";
428 int InsetSpecialChar::plaintext(odocstringstream & os,
429 OutputParams const &, size_t) const
437 case END_OF_SENTENCE:
470 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
476 case END_OF_SENTENCE:
509 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
515 xs << XHTMLStream::ESCAPE_NONE << "‌";
517 case END_OF_SENTENCE:
521 xs << XHTMLStream::ESCAPE_NONE << "…";
524 xs << XHTMLStream::ESCAPE_NONE << "⇒";
527 xs << XHTMLStream::ESCAPE_NONE << "⁄";
530 xs << XHTMLStream::ESCAPE_NONE << "‑";
539 xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε";
549 void InsetSpecialChar::toString(odocstream & os) const
553 // Do not output ZERO WIDTH NON JOINER here
554 // Spell checker would choke on it.
559 odocstringstream ods;
560 plaintext(ods, OutputParams(0));
565 void InsetSpecialChar::forOutliner(docstring & os, size_t const,
568 odocstringstream ods;
569 plaintext(ods, OutputParams(0));
574 void InsetSpecialChar::validate(LaTeXFeatures & features) const
576 if (kind_ == MENU_SEPARATOR)
577 features.require("lyxarrow");
578 if (kind_ == NOBREAKDASH)
579 features.require("amsmath");
580 if (kind_ == PHRASE_LYX)
581 features.require("LyX");
585 bool InsetSpecialChar::isLetter() const
587 return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
588 || kind_ == NOBREAKDASH;
592 bool InsetSpecialChar::isLineSeparator() const
595 // this would be nice, but it does not work, since
596 // Paragraph::stripLeadingSpaces nukes the characters which
597 // have this property. I leave the code here, since it should
598 // eventually be made to work. (JMarc 20020327)
599 return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR