3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup Nielsen
7 * \author Jean-Marc Lasgouttes
8 * \author Lars Gullik Bjønnes
9 * \author Jürgen Spitzmüller
11 * Full author contact details are available in file CREDITS.
16 #include "InsetSpace.h"
19 #include "Dimension.h"
20 #include "FuncRequest.h"
23 #include "MetricsInfo.h"
24 #include "OutputParams.h"
26 #include "frontends/FontMetrics.h"
27 #include "frontends/Painter.h"
29 #include "support/debug.h"
30 #include "support/docstream.h"
31 #include "support/gettext.h"
32 #include "support/lstrings.h"
39 InsetSpace::InsetSpace()
43 InsetSpace::InsetSpace(InsetSpaceParams par)
45 params_.kind = par.kind;
46 params_.length = par.length;
50 InsetSpaceParams::Kind InsetSpace::kind() const
56 Length InsetSpace::length() const
58 return params_.length;
62 InsetSpace::~InsetSpace()
64 InsetSpaceMailer(*this).hideDialog();
68 docstring InsetSpace::toolTip(BufferView const &, int, int) const
71 switch (params_.kind) {
72 case InsetSpaceParams::NORMAL:
73 message = _("Interword Space");
75 case InsetSpaceParams::PROTECTED:
76 message = _("Protected Space");
78 case InsetSpaceParams::THIN:
79 message = _("Thin Space");
81 case InsetSpaceParams::QUAD:
82 message = _("Quad Space");
84 case InsetSpaceParams::QQUAD:
85 message = _("QQuad Space");
87 case InsetSpaceParams::ENSPACE:
88 message = _("Enspace");
90 case InsetSpaceParams::ENSKIP:
91 message = _("Enskip");
93 case InsetSpaceParams::NEGTHIN:
94 message = _("Negative Thin Space");
96 case InsetSpaceParams::HFILL:
97 message = _("Horizontal Fill");
99 case InsetSpaceParams::HFILL_PROTECTED:
100 message = _("Protected Horizontal Fill");
102 case InsetSpaceParams::DOTFILL:
103 message = _("Horizontal Fill (Dots)");
105 case InsetSpaceParams::HRULEFILL:
106 message = _("Horizontal Fill (Rule)");
108 case InsetSpaceParams::CUSTOM:
109 message = support::bformat(_("Horizontal Space (%1$s)"),
110 params_.length.asDocstring());
112 case InsetSpaceParams::CUSTOM_PROTECTED:
113 message = support::bformat(_("Protected Horizontal Space (%1$s)"),
114 params_.length.asDocstring());
121 void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
123 switch (cmd.action) {
125 case LFUN_INSET_MODIFY: {
126 InsetSpaceParams params;
127 InsetSpaceMailer::string2params(to_utf8(cmd.argument()), params);
128 params_.kind = params.kind;
129 params_.length = params.length;
133 case LFUN_MOUSE_RELEASE:
134 if (!cur.selection())
135 InsetSpaceMailer(*this).showDialog(&cur.bv());
139 Inset::doDispatch(cur, cmd);
145 void InsetSpace::edit(Cursor & cur, bool, EntryDirection)
147 InsetSpaceMailer(*this).showDialog(&cur.bv());
151 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
153 if (isStretchableSpace()) {
154 // The metrics for this kinds are calculated externally in
155 // \c TextMetrics::computeRowMetrics. Those are dummy value:
156 dim = Dimension(10, 10, 10);
160 frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
161 dim.asc = fm.maxAscent();
162 dim.des = fm.maxDescent();
164 switch (params_.kind) {
165 case InsetSpaceParams::THIN:
166 case InsetSpaceParams::NEGTHIN:
167 dim.wid = fm.width(char_type('M')) / 6;
169 case InsetSpaceParams::PROTECTED:
170 case InsetSpaceParams::NORMAL:
171 dim.wid = fm.width(char_type(' '));
173 case InsetSpaceParams::QUAD:
174 dim.wid = fm.width(char_type('M'));
176 case InsetSpaceParams::QQUAD:
177 dim.wid = 2 * fm.width(char_type('M'));
179 case InsetSpaceParams::ENSPACE:
180 case InsetSpaceParams::ENSKIP:
181 dim.wid = int(0.5 * fm.width(char_type('M')));
183 case InsetSpaceParams::CUSTOM:
184 case InsetSpaceParams::CUSTOM_PROTECTED:
185 dim.wid = params_.length.inBP();
187 case InsetSpaceParams::HFILL:
188 case InsetSpaceParams::HFILL_PROTECTED:
189 case InsetSpaceParams::DOTFILL:
190 case InsetSpaceParams::HRULEFILL:
194 // Cache the inset dimension.
195 setDimCache(mi, dim);
199 void InsetSpace::draw(PainterInfo & pi, int x, int y) const
201 Dimension const dim = dimension(*pi.base.bv);
203 if (isStretchableSpace()) {
204 int const asc = theFontMetrics(pi.base.font).ascent('M');
205 int const desc = theFontMetrics(pi.base.font).descent('M');
206 int const x0 = x + 1;
207 int const x1 = x + dim.wid - 2;
208 int const y0 = y + desc;
209 int const y1 = y - asc;
210 int const y2 = y - asc / 2;
212 if (params_.kind == InsetSpaceParams::HFILL) {
213 pi.pain.line(x0, y1, x0, y0, Color_added_space);
214 pi.pain.line(x0, y2 , x1, y2, Color_added_space,
215 frontend::Painter::line_onoffdash);
216 pi.pain.line(x1, y1, x1, y0, Color_added_space);
217 } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
218 pi.pain.line(x0, y1, x0, y0, Color_latex);
219 pi.pain.line(x0, y2 , x1, y2, Color_latex,
220 frontend::Painter::line_onoffdash);
221 pi.pain.line(x1, y1, x1, y0, Color_latex);
222 } else if (params_.kind == InsetSpaceParams::DOTFILL) {
223 pi.pain.line(x0, y1, x0, y0, Color_special);
224 pi.pain.line(x0, y, x1, y, Color_special,
225 frontend::Painter::line_onoffdash);
226 pi.pain.line(x1, y1, x1, y0, Color_special);
227 } if (params_.kind == InsetSpaceParams::HRULEFILL) {
228 pi.pain.line(x0, y1, x0, y0, Color_special);
229 pi.pain.line(x0, y, x1, y, Color_special);
230 pi.pain.line(x1, y1, x1, y0, Color_special);
235 int const w = dim.wid;
236 int const h = theFontMetrics(pi.base.font).ascent('x');
240 yp[0] = y - max(h / 4, 1);
241 if (params_.kind == InsetSpaceParams::NORMAL ||
242 params_.kind == InsetSpaceParams::PROTECTED) {
243 xp[1] = x; yp[1] = y;
244 xp[2] = x + w; yp[2] = y;
246 xp[1] = x; yp[1] = y + max(h / 4, 1);
247 xp[2] = x + w; yp[2] = y + max(h / 4, 1);
250 yp[3] = y - max(h / 4, 1);
252 if (params_.kind == InsetSpaceParams::PROTECTED ||
253 params_.kind == InsetSpaceParams::ENSPACE ||
254 params_.kind == InsetSpaceParams::NEGTHIN ||
255 params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
256 pi.pain.lines(xp, yp, 4, Color_latex);
258 pi.pain.lines(xp, yp, 4, Color_special);
262 void InsetSpaceParams::write(ostream & os) const
266 case InsetSpaceParams::NORMAL:
269 case InsetSpaceParams::PROTECTED:
272 case InsetSpaceParams::THIN:
273 os << "\\thinspace{}";
275 case InsetSpaceParams::QUAD:
278 case InsetSpaceParams::QQUAD:
281 case InsetSpaceParams::ENSPACE:
284 case InsetSpaceParams::ENSKIP:
287 case InsetSpaceParams::NEGTHIN:
288 os << "\\negthinspace{}";
290 case InsetSpaceParams::HFILL:
293 case InsetSpaceParams::HFILL_PROTECTED:
294 os << "\\hspace*{\\fill}";
296 case InsetSpaceParams::DOTFILL:
299 case InsetSpaceParams::HRULEFILL:
300 os << "\\hrulefill{}";
302 case InsetSpaceParams::CUSTOM:
305 case InsetSpaceParams::CUSTOM_PROTECTED:
311 os << "\n\\length " << length.asString();
315 void InsetSpaceParams::read(Lexer & lex)
318 string const command = lex.getString();
320 if (command == "\\space{}")
321 kind = InsetSpaceParams::NORMAL;
322 else if (command == "~")
323 kind = InsetSpaceParams::PROTECTED;
324 else if (command == "\\thinspace{}")
325 kind = InsetSpaceParams::THIN;
326 else if (command == "\\quad{}")
327 kind = InsetSpaceParams::QUAD;
328 else if (command == "\\qquad{}")
329 kind = InsetSpaceParams::QQUAD;
330 else if (command == "\\enspace{}")
331 kind = InsetSpaceParams::ENSPACE;
332 else if (command == "\\enskip{}")
333 kind = InsetSpaceParams::ENSKIP;
334 else if (command == "\\negthinspace{}")
335 kind = InsetSpaceParams::NEGTHIN;
336 else if (command == "\\hfill{}")
337 kind = InsetSpaceParams::HFILL;
338 else if (command == "\\hspace*{\\fill}")
339 kind = InsetSpaceParams::HFILL_PROTECTED;
340 else if (command == "\\dotfill{}")
341 kind = InsetSpaceParams::DOTFILL;
342 else if (command == "\\hrulefill{}")
343 kind = InsetSpaceParams::HRULEFILL;
344 else if (command == "\\hspace{}")
345 kind = InsetSpaceParams::CUSTOM;
346 else if (command == "\\hspace*{}")
347 kind = InsetSpaceParams::CUSTOM_PROTECTED;
349 lex.printError("InsetSpace: Unknown kind: `$$Token'");
354 if (token == "\\length") {
356 string const len = lex.getString();
357 length = Length(len);
359 token = lex.getString();
363 if (token != "\\end_inset")
364 lex.printError("Missing \\end_inset at this point. "
369 void InsetSpace::write(ostream & os) const
376 void InsetSpace::read(Lexer & lex)
382 int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
384 switch (params_.kind) {
385 case InsetSpaceParams::NORMAL:
386 os << (runparams.free_spacing ? " " : "\\ ");
388 case InsetSpaceParams::PROTECTED:
389 os << (runparams.free_spacing ? ' ' : '~');
391 case InsetSpaceParams::THIN:
392 os << (runparams.free_spacing ? " " : "\\,");
394 case InsetSpaceParams::QUAD:
395 os << (runparams.free_spacing ? " " : "\\quad{}");
397 case InsetSpaceParams::QQUAD:
398 os << (runparams.free_spacing ? " " : "\\qquad{}");
400 case InsetSpaceParams::ENSPACE:
401 os << (runparams.free_spacing ? " " : "\\enspace{}");
403 case InsetSpaceParams::ENSKIP:
404 os << (runparams.free_spacing ? " " : "\\enskip{}");
406 case InsetSpaceParams::NEGTHIN:
407 os << (runparams.free_spacing ? " " : "\\negthinspace{}");
409 case InsetSpaceParams::HFILL:
410 os << (runparams.free_spacing ? " " : "\\hfill{}");
412 case InsetSpaceParams::HFILL_PROTECTED:
413 os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}");
415 case InsetSpaceParams::DOTFILL:
416 os << (runparams.free_spacing ? " " : "\\dotfill{}");
418 case InsetSpaceParams::HRULEFILL:
419 os << (runparams.free_spacing ? " " : "\\hrulefill{}");
421 case InsetSpaceParams::CUSTOM:
422 if (runparams.free_spacing)
425 os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
427 case InsetSpaceParams::CUSTOM_PROTECTED:
428 if (runparams.free_spacing)
431 os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
438 int InsetSpace::plaintext(odocstream & os, OutputParams const &) const
440 switch (params_.kind) {
441 case InsetSpaceParams::HFILL:
442 case InsetSpaceParams::HFILL_PROTECTED:
445 case InsetSpaceParams::DOTFILL:
448 case InsetSpaceParams::HRULEFILL:
458 int InsetSpace::docbook(odocstream & os, OutputParams const &) const
460 switch (params_.kind) {
461 case InsetSpaceParams::NORMAL:
462 case InsetSpaceParams::QUAD:
463 case InsetSpaceParams::QQUAD:
464 case InsetSpaceParams::ENSKIP:
467 case InsetSpaceParams::PROTECTED:
468 case InsetSpaceParams::ENSPACE:
469 case InsetSpaceParams::THIN:
470 case InsetSpaceParams::NEGTHIN:
473 case InsetSpaceParams::HFILL:
474 case InsetSpaceParams::HFILL_PROTECTED:
476 case InsetSpaceParams::DOTFILL:
479 case InsetSpaceParams::HRULEFILL:
482 case InsetSpaceParams::CUSTOM:
483 case InsetSpaceParams::CUSTOM_PROTECTED:
491 void InsetSpace::textString(odocstream & os) const
493 plaintext(os, OutputParams(0));
497 bool InsetSpace::isStretchableSpace() const
499 return (params_.kind == InsetSpaceParams::HFILL ||
500 params_.kind == InsetSpaceParams::HFILL_PROTECTED ||
501 params_.kind == InsetSpaceParams::DOTFILL ||
502 params_.kind == InsetSpaceParams::HRULEFILL);
506 docstring InsetSpace::contextMenu(BufferView const &, int, int) const
508 return from_ascii("context-space");
512 string const InsetSpaceMailer::name_ = "space";
515 InsetSpaceMailer::InsetSpaceMailer(InsetSpace & inset)
520 string const InsetSpaceMailer::inset2string(Buffer const &) const
522 return params2string(inset_.params());
526 void InsetSpaceMailer::string2params(string const & in, InsetSpaceParams & params)
528 params = InsetSpaceParams();
532 istringstream data(in);
538 if (!lex || name != name_)
539 return print_mailer_error("InsetSpaceMailer", in, 1, name_);
545 string const InsetSpaceMailer::params2string(InsetSpaceParams const & params)
548 data << name_ << ' ';