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);
139 // helper function: draw text and update x.
140 void drawChar(PainterInfo & pi, int & x, int const y, char_type ch)
142 FontInfo font = pi.base.font;
143 font.setPaintColor(pi.textColor(font.realColor()));
144 pi.pain.text(x, y, ch, font);
145 x += theFontMetrics(font).width(ch);
149 void drawLogo(PainterInfo & pi, int & x, int const y, InsetSpecialChar::Kind kind)
151 FontInfo const & font = pi.base.font;
152 int const em = theFontMetrics(font).em();
154 case InsetSpecialChar::PHRASE_LYX:
156 * \providecommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\\@};
158 drawChar(pi, x, y, 'L');
160 drawChar(pi, x, y + em / 4, 'Y');
162 drawChar(pi, x, y, 'X');
165 case InsetSpecialChar::PHRASE_TEX: {
167 * \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
169 int const ex = theFontMetrics(font).ascent('x');
170 drawChar(pi, x, y, 'T');
172 drawChar(pi, x, y + ex / 2, 'E');
174 drawChar(pi, x, y, 'X');
177 case InsetSpecialChar::PHRASE_LATEX2E:
179 * \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th
180 * \if b\expandafter\@car\f@series\@nil\boldmath\fi
181 * \LaTeX\kern.15em2$_{\textstyle\varepsilon}$}}
183 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_LATEX);
185 drawChar(pi, x, y, '2');
186 drawChar(pi, x, y + em / 4, char_type(0x03b5));
189 case InsetSpecialChar::PHRASE_LATEX: {
191 * \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
193 * \vbox to\ht\z@{\hbox{\check@mathfonts
194 * \fontsize\sf@size\z@
195 * \math@fontsfalse\selectfont
202 drawChar(pi, x, y, 'L');
204 PainterInfo pi2 = pi;
205 pi2.base.font.decSize().decSize();
206 drawChar(pi2, x, y - em / 5, 'A');
208 drawLogo(pi, x, y, InsetSpecialChar::PHRASE_TEX);
212 LYXERR0("No information for drawing logo " << kind);
218 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
220 FontInfo font = pi.base.font;
225 font.setColor(Color_special);
226 pi.pain.text(x, y, char_type('-'), font);
231 font.setColor(Color_special);
232 pi.pain.text(x, y, char_type('|'), font);
235 case END_OF_SENTENCE:
237 font.setColor(Color_special);
238 pi.pain.text(x, y, char_type('.'), font);
243 font.setColor(Color_special);
244 string ell = ". . . ";
245 docstring dell(ell.begin(), ell.end());
246 pi.pain.text(x, y, dell, font);
251 frontend::FontMetrics const & fm =
252 theFontMetrics(font);
254 // A triangle the width and height of an 'x'
255 int w = fm.width(char_type('x'));
256 int ox = fm.width(char_type(' ')) + x;
257 int h = fm.ascent(char_type('x'));
260 xp[0] = ox; yp[0] = y;
261 xp[1] = ox; yp[1] = y - h;
262 xp[2] = ox + w; yp[2] = y - h/2;
263 xp[3] = ox; yp[3] = y;
265 pi.pain.lines(xp, yp, 4, Color_special);
270 font.setColor(Color_special);
271 pi.pain.text(x, y, char_type('/'), font);
276 font.setColor(Color_latex);
277 pi.pain.text(x, y, char_type('-'), font);
284 drawLogo(pi, x, y, kind_);
290 // In lyxf3 this will be just LaTeX
291 void InsetSpecialChar::write(ostream & os) const
296 command = "softhyphen";
299 command = "ligaturebreak";
301 case END_OF_SENTENCE:
302 command = "endofsentence";
308 command = "menuseparator";
311 command = "breakableslash";
314 command = "nobreakdash";
329 os << "\\SpecialChar " << command << "\n";
333 // This function will not be necessary when lyx3
334 void InsetSpecialChar::read(Lexer & lex)
337 string const command = lex.getString();
339 if (command == "softhyphen")
341 else if (command == "ligaturebreak")
342 kind_ = LIGATURE_BREAK;
343 else if (command == "endofsentence")
344 kind_ = END_OF_SENTENCE;
345 else if (command == "ldots")
347 else if (command == "menuseparator")
348 kind_ = MENU_SEPARATOR;
349 else if (command == "breakableslash")
351 else if (command == "nobreakdash")
353 else if (command == "LyX")
355 else if (command == "TeX")
357 else if (command == "LaTeX2e")
358 kind_ = PHRASE_LATEX2E;
359 else if (command == "LaTeX")
360 kind_ = PHRASE_LATEX;
362 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
366 void InsetSpecialChar::latex(otexstream & os,
367 OutputParams const & rp) const
374 os << "\\textcompwordmark{}";
376 case END_OF_SENTENCE:
383 if (rp.local_font->isRightToLeft())
384 os << "\\lyxarrow*{}";
386 os << "\\lyxarrow{}";
394 os << "\\nobreakdash-";
420 int InsetSpecialChar::plaintext(odocstringstream & os,
421 OutputParams const &, size_t) const
429 case END_OF_SENTENCE:
462 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
468 case END_OF_SENTENCE:
501 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
507 xs << XHTMLStream::ESCAPE_NONE << "‌";
509 case END_OF_SENTENCE:
513 xs << XHTMLStream::ESCAPE_NONE << "…";
516 xs << XHTMLStream::ESCAPE_NONE << "⇒";
519 xs << XHTMLStream::ESCAPE_NONE << "⁄";
522 xs << XHTMLStream::ESCAPE_NONE << "‑";
531 xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε";
541 void InsetSpecialChar::toString(odocstream & os) const
545 // Do not output ZERO WIDTH NON JOINER here
546 // Spell checker would choke on it.
551 odocstringstream ods;
552 plaintext(ods, OutputParams(0));
557 void InsetSpecialChar::forOutliner(docstring & os, size_t const,
560 odocstringstream ods;
561 plaintext(ods, OutputParams(0));
566 void InsetSpecialChar::validate(LaTeXFeatures & features) const
568 if (kind_ == MENU_SEPARATOR)
569 features.require("lyxarrow");
570 if (kind_ == NOBREAKDASH)
571 features.require("amsmath");
572 if (kind_ == PHRASE_LYX)
573 features.require("LyX");
577 bool InsetSpecialChar::isLetter() const
579 return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
580 || kind_ == NOBREAKDASH;
584 bool InsetSpecialChar::isLineSeparator() const
587 // this would be nice, but it does not work, since
588 // Paragraph::stripLeadingSpaces nukes the characters which
589 // have this property. I leave the code here, since it should
590 // eventually be made to work. (JMarc 20020327)
591 return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR