#include "MetricsInfo.h"
#include "OutputParams.h"
#include "output_xhtml.h"
+#include "texstream.h"
#include "support/debug.h"
#include "support/docstream.h"
case InsetSpaceParams::PROTECTED:
message = _("Protected Space");
break;
+ case InsetSpaceParams::VISIBLE:
+ message = _("Visible Space");
+ break;
case InsetSpaceParams::THIN:
message = _("Thin Space");
break;
{
switch (cmd.action()) {
- case LFUN_INSET_MODIFY:
+ case LFUN_INSET_MODIFY: {
cur.recordUndo();
- string2params(to_utf8(cmd.argument()), params_);
+ 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_INSET_DIALOG_UPDATE:
cur.bv().updateDialog("space", params2string(params()));
InsetSpaceParams params;
string2params(to_utf8(cmd.argument()), params);
status.setOnOff(params_.kind == params.kind);
- }
- // fall through
+ status.setEnabled(true);
+ } else
+ status.setEnabled(false);
+ return true;
+
case LFUN_INSET_DIALOG_UPDATE:
status.setEnabled(true);
return true;
}
+Inset::RowFlags InsetSpace::rowFlags() const
+{
+ 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 = fm.width(char_type('M')) / 4;
+ dim.wid = em / 4;
break;
case InsetSpaceParams::THICK:
case InsetSpaceParams::NEGTHICK:
- dim.wid = fm.width(char_type('M')) / 2;
+ 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 const w =
- params_.length.len().inPixels(mi.base.textwidth,
- fm.width(char_type('M')));
+ 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;
// shut up compiler
break;
}
- // Cache the inset dimension.
- setDimCache(mi, dim);
}
{
Dimension const dim = dimension(*pi.base.bv);
- if (isStretchableSpace() || params_.length.len().value() < 0) {
+ 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:
}
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;
+ xp[0] = x + 1;
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 + 1; yp[1] = y;
+ xp[2] = x + w - 2; 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 + 1; yp[1] = y + max(h / 4, 1);
+ xp[2] = x + w - 2; yp[2] = y + max(h / 4, 1);
}
- xp[3] = x + w;
+ xp[3] = x + w - 2;
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{}";
case InsetSpaceParams::PROTECTED:
os << "~";
break;
+ case InsetSpaceParams::VISIBLE:
+ os << "\\textvisiblespace{}";
+ break;
case InsetSpaceParams::THIN:
os << "\\thinspace{}";
break;
os << "\\hspace*{}";
break;
}
-
+
if (!length.len().empty())
os << "\n\\length " << length.asString();
}
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 (math && command == "\\medspace{}")
+ else if (command == "\\medspace{}")
kind = InsetSpaceParams::MEDIUM;
- else if (math && command == "\\thickspace{}")
+ else if (command == "\\thickspace{}")
kind = InsetSpaceParams::THICK;
else if (command == "\\quad{}")
kind = InsetSpaceParams::QUAD;
kind = InsetSpaceParams::ENSKIP;
else if (command == "\\negthinspace{}")
kind = InsetSpaceParams::NEGTHIN;
- else if (math && command == "\\negmedspace{}")
+ else if (command == "\\negmedspace{}")
kind = InsetSpaceParams::NEGMEDIUM;
- else if (math && command == "\\negthickspace{}")
+ else if (command == "\\negthickspace{}")
kind = InsetSpaceParams::NEGTHICK;
else if (command == "\\hfill{}")
kind = InsetSpaceParams::HFILL;
}
-int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
+void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const
{
switch (params_.kind) {
case InsetSpaceParams::NORMAL:
else
os << (runparams.free_spacing ? ' ' : '~');
break;
+ case InsetSpaceParams::VISIBLE:
+ os << (runparams.free_spacing ? " " : "\\textvisiblespace{}");
+ break;
case InsetSpaceParams::THIN:
os << (runparams.free_spacing ? " " : "\\,");
break;
case InsetSpaceParams::MEDIUM:
- os << (runparams.free_spacing ? " " : "\\:");
+ if (params_.math)
+ os << (runparams.free_spacing ? " " : "\\:");
+ else
+ os << (runparams.free_spacing ? " " : "\\medspace{}");
break;
case InsetSpaceParams::THICK:
- os << (runparams.free_spacing ? " " : "\\;");
+ if (params_.math)
+ os << (runparams.free_spacing ? " " : "\\;");
+ else
+ os << (runparams.free_spacing ? " " : "\\thickspace{}");
break;
case InsetSpaceParams::QUAD:
os << (runparams.free_spacing ? " " : "\\quad{}");
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:
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;
{
switch (params_.kind) {
case InsetSpaceParams::NORMAL:
+ os << " ";
+ break;
case InsetSpaceParams::QUAD:
+ os << " ";
+ break;
case InsetSpaceParams::QQUAD:
+ os << "  ";
+ break;
case InsetSpaceParams::ENSKIP:
- os << " ";
+ os << " ";
break;
case InsetSpaceParams::PROTECTED:
+ os << " ";
+ break;
+ case InsetSpaceParams::VISIBLE:
+ os << "␣";
+ break;
case InsetSpaceParams::ENSPACE:
+ os << "⁠ ⁠";
+ break;
case InsetSpaceParams::THIN:
+ os << " ";
+ break;
case InsetSpaceParams::MEDIUM:
+ os << " ";
+ break;
case InsetSpaceParams::THICK:
+ os << " ";
+ break;
case InsetSpaceParams::NEGTHIN:
case InsetSpaceParams::NEGMEDIUM:
case InsetSpaceParams::NEGTHICK:
+ // FIXME
os << " ";
break;
case InsetSpaceParams::HFILL:
case InsetSpaceParams::HFILL_PROTECTED:
os << '\n';
+ break;
case InsetSpaceParams::DOTFILL:
// FIXME
os << '\n';
+ break;
case InsetSpaceParams::HRULEFILL:
// FIXME
os << '\n';
+ break;
case InsetSpaceParams::LEFTARROWFILL:
case InsetSpaceParams::RIGHTARROWFILL:
case InsetSpaceParams::UPBRACEFILL:
case InsetSpaceParams::CUSTOM_PROTECTED:
// FIXME
os << '\n';
+ break;
}
return 0;
}
-docstring InsetSpace::xhtml(XHTMLStream & xs, OutputParams const &) const
+docstring InsetSpace::xhtml(XMLStream & xs, OutputParams const &) const
{
string output;
switch (params_.kind) {
output = " ";
break;
case InsetSpaceParams::ENSKIP:
- case InsetSpaceParams::ENSPACE:
output =" ";
break;
+ case InsetSpaceParams::ENSPACE:
+ output ="⁠ ⁠";
+ break;
case InsetSpaceParams::QQUAD:
- output =" ";
+ 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::MEDIUM:
case InsetSpaceParams::NEGTHIN:
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:
case InsetSpaceParams::DOTFILL:
// 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 XHTML
// Probably we could do some sort of blank span?
+ output =" ";
break;
}
// don't escape the entities!
- xs << XHTMLStream::ESCAPE_NONE << from_ascii(output);
+ xs << XMLStream::ESCAPE_NONE << from_ascii(output);
return docstring();
}
void InsetSpace::validate(LaTeXFeatures & features) const
{
- if (params_.kind == InsetSpaceParams::NEGMEDIUM ||
- params_.kind == InsetSpaceParams::NEGTHICK)
+ if ((params_.kind == InsetSpaceParams::NEGMEDIUM
+ || params_.kind == InsetSpaceParams::NEGTHICK)
+ || (!params_.math
+ && (params_.kind == InsetSpaceParams::MEDIUM
+ || params_.kind == InsetSpaceParams::THICK)))
features.require("amsmath");
}
-void InsetSpace::tocString(odocstream & os) const
+void InsetSpace::toString(odocstream & os) const
+{
+ odocstringstream ods;
+ plaintext(ods, OutputParams(0));
+ os << ods.str();
+}
+
+
+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
}
-docstring InsetSpace::contextMenu(BufferView const &, int, int) const
+string InsetSpace::contextMenuName() const
{
- return from_ascii("context-space");
+ return "context-space";
}
params.math = true;
else {
params.math = false;
- LASSERT(name == "space", /**/);
+ // 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