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"
26 #include "MetricsInfo.h"
27 #include "texstream.h"
30 #include "support/debug.h"
31 #include "support/docstream.h"
32 #include "support/gettext.h"
33 #include "support/lassert.h"
34 #include "support/Length.h"
35 #include "support/lstrings.h"
37 #include "frontends/Application.h"
38 #include "frontends/FontMetrics.h"
39 #include "frontends/Painter.h"
46 InsetSpace::InsetSpace(InsetSpaceParams const & params)
47 : Inset(nullptr), params_(params)
51 InsetSpaceParams::Kind InsetSpace::kind() const
57 GlueLength InsetSpace::length() const
59 return params_.length;
63 docstring InsetSpace::toolTip(BufferView const &, int, int) const
66 switch (params_.kind) {
67 case InsetSpaceParams::NORMAL:
68 message = _("Interword Space");
70 case InsetSpaceParams::PROTECTED:
71 message = _("Protected Space");
73 case InsetSpaceParams::VISIBLE:
74 message = _("Visible Space");
76 case InsetSpaceParams::THIN:
77 message = _("Thin Space");
79 case InsetSpaceParams::MEDIUM:
80 message = _("Medium Space");
82 case InsetSpaceParams::THICK:
83 message = _("Thick Space");
85 case InsetSpaceParams::QUAD:
86 message = _("Quad Space");
88 case InsetSpaceParams::QQUAD:
89 message = _("Double Quad Space");
91 case InsetSpaceParams::ENSPACE:
92 message = _("Enspace");
94 case InsetSpaceParams::ENSKIP:
95 message = _("Enskip");
97 case InsetSpaceParams::NEGTHIN:
98 message = _("Negative Thin Space");
100 case InsetSpaceParams::NEGMEDIUM:
101 message = _("Negative Medium Space");
103 case InsetSpaceParams::NEGTHICK:
104 message = _("Negative Thick Space");
106 case InsetSpaceParams::HFILL:
107 message = _("Horizontal Fill");
109 case InsetSpaceParams::HFILL_PROTECTED:
110 message = _("Protected Horizontal Fill");
112 case InsetSpaceParams::DOTFILL:
113 message = _("Horizontal Fill (Dots)");
115 case InsetSpaceParams::HRULEFILL:
116 message = _("Horizontal Fill (Rule)");
118 case InsetSpaceParams::LEFTARROWFILL:
119 message = _("Horizontal Fill (Left Arrow)");
121 case InsetSpaceParams::RIGHTARROWFILL:
122 message = _("Horizontal Fill (Right Arrow)");
124 case InsetSpaceParams::UPBRACEFILL:
125 message = _("Horizontal Fill (Up Brace)");
127 case InsetSpaceParams::DOWNBRACEFILL:
128 message = _("Horizontal Fill (Down Brace)");
130 case InsetSpaceParams::CUSTOM:
132 message = support::bformat(_("Horizontal Space (%1$s)"),
133 from_ascii(params_.length.asString()));
135 case InsetSpaceParams::CUSTOM_PROTECTED:
137 message = support::bformat(_("Protected Horizontal Space (%1$s)"),
138 from_ascii(params_.length.asString()));
145 void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
147 switch (cmd.action()) {
149 case LFUN_INSET_MODIFY: {
151 string arg = to_utf8(cmd.argument());
152 if (arg == "space \\hspace{}")
153 arg += params_.length.len().empty()
154 ? " \\length 1" + string(stringFromUnit(Length::defaultUnit()))
155 : " \\length " + params_.length.asString();
156 string2params(arg, params_);
160 case LFUN_INSET_DIALOG_UPDATE:
161 cur.bv().updateDialog("space", params2string(params()));
165 Inset::doDispatch(cur, cmd);
171 bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
172 FuncStatus & status) const
174 switch (cmd.action()) {
176 case LFUN_INSET_MODIFY:
177 if (cmd.getArg(0) == "space") {
178 InsetSpaceParams params;
179 string2params(to_utf8(cmd.argument()), params);
180 status.setOnOff(params_.kind == params.kind);
181 status.setEnabled(true);
183 status.setEnabled(false);
186 case LFUN_INSET_DIALOG_UPDATE:
187 status.setEnabled(true);
190 return Inset::getStatus(cur, cmd, status);
195 int InsetSpace::rowFlags() const
197 switch (params_.kind) {
198 case InsetSpaceParams::PROTECTED:
199 case InsetSpaceParams::CUSTOM_PROTECTED:
200 case InsetSpaceParams::HFILL_PROTECTED:
201 case InsetSpaceParams::THIN:
202 case InsetSpaceParams::NEGTHIN:
203 case InsetSpaceParams::MEDIUM:
204 case InsetSpaceParams::NEGMEDIUM:
205 case InsetSpaceParams::THICK:
206 case InsetSpaceParams::NEGTHICK:
207 case InsetSpaceParams::ENSPACE:
208 case InsetSpaceParams::VISIBLE:
209 // no break after these
211 case InsetSpaceParams::NORMAL:
212 case InsetSpaceParams::QUAD:
213 case InsetSpaceParams::QQUAD:
214 case InsetSpaceParams::ENSKIP:
215 case InsetSpaceParams::CUSTOM:
216 case InsetSpaceParams::HFILL:
217 case InsetSpaceParams::DOTFILL:
218 case InsetSpaceParams::HRULEFILL:
219 case InsetSpaceParams::LEFTARROWFILL:
220 case InsetSpaceParams::RIGHTARROWFILL:
221 case InsetSpaceParams::UPBRACEFILL:
222 case InsetSpaceParams::DOWNBRACEFILL:
223 // these allow line breaking
226 return CanBreakAfter;
231 int const arrow_size = 8;
235 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
238 // The width for hfills is calculated externally in
239 // TextMetrics::setRowAlignment. The value of 5 is the
240 // minimal value when the hfill is not active.
241 dim = Dimension(5, 10, 10);
245 frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
246 dim.asc = fm.maxAscent();
247 dim.des = fm.maxDescent();
248 int const em = fm.em();
250 switch (params_.kind) {
251 case InsetSpaceParams::THIN:
252 case InsetSpaceParams::NEGTHIN:
255 case InsetSpaceParams::MEDIUM:
256 case InsetSpaceParams::NEGMEDIUM:
259 case InsetSpaceParams::THICK:
260 case InsetSpaceParams::NEGTHICK:
263 case InsetSpaceParams::PROTECTED:
264 case InsetSpaceParams::VISIBLE:
265 case InsetSpaceParams::NORMAL:
266 dim.wid = fm.width(char_type(' '));
268 case InsetSpaceParams::QUAD:
271 case InsetSpaceParams::QQUAD:
274 case InsetSpaceParams::ENSPACE:
275 case InsetSpaceParams::ENSKIP:
276 dim.wid = int(0.5 * em);
278 case InsetSpaceParams::CUSTOM:
279 case InsetSpaceParams::CUSTOM_PROTECTED: {
280 int const w = mi.base.inPixels(params_.length.len());
281 int const minw = (w < 0) ? 3 * arrow_size : 4;
282 dim.wid = max(minw, abs(w));
285 case InsetSpaceParams::HFILL:
286 case InsetSpaceParams::HFILL_PROTECTED:
287 case InsetSpaceParams::DOTFILL:
288 case InsetSpaceParams::HRULEFILL:
289 case InsetSpaceParams::LEFTARROWFILL:
290 case InsetSpaceParams::RIGHTARROWFILL:
291 case InsetSpaceParams::UPBRACEFILL:
292 case InsetSpaceParams::DOWNBRACEFILL:
299 void InsetSpace::draw(PainterInfo & pi, int x, int y) const
301 Dimension const dim = dimension(*pi.base.bv);
303 if (isHfill() || params_.length.len().value() < 0) {
304 int const asc = theFontMetrics(pi.base.font).ascent('M');
305 int const desc = theFontMetrics(pi.base.font).descent('M');
306 // Pixel height divisible by 2 for prettier fill graphics:
307 int const oddheight = (asc ^ desc) & 1;
308 int const x0 = x + 1;
309 int const x1 = x + dim.wid - 2;
310 int const y0 = y + desc - 1;
311 int const y1 = y - asc + oddheight - 1;
312 int const y2 = (y0 + y1) / 2;
313 int xoffset = (y0 - y1) / 2;
315 // Two tests for very narrow insets
316 if (xoffset > x1 - x0
317 && (params_.kind == InsetSpaceParams::LEFTARROWFILL
318 || params_.kind == InsetSpaceParams::RIGHTARROWFILL))
320 if (xoffset * 6 > (x1 - x0)
321 && (params_.kind == InsetSpaceParams::UPBRACEFILL
322 || params_.kind == InsetSpaceParams::DOWNBRACEFILL))
323 xoffset = (x1 - x0) / 6;
325 int const x2 = x0 + xoffset;
326 int const x3 = x1 - xoffset;
327 int const xm = (x0 + x1) / 2;
328 int const xml = xm - xoffset;
329 int const xmr = xm + xoffset;
331 if (params_.kind == InsetSpaceParams::HFILL) {
332 pi.pain.line(x0, y1, x0, y0, Color_added_space);
333 pi.pain.line(x0, y2, x1, y2, Color_added_space,
334 frontend::Painter::line_onoffdash);
335 pi.pain.line(x1, y1, x1, y0, Color_added_space);
336 } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
337 pi.pain.line(x0, y1, x0, y0, Color_latex);
338 pi.pain.line(x0, y2, x1, y2, Color_latex,
339 frontend::Painter::line_onoffdash);
340 pi.pain.line(x1, y1, x1, y0, Color_latex);
341 } else if (params_.kind == InsetSpaceParams::DOTFILL) {
342 pi.pain.line(x0, y1, x0, y0, Color_special);
343 pi.pain.line(x0, y0, x1, y0, Color_special,
344 frontend::Painter::line_onoffdash);
345 pi.pain.line(x1, y1, x1, y0, Color_special);
346 } else if (params_.kind == InsetSpaceParams::HRULEFILL) {
347 pi.pain.line(x0, y1, x0, y0, Color_special);
348 pi.pain.line(x0, y0, x1, y0, Color_special);
349 pi.pain.line(x1, y1, x1, y0, Color_special);
350 } else if (params_.kind == InsetSpaceParams::LEFTARROWFILL) {
351 pi.pain.line(x2, y1 + 1 , x0 + 1, y2, Color_special);
352 pi.pain.line(x0 + 1, y2 + 1 , x2, y0, Color_special);
353 pi.pain.line(x0, y2 , x1, y2, Color_special);
354 } else if (params_.kind == InsetSpaceParams::RIGHTARROWFILL) {
355 pi.pain.line(x3 + 1, y1 + 1 , x1, y2, Color_special);
356 pi.pain.line(x1, y2 + 1 , x3 + 1, y0, Color_special);
357 pi.pain.line(x0, y2 , x1, y2, Color_special);
358 } else if (params_.kind == InsetSpaceParams::UPBRACEFILL) {
359 pi.pain.line(x0 + 1, y1 + 1 , x2, y2, Color_special);
360 pi.pain.line(x2, y2 , xml, y2, Color_special);
361 pi.pain.line(xml + 1, y2 + 1 , xm, y0, Color_special);
362 pi.pain.line(xm + 1, y0 , xmr, y2 + 1, Color_special);
363 pi.pain.line(xmr, y2 , x3, y2, Color_special);
364 pi.pain.line(x3 + 1, y2 , x1, y1 + 1, Color_special);
365 } else if (params_.kind == InsetSpaceParams::DOWNBRACEFILL) {
366 pi.pain.line(x0 + 1, y0 , x2, y2 + 1, Color_special);
367 pi.pain.line(x2, y2 , xml, y2, Color_special);
368 pi.pain.line(xml + 1, y2 , xm, y1 + 1, Color_special);
369 pi.pain.line(xm + 1, y1 + 1 , xmr, y2, Color_special);
370 pi.pain.line(xmr, y2 , x3, y2, Color_special);
371 pi.pain.line(x3 + 1, y2 + 1 , x1, y0, Color_special);
372 } else if (params_.kind == InsetSpaceParams::CUSTOM) {
373 pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_special);
374 pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_special);
375 pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_special);
376 pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_special);
377 pi.pain.line(x2, y2 , x3, y2, Color_special);
378 } else if (params_.kind == InsetSpaceParams::CUSTOM_PROTECTED) {
379 pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_latex);
380 pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_latex);
381 pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_latex);
382 pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_latex);
383 pi.pain.line(x2, y2 , x3, y2, Color_latex);
388 int const w = dim.wid;
389 int const h = theFontMetrics(pi.base.font).xHeight();
393 yp[0] = y - max(h / 4, 1);
394 if (params_.kind == InsetSpaceParams::NORMAL ||
395 params_.kind == InsetSpaceParams::PROTECTED ||
396 params_.kind == InsetSpaceParams::VISIBLE) {
397 xp[1] = x; yp[1] = y;
398 xp[2] = x + w - 1; yp[2] = y;
400 xp[1] = x; yp[1] = y + max(h / 4, 1);
401 xp[2] = x + w - 1; yp[2] = y + max(h / 4, 1);
404 yp[3] = y - max(h / 4, 1);
406 Color col = Color_special;
407 if (params_.kind == InsetSpaceParams::PROTECTED ||
408 params_.kind == InsetSpaceParams::ENSPACE ||
409 params_.kind == InsetSpaceParams::THIN ||
410 params_.kind == InsetSpaceParams::NEGTHIN ||
411 params_.kind == InsetSpaceParams::MEDIUM ||
412 params_.kind == InsetSpaceParams::NEGMEDIUM ||
413 params_.kind == InsetSpaceParams::THICK ||
414 params_.kind == InsetSpaceParams::NEGTHICK ||
415 params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
417 else if (params_.kind == InsetSpaceParams::VISIBLE)
418 col = Color_foreground;
420 pi.pain.lines(xp, yp, 4, col);
424 void InsetSpaceParams::write(ostream & os) const
427 case InsetSpaceParams::NORMAL:
430 case InsetSpaceParams::PROTECTED:
433 case InsetSpaceParams::VISIBLE:
434 os << "\\textvisiblespace{}";
436 case InsetSpaceParams::THIN:
437 os << "\\thinspace{}";
439 case InsetSpaceParams::MEDIUM:
440 os << "\\medspace{}";
442 case InsetSpaceParams::THICK:
443 os << "\\thickspace{}";
445 case InsetSpaceParams::QUAD:
448 case InsetSpaceParams::QQUAD:
451 case InsetSpaceParams::ENSPACE:
454 case InsetSpaceParams::ENSKIP:
457 case InsetSpaceParams::NEGTHIN:
458 os << "\\negthinspace{}";
460 case InsetSpaceParams::NEGMEDIUM:
461 os << "\\negmedspace{}";
463 case InsetSpaceParams::NEGTHICK:
464 os << "\\negthickspace{}";
466 case InsetSpaceParams::HFILL:
469 case InsetSpaceParams::HFILL_PROTECTED:
470 os << "\\hspace*{\\fill}";
472 case InsetSpaceParams::DOTFILL:
475 case InsetSpaceParams::HRULEFILL:
476 os << "\\hrulefill{}";
478 case InsetSpaceParams::LEFTARROWFILL:
479 os << "\\leftarrowfill{}";
481 case InsetSpaceParams::RIGHTARROWFILL:
482 os << "\\rightarrowfill{}";
484 case InsetSpaceParams::UPBRACEFILL:
485 os << "\\upbracefill{}";
487 case InsetSpaceParams::DOWNBRACEFILL:
488 os << "\\downbracefill{}";
490 case InsetSpaceParams::CUSTOM:
493 case InsetSpaceParams::CUSTOM_PROTECTED:
498 if (!length.len().empty())
499 os << "\n\\length " << length.asString();
503 void InsetSpaceParams::read(Lexer & lex)
505 lex.setContext("InsetSpaceParams::read");
509 // The tests for math might be disabled after a file format change
510 if (command == "\\space{}")
511 kind = InsetSpaceParams::NORMAL;
512 else if (command == "~")
513 kind = InsetSpaceParams::PROTECTED;
514 else if (command == "\\textvisiblespace{}")
515 kind = InsetSpaceParams::VISIBLE;
516 else if (command == "\\thinspace{}")
517 kind = InsetSpaceParams::THIN;
518 else if (command == "\\medspace{}")
519 kind = InsetSpaceParams::MEDIUM;
520 else if (command == "\\thickspace{}")
521 kind = InsetSpaceParams::THICK;
522 else if (command == "\\quad{}")
523 kind = InsetSpaceParams::QUAD;
524 else if (command == "\\qquad{}")
525 kind = InsetSpaceParams::QQUAD;
526 else if (command == "\\enspace{}")
527 kind = InsetSpaceParams::ENSPACE;
528 else if (command == "\\enskip{}")
529 kind = InsetSpaceParams::ENSKIP;
530 else if (command == "\\negthinspace{}")
531 kind = InsetSpaceParams::NEGTHIN;
532 else if (command == "\\negmedspace{}")
533 kind = InsetSpaceParams::NEGMEDIUM;
534 else if (command == "\\negthickspace{}")
535 kind = InsetSpaceParams::NEGTHICK;
536 else if (command == "\\hfill{}")
537 kind = InsetSpaceParams::HFILL;
538 else if (command == "\\hspace*{\\fill}")
539 kind = InsetSpaceParams::HFILL_PROTECTED;
540 else if (command == "\\dotfill{}")
541 kind = InsetSpaceParams::DOTFILL;
542 else if (command == "\\hrulefill{}")
543 kind = InsetSpaceParams::HRULEFILL;
544 else if (command == "\\hspace{}")
545 kind = InsetSpaceParams::CUSTOM;
546 else if (command == "\\leftarrowfill{}")
547 kind = InsetSpaceParams::LEFTARROWFILL;
548 else if (command == "\\rightarrowfill{}")
549 kind = InsetSpaceParams::RIGHTARROWFILL;
550 else if (command == "\\upbracefill{}")
551 kind = InsetSpaceParams::UPBRACEFILL;
552 else if (command == "\\downbracefill{}")
553 kind = InsetSpaceParams::DOWNBRACEFILL;
554 else if (command == "\\hspace*{}")
555 kind = InsetSpaceParams::CUSTOM_PROTECTED;
557 lex.printError("InsetSpace: Unknown kind: `$$Token'");
559 if (lex.checkFor("\\length"))
564 void InsetSpace::write(ostream & os) const
571 void InsetSpace::read(Lexer & lex)
574 lex >> "\\end_inset";
578 void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const
580 switch (params_.kind) {
581 case InsetSpaceParams::NORMAL:
582 os << (runparams.free_spacing && (runparams.for_search == OutputParams::NoSearch) ? " " : "\\ ");
584 case InsetSpaceParams::PROTECTED:
585 if (runparams.local_font &&
586 runparams.local_font->language()->lang() == "polutonikogreek")
587 // in babel's polutonikogreek, ~ is active
588 os << (runparams.free_spacing && (runparams.for_search == OutputParams::NoSearch) ? " " : "\\nobreakspace{}");
590 os << (runparams.free_spacing && (runparams.for_search == OutputParams::NoSearch) ? ' ' : '~');
592 case InsetSpaceParams::VISIBLE:
593 os << (runparams.free_spacing && (runparams.for_search == OutputParams::NoSearch) ? " " : "\\textvisiblespace{}");
595 case InsetSpaceParams::THIN:
596 if (runparams.for_search != OutputParams::NoSearch)
597 os << "\\thinspace{}";
599 os << (runparams.free_spacing ? " " : "\\,");
601 case InsetSpaceParams::MEDIUM:
602 if (runparams.for_search != OutputParams::NoSearch)
603 os << "\\medspace{}";
604 else if (params_.math)
605 os << (runparams.free_spacing ? " " : "\\:");
607 os << (runparams.free_spacing ? " " : "\\medspace{}");
609 case InsetSpaceParams::THICK:
610 if (runparams.for_search != OutputParams::NoSearch)
611 os << "\\thickspace{}";
612 else if (params_.math)
613 os << (runparams.free_spacing ? " " : "\\;");
615 os << (runparams.free_spacing ? " " : "\\thickspace{}");
617 case InsetSpaceParams::QUAD:
618 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\quad{}");
620 case InsetSpaceParams::QQUAD:
621 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\qquad{}");
623 case InsetSpaceParams::ENSPACE:
624 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\enspace{}");
626 case InsetSpaceParams::ENSKIP:
627 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\enskip{}");
629 case InsetSpaceParams::NEGTHIN:
630 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\negthinspace{}");
632 case InsetSpaceParams::NEGMEDIUM:
633 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\negmedspace{}");
635 case InsetSpaceParams::NEGTHICK:
636 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\negthickspace{}");
638 case InsetSpaceParams::HFILL:
639 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\hfill{}");
641 case InsetSpaceParams::HFILL_PROTECTED:
642 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\hspace*{\\fill}");
644 case InsetSpaceParams::DOTFILL:
645 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\dotfill{}");
647 case InsetSpaceParams::HRULEFILL:
648 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\hrulefill{}");
650 case InsetSpaceParams::LEFTARROWFILL:
651 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\leftarrowfill{}");
653 case InsetSpaceParams::RIGHTARROWFILL:
654 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\rightarrowfill{}");
656 case InsetSpaceParams::UPBRACEFILL:
657 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\upbracefill{}");
659 case InsetSpaceParams::DOWNBRACEFILL:
660 os << (runparams.free_spacing && (runparams.for_search != OutputParams::NoSearch) ? " " : "\\downbracefill{}");
662 case InsetSpaceParams::CUSTOM:
663 if (runparams.free_spacing)
666 os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
668 case InsetSpaceParams::CUSTOM_PROTECTED:
669 if (runparams.free_spacing)
672 os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
678 int InsetSpace::plaintext(odocstringstream & os,
679 OutputParams const &, size_t) const
681 switch (params_.kind) {
682 case InsetSpaceParams::HFILL:
683 case InsetSpaceParams::HFILL_PROTECTED:
686 case InsetSpaceParams::DOTFILL:
689 case InsetSpaceParams::HRULEFILL:
692 case InsetSpaceParams::LEFTARROWFILL:
695 case InsetSpaceParams::RIGHTARROWFILL:
698 case InsetSpaceParams::UPBRACEFILL:
701 case InsetSpaceParams::DOWNBRACEFILL:
704 case InsetSpaceParams::VISIBLE:
707 case InsetSpaceParams::ENSKIP:
710 case InsetSpaceParams::ENSPACE:
711 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
713 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
715 case InsetSpaceParams::QUAD:
718 case InsetSpaceParams::QQUAD:
722 case InsetSpaceParams::THIN:
725 case InsetSpaceParams::MEDIUM:
726 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
728 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
730 case InsetSpaceParams::THICK:
731 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
733 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
735 case InsetSpaceParams::PROTECTED:
736 case InsetSpaceParams::CUSTOM_PROTECTED:
739 case InsetSpaceParams::NEGTHIN:
740 case InsetSpaceParams::NEGMEDIUM:
741 case InsetSpaceParams::NEGTHICK:
750 void InsetSpace::docbook(XMLStream & xs, OutputParams const &) const
752 switch (params_.kind) {
753 case InsetSpaceParams::NORMAL:
754 xs << XMLStream::ESCAPE_NONE << " ";
756 case InsetSpaceParams::QUAD:
757 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
759 case InsetSpaceParams::QQUAD:
760 xs << XMLStream::ESCAPE_NONE << "  "; // HTML:   
762 case InsetSpaceParams::ENSKIP:
763 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
765 case InsetSpaceParams::PROTECTED:
766 xs << XMLStream::ESCAPE_NONE << " "; // HTML:
768 case InsetSpaceParams::VISIBLE:
769 xs << XMLStream::ESCAPE_NONE << "␣";
771 case InsetSpaceParams::ENSPACE: // HTML: ⁠ ⁠ (word joiners)
772 xs << XMLStream::ESCAPE_NONE << "⁠ ⁠";
774 case InsetSpaceParams::THIN:
775 xs << XMLStream::ESCAPE_NONE << " "; // HTML: &thinspace;
777 case InsetSpaceParams::MEDIUM:
778 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
780 case InsetSpaceParams::THICK:
781 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
783 case InsetSpaceParams::NEGTHIN:
784 case InsetSpaceParams::NEGMEDIUM:
785 case InsetSpaceParams::NEGTHICK:
786 xs << XMLStream::ESCAPE_NONE << " "; // HTML:
788 case InsetSpaceParams::HFILL:
789 case InsetSpaceParams::HFILL_PROTECTED:
790 case InsetSpaceParams::DOTFILL:
791 case InsetSpaceParams::HRULEFILL:
792 case InsetSpaceParams::LEFTARROWFILL:
793 case InsetSpaceParams::RIGHTARROWFILL:
794 case InsetSpaceParams::UPBRACEFILL:
795 case InsetSpaceParams::DOWNBRACEFILL:
796 case InsetSpaceParams::CUSTOM:
797 case InsetSpaceParams::CUSTOM_PROTECTED:
804 docstring InsetSpace::xhtml(XMLStream & xs, OutputParams const &) const
807 switch (params_.kind) {
808 case InsetSpaceParams::NORMAL:
811 case InsetSpaceParams::ENSKIP:
814 case InsetSpaceParams::ENSPACE:
815 output ="⁠ ⁠";
817 case InsetSpaceParams::QQUAD:
818 output ="  ";
820 case InsetSpaceParams::THICK:
823 case InsetSpaceParams::QUAD:
826 case InsetSpaceParams::MEDIUM:
829 case InsetSpaceParams::THIN:
832 case InsetSpaceParams::PROTECTED:
833 case InsetSpaceParams::NEGTHIN:
834 case InsetSpaceParams::NEGMEDIUM:
835 case InsetSpaceParams::NEGTHICK:
838 // no XHTML entity, only unicode code for space character exists
839 case InsetSpaceParams::VISIBLE:
842 case InsetSpaceParams::HFILL:
843 case InsetSpaceParams::HFILL_PROTECTED:
844 case InsetSpaceParams::DOTFILL:
845 case InsetSpaceParams::HRULEFILL:
846 case InsetSpaceParams::LEFTARROWFILL:
847 case InsetSpaceParams::RIGHTARROWFILL:
848 case InsetSpaceParams::UPBRACEFILL:
849 case InsetSpaceParams::DOWNBRACEFILL:
851 // Can we do anything with those in HTML?
853 case InsetSpaceParams::CUSTOM:
855 // Probably we could do some sort of blank span?
857 case InsetSpaceParams::CUSTOM_PROTECTED:
859 // Probably we could do some sort of blank span?
863 // don't escape the entities!
864 xs << XMLStream::ESCAPE_NONE << from_ascii(output);
869 void InsetSpace::validate(LaTeXFeatures & features) const
871 if (features.isAvailable("LaTeX-2020/10/01"))
872 // As of this version, the LaTeX kernel
873 // includes all spaces.
876 // In earlier versions, we require amsmath
877 // for some text and math spaces
878 if ((params_.kind == InsetSpaceParams::NEGMEDIUM
879 || params_.kind == InsetSpaceParams::NEGTHICK)
881 && (params_.kind == InsetSpaceParams::MEDIUM
882 || params_.kind == InsetSpaceParams::THICK)))
883 features.require("amsmath");
887 void InsetSpace::toString(odocstream & os) const
889 odocstringstream ods;
890 plaintext(ods, OutputParams(0));
895 void InsetSpace::forOutliner(docstring & os, size_t const, bool const) const
897 // There's no need to be cute here.
902 bool InsetSpace::isHfill() const
904 return params_.kind == InsetSpaceParams::HFILL
905 || params_.kind == InsetSpaceParams::HFILL_PROTECTED
906 || params_.kind == InsetSpaceParams::DOTFILL
907 || params_.kind == InsetSpaceParams::HRULEFILL
908 || params_.kind == InsetSpaceParams::LEFTARROWFILL
909 || params_.kind == InsetSpaceParams::RIGHTARROWFILL
910 || params_.kind == InsetSpaceParams::UPBRACEFILL
911 || params_.kind == InsetSpaceParams::DOWNBRACEFILL;
915 string InsetSpace::contextMenuName() const
917 return "context-space";
921 void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
923 params = InsetSpaceParams();
927 istringstream data(in);
930 lex.setContext("InsetSpace::string2params");
932 string const name = lex.getString();
933 if (name == "mathspace")
937 // we can try to read this even if the name is wrong
938 LATTEST(name == "space");
941 // There are cases, such as when we are called via getStatus() from
942 // Dialog::canApply(), where we are just called with "space" rather
943 // than a full "space \type{}\n\\end_inset".
949 string InsetSpace::params2string(InsetSpaceParams const & params)
954 data << "space" << ' ';