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"
24 #include "LaTeXFeatures.h"
25 #include "MetricsInfo.h"
26 #include "texstream.h"
29 #include "support/debug.h"
30 #include "support/docstream.h"
31 #include "support/gettext.h"
32 #include "support/lassert.h"
33 #include "support/Length.h"
34 #include "support/lstrings.h"
35 #include "support/qstring_helpers.h"
37 #include "frontends/Application.h"
38 #include "frontends/FontMetrics.h"
39 #include "support/Lexer.h"
40 #include "frontends/Painter.h"
48 InsetSpace::InsetSpace(InsetSpaceParams const & params)
49 : Inset(nullptr), params_(params)
53 InsetSpaceParams::Kind InsetSpace::kind() const
59 GlueLength InsetSpace::length() const
61 return params_.length;
65 docstring InsetSpace::toolTip(BufferView const &, int, int) const
68 switch (params_.kind) {
69 case InsetSpaceParams::NORMAL:
70 message = _("Normal Space");
72 case InsetSpaceParams::PROTECTED:
73 message = _("Non-Breaking Normal Space");
75 case InsetSpaceParams::VISIBLE:
76 message = _("Non-Breaking Visible Normal Space");
78 case InsetSpaceParams::THIN:
79 message = _("Non-Breaking Thin Space (1/6 em)");
81 case InsetSpaceParams::MEDIUM:
82 message = _("Non-Breaking Medium Space (2/9 em)");
84 case InsetSpaceParams::THICK:
85 message = _("Non-Breaking Thick Space (5/18 em)");
87 case InsetSpaceParams::QUAD:
88 message = _("Quad Space (1 em)");
90 case InsetSpaceParams::QQUAD:
91 message = _("Double Quad Space (2 em)");
93 case InsetSpaceParams::ENSPACE:
94 message = _("Non-Breaking Half Quad Space (1/2 em)");
96 case InsetSpaceParams::ENSKIP:
97 message = _("Half Quad Space (1/2 em)");
99 case InsetSpaceParams::NEGTHIN:
100 message = _("Non-Breaking Negative Thin Space (-1/6 em)");
102 case InsetSpaceParams::NEGMEDIUM:
103 message = _("Non-Breaking Negative Medium Space (-2/9 em)");
105 case InsetSpaceParams::NEGTHICK:
106 message = _("Non-Breaking Negative Thick Space (-5/18 em)");
108 case InsetSpaceParams::HFILL:
109 message = _("Horizontal Fill");
111 case InsetSpaceParams::HFILL_PROTECTED:
112 message = _("Non-Breaking Horizontal Fill");
114 case InsetSpaceParams::DOTFILL:
115 message = _("Non-Breaking Horizontal Fill (Dots)");
117 case InsetSpaceParams::HRULEFILL:
118 message = _("Non-Breaking Horizontal Fill (Rule)");
120 case InsetSpaceParams::LEFTARROWFILL:
121 message = _("Non-Breaking Horizontal Fill (Left Arrow)");
123 case InsetSpaceParams::RIGHTARROWFILL:
124 message = _("Non-Breaking Horizontal Fill (Right Arrow)");
126 case InsetSpaceParams::UPBRACEFILL:
127 message = _("Non-Breaking Horizontal Fill (Up Brace)");
129 case InsetSpaceParams::DOWNBRACEFILL:
130 message = _("Non-Breaking Horizontal Fill (Down Brace)");
132 case InsetSpaceParams::CUSTOM:
134 message = support::bformat(_("Horizontal Space (%1$s)"),
135 locLengthDocString(from_ascii(params_.length.asString())));
137 case InsetSpaceParams::CUSTOM_PROTECTED:
139 message = support::bformat(_("Non-Breaking Horizontal Space (%1$s)"),
140 locLengthDocString(from_ascii(params_.length.asString())));
147 void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
149 switch (cmd.action()) {
151 case LFUN_INSET_MODIFY: {
153 string arg = to_utf8(cmd.argument());
154 if (arg == "space \\hspace{}")
155 arg += params_.length.len().empty()
156 ? " \\length 1" + string(stringFromUnit(Length::defaultUnit()))
157 : " \\length " + params_.length.asString();
158 string2params(arg, params_);
162 case LFUN_INSET_DIALOG_UPDATE:
163 cur.bv().updateDialog("space", params2string(params()));
167 Inset::doDispatch(cur, cmd);
173 bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
174 FuncStatus & status) const
176 switch (cmd.action()) {
178 case LFUN_INSET_MODIFY:
179 if (cmd.getArg(0) == "space") {
180 InsetSpaceParams params;
181 string2params(to_utf8(cmd.argument()), params);
182 status.setOnOff(params_.kind == params.kind);
183 status.setEnabled(true);
185 status.setEnabled(false);
188 case LFUN_INSET_DIALOG_UPDATE:
189 status.setEnabled(true);
192 return Inset::getStatus(cur, cmd, status);
197 int InsetSpace::rowFlags() const
199 switch (params_.kind) {
200 case InsetSpaceParams::PROTECTED:
201 case InsetSpaceParams::CUSTOM_PROTECTED:
202 case InsetSpaceParams::HFILL_PROTECTED:
203 case InsetSpaceParams::THIN:
204 case InsetSpaceParams::NEGTHIN:
205 case InsetSpaceParams::MEDIUM:
206 case InsetSpaceParams::NEGMEDIUM:
207 case InsetSpaceParams::THICK:
208 case InsetSpaceParams::NEGTHICK:
209 case InsetSpaceParams::ENSPACE:
210 case InsetSpaceParams::VISIBLE:
211 // no break after these
213 case InsetSpaceParams::NORMAL:
214 case InsetSpaceParams::QUAD:
215 case InsetSpaceParams::QQUAD:
216 case InsetSpaceParams::ENSKIP:
217 case InsetSpaceParams::CUSTOM:
218 case InsetSpaceParams::HFILL:
219 case InsetSpaceParams::DOTFILL:
220 case InsetSpaceParams::HRULEFILL:
221 case InsetSpaceParams::LEFTARROWFILL:
222 case InsetSpaceParams::RIGHTARROWFILL:
223 case InsetSpaceParams::UPBRACEFILL:
224 case InsetSpaceParams::DOWNBRACEFILL:
225 // these allow line breaking
228 return CanBreakAfter;
233 int const arrow_size = 8;
237 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
240 // The width for hfills is calculated externally in
241 // TextMetrics::setRowAlignment. The value of 5 is the
242 // minimal value when the hfill is not active.
243 dim = Dimension(5, 10, 10);
247 frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
248 dim.asc = fm.maxAscent();
249 dim.des = fm.maxDescent();
250 int const em = fm.em();
252 switch (params_.kind) {
253 case InsetSpaceParams::THIN:
254 case InsetSpaceParams::NEGTHIN:
257 case InsetSpaceParams::MEDIUM:
258 case InsetSpaceParams::NEGMEDIUM:
261 case InsetSpaceParams::THICK:
262 case InsetSpaceParams::NEGTHICK:
265 case InsetSpaceParams::PROTECTED:
266 case InsetSpaceParams::VISIBLE:
267 case InsetSpaceParams::NORMAL:
268 dim.wid = fm.width(char_type(' '));
270 case InsetSpaceParams::QUAD:
273 case InsetSpaceParams::QQUAD:
276 case InsetSpaceParams::ENSPACE:
277 case InsetSpaceParams::ENSKIP:
278 dim.wid = int(0.5 * em);
280 case InsetSpaceParams::CUSTOM:
281 case InsetSpaceParams::CUSTOM_PROTECTED: {
282 int const w = mi.base.inPixels(params_.length.len());
283 int const minw = (w < 0) ? 3 * arrow_size : 4;
284 dim.wid = max(minw, abs(w));
287 case InsetSpaceParams::HFILL:
288 case InsetSpaceParams::HFILL_PROTECTED:
289 case InsetSpaceParams::DOTFILL:
290 case InsetSpaceParams::HRULEFILL:
291 case InsetSpaceParams::LEFTARROWFILL:
292 case InsetSpaceParams::RIGHTARROWFILL:
293 case InsetSpaceParams::UPBRACEFILL:
294 case InsetSpaceParams::DOWNBRACEFILL:
301 void InsetSpace::draw(PainterInfo & pi, int x, int y) const
303 Dimension const dim = dimension(*pi.base.bv);
305 if (isHfill() || params_.length.len().value() < 0) {
306 int const asc = theFontMetrics(pi.base.font).ascent('M');
307 int const desc = theFontMetrics(pi.base.font).descent('M');
308 // Pixel height divisible by 2 for prettier fill graphics:
309 int const oddheight = (asc ^ desc) & 1;
310 int const x0 = x + 1;
311 int const x1 = x + dim.wid - 2;
312 int const y0 = y + desc - 1;
313 int const y1 = y - asc + oddheight - 1;
314 int const y2 = (y0 + y1) / 2;
315 int xoffset = (y0 - y1) / 2;
317 // Two tests for very narrow insets
318 if (xoffset > x1 - x0
319 && (params_.kind == InsetSpaceParams::LEFTARROWFILL
320 || params_.kind == InsetSpaceParams::RIGHTARROWFILL))
322 if (xoffset * 6 > (x1 - x0)
323 && (params_.kind == InsetSpaceParams::UPBRACEFILL
324 || params_.kind == InsetSpaceParams::DOWNBRACEFILL))
325 xoffset = (x1 - x0) / 6;
327 int const x2 = x0 + xoffset;
328 int const x3 = x1 - xoffset;
329 int const xm = (x0 + x1) / 2;
330 int const xml = xm - xoffset;
331 int const xmr = xm + xoffset;
333 if (params_.kind == InsetSpaceParams::HFILL) {
334 pi.pain.line(x0, y1, x0, y0, Color_added_space);
335 pi.pain.line(x0, y2, x1, y2, Color_added_space,
336 frontend::Painter::line_onoffdash);
337 pi.pain.line(x1, y1, x1, y0, Color_added_space);
338 } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
339 pi.pain.line(x0, y1, x0, y0, Color_latex);
340 pi.pain.line(x0, y2, x1, y2, Color_latex,
341 frontend::Painter::line_onoffdash);
342 pi.pain.line(x1, y1, x1, y0, Color_latex);
343 } else if (params_.kind == InsetSpaceParams::DOTFILL) {
344 pi.pain.line(x0, y1, x0, y0, Color_special);
345 pi.pain.line(x0, y0, x1, y0, Color_special,
346 frontend::Painter::line_onoffdash);
347 pi.pain.line(x1, y1, x1, y0, Color_special);
348 } else if (params_.kind == InsetSpaceParams::HRULEFILL) {
349 pi.pain.line(x0, y1, x0, y0, Color_special);
350 pi.pain.line(x0, y0, x1, y0, Color_special);
351 pi.pain.line(x1, y1, x1, y0, Color_special);
352 } else if (params_.kind == InsetSpaceParams::LEFTARROWFILL) {
353 pi.pain.line(x2, y1 + 1 , x0 + 1, y2, Color_special);
354 pi.pain.line(x0 + 1, y2 + 1 , x2, y0, Color_special);
355 pi.pain.line(x0, y2 , x1, y2, Color_special);
356 } else if (params_.kind == InsetSpaceParams::RIGHTARROWFILL) {
357 pi.pain.line(x3 + 1, y1 + 1 , x1, y2, Color_special);
358 pi.pain.line(x1, y2 + 1 , x3 + 1, y0, Color_special);
359 pi.pain.line(x0, y2 , x1, y2, Color_special);
360 } else if (params_.kind == InsetSpaceParams::UPBRACEFILL) {
361 pi.pain.line(x0 + 1, y1 + 1 , x2, y2, Color_special);
362 pi.pain.line(x2, y2 , xml, y2, Color_special);
363 pi.pain.line(xml + 1, y2 + 1 , xm, y0, Color_special);
364 pi.pain.line(xm + 1, y0 , xmr, y2 + 1, Color_special);
365 pi.pain.line(xmr, y2 , x3, y2, Color_special);
366 pi.pain.line(x3 + 1, y2 , x1, y1 + 1, Color_special);
367 } else if (params_.kind == InsetSpaceParams::DOWNBRACEFILL) {
368 pi.pain.line(x0 + 1, y0 , x2, y2 + 1, Color_special);
369 pi.pain.line(x2, y2 , xml, y2, Color_special);
370 pi.pain.line(xml + 1, y2 , xm, y1 + 1, Color_special);
371 pi.pain.line(xm + 1, y1 + 1 , xmr, y2, Color_special);
372 pi.pain.line(xmr, y2 , x3, y2, Color_special);
373 pi.pain.line(x3 + 1, y2 + 1 , x1, y0, Color_special);
374 } else if (params_.kind == InsetSpaceParams::CUSTOM) {
375 pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_special);
376 pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_special);
377 pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_special);
378 pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_special);
379 pi.pain.line(x2, y2 , x3, y2, Color_special);
380 } else if (params_.kind == InsetSpaceParams::CUSTOM_PROTECTED) {
381 pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_latex);
382 pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_latex);
383 pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_latex);
384 pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_latex);
385 pi.pain.line(x2, y2 , x3, y2, Color_latex);
390 int const w = dim.wid;
391 int const h = theFontMetrics(pi.base.font).xHeight();
395 yp[0] = y - max(h / 4, 1);
396 if (params_.kind == InsetSpaceParams::NORMAL ||
397 params_.kind == InsetSpaceParams::PROTECTED ||
398 params_.kind == InsetSpaceParams::VISIBLE) {
399 xp[1] = x; yp[1] = y;
400 xp[2] = x + w - 1; yp[2] = y;
402 xp[1] = x; yp[1] = y + max(h / 4, 1);
403 xp[2] = x + w - 1; yp[2] = y + max(h / 4, 1);
406 yp[3] = y - max(h / 4, 1);
408 Color col = Color_special;
409 if (params_.kind == InsetSpaceParams::PROTECTED ||
410 params_.kind == InsetSpaceParams::ENSPACE ||
411 params_.kind == InsetSpaceParams::THIN ||
412 params_.kind == InsetSpaceParams::NEGTHIN ||
413 params_.kind == InsetSpaceParams::MEDIUM ||
414 params_.kind == InsetSpaceParams::NEGMEDIUM ||
415 params_.kind == InsetSpaceParams::THICK ||
416 params_.kind == InsetSpaceParams::NEGTHICK ||
417 params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
419 else if (params_.kind == InsetSpaceParams::VISIBLE)
420 col = Color_foreground;
422 pi.pain.lines(xp, yp, 4, col);
426 void InsetSpaceParams::write(ostream & os) const
429 case InsetSpaceParams::NORMAL:
432 case InsetSpaceParams::PROTECTED:
435 case InsetSpaceParams::VISIBLE:
436 os << "\\textvisiblespace{}";
438 case InsetSpaceParams::THIN:
439 os << "\\thinspace{}";
441 case InsetSpaceParams::MEDIUM:
442 os << "\\medspace{}";
444 case InsetSpaceParams::THICK:
445 os << "\\thickspace{}";
447 case InsetSpaceParams::QUAD:
450 case InsetSpaceParams::QQUAD:
453 case InsetSpaceParams::ENSPACE:
456 case InsetSpaceParams::ENSKIP:
459 case InsetSpaceParams::NEGTHIN:
460 os << "\\negthinspace{}";
462 case InsetSpaceParams::NEGMEDIUM:
463 os << "\\negmedspace{}";
465 case InsetSpaceParams::NEGTHICK:
466 os << "\\negthickspace{}";
468 case InsetSpaceParams::HFILL:
471 case InsetSpaceParams::HFILL_PROTECTED:
472 os << "\\hspace*{\\fill}";
474 case InsetSpaceParams::DOTFILL:
477 case InsetSpaceParams::HRULEFILL:
478 os << "\\hrulefill{}";
480 case InsetSpaceParams::LEFTARROWFILL:
481 os << "\\leftarrowfill{}";
483 case InsetSpaceParams::RIGHTARROWFILL:
484 os << "\\rightarrowfill{}";
486 case InsetSpaceParams::UPBRACEFILL:
487 os << "\\upbracefill{}";
489 case InsetSpaceParams::DOWNBRACEFILL:
490 os << "\\downbracefill{}";
492 case InsetSpaceParams::CUSTOM:
495 case InsetSpaceParams::CUSTOM_PROTECTED:
500 if (!length.len().empty())
501 os << "\n\\length " << length.asString();
505 void InsetSpaceParams::read(Lexer & lex)
507 lex.setContext("InsetSpaceParams::read");
511 // The tests for math might be disabled after a file format change
512 if (command == "\\space{}")
513 kind = InsetSpaceParams::NORMAL;
514 else if (command == "~")
515 kind = InsetSpaceParams::PROTECTED;
516 else if (command == "\\textvisiblespace{}")
517 kind = InsetSpaceParams::VISIBLE;
518 else if (command == "\\thinspace{}")
519 kind = InsetSpaceParams::THIN;
520 else if (command == "\\medspace{}")
521 kind = InsetSpaceParams::MEDIUM;
522 else if (command == "\\thickspace{}")
523 kind = InsetSpaceParams::THICK;
524 else if (command == "\\quad{}")
525 kind = InsetSpaceParams::QUAD;
526 else if (command == "\\qquad{}")
527 kind = InsetSpaceParams::QQUAD;
528 else if (command == "\\enspace{}")
529 kind = InsetSpaceParams::ENSPACE;
530 else if (command == "\\enskip{}")
531 kind = InsetSpaceParams::ENSKIP;
532 else if (command == "\\negthinspace{}")
533 kind = InsetSpaceParams::NEGTHIN;
534 else if (command == "\\negmedspace{}")
535 kind = InsetSpaceParams::NEGMEDIUM;
536 else if (command == "\\negthickspace{}")
537 kind = InsetSpaceParams::NEGTHICK;
538 else if (command == "\\hfill{}")
539 kind = InsetSpaceParams::HFILL;
540 else if (command == "\\hspace*{\\fill}")
541 kind = InsetSpaceParams::HFILL_PROTECTED;
542 else if (command == "\\dotfill{}")
543 kind = InsetSpaceParams::DOTFILL;
544 else if (command == "\\hrulefill{}")
545 kind = InsetSpaceParams::HRULEFILL;
546 else if (command == "\\hspace{}")
547 kind = InsetSpaceParams::CUSTOM;
548 else if (command == "\\leftarrowfill{}")
549 kind = InsetSpaceParams::LEFTARROWFILL;
550 else if (command == "\\rightarrowfill{}")
551 kind = InsetSpaceParams::RIGHTARROWFILL;
552 else if (command == "\\upbracefill{}")
553 kind = InsetSpaceParams::UPBRACEFILL;
554 else if (command == "\\downbracefill{}")
555 kind = InsetSpaceParams::DOWNBRACEFILL;
556 else if (command == "\\hspace*{}")
557 kind = InsetSpaceParams::CUSTOM_PROTECTED;
559 lex.printError("InsetSpace: Unknown kind: `$$Token'");
561 if (lex.checkFor("\\length"))
566 void InsetSpace::write(ostream & os) const
573 void InsetSpace::read(Lexer & lex)
576 lex >> "\\end_inset";
580 void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const
582 switch (params_.kind) {
583 case InsetSpaceParams::NORMAL:
584 if (runparams.find_effective())
587 os << (runparams.free_spacing ? " " : "\\ ");
589 case InsetSpaceParams::PROTECTED:
590 if (runparams.find_effective())
592 else if (getLocalOrDefaultLang(runparams)->lang() == "polutonikogreek")
593 // in babel's polutonikogreek, ~ is active
594 os << (runparams.free_spacing ? " " : "\\nobreakspace{}");
596 os << (runparams.free_spacing ? ' ' : '~');
598 case InsetSpaceParams::VISIBLE:
599 if (runparams.find_effective())
602 os << (runparams.free_spacing ? " " : "\\textvisiblespace{}");
604 case InsetSpaceParams::THIN:
605 if (runparams.find_effective())
608 os << (runparams.free_spacing ? " " : "\\,");
610 case InsetSpaceParams::MEDIUM:
611 if (runparams.find_effective())
613 else if (params_.math)
614 os << (runparams.free_spacing ? " " : "\\:");
616 os << (runparams.free_spacing ? " " : "\\medspace{}");
618 case InsetSpaceParams::THICK:
619 if (runparams.find_effective())
621 else if (params_.math)
622 os << (runparams.free_spacing ? " " : "\\;");
624 os << (runparams.free_spacing ? " " : "\\thickspace{}");
626 case InsetSpaceParams::QUAD:
627 if (runparams.find_effective())
630 os << (runparams.free_spacing ? " " : "\\quad{}");
632 case InsetSpaceParams::QQUAD:
633 if (runparams.find_effective()) {
638 os << (runparams.free_spacing ? " " : "\\qquad{}");
640 case InsetSpaceParams::ENSPACE:
641 if (runparams.find_effective())
644 os << (runparams.free_spacing ? " " : "\\enspace{}");
646 case InsetSpaceParams::ENSKIP:
647 if (runparams.find_effective())
650 os << (runparams.free_spacing ? " " : "\\enskip{}");
652 case InsetSpaceParams::NEGTHIN:
653 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negthinspace{}");
655 case InsetSpaceParams::NEGMEDIUM:
656 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negmedspace{}");
658 case InsetSpaceParams::NEGTHICK:
659 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\negthickspace{}");
661 case InsetSpaceParams::HFILL:
662 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hfill{}");
664 case InsetSpaceParams::HFILL_PROTECTED:
665 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hspace*{\\fill}");
667 case InsetSpaceParams::DOTFILL:
668 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\dotfill{}");
670 case InsetSpaceParams::HRULEFILL:
671 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\hrulefill{}");
673 case InsetSpaceParams::LEFTARROWFILL:
674 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\leftarrowfill{}");
676 case InsetSpaceParams::RIGHTARROWFILL:
677 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\rightarrowfill{}");
679 case InsetSpaceParams::UPBRACEFILL:
680 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\upbracefill{}");
682 case InsetSpaceParams::DOWNBRACEFILL:
683 os << (runparams.free_spacing && runparams.find_effective() ? " " : "\\downbracefill{}");
685 case InsetSpaceParams::CUSTOM:
686 if (runparams.find_effective())
688 else if (runparams.free_spacing)
691 os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
693 case InsetSpaceParams::CUSTOM_PROTECTED:
694 if (runparams.find_effective())
696 else if (runparams.free_spacing)
699 os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
705 int InsetSpace::plaintext(odocstringstream & os,
706 OutputParams const & rp, size_t) const
708 switch (params_.kind) {
709 case InsetSpaceParams::HFILL:
710 case InsetSpaceParams::HFILL_PROTECTED:
713 case InsetSpaceParams::DOTFILL:
716 case InsetSpaceParams::HRULEFILL:
719 case InsetSpaceParams::LEFTARROWFILL:
722 case InsetSpaceParams::RIGHTARROWFILL:
725 case InsetSpaceParams::UPBRACEFILL:
728 case InsetSpaceParams::DOWNBRACEFILL:
731 case InsetSpaceParams::VISIBLE:
734 case InsetSpaceParams::ENSKIP:
737 case InsetSpaceParams::ENSPACE:
738 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
740 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
742 case InsetSpaceParams::QUAD:
745 case InsetSpaceParams::QQUAD:
749 case InsetSpaceParams::THIN:
750 if (rp.find_effective())
756 case InsetSpaceParams::MEDIUM:
757 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
759 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
761 case InsetSpaceParams::THICK:
762 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
764 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
766 case InsetSpaceParams::PROTECTED:
767 case InsetSpaceParams::CUSTOM_PROTECTED:
768 if (rp.find_effective())
774 case InsetSpaceParams::NEGTHIN:
775 case InsetSpaceParams::NEGMEDIUM:
776 case InsetSpaceParams::NEGTHICK:
777 if (rp.find_effective()) {
791 std::string spaceToXMLEntity(InsetSpaceParams::Kind kind) {
793 case InsetSpaceParams::NORMAL:
795 case InsetSpaceParams::QUAD:
796 return " "; // HTML:  
797 case InsetSpaceParams::QQUAD:
798 return "  "; // HTML:   
799 case InsetSpaceParams::ENSKIP:
800 return " "; // HTML:  
801 case InsetSpaceParams::VISIBLE:
803 case InsetSpaceParams::ENSPACE: // HTML: ⁠ ⁠ (word joiners)
804 return "⁠ ⁠";
805 case InsetSpaceParams::THIN:
806 return " "; // HTML: &thinspace;
807 case InsetSpaceParams::MEDIUM:
808 return " "; // HTML:  
809 case InsetSpaceParams::THICK:
810 return " "; // HTML:  
811 case InsetSpaceParams::PROTECTED:
812 case InsetSpaceParams::NEGTHIN:
813 case InsetSpaceParams::NEGMEDIUM:
814 case InsetSpaceParams::NEGTHICK:
815 return " "; // HTML:
816 case InsetSpaceParams::CUSTOM_PROTECTED:
817 // FIXME XHTML/DocBook
818 // Probably we could do some sort of blank span?
820 case InsetSpaceParams::HFILL:
821 case InsetSpaceParams::HFILL_PROTECTED:
822 case InsetSpaceParams::DOTFILL:
823 case InsetSpaceParams::HRULEFILL:
824 case InsetSpaceParams::LEFTARROWFILL:
825 case InsetSpaceParams::RIGHTARROWFILL:
826 case InsetSpaceParams::UPBRACEFILL:
827 case InsetSpaceParams::DOWNBRACEFILL:
828 case InsetSpaceParams::CUSTOM:
829 // FIXME XHTML/DocBook
830 // Can we do anything with those?
838 void InsetSpace::docbook(XMLStream & xs, OutputParams const &) const
840 xs << XMLStream::ESCAPE_NONE << from_ascii(spaceToXMLEntity(params_.kind));
844 docstring InsetSpace::xhtml(XMLStream & xs, OutputParams const &) const
846 xs << XMLStream::ESCAPE_NONE << from_ascii(spaceToXMLEntity(params_.kind));
851 void InsetSpace::validate(LaTeXFeatures & features) const
853 if (features.isAvailableAtLeastFrom("LaTeX", 2020, 10))
854 // As of this version, the LaTeX kernel
855 // includes all spaces.
858 // In earlier versions, we require amsmath
859 // for some text and math spaces
860 if ((params_.kind == InsetSpaceParams::NEGMEDIUM
861 || params_.kind == InsetSpaceParams::NEGTHICK)
863 && (params_.kind == InsetSpaceParams::MEDIUM
864 || params_.kind == InsetSpaceParams::THICK)))
865 features.require("amsmath");
869 void InsetSpace::toString(odocstream & os) const
871 odocstringstream ods;
872 plaintext(ods, OutputParams(0));
877 void InsetSpace::forOutliner(docstring & os, size_t const, bool const) const
879 // There's no need to be cute here.
884 bool InsetSpace::isHfill() const
886 return params_.kind == InsetSpaceParams::HFILL
887 || params_.kind == InsetSpaceParams::HFILL_PROTECTED
888 || params_.kind == InsetSpaceParams::DOTFILL
889 || params_.kind == InsetSpaceParams::HRULEFILL
890 || params_.kind == InsetSpaceParams::LEFTARROWFILL
891 || params_.kind == InsetSpaceParams::RIGHTARROWFILL
892 || params_.kind == InsetSpaceParams::UPBRACEFILL
893 || params_.kind == InsetSpaceParams::DOWNBRACEFILL;
897 string InsetSpace::contextMenuName() const
899 return "context-space";
903 void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
905 params = InsetSpaceParams();
909 istringstream data(in);
912 lex.setContext("InsetSpace::string2params");
914 string const name = lex.getString();
915 if (name == "mathspace")
919 // we can try to read this even if the name is wrong
920 LATTEST(name == "space");
923 // There are cases, such as when we are called via getStatus() from
924 // Dialog::canApply(), where we are just called with "space" rather
925 // than a full "space \type{}\n\\end_inset".
931 string InsetSpace::params2string(InsetSpaceParams const & params)
936 data << "space" << ' ';