X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetSpace.cpp;h=3f86eb8c074cf1c1775b6ca50c920d72e3fa85fc;hb=e26a60edef3eae39c2e8379f395febedc5ba7efa;hp=c80fe6c2b4640ed8e8693fd5a93a8feaa49dd786;hpb=01fb1898ad0ba5c9700728a22020b22cb3c452fa;p=features.git diff --git a/src/insets/InsetSpace.cpp b/src/insets/InsetSpace.cpp index c80fe6c2b4..3f86eb8c07 100644 --- a/src/insets/InsetSpace.cpp +++ b/src/insets/InsetSpace.cpp @@ -5,8 +5,8 @@ * * \author Asger Alstrup Nielsen * \author Jean-Marc Lasgouttes - * \author Lars Gullik Bjønnes - * \author Jürgen Spitzmüller + * \author Lars Gullik Bjønnes + * \author Jürgen Spitzmüller * * Full author contact details are available in file CREDITS. */ @@ -20,15 +20,20 @@ #include "Dimension.h" #include "FuncRequest.h" #include "FuncStatus.h" -#include "Length.h" +#include "Language.h" +#include "LaTeXFeatures.h" #include "Lexer.h" #include "MetricsInfo.h" -#include "OutputParams.h" +#include "texstream.h" +#include "xml.h" #include "support/debug.h" #include "support/docstream.h" #include "support/gettext.h" +#include "support/lassert.h" +#include "support/Length.h" #include "support/lstrings.h" +#include "support/qstring_helpers.h" #include "frontends/Application.h" #include "frontends/FontMetrics.h" @@ -40,7 +45,7 @@ namespace lyx { InsetSpace::InsetSpace(InsetSpaceParams const & params) - : params_(params) + : Inset(nullptr), params_(params) {} @@ -50,77 +55,88 @@ InsetSpaceParams::Kind InsetSpace::kind() const } -Length InsetSpace::length() const +GlueLength InsetSpace::length() const { return params_.length; } -InsetSpace::~InsetSpace() -{ - hideDialogs("space", this); -} - - docstring InsetSpace::toolTip(BufferView const &, int, int) const { docstring message; switch (params_.kind) { case InsetSpaceParams::NORMAL: - message = _("Interword Space"); + message = _("Normal Space"); break; case InsetSpaceParams::PROTECTED: - message = _("Protected Space"); + message = _("Non-Breaking Normal Space"); + break; + case InsetSpaceParams::VISIBLE: + message = _("Non-Breaking Visible Normal Space"); break; case InsetSpaceParams::THIN: - message = _("Thin Space"); + message = _("Non-Breaking Thin Space (1/6 em)"); + break; + case InsetSpaceParams::MEDIUM: + message = _("Non-Breaking Medium Space (2/9 em)"); + break; + case InsetSpaceParams::THICK: + message = _("Non-Breaking Thick Space (5/18 em)"); break; case InsetSpaceParams::QUAD: - message = _("Quad Space"); + message = _("Quad Space (1 em)"); break; case InsetSpaceParams::QQUAD: - message = _("QQuad Space"); + message = _("Double Quad Space (2 em)"); break; case InsetSpaceParams::ENSPACE: - message = _("Enspace"); + message = _("Non-Breaking Half Quad Space (1/2 em)"); break; case InsetSpaceParams::ENSKIP: - message = _("Enskip"); + message = _("Half Quad Space (1/2 em)"); break; case InsetSpaceParams::NEGTHIN: - message = _("Negative Thin Space"); + message = _("Non-Breaking Negative Thin Space (-1/6 em)"); + break; + case InsetSpaceParams::NEGMEDIUM: + message = _("Non-Breaking Negative Medium Space (-2/9 em)"); + break; + case InsetSpaceParams::NEGTHICK: + message = _("Non-Breaking Negative Thick Space (-5/18 em)"); break; case InsetSpaceParams::HFILL: message = _("Horizontal Fill"); break; case InsetSpaceParams::HFILL_PROTECTED: - message = _("Protected Horizontal Fill"); + message = _("Non-Breaking Horizontal Fill"); break; case InsetSpaceParams::DOTFILL: - message = _("Horizontal Fill (Dots)"); + message = _("Non-Breaking Horizontal Fill (Dots)"); break; case InsetSpaceParams::HRULEFILL: - message = _("Horizontal Fill (Rule)"); + message = _("Non-Breaking Horizontal Fill (Rule)"); break; case InsetSpaceParams::LEFTARROWFILL: - message = _("Horizontal Fill (Left Arrow)"); + message = _("Non-Breaking Horizontal Fill (Left Arrow)"); break; case InsetSpaceParams::RIGHTARROWFILL: - message = _("Horizontal Fill (Right Arrow)"); + message = _("Non-Breaking Horizontal Fill (Right Arrow)"); break; case InsetSpaceParams::UPBRACEFILL: - message = _("Horizontal Fill (Up Brace)"); + message = _("Non-Breaking Horizontal Fill (Up Brace)"); break; case InsetSpaceParams::DOWNBRACEFILL: - message = _("Horizontal Fill (Down Brace)"); + message = _("Non-Breaking Horizontal Fill (Down Brace)"); break; case InsetSpaceParams::CUSTOM: + // FIXME unicode message = support::bformat(_("Horizontal Space (%1$s)"), - params_.length.asDocstring()); + locLengthDocString(from_ascii(params_.length.asString()))); break; case InsetSpaceParams::CUSTOM_PROTECTED: - message = support::bformat(_("Protected Horizontal Space (%1$s)"), - params_.length.asDocstring()); + // FIXME unicode + message = support::bformat(_("Non-Breaking Horizontal Space (%1$s)"), + locLengthDocString(from_ascii(params_.length.asString()))); break; } return message; @@ -129,16 +145,21 @@ docstring InsetSpace::toolTip(BufferView const &, int, int) const void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd) { - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_MODIFY: { - string2params(to_utf8(cmd.argument()), params_); + cur.recordUndo(); + string arg = to_utf8(cmd.argument()); + if (arg == "space \\hspace{}") + arg += params_.length.len().empty() + ? " \\length 1" + string(stringFromUnit(Length::defaultUnit())) + : " \\length " + params_.length.asString(); + string2params(arg, params_); break; } - case LFUN_MOUSE_RELEASE: - if (!cur.selection() && cmd.button() == mouse_button::button1) - cur.bv().showDialog("space", params2string(params()), this); + case LFUN_INSET_DIALOG_UPDATE: + cur.bv().updateDialog("space", params2string(params())); break; default: @@ -151,14 +172,19 @@ void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd) bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { - switch (cmd.action) { + switch (cmd.action()) { // we handle these case LFUN_INSET_MODIFY: if (cmd.getArg(0) == "space") { InsetSpaceParams params; string2params(to_utf8(cmd.argument()), params); status.setOnOff(params_.kind == params.kind); - } + status.setEnabled(true); + } else + status.setEnabled(false); + return true; + + case LFUN_INSET_DIALOG_UPDATE: status.setEnabled(true); return true; default: @@ -167,50 +193,94 @@ bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd, } -void InsetSpace::edit(Cursor & cur, bool, EntryDirection) +int InsetSpace::rowFlags() const { - cur.bv().showDialog("space", params2string(params()), this); + switch (params_.kind) { + case InsetSpaceParams::PROTECTED: + case InsetSpaceParams::CUSTOM_PROTECTED: + case InsetSpaceParams::HFILL_PROTECTED: + case InsetSpaceParams::THIN: + case InsetSpaceParams::NEGTHIN: + case InsetSpaceParams::MEDIUM: + case InsetSpaceParams::NEGMEDIUM: + case InsetSpaceParams::THICK: + case InsetSpaceParams::NEGTHICK: + case InsetSpaceParams::ENSPACE: + case InsetSpaceParams::VISIBLE: + // no break after these + return Inline; + case InsetSpaceParams::NORMAL: + case InsetSpaceParams::QUAD: + case InsetSpaceParams::QQUAD: + case InsetSpaceParams::ENSKIP: + case InsetSpaceParams::CUSTOM: + case InsetSpaceParams::HFILL: + case InsetSpaceParams::DOTFILL: + case InsetSpaceParams::HRULEFILL: + case InsetSpaceParams::LEFTARROWFILL: + case InsetSpaceParams::RIGHTARROWFILL: + case InsetSpaceParams::UPBRACEFILL: + case InsetSpaceParams::DOWNBRACEFILL: + // these allow line breaking + break; + } + return CanBreakAfter; +} + + +namespace { +int const arrow_size = 8; } void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const { - if (isStretchableSpace()) { - // The metrics for this kinds are calculated externally in - // \c TextMetrics::computeRowMetrics. Those are dummy value: - dim = Dimension(10, 10, 10); + if (isHfill()) { + // The width for hfills is calculated externally in + // TextMetrics::setRowAlignment. The value of 5 is the + // minimal value when the hfill is not active. + dim = Dimension(5, 10, 10); return; } frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); dim.asc = fm.maxAscent(); dim.des = fm.maxDescent(); + int const em = fm.em(); switch (params_.kind) { case InsetSpaceParams::THIN: case InsetSpaceParams::NEGTHIN: - dim.wid = fm.width(char_type('M')) / 6; + dim.wid = em / 6; + break; + case InsetSpaceParams::MEDIUM: + case InsetSpaceParams::NEGMEDIUM: + dim.wid = em / 4; + break; + case InsetSpaceParams::THICK: + case InsetSpaceParams::NEGTHICK: + dim.wid = em / 2; break; case InsetSpaceParams::PROTECTED: + case InsetSpaceParams::VISIBLE: case InsetSpaceParams::NORMAL: dim.wid = fm.width(char_type(' ')); break; case InsetSpaceParams::QUAD: - dim.wid = fm.width(char_type('M')); + dim.wid = em; break; case InsetSpaceParams::QQUAD: - dim.wid = 2 * fm.width(char_type('M')); + dim.wid = 2 * em; break; case InsetSpaceParams::ENSPACE: case InsetSpaceParams::ENSKIP: - dim.wid = int(0.5 * fm.width(char_type('M'))); + dim.wid = int(0.5 * em); break; case InsetSpaceParams::CUSTOM: case InsetSpaceParams::CUSTOM_PROTECTED: { - int length = params_.length.inBP(); - if (length < 0) - length = -1 * length; - dim.wid = length; + int const w = mi.base.inPixels(params_.length.len()); + int const minw = (w < 0) ? 3 * arrow_size : 4; + dim.wid = max(minw, abs(w)); break; } case InsetSpaceParams::HFILL: @@ -224,8 +294,6 @@ void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const // shut up compiler break; } - // Cache the inset dimension. - setDimCache(mi, dim); } @@ -233,10 +301,10 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const { Dimension const dim = dimension(*pi.base.bv); - if (isStretchableSpace()) { + if (isHfill() || params_.length.len().value() < 0) { int const asc = theFontMetrics(pi.base.font).ascent('M'); int const desc = theFontMetrics(pi.base.font).descent('M'); - //Pixel height divisible by 2 for prettier fill graphics: + // Pixel height divisible by 2 for prettier fill graphics: int const oddheight = (asc ^ desc) & 1; int const x0 = x + 1; int const x1 = x + dim.wid - 2; @@ -245,7 +313,7 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const int const y2 = (y0 + y1) / 2; int xoffset = (y0 - y1) / 2; - //Two tests for very narrow insets + // Two tests for very narrow insets if (xoffset > x1 - x0 && (params_.kind == InsetSpaceParams::LEFTARROWFILL || params_.kind == InsetSpaceParams::RIGHTARROWFILL)) @@ -263,12 +331,12 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const if (params_.kind == InsetSpaceParams::HFILL) { pi.pain.line(x0, y1, x0, y0, Color_added_space); - pi.pain.line(x0, y2 , x1, y2, Color_added_space, + pi.pain.line(x0, y2, x1, y2, Color_added_space, frontend::Painter::line_onoffdash); pi.pain.line(x1, y1, x1, y0, Color_added_space); } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) { pi.pain.line(x0, y1, x0, y0, Color_latex); - pi.pain.line(x0, y2 , x1, y2, Color_latex, + pi.pain.line(x0, y2, x1, y2, Color_latex, frontend::Painter::line_onoffdash); pi.pain.line(x1, y1, x1, y0, Color_latex); } else if (params_.kind == InsetSpaceParams::DOTFILL) { @@ -302,40 +370,60 @@ void InsetSpace::draw(PainterInfo & pi, int x, int y) const pi.pain.line(xm + 1, y1 + 1 , xmr, y2, Color_special); pi.pain.line(xmr, y2 , x3, y2, Color_special); pi.pain.line(x3 + 1, y2 + 1 , x1, y0, Color_special); + } else if (params_.kind == InsetSpaceParams::CUSTOM) { + pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_special); + pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_special); + pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_special); + pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_special); + pi.pain.line(x2, y2 , x3, y2, Color_special); + } else if (params_.kind == InsetSpaceParams::CUSTOM_PROTECTED) { + pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_latex); + pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_latex); + pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_latex); + pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_latex); + pi.pain.line(x2, y2 , x3, y2, Color_latex); } return; } int const w = dim.wid; - int const h = theFontMetrics(pi.base.font).ascent('x'); + int const h = theFontMetrics(pi.base.font).xHeight(); int xp[4], yp[4]; xp[0] = x; yp[0] = y - max(h / 4, 1); if (params_.kind == InsetSpaceParams::NORMAL || - params_.kind == InsetSpaceParams::PROTECTED) { - xp[1] = x; yp[1] = y; - xp[2] = x + w; yp[2] = y; + params_.kind == InsetSpaceParams::PROTECTED || + params_.kind == InsetSpaceParams::VISIBLE) { + xp[1] = x; yp[1] = y; + xp[2] = x + w - 1; yp[2] = y; } else { - xp[1] = x; yp[1] = y + max(h / 4, 1); - xp[2] = x + w; yp[2] = y + max(h / 4, 1); + xp[1] = x; yp[1] = y + max(h / 4, 1); + xp[2] = x + w - 1; yp[2] = y + max(h / 4, 1); } - xp[3] = x + w; + xp[3] = x + w - 1; yp[3] = y - max(h / 4, 1); + Color col = Color_special; if (params_.kind == InsetSpaceParams::PROTECTED || params_.kind == InsetSpaceParams::ENSPACE || + params_.kind == InsetSpaceParams::THIN || params_.kind == InsetSpaceParams::NEGTHIN || + params_.kind == InsetSpaceParams::MEDIUM || + params_.kind == InsetSpaceParams::NEGMEDIUM || + params_.kind == InsetSpaceParams::THICK || + params_.kind == InsetSpaceParams::NEGTHICK || params_.kind == InsetSpaceParams::CUSTOM_PROTECTED) - pi.pain.lines(xp, yp, 4, Color_latex); - else - pi.pain.lines(xp, yp, 4, Color_special); + col = Color_latex; + else if (params_.kind == InsetSpaceParams::VISIBLE) + col = Color_foreground; + + pi.pain.lines(xp, yp, 4, col); } void InsetSpaceParams::write(ostream & os) const { - string command; switch (kind) { case InsetSpaceParams::NORMAL: os << "\\space{}"; @@ -343,9 +431,18 @@ void InsetSpaceParams::write(ostream & os) const case InsetSpaceParams::PROTECTED: os << "~"; break; + case InsetSpaceParams::VISIBLE: + os << "\\textvisiblespace{}"; + break; case InsetSpaceParams::THIN: os << "\\thinspace{}"; break; + case InsetSpaceParams::MEDIUM: + os << "\\medspace{}"; + break; + case InsetSpaceParams::THICK: + os << "\\thickspace{}"; + break; case InsetSpaceParams::QUAD: os << "\\quad{}"; break; @@ -361,6 +458,12 @@ void InsetSpaceParams::write(ostream & os) const case InsetSpaceParams::NEGTHIN: os << "\\negthinspace{}"; break; + case InsetSpaceParams::NEGMEDIUM: + os << "\\negmedspace{}"; + break; + case InsetSpaceParams::NEGTHICK: + os << "\\negthickspace{}"; + break; case InsetSpaceParams::HFILL: os << "\\hfill{}"; break; @@ -392,8 +495,8 @@ void InsetSpaceParams::write(ostream & os) const os << "\\hspace*{}"; break; } - - if (!length.empty()) + + if (!length.len().empty()) os << "\n\\length " << length.asString(); } @@ -404,12 +507,19 @@ void InsetSpaceParams::read(Lexer & lex) string command; lex >> command; + // The tests for math might be disabled after a file format change if (command == "\\space{}") kind = InsetSpaceParams::NORMAL; else if (command == "~") kind = InsetSpaceParams::PROTECTED; + else if (command == "\\textvisiblespace{}") + kind = InsetSpaceParams::VISIBLE; else if (command == "\\thinspace{}") kind = InsetSpaceParams::THIN; + else if (command == "\\medspace{}") + kind = InsetSpaceParams::MEDIUM; + else if (command == "\\thickspace{}") + kind = InsetSpaceParams::THICK; else if (command == "\\quad{}") kind = InsetSpaceParams::QUAD; else if (command == "\\qquad{}") @@ -420,6 +530,10 @@ void InsetSpaceParams::read(Lexer & lex) kind = InsetSpaceParams::ENSKIP; else if (command == "\\negthinspace{}") kind = InsetSpaceParams::NEGTHIN; + else if (command == "\\negmedspace{}") + kind = InsetSpaceParams::NEGMEDIUM; + else if (command == "\\negthickspace{}") + kind = InsetSpaceParams::NEGTHICK; else if (command == "\\hfill{}") kind = InsetSpaceParams::HFILL; else if (command == "\\hspace*{\\fill}") @@ -462,75 +576,134 @@ void InsetSpace::read(Lexer & lex) } -int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const +void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const { switch (params_.kind) { case InsetSpaceParams::NORMAL: - os << (runparams.free_spacing ? " " : "\\ "); + if (runparams.find_effective()) + os << "~"; + else + os << (runparams.free_spacing ? " " : "\\ "); break; case InsetSpaceParams::PROTECTED: - os << (runparams.free_spacing ? ' ' : '~'); + if (runparams.find_effective()) + os.put(0xa0); + else if (runparams.local_font && + runparams.local_font->language()->lang() == "polutonikogreek") + // in babel's polutonikogreek, ~ is active + os << (runparams.free_spacing ? " " : "\\nobreakspace{}"); + else + os << (runparams.free_spacing ? ' ' : '~'); + break; + case InsetSpaceParams::VISIBLE: + if (runparams.find_effective()) + os.put(0x2423); + else + os << (runparams.free_spacing ? " " : "\\textvisiblespace{}"); break; case InsetSpaceParams::THIN: - os << (runparams.free_spacing ? " " : "\\,"); + if (runparams.find_effective()) + os.put(0x2009); + else + os << (runparams.free_spacing ? " " : "\\,"); + break; + case InsetSpaceParams::MEDIUM: + if (runparams.find_effective()) + os.put(0x2005); + else if (params_.math) + os << (runparams.free_spacing ? " " : "\\:"); + else + os << (runparams.free_spacing ? " " : "\\medspace{}"); + break; + case InsetSpaceParams::THICK: + if (runparams.find_effective()) + os.put(0x2004); + else if (params_.math) + os << (runparams.free_spacing ? " " : "\\;"); + else + os << (runparams.free_spacing ? " " : "\\thickspace{}"); break; case InsetSpaceParams::QUAD: - os << (runparams.free_spacing ? " " : "\\quad{}"); + if (runparams.find_effective()) + os.put(0x2003); + else + os << (runparams.free_spacing ? " " : "\\quad{}"); break; case InsetSpaceParams::QQUAD: - os << (runparams.free_spacing ? " " : "\\qquad{}"); + if (runparams.find_effective()) { + os.put(0x2003); + os.put(0x2003); + } + else + os << (runparams.free_spacing ? " " : "\\qquad{}"); break; case InsetSpaceParams::ENSPACE: - os << (runparams.free_spacing ? " " : "\\enspace{}"); + if (runparams.find_effective()) + os.put(0x2002); + else + os << (runparams.free_spacing ? " " : "\\enspace{}"); break; case InsetSpaceParams::ENSKIP: - os << (runparams.free_spacing ? " " : "\\enskip{}"); + if (runparams.find_effective()) + os.put(0x2002); + else + os << (runparams.free_spacing ? " " : "\\enskip{}"); break; case InsetSpaceParams::NEGTHIN: - os << (runparams.free_spacing ? " " : "\\negthinspace{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negthinspace{}"); + break; + case InsetSpaceParams::NEGMEDIUM: + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negmedspace{}"); + break; + case InsetSpaceParams::NEGTHICK: + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negthickspace{}"); break; case InsetSpaceParams::HFILL: - os << (runparams.free_spacing ? " " : "\\hfill{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hfill{}"); break; case InsetSpaceParams::HFILL_PROTECTED: - os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hspace*{\\fill}"); break; case InsetSpaceParams::DOTFILL: - os << (runparams.free_spacing ? " " : "\\dotfill{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\dotfill{}"); break; case InsetSpaceParams::HRULEFILL: - os << (runparams.free_spacing ? " " : "\\hrulefill{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hrulefill{}"); break; case InsetSpaceParams::LEFTARROWFILL: - os << (runparams.free_spacing ? " " : "\\leftarrowfill{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\leftarrowfill{}"); break; case InsetSpaceParams::RIGHTARROWFILL: - os << (runparams.free_spacing ? " " : "\\rightarrowfill{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\rightarrowfill{}"); break; case InsetSpaceParams::UPBRACEFILL: - os << (runparams.free_spacing ? " " : "\\upbracefill{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\upbracefill{}"); break; case InsetSpaceParams::DOWNBRACEFILL: - os << (runparams.free_spacing ? " " : "\\downbracefill{}"); + os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\downbracefill{}"); break; case InsetSpaceParams::CUSTOM: - if (runparams.free_spacing) + if (runparams.find_effective()) + os.put(0x00a0); + else if (runparams.free_spacing) os << " "; else os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}"; break; case InsetSpaceParams::CUSTOM_PROTECTED: - if (runparams.free_spacing) + if (runparams.find_effective()) + os.put(0x00a0); + else if (runparams.free_spacing) os << " "; else os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}"; break; } - return 0; } -int InsetSpace::plaintext(odocstream & os, OutputParams const &) const +int InsetSpace::plaintext(odocstringstream & os, + OutputParams const &, size_t) const { switch (params_.kind) { case InsetSpaceParams::HFILL: @@ -555,6 +728,45 @@ int InsetSpace::plaintext(odocstream & os, OutputParams const &) const case InsetSpaceParams::DOWNBRACEFILL: os << "/-^-\\"; return 5; + case InsetSpaceParams::VISIBLE: + os.put(0x2423); + return 1; + case InsetSpaceParams::ENSKIP: + os.put(0x2002); + return 1; + case InsetSpaceParams::ENSPACE: + os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable + os.put(0x2002); + os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable + return 3; + case InsetSpaceParams::QUAD: + os.put(0x2003); + return 1; + case InsetSpaceParams::QQUAD: + os.put(0x2003); + os.put(0x2003); + return 2; + case InsetSpaceParams::THIN: + os.put(0x202f); + return 1; + case InsetSpaceParams::MEDIUM: + os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable + os.put(0x2005); + os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable + return 1; + case InsetSpaceParams::THICK: + os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable + os.put(0x2004); + os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable + return 1; + case InsetSpaceParams::PROTECTED: + case InsetSpaceParams::CUSTOM_PROTECTED: + os.put(0x00a0); + return 1; + case InsetSpaceParams::NEGTHIN: + case InsetSpaceParams::NEGMEDIUM: + case InsetSpaceParams::NEGTHICK: + return 0; default: os << ' '; return 1; @@ -562,50 +774,159 @@ int InsetSpace::plaintext(odocstream & os, OutputParams const &) const } -int InsetSpace::docbook(odocstream & os, OutputParams const &) const +void InsetSpace::docbook(XMLStream & xs, OutputParams const &) const { switch (params_.kind) { case InsetSpaceParams::NORMAL: + xs << XMLStream::ESCAPE_NONE << " "; + break; case InsetSpaceParams::QUAD: + xs << XMLStream::ESCAPE_NONE << " "; // HTML:   + break; case InsetSpaceParams::QQUAD: + xs << XMLStream::ESCAPE_NONE << "  "; // HTML:    + break; case InsetSpaceParams::ENSKIP: - os << " "; + xs << XMLStream::ESCAPE_NONE << " "; // HTML:   break; case InsetSpaceParams::PROTECTED: + xs << XMLStream::ESCAPE_NONE << " "; // HTML:   + break; + case InsetSpaceParams::VISIBLE: + xs << XMLStream::ESCAPE_NONE << "␣"; + break; + case InsetSpaceParams::ENSPACE: // HTML: ⁠ ⁠ (word joiners) + xs << XMLStream::ESCAPE_NONE << "⁠ ⁠"; + break; + case InsetSpaceParams::THIN: + xs << XMLStream::ESCAPE_NONE << " "; // HTML: &thinspace; + break; + case InsetSpaceParams::MEDIUM: + xs << XMLStream::ESCAPE_NONE << " "; // HTML:   + break; + case InsetSpaceParams::THICK: + xs << XMLStream::ESCAPE_NONE << " "; // HTML:   + break; + case InsetSpaceParams::NEGTHIN: + case InsetSpaceParams::NEGMEDIUM: + case InsetSpaceParams::NEGTHICK: + xs << XMLStream::ESCAPE_NONE << " "; // HTML:   + break; + case InsetSpaceParams::HFILL: + case InsetSpaceParams::HFILL_PROTECTED: + case InsetSpaceParams::DOTFILL: + case InsetSpaceParams::HRULEFILL: + case InsetSpaceParams::LEFTARROWFILL: + case InsetSpaceParams::RIGHTARROWFILL: + case InsetSpaceParams::UPBRACEFILL: + case InsetSpaceParams::DOWNBRACEFILL: + case InsetSpaceParams::CUSTOM: + case InsetSpaceParams::CUSTOM_PROTECTED: + xs << '\n'; + break; + } +} + + +docstring InsetSpace::xhtml(XMLStream & xs, OutputParams const &) const +{ + string output; + switch (params_.kind) { + case InsetSpaceParams::NORMAL: + output = " "; + break; + case InsetSpaceParams::ENSKIP: + output =" "; + break; case InsetSpaceParams::ENSPACE: + output ="⁠ ⁠"; + break; + case InsetSpaceParams::QQUAD: + output ="  "; + break; + case InsetSpaceParams::THICK: + output =" "; + break; + case InsetSpaceParams::QUAD: + output =" "; + break; + case InsetSpaceParams::MEDIUM: + output =" "; + break; case InsetSpaceParams::THIN: + output =" "; + break; + case InsetSpaceParams::PROTECTED: case InsetSpaceParams::NEGTHIN: - os << " "; + case InsetSpaceParams::NEGMEDIUM: + case InsetSpaceParams::NEGTHICK: + output =" "; + break; + // no XHTML entity, only unicode code for space character exists + case InsetSpaceParams::VISIBLE: + output ="␣"; break; case InsetSpaceParams::HFILL: case InsetSpaceParams::HFILL_PROTECTED: - os << '\n'; case InsetSpaceParams::DOTFILL: - // FIXME - os << '\n'; case InsetSpaceParams::HRULEFILL: - // FIXME - os << '\n'; case InsetSpaceParams::LEFTARROWFILL: case InsetSpaceParams::RIGHTARROWFILL: case InsetSpaceParams::UPBRACEFILL: case InsetSpaceParams::DOWNBRACEFILL: + // FIXME XHTML + // Can we do anything with those in HTML? + break; case InsetSpaceParams::CUSTOM: + // FIXME XHTML + // Probably we could do some sort of blank span? + break; case InsetSpaceParams::CUSTOM_PROTECTED: - // FIXME - os << '\n'; + // FIXME XHTML + // Probably we could do some sort of blank span? + output =" "; + break; } - return 0; + // don't escape the entities! + xs << XMLStream::ESCAPE_NONE << from_ascii(output); + return docstring(); +} + + +void InsetSpace::validate(LaTeXFeatures & features) const +{ + if (features.isAvailable("LaTeX-2020/10/01")) + // As of this version, the LaTeX kernel + // includes all spaces. + return; + + // In earlier versions, we require amsmath + // for some text and math spaces + if ((params_.kind == InsetSpaceParams::NEGMEDIUM + || params_.kind == InsetSpaceParams::NEGTHICK) + || (!params_.math + && (params_.kind == InsetSpaceParams::MEDIUM + || params_.kind == InsetSpaceParams::THICK))) + features.require("amsmath"); +} + + +void InsetSpace::toString(odocstream & os) const +{ + odocstringstream ods; + plaintext(ods, OutputParams(0)); + os << ods.str(); } -void InsetSpace::textString(odocstream & os) const +void InsetSpace::forOutliner(docstring & os, size_t const, bool const) const { - plaintext(os, OutputParams(0)); + // There's no need to be cute here. + os += " "; } -bool InsetSpace::isStretchableSpace() const +bool InsetSpace::isHfill() const { return params_.kind == InsetSpaceParams::HFILL || params_.kind == InsetSpaceParams::HFILL_PROTECTED @@ -618,9 +939,9 @@ bool InsetSpace::isStretchableSpace() const } -docstring InsetSpace::contextMenu(BufferView const &, int, int) const +string InsetSpace::contextMenuName() const { - return from_ascii("context-space"); + return "context-space"; } @@ -634,7 +955,15 @@ void InsetSpace::string2params(string const & in, InsetSpaceParams & params) Lexer lex; lex.setStream(data); lex.setContext("InsetSpace::string2params"); - lex >> "space"; + lex.next(); + string const name = lex.getString(); + if (name == "mathspace") + params.math = true; + else { + params.math = false; + // we can try to read this even if the name is wrong + LATTEST(name == "space"); + } // There are cases, such as when we are called via getStatus() from // Dialog::canApply(), where we are just called with "space" rather @@ -647,6 +976,8 @@ void InsetSpace::string2params(string const & in, InsetSpaceParams & params) string InsetSpace::params2string(InsetSpaceParams const & params) { ostringstream data; + if (params.math) + data << "math"; data << "space" << ' '; params.write(data); return data.str();