#include "InsetSpace.h"
-#include "debug.h"
-#include "Color.h"
+#include "Cursor.h"
+#include "Dimension.h"
+#include "FuncRequest.h"
+#include "Length.h"
#include "Lexer.h"
#include "MetricsInfo.h"
#include "OutputParams.h"
#include "frontends/FontMetrics.h"
#include "frontends/Painter.h"
+#include "support/debug.h"
+#include "support/docstream.h"
+#include "support/gettext.h"
+#include "support/lstrings.h"
-namespace lyx {
+using namespace std;
-using std::string;
-using std::max;
-using std::auto_ptr;
-using std::ostream;
+namespace lyx {
InsetSpace::InsetSpace()
{}
-InsetSpace::InsetSpace(Kind k)
- : kind_(k)
-{}
+InsetSpace::InsetSpace(InsetSpaceParams par)
+{
+ params_.kind = par.kind;
+ params_.length = par.length;
+}
+
+
+InsetSpaceParams::Kind InsetSpace::kind() const
+{
+ return params_.kind;
+}
+
+
+Length InsetSpace::length() const
+{
+ return params_.length;
+}
+
+
+InsetSpace::~InsetSpace()
+{
+ InsetSpaceMailer(*this).hideDialog();
+}
+
+
+docstring InsetSpace::toolTip(BufferView const &, int, int) const
+{
+ docstring message;
+ switch (params_.kind) {
+ case InsetSpaceParams::NORMAL:
+ message = _("Interword Space");
+ break;
+ case InsetSpaceParams::PROTECTED:
+ message = _("Protected Space");
+ break;
+ case InsetSpaceParams::THIN:
+ message = _("Thin Space");
+ break;
+ case InsetSpaceParams::QUAD:
+ message = _("Quad Space");
+ break;
+ case InsetSpaceParams::QQUAD:
+ message = _("QQuad Space");
+ break;
+ case InsetSpaceParams::ENSPACE:
+ message = _("Enspace");
+ break;
+ case InsetSpaceParams::ENSKIP:
+ message = _("Enskip");
+ break;
+ case InsetSpaceParams::NEGTHIN:
+ message = _("Negative Thin Space");
+ break;
+ case InsetSpaceParams::HFILL:
+ message = _("Horizontal Fill");
+ break;
+ case InsetSpaceParams::HFILL_PROTECTED:
+ message = _("Protected Horizontal Fill");
+ break;
+ case InsetSpaceParams::DOTFILL:
+ message = _("Horizontal Fill (Dots)");
+ break;
+ case InsetSpaceParams::HRULEFILL:
+ message = _("Horizontal Fill (Rule)");
+ break;
+ case InsetSpaceParams::CUSTOM:
+ message = support::bformat(_("Horizontal Space (%1$s)"),
+ params_.length.asDocstring());
+ break;
+ case InsetSpaceParams::CUSTOM_PROTECTED:
+ message = support::bformat(_("Protected Horizontal Space (%1$s)"),
+ params_.length.asDocstring());
+ break;
+ }
+ return message;
+}
-InsetSpace::Kind InsetSpace::kind() const
+void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
{
- return kind_;
+ switch (cmd.action) {
+
+ case LFUN_INSET_MODIFY: {
+ InsetSpaceParams params;
+ InsetSpaceMailer::string2params(to_utf8(cmd.argument()), params);
+ params_.kind = params.kind;
+ params_.length = params.length;
+ break;
+ }
+
+ case LFUN_MOUSE_RELEASE:
+ if (!cur.selection())
+ InsetSpaceMailer(*this).showDialog(&cur.bv());
+ break;
+
+ default:
+ Inset::doDispatch(cur, cmd);
+ break;
+ }
}
-bool InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
+void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
{
- frontend::FontMetrics const & fm =
- theFontMetrics(mi.base.font);
+ if (isStretchableSpace()) {
+ // The metrics for this kinds are calculated externally in
+ // \c TextMetrics::computeRowMetrics. Those are dummy value:
+ dim = Dimension(10, 10, 10);
+ return;
+ }
+
+ frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
dim.asc = fm.maxAscent();
dim.des = fm.maxDescent();
- switch (kind_) {
- case THIN:
- case NEGTHIN:
- dim.wid = fm.width(char_type('x')) / 3;
+ switch (params_.kind) {
+ case InsetSpaceParams::THIN:
+ case InsetSpaceParams::NEGTHIN:
+ dim.wid = fm.width(char_type('M')) / 6;
+ break;
+ case InsetSpaceParams::PROTECTED:
+ case InsetSpaceParams::NORMAL:
+ dim.wid = fm.width(char_type(' '));
+ break;
+ case InsetSpaceParams::QUAD:
+ dim.wid = fm.width(char_type('M'));
break;
- case PROTECTED:
- case NORMAL:
- dim.wid = fm.width(char_type('x'));
+ case InsetSpaceParams::QQUAD:
+ dim.wid = 2 * fm.width(char_type('M'));
break;
- case QUAD:
- dim.wid = 20;
+ case InsetSpaceParams::ENSPACE:
+ case InsetSpaceParams::ENSKIP:
+ dim.wid = int(0.5 * fm.width(char_type('M')));
break;
- case QQUAD:
- dim.wid = 40;
+ case InsetSpaceParams::CUSTOM:
+ case InsetSpaceParams::CUSTOM_PROTECTED:
+ dim.wid = params_.length.inBP();
break;
- case ENSPACE:
- case ENSKIP:
- dim.wid = 10;
+ case InsetSpaceParams::HFILL:
+ case InsetSpaceParams::HFILL_PROTECTED:
+ case InsetSpaceParams::DOTFILL:
+ case InsetSpaceParams::HRULEFILL:
+ // shut up compiler
break;
}
- bool const changed = dim_ != dim;
- dim_ = dim;
- return changed;
+ // Cache the inset dimension.
+ setDimCache(mi, dim);
}
void InsetSpace::draw(PainterInfo & pi, int x, int y) const
{
- int const w = width();
- int const h = theFontMetrics(pi.base.font)
- .ascent('x');
+ Dimension const dim = dimension(*pi.base.bv);
+
+ if (isStretchableSpace()) {
+ int const asc = theFontMetrics(pi.base.font).ascent('M');
+ int const desc = theFontMetrics(pi.base.font).descent('M');
+ int const x0 = x + 1;
+ int const x1 = x + dim.wid - 2;
+ int const y0 = y + desc;
+ int const y1 = y - asc;
+ int const y2 = y - asc / 2;
+
+ 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,
+ 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,
+ frontend::Painter::line_onoffdash);
+ pi.pain.line(x1, y1, x1, y0, Color_latex);
+ } else if (params_.kind == InsetSpaceParams::DOTFILL) {
+ pi.pain.line(x0, y1, x0, y0, Color_special);
+ pi.pain.line(x0, y, x1, y, Color_special,
+ frontend::Painter::line_onoffdash);
+ pi.pain.line(x1, y1, x1, y0, Color_special);
+ } if (params_.kind == InsetSpaceParams::HRULEFILL) {
+ pi.pain.line(x0, y1, x0, y0, Color_special);
+ pi.pain.line(x0, y, x1, y, Color_special);
+ pi.pain.line(x1, y1, x1, y0, Color_special);
+ }
+ return;
+ }
+
+ int const w = dim.wid;
+ int const h = theFontMetrics(pi.base.font).ascent('x');
int xp[4], yp[4];
xp[0] = x;
yp[0] = y - max(h / 4, 1);
- if (kind_ == NORMAL) {
+ if (params_.kind == InsetSpaceParams::NORMAL ||
+ params_.kind == InsetSpaceParams::PROTECTED) {
xp[1] = x; yp[1] = y;
xp[2] = x + w; yp[2] = y;
} else {
xp[3] = x + w;
yp[3] = y - max(h / 4, 1);
- if (kind_ == PROTECTED || kind_ == ENSPACE || kind_ == NEGTHIN)
- pi.pain.lines(xp, yp, 4, Color::latex);
+ if (params_.kind == InsetSpaceParams::PROTECTED ||
+ params_.kind == InsetSpaceParams::ENSPACE ||
+ params_.kind == InsetSpaceParams::NEGTHIN ||
+ params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
+ pi.pain.lines(xp, yp, 4, Color_latex);
else
- pi.pain.lines(xp, yp, 4, Color::special);
+ pi.pain.lines(xp, yp, 4, Color_special);
}
-void InsetSpace::write(Buffer const &, ostream & os) const
+void InsetSpaceParams::write(ostream & os) const
{
string command;
- switch (kind_) {
- case NORMAL:
- command = "\\space{}";
+ switch (kind) {
+ case InsetSpaceParams::NORMAL:
+ os << "\\space{}";
+ break;
+ case InsetSpaceParams::PROTECTED:
+ os << "~";
+ break;
+ case InsetSpaceParams::THIN:
+ os << "\\thinspace{}";
+ break;
+ case InsetSpaceParams::QUAD:
+ os << "\\quad{}";
break;
- case PROTECTED:
- command = "~";
+ case InsetSpaceParams::QQUAD:
+ os << "\\qquad{}";
break;
- case THIN:
- command = "\\thinspace{}";
+ case InsetSpaceParams::ENSPACE:
+ os << "\\enspace{}";
break;
- case QUAD:
- command = "\\quad{}";
+ case InsetSpaceParams::ENSKIP:
+ os << "\\enskip{}";
break;
- case QQUAD:
- command = "\\qquad{}";
+ case InsetSpaceParams::NEGTHIN:
+ os << "\\negthinspace{}";
break;
- case ENSPACE:
- command = "\\enspace{}";
+ case InsetSpaceParams::HFILL:
+ os << "\\hfill{}";
break;
- case ENSKIP:
- command = "\\enskip{}";
+ case InsetSpaceParams::HFILL_PROTECTED:
+ os << "\\hspace*{\\fill}";
break;
- case NEGTHIN:
- command = "\\negthinspace{}";
+ case InsetSpaceParams::DOTFILL:
+ os << "\\dotfill{}";
+ break;
+ case InsetSpaceParams::HRULEFILL:
+ os << "\\hrulefill{}";
+ break;
+ case InsetSpaceParams::CUSTOM:
+ os << "\\hspace{}";
+ break;
+ case InsetSpaceParams::CUSTOM_PROTECTED:
+ os << "\\hspace*{}";
break;
}
- os << "\\InsetSpace " << command << "\n";
+
+ if (!length.empty())
+ os << "\n\\length " << length.asString();
}
-void InsetSpace::read(Buffer const &, Lexer & lex)
+void InsetSpaceParams::read(Lexer & lex)
{
lex.next();
string const command = lex.getString();
if (command == "\\space{}")
- kind_ = NORMAL;
+ kind = InsetSpaceParams::NORMAL;
else if (command == "~")
- kind_ = PROTECTED;
+ kind = InsetSpaceParams::PROTECTED;
else if (command == "\\thinspace{}")
- kind_ = THIN;
+ kind = InsetSpaceParams::THIN;
else if (command == "\\quad{}")
- kind_ = QUAD;
+ kind = InsetSpaceParams::QUAD;
else if (command == "\\qquad{}")
- kind_ = QQUAD;
+ kind = InsetSpaceParams::QQUAD;
else if (command == "\\enspace{}")
- kind_ = ENSPACE;
+ kind = InsetSpaceParams::ENSPACE;
else if (command == "\\enskip{}")
- kind_ = ENSKIP;
+ kind = InsetSpaceParams::ENSKIP;
else if (command == "\\negthinspace{}")
- kind_ = NEGTHIN;
+ kind = InsetSpaceParams::NEGTHIN;
+ else if (command == "\\hfill{}")
+ kind = InsetSpaceParams::HFILL;
+ else if (command == "\\hspace*{\\fill}")
+ kind = InsetSpaceParams::HFILL_PROTECTED;
+ else if (command == "\\dotfill{}")
+ kind = InsetSpaceParams::DOTFILL;
+ else if (command == "\\hrulefill{}")
+ kind = InsetSpaceParams::HRULEFILL;
+ else if (command == "\\hspace{}")
+ kind = InsetSpaceParams::CUSTOM;
+ else if (command == "\\hspace*{}")
+ kind = InsetSpaceParams::CUSTOM_PROTECTED;
else
lex.printError("InsetSpace: Unknown kind: `$$Token'");
+
+
+ string token;
+ lex >> token;
+ if (token == "\\length") {
+ lex.next();
+ string const len = lex.getString();
+ length = Length(len);
+ lex.next();
+ token = lex.getString();
+ }
+ if (!lex)
+ return;
+ if (token != "\\end_inset")
+ lex.printError("Missing \\end_inset at this point. "
+ "Read: `$$Token'");
+}
+
+
+void InsetSpace::write(ostream & os) const
+{
+ os << "Space ";
+ params_.write(os);
}
-int InsetSpace::latex(Buffer const &, odocstream & os,
- OutputParams const & runparams) const
+void InsetSpace::read(Lexer & lex)
{
- switch (kind_) {
- case NORMAL:
+ params_.read(lex);
+}
+
+
+int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
+{
+ switch (params_.kind) {
+ case InsetSpaceParams::NORMAL:
os << (runparams.free_spacing ? " " : "\\ ");
break;
- case PROTECTED:
+ case InsetSpaceParams::PROTECTED:
os << (runparams.free_spacing ? ' ' : '~');
break;
- case THIN:
+ case InsetSpaceParams::THIN:
os << (runparams.free_spacing ? " " : "\\,");
break;
- case QUAD:
+ case InsetSpaceParams::QUAD:
os << (runparams.free_spacing ? " " : "\\quad{}");
break;
- case QQUAD:
+ case InsetSpaceParams::QQUAD:
os << (runparams.free_spacing ? " " : "\\qquad{}");
break;
- case ENSPACE:
+ case InsetSpaceParams::ENSPACE:
os << (runparams.free_spacing ? " " : "\\enspace{}");
break;
- case ENSKIP:
+ case InsetSpaceParams::ENSKIP:
os << (runparams.free_spacing ? " " : "\\enskip{}");
break;
- case NEGTHIN:
+ case InsetSpaceParams::NEGTHIN:
os << (runparams.free_spacing ? " " : "\\negthinspace{}");
break;
+ case InsetSpaceParams::HFILL:
+ os << (runparams.free_spacing ? " " : "\\hfill{}");
+ break;
+ case InsetSpaceParams::HFILL_PROTECTED:
+ os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}");
+ break;
+ case InsetSpaceParams::DOTFILL:
+ os << (runparams.free_spacing ? " " : "\\dotfill{}");
+ break;
+ case InsetSpaceParams::HRULEFILL:
+ os << (runparams.free_spacing ? " " : "\\hrulefill{}");
+ break;
+ case InsetSpaceParams::CUSTOM:
+ if (runparams.free_spacing)
+ os << " ";
+ else
+ os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
+ break;
+ case InsetSpaceParams::CUSTOM_PROTECTED:
+ if (runparams.free_spacing)
+ os << " ";
+ else
+ os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
+ break;
}
return 0;
}
-int InsetSpace::plaintext(Buffer const &, odocstream & os,
- OutputParams const &) const
+int InsetSpace::plaintext(odocstream & os, OutputParams const &) const
{
- os << ' ';
- return 1;
+ switch (params_.kind) {
+ case InsetSpaceParams::HFILL:
+ case InsetSpaceParams::HFILL_PROTECTED:
+ os << " ";
+ return 5;
+ case InsetSpaceParams::DOTFILL:
+ os << ".....";
+ return 5;
+ case InsetSpaceParams::HRULEFILL:
+ os << "_____";
+ return 5;
+ default:
+ os << ' ';
+ return 1;
+ }
}
-int InsetSpace::docbook(Buffer const &, odocstream & os,
- OutputParams const &) const
+int InsetSpace::docbook(odocstream & os, OutputParams const &) const
{
- switch (kind_) {
- case NORMAL:
- case QUAD:
- case QQUAD:
- case ENSKIP:
+ switch (params_.kind) {
+ case InsetSpaceParams::NORMAL:
+ case InsetSpaceParams::QUAD:
+ case InsetSpaceParams::QQUAD:
+ case InsetSpaceParams::ENSKIP:
os << " ";
break;
- case PROTECTED:
- case ENSPACE:
- case THIN:
- case NEGTHIN:
+ case InsetSpaceParams::PROTECTED:
+ case InsetSpaceParams::ENSPACE:
+ case InsetSpaceParams::THIN:
+ case InsetSpaceParams::NEGTHIN:
os << " ";
break;
+ case InsetSpaceParams::HFILL:
+ case InsetSpaceParams::HFILL_PROTECTED:
+ os << '\n';
+ case InsetSpaceParams::DOTFILL:
+ // FIXME
+ os << '\n';
+ case InsetSpaceParams::HRULEFILL:
+ // FIXME
+ os << '\n';
+ case InsetSpaceParams::CUSTOM:
+ case InsetSpaceParams::CUSTOM_PROTECTED:
+ // FIXME
+ os << '\n';
}
return 0;
}
-int InsetSpace::textString(Buffer const & buf, odocstream & os,
- OutputParams const & op) const
+void InsetSpace::textString(odocstream & os) const
{
- return plaintext(buf, os, op);
+ plaintext(os, OutputParams(0));
}
-auto_ptr<InsetBase> InsetSpace::doClone() const
+bool InsetSpace::isStretchableSpace() const
{
- return auto_ptr<InsetBase>(new InsetSpace(kind_));
+ return (params_.kind == InsetSpaceParams::HFILL ||
+ params_.kind == InsetSpaceParams::HFILL_PROTECTED ||
+ params_.kind == InsetSpaceParams::DOTFILL ||
+ params_.kind == InsetSpaceParams::HRULEFILL);
}
-bool InsetSpace::isChar() const
+string const InsetSpaceMailer::name_ = "space";
+
+
+InsetSpaceMailer::InsetSpaceMailer(InsetSpace & inset)
+ : inset_(inset)
+{}
+
+
+string const InsetSpaceMailer::inset2string(Buffer const &) const
{
- return true;
+ return params2string(inset_.params());
}
-bool InsetSpace::isLetter() const
+
+void InsetSpaceMailer::string2params(string const & in, InsetSpaceParams & params)
{
- return false;
+ params = InsetSpaceParams();
+ if (in.empty())
+ return;
+
+ istringstream data(in);
+ Lexer lex(0,0);
+ lex.setStream(data);
+
+ string name;
+ lex >> name;
+ if (!lex || name != name_)
+ return print_mailer_error("InsetSpaceMailer", in, 1, name_);
+
+ params.read(lex);
}
-bool InsetSpace::isSpace() const
+
+string const InsetSpaceMailer::params2string(InsetSpaceParams const & params)
{
- return true;
+ ostringstream data;
+ data << name_ << ' ';
+ params.write(data);
+ return data.str();
}