lyx_mirror/src/insets/InsetSpace.cpp
Jürgen Spitzmüller 48778460a0 * src/insets/InsetSpace.{cpp, h}:
- this inset is now editable. Mark as such and add an editable method (allows for opening the inset dialog with
	  "next-inset-toggle".
	- implement context menu (no actual menu yet).

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@23907 a592a061-630c-0410-9148-cb99ea01b6c8
2008-03-23 15:19:01 +00:00

555 lines
13 KiB
C++

/**
* \file InsetSpace.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Asger Alstrup Nielsen
* \author Jean-Marc Lasgouttes
* \author Lars Gullik Bjønnes
* \author Jürgen Spitzmüller
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "InsetSpace.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"
using namespace std;
namespace lyx {
InsetSpace::InsetSpace()
{}
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;
}
void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
{
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;
}
}
void InsetSpace::edit(Cursor & cur, bool, EntryDirection)
{
InsetSpaceMailer(*this).showDialog(&cur.bv());
}
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);
return;
}
frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
dim.asc = fm.maxAscent();
dim.des = fm.maxDescent();
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 InsetSpaceParams::QQUAD:
dim.wid = 2 * fm.width(char_type('M'));
break;
case InsetSpaceParams::ENSPACE:
case InsetSpaceParams::ENSKIP:
dim.wid = int(0.5 * fm.width(char_type('M')));
break;
case InsetSpaceParams::CUSTOM:
case InsetSpaceParams::CUSTOM_PROTECTED:
dim.wid = params_.length.inBP();
break;
case InsetSpaceParams::HFILL:
case InsetSpaceParams::HFILL_PROTECTED:
case InsetSpaceParams::DOTFILL:
case InsetSpaceParams::HRULEFILL:
// shut up compiler
break;
}
// Cache the inset dimension.
setDimCache(mi, dim);
}
void InsetSpace::draw(PainterInfo & pi, int x, int y) const
{
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 (params_.kind == InsetSpaceParams::NORMAL ||
params_.kind == InsetSpaceParams::PROTECTED) {
xp[1] = x; yp[1] = y;
xp[2] = x + w; 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[3] = x + w;
yp[3] = y - max(h / 4, 1);
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);
}
void InsetSpaceParams::write(ostream & os) const
{
string command;
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 InsetSpaceParams::QQUAD:
os << "\\qquad{}";
break;
case InsetSpaceParams::ENSPACE:
os << "\\enspace{}";
break;
case InsetSpaceParams::ENSKIP:
os << "\\enskip{}";
break;
case InsetSpaceParams::NEGTHIN:
os << "\\negthinspace{}";
break;
case InsetSpaceParams::HFILL:
os << "\\hfill{}";
break;
case InsetSpaceParams::HFILL_PROTECTED:
os << "\\hspace*{\\fill}";
break;
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;
}
if (!length.empty())
os << "\n\\length " << length.asString();
}
void InsetSpaceParams::read(Lexer & lex)
{
lex.next();
string const command = lex.getString();
if (command == "\\space{}")
kind = InsetSpaceParams::NORMAL;
else if (command == "~")
kind = InsetSpaceParams::PROTECTED;
else if (command == "\\thinspace{}")
kind = InsetSpaceParams::THIN;
else if (command == "\\quad{}")
kind = InsetSpaceParams::QUAD;
else if (command == "\\qquad{}")
kind = InsetSpaceParams::QQUAD;
else if (command == "\\enspace{}")
kind = InsetSpaceParams::ENSPACE;
else if (command == "\\enskip{}")
kind = InsetSpaceParams::ENSKIP;
else if (command == "\\negthinspace{}")
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);
}
void InsetSpace::read(Lexer & lex)
{
params_.read(lex);
}
int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
{
switch (params_.kind) {
case InsetSpaceParams::NORMAL:
os << (runparams.free_spacing ? " " : "\\ ");
break;
case InsetSpaceParams::PROTECTED:
os << (runparams.free_spacing ? ' ' : '~');
break;
case InsetSpaceParams::THIN:
os << (runparams.free_spacing ? " " : "\\,");
break;
case InsetSpaceParams::QUAD:
os << (runparams.free_spacing ? " " : "\\quad{}");
break;
case InsetSpaceParams::QQUAD:
os << (runparams.free_spacing ? " " : "\\qquad{}");
break;
case InsetSpaceParams::ENSPACE:
os << (runparams.free_spacing ? " " : "\\enspace{}");
break;
case InsetSpaceParams::ENSKIP:
os << (runparams.free_spacing ? " " : "\\enskip{}");
break;
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(odocstream & os, OutputParams const &) const
{
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(odocstream & os, OutputParams const &) const
{
switch (params_.kind) {
case InsetSpaceParams::NORMAL:
case InsetSpaceParams::QUAD:
case InsetSpaceParams::QQUAD:
case InsetSpaceParams::ENSKIP:
os << " ";
break;
case InsetSpaceParams::PROTECTED:
case InsetSpaceParams::ENSPACE:
case InsetSpaceParams::THIN:
case InsetSpaceParams::NEGTHIN:
os << "&nbsp;";
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;
}
void InsetSpace::textString(odocstream & os) const
{
plaintext(os, OutputParams(0));
}
bool InsetSpace::isStretchableSpace() const
{
return (params_.kind == InsetSpaceParams::HFILL ||
params_.kind == InsetSpaceParams::HFILL_PROTECTED ||
params_.kind == InsetSpaceParams::DOTFILL ||
params_.kind == InsetSpaceParams::HRULEFILL);
}
docstring InsetSpace::contextMenu(BufferView const &, int, int) const
{
return from_ascii("context-space");
}
string const InsetSpaceMailer::name_ = "space";
InsetSpaceMailer::InsetSpaceMailer(InsetSpace & inset)
: inset_(inset)
{}
string const InsetSpaceMailer::inset2string(Buffer const &) const
{
return params2string(inset_.params());
}
void InsetSpaceMailer::string2params(string const & in, InsetSpaceParams & params)
{
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);
}
string const InsetSpaceMailer::params2string(InsetSpaceParams const & params)
{
ostringstream data;
data << name_ << ' ';
params.write(data);
return data.str();
}
} // namespace lyx