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 "OutputParams.h"
28 #include "texstream.h"
31 #include "support/debug.h"
32 #include "support/docstream.h"
33 #include "support/gettext.h"
34 #include "support/lassert.h"
35 #include "support/Length.h"
36 #include "support/lstrings.h"
38 #include "frontends/Application.h"
39 #include "frontends/FontMetrics.h"
40 #include "frontends/Painter.h"
47 InsetSpace::InsetSpace(InsetSpaceParams const & params)
48 : Inset(0), params_(params)
52 InsetSpaceParams::Kind InsetSpace::kind() const
58 GlueLength InsetSpace::length() const
60 return params_.length;
64 docstring InsetSpace::toolTip(BufferView const &, int, int) const
67 switch (params_.kind) {
68 case InsetSpaceParams::NORMAL:
69 message = _("Interword Space");
71 case InsetSpaceParams::PROTECTED:
72 message = _("Protected Space");
74 case InsetSpaceParams::VISIBLE:
75 message = _("Visible Space");
77 case InsetSpaceParams::THIN:
78 message = _("Thin Space");
80 case InsetSpaceParams::MEDIUM:
81 message = _("Medium Space");
83 case InsetSpaceParams::THICK:
84 message = _("Thick Space");
86 case InsetSpaceParams::QUAD:
87 message = _("Quad Space");
89 case InsetSpaceParams::QQUAD:
90 message = _("Double Quad Space");
92 case InsetSpaceParams::ENSPACE:
93 message = _("Enspace");
95 case InsetSpaceParams::ENSKIP:
96 message = _("Enskip");
98 case InsetSpaceParams::NEGTHIN:
99 message = _("Negative Thin Space");
101 case InsetSpaceParams::NEGMEDIUM:
102 message = _("Negative Medium Space");
104 case InsetSpaceParams::NEGTHICK:
105 message = _("Negative Thick Space");
107 case InsetSpaceParams::HFILL:
108 message = _("Horizontal Fill");
110 case InsetSpaceParams::HFILL_PROTECTED:
111 message = _("Protected Horizontal Fill");
113 case InsetSpaceParams::DOTFILL:
114 message = _("Horizontal Fill (Dots)");
116 case InsetSpaceParams::HRULEFILL:
117 message = _("Horizontal Fill (Rule)");
119 case InsetSpaceParams::LEFTARROWFILL:
120 message = _("Horizontal Fill (Left Arrow)");
122 case InsetSpaceParams::RIGHTARROWFILL:
123 message = _("Horizontal Fill (Right Arrow)");
125 case InsetSpaceParams::UPBRACEFILL:
126 message = _("Horizontal Fill (Up Brace)");
128 case InsetSpaceParams::DOWNBRACEFILL:
129 message = _("Horizontal Fill (Down Brace)");
131 case InsetSpaceParams::CUSTOM:
133 message = support::bformat(_("Horizontal Space (%1$s)"),
134 from_ascii(params_.length.asString()));
136 case InsetSpaceParams::CUSTOM_PROTECTED:
138 message = support::bformat(_("Protected Horizontal Space (%1$s)"),
139 from_ascii(params_.length.asString()));
146 void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
148 switch (cmd.action()) {
150 case LFUN_INSET_MODIFY: {
152 string arg = to_utf8(cmd.argument());
153 if (arg == "space \\hspace{}")
154 arg += params_.length.len().empty()
155 ? " \\length 1" + string(stringFromUnit(Length::defaultUnit()))
156 : " \\length " + params_.length.asString();
157 string2params(arg, params_);
161 case LFUN_INSET_DIALOG_UPDATE:
162 cur.bv().updateDialog("space", params2string(params()));
166 Inset::doDispatch(cur, cmd);
172 bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
173 FuncStatus & status) const
175 switch (cmd.action()) {
177 case LFUN_INSET_MODIFY:
178 if (cmd.getArg(0) == "space") {
179 InsetSpaceParams params;
180 string2params(to_utf8(cmd.argument()), params);
181 status.setOnOff(params_.kind == params.kind);
182 status.setEnabled(true);
184 status.setEnabled(false);
187 case LFUN_INSET_DIALOG_UPDATE:
188 status.setEnabled(true);
191 return Inset::getStatus(cur, cmd, status);
196 Inset::RowFlags InsetSpace::rowFlags() const
198 switch (params_.kind) {
199 case InsetSpaceParams::PROTECTED:
200 case InsetSpaceParams::CUSTOM_PROTECTED:
201 case InsetSpaceParams::HFILL_PROTECTED:
202 case InsetSpaceParams::THIN:
203 case InsetSpaceParams::NEGTHIN:
204 case InsetSpaceParams::MEDIUM:
205 case InsetSpaceParams::NEGMEDIUM:
206 case InsetSpaceParams::THICK:
207 case InsetSpaceParams::NEGTHICK:
208 case InsetSpaceParams::ENSPACE:
209 case InsetSpaceParams::VISIBLE:
210 // no break after these
212 case InsetSpaceParams::NORMAL:
213 case InsetSpaceParams::QUAD:
214 case InsetSpaceParams::QQUAD:
215 case InsetSpaceParams::ENSKIP:
216 case InsetSpaceParams::CUSTOM:
217 case InsetSpaceParams::HFILL:
218 case InsetSpaceParams::DOTFILL:
219 case InsetSpaceParams::HRULEFILL:
220 case InsetSpaceParams::LEFTARROWFILL:
221 case InsetSpaceParams::RIGHTARROWFILL:
222 case InsetSpaceParams::UPBRACEFILL:
223 case InsetSpaceParams::DOWNBRACEFILL:
224 // these allow line breaking
227 return CanBreakAfter;
232 int const arrow_size = 8;
236 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
239 // The width for hfills is calculated externally in
240 // TextMetrics::setRowAlignment. The value of 5 is the
241 // minimal value when the hfill is not active.
242 dim = Dimension(5, 10, 10);
246 frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
247 dim.asc = fm.maxAscent();
248 dim.des = fm.maxDescent();
249 int const em = fm.em();
251 switch (params_.kind) {
252 case InsetSpaceParams::THIN:
253 case InsetSpaceParams::NEGTHIN:
256 case InsetSpaceParams::MEDIUM:
257 case InsetSpaceParams::NEGMEDIUM:
260 case InsetSpaceParams::THICK:
261 case InsetSpaceParams::NEGTHICK:
264 case InsetSpaceParams::PROTECTED:
265 case InsetSpaceParams::VISIBLE:
266 case InsetSpaceParams::NORMAL:
267 dim.wid = fm.width(char_type(' '));
269 case InsetSpaceParams::QUAD:
272 case InsetSpaceParams::QQUAD:
275 case InsetSpaceParams::ENSPACE:
276 case InsetSpaceParams::ENSKIP:
277 dim.wid = int(0.5 * em);
279 case InsetSpaceParams::CUSTOM:
280 case InsetSpaceParams::CUSTOM_PROTECTED: {
281 int const w = mi.base.inPixels(params_.length.len());
282 int const minw = (w < 0) ? 3 * arrow_size : 4;
283 dim.wid = max(minw, abs(w));
286 case InsetSpaceParams::HFILL:
287 case InsetSpaceParams::HFILL_PROTECTED:
288 case InsetSpaceParams::DOTFILL:
289 case InsetSpaceParams::HRULEFILL:
290 case InsetSpaceParams::LEFTARROWFILL:
291 case InsetSpaceParams::RIGHTARROWFILL:
292 case InsetSpaceParams::UPBRACEFILL:
293 case InsetSpaceParams::DOWNBRACEFILL:
300 void InsetSpace::draw(PainterInfo & pi, int x, int y) const
302 Dimension const dim = dimension(*pi.base.bv);
304 if (isHfill() || params_.length.len().value() < 0) {
305 int const asc = theFontMetrics(pi.base.font).ascent('M');
306 int const desc = theFontMetrics(pi.base.font).descent('M');
307 // Pixel height divisible by 2 for prettier fill graphics:
308 int const oddheight = (asc ^ desc) & 1;
309 int const x0 = x + 1;
310 int const x1 = x + dim.wid - 2;
311 int const y0 = y + desc - 1;
312 int const y1 = y - asc + oddheight - 1;
313 int const y2 = (y0 + y1) / 2;
314 int xoffset = (y0 - y1) / 2;
316 // Two tests for very narrow insets
317 if (xoffset > x1 - x0
318 && (params_.kind == InsetSpaceParams::LEFTARROWFILL
319 || params_.kind == InsetSpaceParams::RIGHTARROWFILL))
321 if (xoffset * 6 > (x1 - x0)
322 && (params_.kind == InsetSpaceParams::UPBRACEFILL
323 || params_.kind == InsetSpaceParams::DOWNBRACEFILL))
324 xoffset = (x1 - x0) / 6;
326 int const x2 = x0 + xoffset;
327 int const x3 = x1 - xoffset;
328 int const xm = (x0 + x1) / 2;
329 int const xml = xm - xoffset;
330 int const xmr = xm + xoffset;
332 if (params_.kind == InsetSpaceParams::HFILL) {
333 pi.pain.line(x0, y1, x0, y0, Color_added_space);
334 pi.pain.line(x0, y2, x1, y2, Color_added_space,
335 frontend::Painter::line_onoffdash);
336 pi.pain.line(x1, y1, x1, y0, Color_added_space);
337 } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
338 pi.pain.line(x0, y1, x0, y0, Color_latex);
339 pi.pain.line(x0, y2, x1, y2, Color_latex,
340 frontend::Painter::line_onoffdash);
341 pi.pain.line(x1, y1, x1, y0, Color_latex);
342 } else if (params_.kind == InsetSpaceParams::DOTFILL) {
343 pi.pain.line(x0, y1, x0, y0, Color_special);
344 pi.pain.line(x0, y0, x1, y0, Color_special,
345 frontend::Painter::line_onoffdash);
346 pi.pain.line(x1, y1, x1, y0, Color_special);
347 } else if (params_.kind == InsetSpaceParams::HRULEFILL) {
348 pi.pain.line(x0, y1, x0, y0, Color_special);
349 pi.pain.line(x0, y0, x1, y0, Color_special);
350 pi.pain.line(x1, y1, x1, y0, Color_special);
351 } else if (params_.kind == InsetSpaceParams::LEFTARROWFILL) {
352 pi.pain.line(x2, y1 + 1 , x0 + 1, y2, Color_special);
353 pi.pain.line(x0 + 1, y2 + 1 , x2, y0, Color_special);
354 pi.pain.line(x0, y2 , x1, y2, Color_special);
355 } else if (params_.kind == InsetSpaceParams::RIGHTARROWFILL) {
356 pi.pain.line(x3 + 1, y1 + 1 , x1, y2, Color_special);
357 pi.pain.line(x1, y2 + 1 , x3 + 1, y0, Color_special);
358 pi.pain.line(x0, y2 , x1, y2, Color_special);
359 } else if (params_.kind == InsetSpaceParams::UPBRACEFILL) {
360 pi.pain.line(x0 + 1, y1 + 1 , x2, y2, Color_special);
361 pi.pain.line(x2, y2 , xml, y2, Color_special);
362 pi.pain.line(xml + 1, y2 + 1 , xm, y0, Color_special);
363 pi.pain.line(xm + 1, y0 , xmr, y2 + 1, Color_special);
364 pi.pain.line(xmr, y2 , x3, y2, Color_special);
365 pi.pain.line(x3 + 1, y2 , x1, y1 + 1, Color_special);
366 } else if (params_.kind == InsetSpaceParams::DOWNBRACEFILL) {
367 pi.pain.line(x0 + 1, y0 , x2, y2 + 1, Color_special);
368 pi.pain.line(x2, y2 , xml, y2, Color_special);
369 pi.pain.line(xml + 1, y2 , xm, y1 + 1, Color_special);
370 pi.pain.line(xm + 1, y1 + 1 , xmr, y2, Color_special);
371 pi.pain.line(xmr, y2 , x3, y2, Color_special);
372 pi.pain.line(x3 + 1, y2 + 1 , x1, y0, Color_special);
373 } else if (params_.kind == InsetSpaceParams::CUSTOM) {
374 pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_special);
375 pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_special);
376 pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_special);
377 pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_special);
378 pi.pain.line(x2, y2 , x3, y2, Color_special);
379 } else if (params_.kind == InsetSpaceParams::CUSTOM_PROTECTED) {
380 pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_latex);
381 pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_latex);
382 pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_latex);
383 pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_latex);
384 pi.pain.line(x2, y2 , x3, y2, Color_latex);
389 int const w = dim.wid;
390 int const h = theFontMetrics(pi.base.font).xHeight();
394 yp[0] = y - max(h / 4, 1);
395 if (params_.kind == InsetSpaceParams::NORMAL ||
396 params_.kind == InsetSpaceParams::PROTECTED ||
397 params_.kind == InsetSpaceParams::VISIBLE) {
398 xp[1] = x + 1; yp[1] = y;
399 xp[2] = x + w - 2; yp[2] = y;
401 xp[1] = x + 1; yp[1] = y + max(h / 4, 1);
402 xp[2] = x + w - 2; yp[2] = y + max(h / 4, 1);
405 yp[3] = y - max(h / 4, 1);
407 Color col = Color_special;
408 if (params_.kind == InsetSpaceParams::PROTECTED ||
409 params_.kind == InsetSpaceParams::ENSPACE ||
410 params_.kind == InsetSpaceParams::THIN ||
411 params_.kind == InsetSpaceParams::NEGTHIN ||
412 params_.kind == InsetSpaceParams::MEDIUM ||
413 params_.kind == InsetSpaceParams::NEGMEDIUM ||
414 params_.kind == InsetSpaceParams::THICK ||
415 params_.kind == InsetSpaceParams::NEGTHICK ||
416 params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
418 else if (params_.kind == InsetSpaceParams::VISIBLE)
419 col = Color_foreground;
421 pi.pain.lines(xp, yp, 4, col);
425 void InsetSpaceParams::write(ostream & os) const
428 case InsetSpaceParams::NORMAL:
431 case InsetSpaceParams::PROTECTED:
434 case InsetSpaceParams::VISIBLE:
435 os << "\\textvisiblespace{}";
437 case InsetSpaceParams::THIN:
438 os << "\\thinspace{}";
440 case InsetSpaceParams::MEDIUM:
441 os << "\\medspace{}";
443 case InsetSpaceParams::THICK:
444 os << "\\thickspace{}";
446 case InsetSpaceParams::QUAD:
449 case InsetSpaceParams::QQUAD:
452 case InsetSpaceParams::ENSPACE:
455 case InsetSpaceParams::ENSKIP:
458 case InsetSpaceParams::NEGTHIN:
459 os << "\\negthinspace{}";
461 case InsetSpaceParams::NEGMEDIUM:
462 os << "\\negmedspace{}";
464 case InsetSpaceParams::NEGTHICK:
465 os << "\\negthickspace{}";
467 case InsetSpaceParams::HFILL:
470 case InsetSpaceParams::HFILL_PROTECTED:
471 os << "\\hspace*{\\fill}";
473 case InsetSpaceParams::DOTFILL:
476 case InsetSpaceParams::HRULEFILL:
477 os << "\\hrulefill{}";
479 case InsetSpaceParams::LEFTARROWFILL:
480 os << "\\leftarrowfill{}";
482 case InsetSpaceParams::RIGHTARROWFILL:
483 os << "\\rightarrowfill{}";
485 case InsetSpaceParams::UPBRACEFILL:
486 os << "\\upbracefill{}";
488 case InsetSpaceParams::DOWNBRACEFILL:
489 os << "\\downbracefill{}";
491 case InsetSpaceParams::CUSTOM:
494 case InsetSpaceParams::CUSTOM_PROTECTED:
499 if (!length.len().empty())
500 os << "\n\\length " << length.asString();
504 void InsetSpaceParams::read(Lexer & lex)
506 lex.setContext("InsetSpaceParams::read");
510 // The tests for math might be disabled after a file format change
511 if (command == "\\space{}")
512 kind = InsetSpaceParams::NORMAL;
513 else if (command == "~")
514 kind = InsetSpaceParams::PROTECTED;
515 else if (command == "\\textvisiblespace{}")
516 kind = InsetSpaceParams::VISIBLE;
517 else if (command == "\\thinspace{}")
518 kind = InsetSpaceParams::THIN;
519 else if (command == "\\medspace{}")
520 kind = InsetSpaceParams::MEDIUM;
521 else if (command == "\\thickspace{}")
522 kind = InsetSpaceParams::THICK;
523 else if (command == "\\quad{}")
524 kind = InsetSpaceParams::QUAD;
525 else if (command == "\\qquad{}")
526 kind = InsetSpaceParams::QQUAD;
527 else if (command == "\\enspace{}")
528 kind = InsetSpaceParams::ENSPACE;
529 else if (command == "\\enskip{}")
530 kind = InsetSpaceParams::ENSKIP;
531 else if (command == "\\negthinspace{}")
532 kind = InsetSpaceParams::NEGTHIN;
533 else if (command == "\\negmedspace{}")
534 kind = InsetSpaceParams::NEGMEDIUM;
535 else if (command == "\\negthickspace{}")
536 kind = InsetSpaceParams::NEGTHICK;
537 else if (command == "\\hfill{}")
538 kind = InsetSpaceParams::HFILL;
539 else if (command == "\\hspace*{\\fill}")
540 kind = InsetSpaceParams::HFILL_PROTECTED;
541 else if (command == "\\dotfill{}")
542 kind = InsetSpaceParams::DOTFILL;
543 else if (command == "\\hrulefill{}")
544 kind = InsetSpaceParams::HRULEFILL;
545 else if (command == "\\hspace{}")
546 kind = InsetSpaceParams::CUSTOM;
547 else if (command == "\\leftarrowfill{}")
548 kind = InsetSpaceParams::LEFTARROWFILL;
549 else if (command == "\\rightarrowfill{}")
550 kind = InsetSpaceParams::RIGHTARROWFILL;
551 else if (command == "\\upbracefill{}")
552 kind = InsetSpaceParams::UPBRACEFILL;
553 else if (command == "\\downbracefill{}")
554 kind = InsetSpaceParams::DOWNBRACEFILL;
555 else if (command == "\\hspace*{}")
556 kind = InsetSpaceParams::CUSTOM_PROTECTED;
558 lex.printError("InsetSpace: Unknown kind: `$$Token'");
560 if (lex.checkFor("\\length"))
565 void InsetSpace::write(ostream & os) const
572 void InsetSpace::read(Lexer & lex)
575 lex >> "\\end_inset";
579 void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const
581 switch (params_.kind) {
582 case InsetSpaceParams::NORMAL:
583 os << (runparams.free_spacing ? " " : "\\ ");
585 case InsetSpaceParams::PROTECTED:
586 if (runparams.local_font &&
587 runparams.local_font->language()->lang() == "polutonikogreek")
588 // in babel's polutonikogreek, ~ is active
589 os << (runparams.free_spacing ? " " : "\\nobreakspace{}");
591 os << (runparams.free_spacing ? ' ' : '~');
593 case InsetSpaceParams::VISIBLE:
594 os << (runparams.free_spacing ? " " : "\\textvisiblespace{}");
596 case InsetSpaceParams::THIN:
597 os << (runparams.free_spacing ? " " : "\\,");
599 case InsetSpaceParams::MEDIUM:
601 os << (runparams.free_spacing ? " " : "\\:");
603 os << (runparams.free_spacing ? " " : "\\medspace{}");
605 case InsetSpaceParams::THICK:
607 os << (runparams.free_spacing ? " " : "\\;");
609 os << (runparams.free_spacing ? " " : "\\thickspace{}");
611 case InsetSpaceParams::QUAD:
612 os << (runparams.free_spacing ? " " : "\\quad{}");
614 case InsetSpaceParams::QQUAD:
615 os << (runparams.free_spacing ? " " : "\\qquad{}");
617 case InsetSpaceParams::ENSPACE:
618 os << (runparams.free_spacing ? " " : "\\enspace{}");
620 case InsetSpaceParams::ENSKIP:
621 os << (runparams.free_spacing ? " " : "\\enskip{}");
623 case InsetSpaceParams::NEGTHIN:
624 os << (runparams.free_spacing ? " " : "\\negthinspace{}");
626 case InsetSpaceParams::NEGMEDIUM:
627 os << (runparams.free_spacing ? " " : "\\negmedspace{}");
629 case InsetSpaceParams::NEGTHICK:
630 os << (runparams.free_spacing ? " " : "\\negthickspace{}");
632 case InsetSpaceParams::HFILL:
633 os << (runparams.free_spacing ? " " : "\\hfill{}");
635 case InsetSpaceParams::HFILL_PROTECTED:
636 os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}");
638 case InsetSpaceParams::DOTFILL:
639 os << (runparams.free_spacing ? " " : "\\dotfill{}");
641 case InsetSpaceParams::HRULEFILL:
642 os << (runparams.free_spacing ? " " : "\\hrulefill{}");
644 case InsetSpaceParams::LEFTARROWFILL:
645 os << (runparams.free_spacing ? " " : "\\leftarrowfill{}");
647 case InsetSpaceParams::RIGHTARROWFILL:
648 os << (runparams.free_spacing ? " " : "\\rightarrowfill{}");
650 case InsetSpaceParams::UPBRACEFILL:
651 os << (runparams.free_spacing ? " " : "\\upbracefill{}");
653 case InsetSpaceParams::DOWNBRACEFILL:
654 os << (runparams.free_spacing ? " " : "\\downbracefill{}");
656 case InsetSpaceParams::CUSTOM:
657 if (runparams.free_spacing)
660 os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
662 case InsetSpaceParams::CUSTOM_PROTECTED:
663 if (runparams.free_spacing)
666 os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
672 int InsetSpace::plaintext(odocstringstream & os,
673 OutputParams const &, size_t) const
675 switch (params_.kind) {
676 case InsetSpaceParams::HFILL:
677 case InsetSpaceParams::HFILL_PROTECTED:
680 case InsetSpaceParams::DOTFILL:
683 case InsetSpaceParams::HRULEFILL:
686 case InsetSpaceParams::LEFTARROWFILL:
689 case InsetSpaceParams::RIGHTARROWFILL:
692 case InsetSpaceParams::UPBRACEFILL:
695 case InsetSpaceParams::DOWNBRACEFILL:
698 case InsetSpaceParams::VISIBLE:
701 case InsetSpaceParams::ENSKIP:
704 case InsetSpaceParams::ENSPACE:
705 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
707 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
709 case InsetSpaceParams::QUAD:
712 case InsetSpaceParams::QQUAD:
716 case InsetSpaceParams::THIN:
719 case InsetSpaceParams::MEDIUM:
720 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
722 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
724 case InsetSpaceParams::THICK:
725 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
727 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
729 case InsetSpaceParams::PROTECTED:
730 case InsetSpaceParams::CUSTOM_PROTECTED:
733 case InsetSpaceParams::NEGTHIN:
734 case InsetSpaceParams::NEGMEDIUM:
735 case InsetSpaceParams::NEGTHICK:
744 void InsetSpace::docbook(XMLStream & xs, OutputParams const &) const
746 switch (params_.kind) {
747 case InsetSpaceParams::NORMAL:
748 xs << XMLStream::ESCAPE_NONE << " ";
750 case InsetSpaceParams::QUAD:
751 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
753 case InsetSpaceParams::QQUAD:
754 xs << XMLStream::ESCAPE_NONE << "  "; // HTML:   
756 case InsetSpaceParams::ENSKIP:
757 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
759 case InsetSpaceParams::PROTECTED:
760 xs << XMLStream::ESCAPE_NONE << " "; // HTML:
762 case InsetSpaceParams::VISIBLE:
763 xs << XMLStream::ESCAPE_NONE << "␣";
765 case InsetSpaceParams::ENSPACE: // HTML: ⁠ ⁠ (word joiners)
766 xs << XMLStream::ESCAPE_NONE << "⁠ ⁠";
768 case InsetSpaceParams::THIN:
769 xs << XMLStream::ESCAPE_NONE << " "; // HTML: &thinspace;
771 case InsetSpaceParams::MEDIUM:
772 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
774 case InsetSpaceParams::THICK:
775 xs << XMLStream::ESCAPE_NONE << " "; // HTML:  
777 case InsetSpaceParams::NEGTHIN:
778 case InsetSpaceParams::NEGMEDIUM:
779 case InsetSpaceParams::NEGTHICK:
780 xs << XMLStream::ESCAPE_NONE << " "; // HTML:
782 case InsetSpaceParams::HFILL:
783 case InsetSpaceParams::HFILL_PROTECTED:
784 case InsetSpaceParams::DOTFILL:
785 case InsetSpaceParams::HRULEFILL:
786 case InsetSpaceParams::LEFTARROWFILL:
787 case InsetSpaceParams::RIGHTARROWFILL:
788 case InsetSpaceParams::UPBRACEFILL:
789 case InsetSpaceParams::DOWNBRACEFILL:
790 case InsetSpaceParams::CUSTOM:
791 case InsetSpaceParams::CUSTOM_PROTECTED:
798 docstring InsetSpace::xhtml(XMLStream & xs, OutputParams const &) const
801 switch (params_.kind) {
802 case InsetSpaceParams::NORMAL:
805 case InsetSpaceParams::ENSKIP:
808 case InsetSpaceParams::ENSPACE:
809 output ="⁠ ⁠";
811 case InsetSpaceParams::QQUAD:
812 output ="  ";
814 case InsetSpaceParams::THICK:
817 case InsetSpaceParams::QUAD:
820 case InsetSpaceParams::MEDIUM:
823 case InsetSpaceParams::THIN:
826 case InsetSpaceParams::PROTECTED:
827 case InsetSpaceParams::NEGTHIN:
828 case InsetSpaceParams::NEGMEDIUM:
829 case InsetSpaceParams::NEGTHICK:
832 // no XHTML entity, only unicode code for space character exists
833 case InsetSpaceParams::VISIBLE:
836 case InsetSpaceParams::HFILL:
837 case InsetSpaceParams::HFILL_PROTECTED:
838 case InsetSpaceParams::DOTFILL:
839 case InsetSpaceParams::HRULEFILL:
840 case InsetSpaceParams::LEFTARROWFILL:
841 case InsetSpaceParams::RIGHTARROWFILL:
842 case InsetSpaceParams::UPBRACEFILL:
843 case InsetSpaceParams::DOWNBRACEFILL:
845 // Can we do anything with those in HTML?
847 case InsetSpaceParams::CUSTOM:
849 // Probably we could do some sort of blank span?
851 case InsetSpaceParams::CUSTOM_PROTECTED:
853 // Probably we could do some sort of blank span?
857 // don't escape the entities!
858 xs << XMLStream::ESCAPE_NONE << from_ascii(output);
863 void InsetSpace::validate(LaTeXFeatures & features) const
865 if ((params_.kind == InsetSpaceParams::NEGMEDIUM
866 || params_.kind == InsetSpaceParams::NEGTHICK)
868 && (params_.kind == InsetSpaceParams::MEDIUM
869 || params_.kind == InsetSpaceParams::THICK)))
870 features.require("amsmath");
874 void InsetSpace::toString(odocstream & os) const
876 odocstringstream ods;
877 plaintext(ods, OutputParams(0));
882 void InsetSpace::forOutliner(docstring & os, size_t const, bool const) const
884 // There's no need to be cute here.
889 bool InsetSpace::isHfill() const
891 return params_.kind == InsetSpaceParams::HFILL
892 || params_.kind == InsetSpaceParams::HFILL_PROTECTED
893 || params_.kind == InsetSpaceParams::DOTFILL
894 || params_.kind == InsetSpaceParams::HRULEFILL
895 || params_.kind == InsetSpaceParams::LEFTARROWFILL
896 || params_.kind == InsetSpaceParams::RIGHTARROWFILL
897 || params_.kind == InsetSpaceParams::UPBRACEFILL
898 || params_.kind == InsetSpaceParams::DOWNBRACEFILL;
902 string InsetSpace::contextMenuName() const
904 return "context-space";
908 void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
910 params = InsetSpaceParams();
914 istringstream data(in);
917 lex.setContext("InsetSpace::string2params");
919 string const name = lex.getString();
920 if (name == "mathspace")
924 // we can try to read this even if the name is wrong
925 LATTEST(name == "space");
928 // There are cases, such as when we are called via getStatus() from
929 // Dialog::canApply(), where we are just called with "space" rather
930 // than a full "space \type{}\n\\end_inset".
936 string InsetSpace::params2string(InsetSpaceParams const & params)
941 data << "space" << ' ';