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"
18 #include "BufferView.h"
20 #include "Dimension.h"
21 #include "FuncRequest.h"
22 #include "FuncStatus.h"
25 #include "MetricsInfo.h"
26 #include "OutputParams.h"
28 #include "support/debug.h"
29 #include "support/docstream.h"
30 #include "support/gettext.h"
31 #include "support/lstrings.h"
33 #include "frontends/Application.h"
34 #include "frontends/FontMetrics.h"
35 #include "frontends/Painter.h"
42 InsetSpace::InsetSpace(InsetSpaceParams const & params)
47 InsetSpaceParams::Kind InsetSpace::kind() const
53 Length InsetSpace::length() const
55 return params_.length;
59 InsetSpace::~InsetSpace()
61 hideDialogs("space", this);
65 docstring InsetSpace::toolTip(BufferView const &, int, int) const
68 switch (params_.kind) {
69 case InsetSpaceParams::NORMAL:
70 message = _("Interword Space");
72 case InsetSpaceParams::PROTECTED:
73 message = _("Protected Space");
75 case InsetSpaceParams::THIN:
76 message = _("Thin Space");
78 case InsetSpaceParams::QUAD:
79 message = _("Quad Space");
81 case InsetSpaceParams::QQUAD:
82 message = _("QQuad Space");
84 case InsetSpaceParams::ENSPACE:
85 message = _("Enspace");
87 case InsetSpaceParams::ENSKIP:
88 message = _("Enskip");
90 case InsetSpaceParams::NEGTHIN:
91 message = _("Negative Thin Space");
93 case InsetSpaceParams::HFILL:
94 message = _("Horizontal Fill");
96 case InsetSpaceParams::HFILL_PROTECTED:
97 message = _("Protected Horizontal Fill");
99 case InsetSpaceParams::DOTFILL:
100 message = _("Horizontal Fill (Dots)");
102 case InsetSpaceParams::HRULEFILL:
103 message = _("Horizontal Fill (Rule)");
105 case InsetSpaceParams::CUSTOM:
106 message = support::bformat(_("Horizontal Space (%1$s)"),
107 params_.length.asDocstring());
109 case InsetSpaceParams::CUSTOM_PROTECTED:
110 message = support::bformat(_("Protected Horizontal Space (%1$s)"),
111 params_.length.asDocstring());
118 void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
120 switch (cmd.action) {
122 case LFUN_INSET_MODIFY: {
123 string2params(to_utf8(cmd.argument()), params_);
127 case LFUN_MOUSE_RELEASE:
128 if (!cur.selection() && cmd.button() == mouse_button::button1)
129 cur.bv().showDialog("space", params2string(params()), this);
133 Inset::doDispatch(cur, cmd);
139 bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
140 FuncStatus & status) const
142 switch (cmd.action) {
144 case LFUN_INSET_MODIFY:
145 if (cmd.getArg(0) == "space") {
146 InsetSpaceParams params;
147 string2params(to_utf8(cmd.argument()), params);
148 status.setOnOff(params_.kind == params.kind);
150 status.enabled(true);
154 return Inset::getStatus(cur, cmd, status);
159 void InsetSpace::edit(Cursor & cur, bool, EntryDirection)
161 cur.bv().showDialog("space", params2string(params()), this);
165 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
167 if (isStretchableSpace()) {
168 // The metrics for this kinds are calculated externally in
169 // \c TextMetrics::computeRowMetrics. Those are dummy value:
170 dim = Dimension(10, 10, 10);
174 frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
175 dim.asc = fm.maxAscent();
176 dim.des = fm.maxDescent();
178 switch (params_.kind) {
179 case InsetSpaceParams::THIN:
180 case InsetSpaceParams::NEGTHIN:
181 dim.wid = fm.width(char_type('M')) / 6;
183 case InsetSpaceParams::PROTECTED:
184 case InsetSpaceParams::NORMAL:
185 dim.wid = fm.width(char_type(' '));
187 case InsetSpaceParams::QUAD:
188 dim.wid = fm.width(char_type('M'));
190 case InsetSpaceParams::QQUAD:
191 dim.wid = 2 * fm.width(char_type('M'));
193 case InsetSpaceParams::ENSPACE:
194 case InsetSpaceParams::ENSKIP:
195 dim.wid = int(0.5 * fm.width(char_type('M')));
197 case InsetSpaceParams::CUSTOM:
198 case InsetSpaceParams::CUSTOM_PROTECTED:
199 dim.wid = params_.length.inBP();
201 case InsetSpaceParams::HFILL:
202 case InsetSpaceParams::HFILL_PROTECTED:
203 case InsetSpaceParams::DOTFILL:
204 case InsetSpaceParams::HRULEFILL:
208 // Cache the inset dimension.
209 setDimCache(mi, dim);
213 void InsetSpace::draw(PainterInfo & pi, int x, int y) const
215 Dimension const dim = dimension(*pi.base.bv);
217 if (isStretchableSpace()) {
218 int const asc = theFontMetrics(pi.base.font).ascent('M');
219 int const desc = theFontMetrics(pi.base.font).descent('M');
220 int const x0 = x + 1;
221 int const x1 = x + dim.wid - 2;
222 int const y0 = y + desc;
223 int const y1 = y - asc;
224 int const y2 = y - asc / 2;
226 if (params_.kind == InsetSpaceParams::HFILL) {
227 pi.pain.line(x0, y1, x0, y0, Color_added_space);
228 pi.pain.line(x0, y2 , x1, y2, Color_added_space,
229 frontend::Painter::line_onoffdash);
230 pi.pain.line(x1, y1, x1, y0, Color_added_space);
231 } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
232 pi.pain.line(x0, y1, x0, y0, Color_latex);
233 pi.pain.line(x0, y2 , x1, y2, Color_latex,
234 frontend::Painter::line_onoffdash);
235 pi.pain.line(x1, y1, x1, y0, Color_latex);
236 } else if (params_.kind == InsetSpaceParams::DOTFILL) {
237 pi.pain.line(x0, y1, x0, y0, Color_special);
238 pi.pain.line(x0, y, x1, y, Color_special,
239 frontend::Painter::line_onoffdash);
240 pi.pain.line(x1, y1, x1, y0, Color_special);
241 } if (params_.kind == InsetSpaceParams::HRULEFILL) {
242 pi.pain.line(x0, y1, x0, y0, Color_special);
243 pi.pain.line(x0, y, x1, y, Color_special);
244 pi.pain.line(x1, y1, x1, y0, Color_special);
249 int const w = dim.wid;
250 int const h = theFontMetrics(pi.base.font).ascent('x');
254 yp[0] = y - max(h / 4, 1);
255 if (params_.kind == InsetSpaceParams::NORMAL ||
256 params_.kind == InsetSpaceParams::PROTECTED) {
257 xp[1] = x; yp[1] = y;
258 xp[2] = x + w; yp[2] = y;
260 xp[1] = x; yp[1] = y + max(h / 4, 1);
261 xp[2] = x + w; yp[2] = y + max(h / 4, 1);
264 yp[3] = y - max(h / 4, 1);
266 if (params_.kind == InsetSpaceParams::PROTECTED ||
267 params_.kind == InsetSpaceParams::ENSPACE ||
268 params_.kind == InsetSpaceParams::NEGTHIN ||
269 params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
270 pi.pain.lines(xp, yp, 4, Color_latex);
272 pi.pain.lines(xp, yp, 4, Color_special);
276 void InsetSpaceParams::write(ostream & os) const
280 case InsetSpaceParams::NORMAL:
283 case InsetSpaceParams::PROTECTED:
286 case InsetSpaceParams::THIN:
287 os << "\\thinspace{}";
289 case InsetSpaceParams::QUAD:
292 case InsetSpaceParams::QQUAD:
295 case InsetSpaceParams::ENSPACE:
298 case InsetSpaceParams::ENSKIP:
301 case InsetSpaceParams::NEGTHIN:
302 os << "\\negthinspace{}";
304 case InsetSpaceParams::HFILL:
307 case InsetSpaceParams::HFILL_PROTECTED:
308 os << "\\hspace*{\\fill}";
310 case InsetSpaceParams::DOTFILL:
313 case InsetSpaceParams::HRULEFILL:
314 os << "\\hrulefill{}";
316 case InsetSpaceParams::CUSTOM:
319 case InsetSpaceParams::CUSTOM_PROTECTED:
325 os << "\n\\length " << length.asString();
329 void InsetSpaceParams::read(Lexer & lex)
331 lex.setContext("InsetSpaceParams::read");
335 if (command == "\\space{}")
336 kind = InsetSpaceParams::NORMAL;
337 else if (command == "~")
338 kind = InsetSpaceParams::PROTECTED;
339 else if (command == "\\thinspace{}")
340 kind = InsetSpaceParams::THIN;
341 else if (command == "\\quad{}")
342 kind = InsetSpaceParams::QUAD;
343 else if (command == "\\qquad{}")
344 kind = InsetSpaceParams::QQUAD;
345 else if (command == "\\enspace{}")
346 kind = InsetSpaceParams::ENSPACE;
347 else if (command == "\\enskip{}")
348 kind = InsetSpaceParams::ENSKIP;
349 else if (command == "\\negthinspace{}")
350 kind = InsetSpaceParams::NEGTHIN;
351 else if (command == "\\hfill{}")
352 kind = InsetSpaceParams::HFILL;
353 else if (command == "\\hspace*{\\fill}")
354 kind = InsetSpaceParams::HFILL_PROTECTED;
355 else if (command == "\\dotfill{}")
356 kind = InsetSpaceParams::DOTFILL;
357 else if (command == "\\hrulefill{}")
358 kind = InsetSpaceParams::HRULEFILL;
359 else if (command == "\\hspace{}")
360 kind = InsetSpaceParams::CUSTOM;
361 else if (command == "\\hspace*{}")
362 kind = InsetSpaceParams::CUSTOM_PROTECTED;
364 lex.printError("InsetSpace: Unknown kind: `$$Token'");
366 if (lex.checkFor("\\length"))
368 lex >> "\\end_inset";
372 void InsetSpace::write(ostream & os) const
379 void InsetSpace::read(Lexer & lex)
385 int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
387 switch (params_.kind) {
388 case InsetSpaceParams::NORMAL:
389 os << (runparams.free_spacing ? " " : "\\ ");
391 case InsetSpaceParams::PROTECTED:
392 os << (runparams.free_spacing ? ' ' : '~');
394 case InsetSpaceParams::THIN:
395 os << (runparams.free_spacing ? " " : "\\,");
397 case InsetSpaceParams::QUAD:
398 os << (runparams.free_spacing ? " " : "\\quad{}");
400 case InsetSpaceParams::QQUAD:
401 os << (runparams.free_spacing ? " " : "\\qquad{}");
403 case InsetSpaceParams::ENSPACE:
404 os << (runparams.free_spacing ? " " : "\\enspace{}");
406 case InsetSpaceParams::ENSKIP:
407 os << (runparams.free_spacing ? " " : "\\enskip{}");
409 case InsetSpaceParams::NEGTHIN:
410 os << (runparams.free_spacing ? " " : "\\negthinspace{}");
412 case InsetSpaceParams::HFILL:
413 os << (runparams.free_spacing ? " " : "\\hfill{}");
415 case InsetSpaceParams::HFILL_PROTECTED:
416 os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}");
418 case InsetSpaceParams::DOTFILL:
419 os << (runparams.free_spacing ? " " : "\\dotfill{}");
421 case InsetSpaceParams::HRULEFILL:
422 os << (runparams.free_spacing ? " " : "\\hrulefill{}");
424 case InsetSpaceParams::CUSTOM:
425 if (runparams.free_spacing)
428 os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
430 case InsetSpaceParams::CUSTOM_PROTECTED:
431 if (runparams.free_spacing)
434 os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
441 int InsetSpace::plaintext(odocstream & os, OutputParams const &) const
443 switch (params_.kind) {
444 case InsetSpaceParams::HFILL:
445 case InsetSpaceParams::HFILL_PROTECTED:
448 case InsetSpaceParams::DOTFILL:
451 case InsetSpaceParams::HRULEFILL:
461 int InsetSpace::docbook(odocstream & os, OutputParams const &) const
463 switch (params_.kind) {
464 case InsetSpaceParams::NORMAL:
465 case InsetSpaceParams::QUAD:
466 case InsetSpaceParams::QQUAD:
467 case InsetSpaceParams::ENSKIP:
470 case InsetSpaceParams::PROTECTED:
471 case InsetSpaceParams::ENSPACE:
472 case InsetSpaceParams::THIN:
473 case InsetSpaceParams::NEGTHIN:
476 case InsetSpaceParams::HFILL:
477 case InsetSpaceParams::HFILL_PROTECTED:
479 case InsetSpaceParams::DOTFILL:
482 case InsetSpaceParams::HRULEFILL:
485 case InsetSpaceParams::CUSTOM:
486 case InsetSpaceParams::CUSTOM_PROTECTED:
494 void InsetSpace::textString(odocstream & os) const
496 plaintext(os, OutputParams(0));
500 bool InsetSpace::isStretchableSpace() const
502 return params_.kind == InsetSpaceParams::HFILL
503 || params_.kind == InsetSpaceParams::HFILL_PROTECTED
504 || params_.kind == InsetSpaceParams::DOTFILL
505 || params_.kind == InsetSpaceParams::HRULEFILL;
509 docstring InsetSpace::contextMenu(BufferView const &, int, int) const
511 return from_ascii("context-space");
515 void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
517 params = InsetSpaceParams();
521 istringstream data(in);
524 lex.setContext("InsetSpace::string2params");
531 string InsetSpace::params2string(InsetSpaceParams const & params)
534 data << "space" << ' ';