X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetSpecialChar.cpp;h=617c7f5331522e268954583207dbee2947da4c3b;hb=d8df5397ca45c7a979268e471cd732213c4a251c;hp=f863b27bc2bd84c2588b1f44c6245e72f707ea95;hpb=5008ee540f84715cd10e87f3fa0cd5dc7b974784;p=lyx.git diff --git a/src/insets/InsetSpecialChar.cpp b/src/insets/InsetSpecialChar.cpp index f863b27bc2..617c7f5331 100644 --- a/src/insets/InsetSpecialChar.cpp +++ b/src/insets/InsetSpecialChar.cpp @@ -5,7 +5,7 @@ * * \author Asger Alstrup Nielsen * \author Jean-Marc Lasgouttes - * \author Lars Gullik Bjønnes + * \author Lars Gullik Bjønnes * * Full author contact details are available in file CREDITS. */ @@ -14,25 +14,27 @@ #include "InsetSpecialChar.h" -#include "debug.h" +#include "Dimension.h" +#include "Font.h" #include "LaTeXFeatures.h" -#include "Color.h" #include "Lexer.h" #include "MetricsInfo.h" +#include "output_xhtml.h" +#include "texstream.h" #include "frontends/FontMetrics.h" #include "frontends/Painter.h" +#include "support/debug.h" +#include "support/docstream.h" -namespace lyx { +using namespace std; -using std::string; -using std::auto_ptr; -using std::ostream; +namespace lyx { InsetSpecialChar::InsetSpecialChar(Kind k) - : kind_(k) + : Inset(0), kind_(k) {} @@ -42,59 +44,203 @@ InsetSpecialChar::Kind InsetSpecialChar::kind() const } -bool InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const +namespace { + +int logoWidth(FontInfo const & font, InsetSpecialChar::Kind kind) { + frontend::FontMetrics const & fm = theFontMetrics(font); + int const em = fm.em(); + int width = 0; + // See drawlogo() below to understand what this does. + switch (kind) { + case InsetSpecialChar::PHRASE_LYX: + width = fm.width(from_ascii("L")) - em / 6 + + fm.width(from_ascii("Y")) - em / 8 + + fm.width(from_ascii("X")); + break; + + case InsetSpecialChar::PHRASE_TEX: + width = fm.width(from_ascii("T")) - em / 6 + + fm.width(from_ascii("E")) - em / 8 + + fm.width(from_ascii("X")); + break; + + case InsetSpecialChar::PHRASE_LATEX2E: + width = logoWidth(font, InsetSpecialChar::PHRASE_LATEX) + + 3 * em / 20 + + fm.width(from_ascii("2") + char_type(0x03b5)); + break; + case InsetSpecialChar::PHRASE_LATEX: { + FontInfo smaller = font; + smaller.decSize().decSize(); + width = fm.width(from_ascii("L")) - 9 * em / 25 + + theFontMetrics(smaller).width(from_ascii("A")) - 3 * em / 20 + + logoWidth(font, InsetSpecialChar::PHRASE_TEX); + break; + } + default: + LYXERR0("No information for computing width of logo " << kind); + } + + return width; +} + +} + + +void InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const { frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); dim.asc = fm.maxAscent(); dim.des = fm.maxDescent(); + dim.wid = 0; - string s; + docstring s; switch (kind_) { - case LIGATURE_BREAK: s = "|"; break; - case END_OF_SENTENCE: s = "."; break; - case LDOTS: s = ". . ."; break; - case MENU_SEPARATOR: s = " x "; break; - case HYPHENATION: s = "-"; break; + case LIGATURE_BREAK: + s = from_ascii("|"); + break; + case END_OF_SENTENCE: + s = from_ascii("."); + break; + case LDOTS: + s = from_ascii(". . ."); + break; + case MENU_SEPARATOR: + s = from_ascii(" x "); + break; + case HYPHENATION: + dim.wid = fm.width(from_ascii("-")); + if (dim.wid > 5) + dim.wid -= 2; // to make it look shorter + break; + case SLASH: + s = from_ascii("/"); + break; + case NOBREAKDASH: + s = from_ascii("-"); + break; + case PHRASE_LYX: + case PHRASE_TEX: + case PHRASE_LATEX2E: + case PHRASE_LATEX: + dim.wid = logoWidth(mi.base.font, kind_); + break; + } + if (dim.wid == 0) + dim.wid = fm.width(s); +} + + +namespace { + +// helper function: draw text and update x. +void drawChar(PainterInfo & pi, int & x, int const y, char_type ch) +{ + FontInfo font = pi.base.font; + font.setPaintColor(pi.textColor(font.realColor())); + pi.pain.text(x, y, ch, font); + x += theFontMetrics(font).width(ch); +} + + +void drawLogo(PainterInfo & pi, int & x, int const y, InsetSpecialChar::Kind kind) +{ + FontInfo const & font = pi.base.font; + int const em = theFontMetrics(font).em(); + switch (kind) { + case InsetSpecialChar::PHRASE_LYX: + /** Reference macro: + * \providecommand{\LyX}{L\kern-.1667em\lower.25em\hbox{Y}\kern-.125emX\\@}; + */ + drawChar(pi, x, y, 'L'); + x -= em / 6; + drawChar(pi, x, y + em / 4, 'Y'); + x -= em / 8; + drawChar(pi, x, y, 'X'); + break; + + case InsetSpecialChar::PHRASE_TEX: { + /** Reference macro: + * \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@} + */ + int const ex = theFontMetrics(font).ascent('x'); + drawChar(pi, x, y, 'T'); + x -= em / 6; + drawChar(pi, x, y + ex / 2, 'E'); + x -= em / 8; + drawChar(pi, x, y, 'X'); + break; + } + case InsetSpecialChar::PHRASE_LATEX2E: + /** Reference macro: + * \DeclareRobustCommand{\LaTeXe}{\mbox{\m@th + * \if b\expandafter\@car\f@series\@nil\boldmath\fi + * \LaTeX\kern.15em2$_{\textstyle\varepsilon}$}} + */ + drawLogo(pi, x, y, InsetSpecialChar::PHRASE_LATEX); + x += 3 * em / 20; + drawChar(pi, x, y, '2'); + drawChar(pi, x, y + em / 4, char_type(0x03b5)); + break; + + case InsetSpecialChar::PHRASE_LATEX: { + /** Reference macro: + * \DeclareRobustCommand{\LaTeX}{L\kern-.36em% + * {\sbox\z@ T% + * \vbox to\ht\z@{\hbox{\check@mathfonts + * \fontsize\sf@size\z@ + * \math@fontsfalse\selectfont + * A}% + * \vss}% + * }% + * \kern-.15em% + * \TeX} + */ + drawChar(pi, x, y, 'L'); + x -= 9 * em / 25; + PainterInfo pi2 = pi; + pi2.base.font.decSize().decSize(); + drawChar(pi2, x, y - em / 5, 'A'); + x -= 3 * em / 20; + drawLogo(pi, x, y, InsetSpecialChar::PHRASE_TEX); + break; + } + default: + LYXERR0("No information for drawing logo " << kind); } - docstring ds(s.begin(), s.end()); - dim.wid = fm.width(ds); - if (kind_ == HYPHENATION && dim.wid > 5) - dim.wid -= 2; // to make it look shorter - bool const changed = dim_ != dim; - dim_ = dim; - return changed; } +} void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const { - LyXFont font = pi.base.font; + FontInfo font = pi.base.font; switch (kind_) { case HYPHENATION: { - font.setColor(Color::special); + font.setColor(Color_special); pi.pain.text(x, y, char_type('-'), font); break; } case LIGATURE_BREAK: { - font.setColor(Color::special); + font.setColor(Color_special); pi.pain.text(x, y, char_type('|'), font); break; } case END_OF_SENTENCE: { - font.setColor(Color::special); + font.setColor(Color_special); pi.pain.text(x, y, char_type('.'), font); break; } case LDOTS: { - font.setColor(Color::special); - string ell = ". . . "; - docstring dell(ell.begin(), ell.end()); + font.setColor(Color_special); + string ell = ". . . "; + docstring dell(ell.begin(), ell.end()); pi.pain.text(x, y, dell, font); break; } @@ -104,7 +250,7 @@ void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const theFontMetrics(font); // A triangle the width and height of an 'x' - int w = fm.width(char_type('x')); + int w = fm.width(char_type('x')); int ox = fm.width(char_type(' ')) + x; int h = fm.ascent(char_type('x')); int xp[4], yp[4]; @@ -114,32 +260,68 @@ void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const xp[2] = ox + w; yp[2] = y - h/2; xp[3] = ox; yp[3] = y; - pi.pain.lines(xp, yp, 4, Color::special); + pi.pain.lines(xp, yp, 4, Color_special); break; } + case SLASH: + { + font.setColor(Color_special); + pi.pain.text(x, y, char_type('/'), font); + break; + } + case NOBREAKDASH: + { + font.setColor(Color_latex); + pi.pain.text(x, y, char_type('-'), font); + break; + } + case PHRASE_LYX: + case PHRASE_TEX: + case PHRASE_LATEX2E: + case PHRASE_LATEX: + drawLogo(pi, x, y, kind_); + break; } } // In lyxf3 this will be just LaTeX -void InsetSpecialChar::write(Buffer const &, ostream & os) const +void InsetSpecialChar::write(ostream & os) const { string command; switch (kind_) { case HYPHENATION: - command = "\\-"; + command = "softhyphen"; break; case LIGATURE_BREAK: - command = "\\textcompwordmark{}"; + command = "ligaturebreak"; break; case END_OF_SENTENCE: - command = "\\@."; + command = "endofsentence"; break; case LDOTS: - command = "\\ldots{}"; + command = "ldots"; break; case MENU_SEPARATOR: - command = "\\menuseparator"; + command = "menuseparator"; + break; + case SLASH: + command = "breakableslash"; + break; + case NOBREAKDASH: + command = "nobreakdash"; + break; + case PHRASE_LYX: + command = "LyX"; + break; + case PHRASE_TEX: + command = "TeX"; + break; + case PHRASE_LATEX2E: + command = "LaTeX2e"; + break; + case PHRASE_LATEX: + command = "LaTeX"; break; } os << "\\SpecialChar " << command << "\n"; @@ -147,73 +329,136 @@ void InsetSpecialChar::write(Buffer const &, ostream & os) const // This function will not be necessary when lyx3 -void InsetSpecialChar::read(Buffer const &, Lexer & lex) +void InsetSpecialChar::read(Lexer & lex) { lex.next(); string const command = lex.getString(); - if (command == "\\-") + if (command == "softhyphen") kind_ = HYPHENATION; - else if (command == "\\textcompwordmark{}") + else if (command == "ligaturebreak") kind_ = LIGATURE_BREAK; - else if (command == "\\@.") + else if (command == "endofsentence") kind_ = END_OF_SENTENCE; - else if (command == "\\ldots{}") + else if (command == "ldots") kind_ = LDOTS; - else if (command == "\\menuseparator") + else if (command == "menuseparator") kind_ = MENU_SEPARATOR; + else if (command == "breakableslash") + kind_ = SLASH; + else if (command == "nobreakdash") + kind_ = NOBREAKDASH; + else if (command == "LyX") + kind_ = PHRASE_LYX; + else if (command == "TeX") + kind_ = PHRASE_TEX; + else if (command == "LaTeX2e") + kind_ = PHRASE_LATEX2E; + else if (command == "LaTeX") + kind_ = PHRASE_LATEX; else lex.printError("InsetSpecialChar: Unknown kind: `$$Token'"); } -int InsetSpecialChar::latex(Buffer const &, odocstream & os, - OutputParams const &) const +void InsetSpecialChar::latex(otexstream & os, + OutputParams const & rp) const { switch (kind_) { case HYPHENATION: os << "\\-"; break; case LIGATURE_BREAK: - os << "\\textcompwordmark{}"; + os << "\\textcompwordmark" << termcmd; break; case END_OF_SENTENCE: os << "\\@."; break; case LDOTS: - os << "\\ldots{}"; + os << "\\ldots" << termcmd; break; case MENU_SEPARATOR: - os << "\\lyxarrow{}"; + if (rp.local_font->isRightToLeft()) + os << "\\lyxarrow*"; + else + os << "\\lyxarrow"; + os << termcmd; + break; + case SLASH: + os << "\\slash" << termcmd; + break; + case NOBREAKDASH: + if (rp.moving_arg) + os << "\\protect"; + os << "\\nobreakdash-"; + break; + case PHRASE_LYX: + if (rp.moving_arg) + os << "\\protect"; + os << "\\LyX" << termcmd; + break; + case PHRASE_TEX: + if (rp.moving_arg) + os << "\\protect"; + os << "\\TeX" << termcmd; + break; + case PHRASE_LATEX2E: + if (rp.moving_arg) + os << "\\protect"; + os << "\\LaTeXe" << termcmd; + break; + case PHRASE_LATEX: + if (rp.moving_arg) + os << "\\protect"; + os << "\\LaTeX" << termcmd; break; } - return 0; } -int InsetSpecialChar::plaintext(Buffer const &, odocstream & os, - OutputParams const &) const +int InsetSpecialChar::plaintext(odocstringstream & os, + OutputParams const &, size_t) const { switch (kind_) { case HYPHENATION: - case LIGATURE_BREAK: return 0; + case LIGATURE_BREAK: + os.put(0x200c); + return 1; case END_OF_SENTENCE: os << '.'; return 1; case LDOTS: - os << "..."; - return 3; + os.put(0x2026); + return 1; case MENU_SEPARATOR: os << "->"; return 2; + case SLASH: + os << '/'; + return 1; + case NOBREAKDASH: + os.put(0x2011); + return 1; + case PHRASE_LYX: + os << "LyX"; + return 3; + case PHRASE_TEX: + os << "TeX"; + return 3; + case PHRASE_LATEX2E: + os << "LaTeX2"; + os.put(0x03b5); + return 7; + case PHRASE_LATEX: + os << "LaTeX"; + return 5; } return 0; } -int InsetSpecialChar::docbook(Buffer const &, odocstream & os, - OutputParams const &) const +int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const { switch (kind_) { case HYPHENATION: @@ -223,46 +468,115 @@ int InsetSpecialChar::docbook(Buffer const &, odocstream & os, os << '.'; break; case LDOTS: - os << "..."; + os << "…"; break; case MENU_SEPARATOR: os << "&lyxarrow;"; break; + case SLASH: + os << '/'; + break; + case NOBREAKDASH: + os << '-'; + break; + case PHRASE_LYX: + os << "LyX"; + break; + case PHRASE_TEX: + os << "TeX"; + break; + case PHRASE_LATEX2E: + os << "LaTeX2"; + os.put(0x03b5); + break; + case PHRASE_LATEX: + os << "LaTeX"; + break; } return 0; } -int InsetSpecialChar::textString(Buffer const & buf, odocstream & os, - OutputParams const & op) const +docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const { - return plaintext(buf, os, op); + switch (kind_) { + case HYPHENATION: + break; + case LIGATURE_BREAK: + xs << XHTMLStream::ESCAPE_NONE << "‌"; + break; + case END_OF_SENTENCE: + xs << '.'; + break; + case LDOTS: + xs << XHTMLStream::ESCAPE_NONE << "…"; + break; + case MENU_SEPARATOR: + xs << XHTMLStream::ESCAPE_NONE << "⇒"; + break; + case SLASH: + xs << XHTMLStream::ESCAPE_NONE << "⁄"; + break; + case NOBREAKDASH: + xs << XHTMLStream::ESCAPE_NONE << "‑"; + break; + case PHRASE_LYX: + xs << "LyX"; + break; + case PHRASE_TEX: + xs << "TeX"; + break; + case PHRASE_LATEX2E: + xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε"; + break; + case PHRASE_LATEX: + xs << "LaTeX"; + break; + } + return docstring(); } -auto_ptr InsetSpecialChar::doClone() const +void InsetSpecialChar::toString(odocstream & os) const { - return auto_ptr(new InsetSpecialChar(kind_)); + switch (kind_) { + case LIGATURE_BREAK: + // Do not output ZERO WIDTH NON JOINER here + // Spell checker would choke on it. + return; + default: + break; + } + odocstringstream ods; + plaintext(ods, OutputParams(0)); + os << ods.str(); } -void InsetSpecialChar::validate(LaTeXFeatures & features) const +void InsetSpecialChar::forOutliner(docstring & os, size_t const, + bool const) const { - if (kind_ == MENU_SEPARATOR) { - features.require("lyxarrow"); - } + odocstringstream ods; + plaintext(ods, OutputParams(0)); + os += ods.str(); } -bool InsetSpecialChar::isChar() const +void InsetSpecialChar::validate(LaTeXFeatures & features) const { - return true; + if (kind_ == MENU_SEPARATOR) + features.require("lyxarrow"); + if (kind_ == NOBREAKDASH) + features.require("amsmath"); + if (kind_ == PHRASE_LYX) + features.require("LyX"); } bool InsetSpecialChar::isLetter() const { - return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK; + return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK + || kind_ == NOBREAKDASH; } @@ -273,7 +587,8 @@ bool InsetSpecialChar::isLineSeparator() const // Paragraph::stripLeadingSpaces nukes the characters which // have this property. I leave the code here, since it should // eventually be made to work. (JMarc 20020327) - return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR; + return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR + || kind_ == SLASH; #else return false; #endif