]> git.lyx.org Git - lyx.git/blob - src/insets/InsetSpace.cpp
Fix trailing whitespace in cpp files.
[lyx.git] / src / insets / InsetSpace.cpp
1 /**
2  * \file InsetSpace.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup Nielsen
7  * \author Jean-Marc Lasgouttes
8  * \author Lars Gullik Bjønnes
9  * \author Jürgen Spitzmüller
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "InsetSpace.h"
17
18 #include "BufferView.h"
19 #include "Cursor.h"
20 #include "Dimension.h"
21 #include "FuncRequest.h"
22 #include "FuncStatus.h"
23 #include "Language.h"
24 #include "LaTeXFeatures.h"
25 #include "Length.h"
26 #include "Lexer.h"
27 #include "MetricsInfo.h"
28 #include "OutputParams.h"
29 #include "output_xhtml.h"
30 #include "texstream.h"
31
32 #include "support/debug.h"
33 #include "support/docstream.h"
34 #include "support/gettext.h"
35 #include "support/lassert.h"
36 #include "support/lstrings.h"
37
38 #include "frontends/Application.h"
39 #include "frontends/FontMetrics.h"
40 #include "frontends/Painter.h"
41
42 using namespace std;
43
44 namespace lyx {
45
46
47 InsetSpace::InsetSpace(InsetSpaceParams const & params)
48         : Inset(0), params_(params)
49 {}
50
51
52 InsetSpaceParams::Kind InsetSpace::kind() const
53 {
54         return params_.kind;
55 }
56
57
58 GlueLength InsetSpace::length() const
59 {
60         return params_.length;
61 }
62
63
64 docstring InsetSpace::toolTip(BufferView const &, int, int) const
65 {
66         docstring message;
67         switch (params_.kind) {
68         case InsetSpaceParams::NORMAL:
69                 message = _("Interword Space");
70                 break;
71         case InsetSpaceParams::PROTECTED:
72                 message = _("Protected Space");
73                 break;
74         case InsetSpaceParams::VISIBLE:
75                 message = _("Visible Space");
76                 break;
77         case InsetSpaceParams::THIN:
78                 message = _("Thin Space");
79                 break;
80         case InsetSpaceParams::MEDIUM:
81                 message = _("Medium Space");
82                 break;
83         case InsetSpaceParams::THICK:
84                 message = _("Thick Space");
85                 break;
86         case InsetSpaceParams::QUAD:
87                 message = _("Quad Space");
88                 break;
89         case InsetSpaceParams::QQUAD:
90                 message = _("Double Quad Space");
91                 break;
92         case InsetSpaceParams::ENSPACE:
93                 message = _("Enspace");
94                 break;
95         case InsetSpaceParams::ENSKIP:
96                 message = _("Enskip");
97                 break;
98         case InsetSpaceParams::NEGTHIN:
99                 message = _("Negative Thin Space");
100                 break;
101         case InsetSpaceParams::NEGMEDIUM:
102                 message = _("Negative Medium Space");
103                 break;
104         case InsetSpaceParams::NEGTHICK:
105                 message = _("Negative Thick Space");
106                 break;
107         case InsetSpaceParams::HFILL:
108                 message = _("Horizontal Fill");
109                 break;
110         case InsetSpaceParams::HFILL_PROTECTED:
111                 message = _("Protected Horizontal Fill");
112                 break;
113         case InsetSpaceParams::DOTFILL:
114                 message = _("Horizontal Fill (Dots)");
115                 break;
116         case InsetSpaceParams::HRULEFILL:
117                 message = _("Horizontal Fill (Rule)");
118                 break;
119         case InsetSpaceParams::LEFTARROWFILL:
120                 message = _("Horizontal Fill (Left Arrow)");
121                 break;
122         case InsetSpaceParams::RIGHTARROWFILL:
123                 message = _("Horizontal Fill (Right Arrow)");
124                 break;
125         case InsetSpaceParams::UPBRACEFILL:
126                 message = _("Horizontal Fill (Up Brace)");
127                 break;
128         case InsetSpaceParams::DOWNBRACEFILL:
129                 message = _("Horizontal Fill (Down Brace)");
130                 break;
131         case InsetSpaceParams::CUSTOM:
132                 // FIXME unicode
133                 message = support::bformat(_("Horizontal Space (%1$s)"),
134                                 from_ascii(params_.length.asString()));
135                 break;
136         case InsetSpaceParams::CUSTOM_PROTECTED:
137                 // FIXME unicode
138                 message = support::bformat(_("Protected Horizontal Space (%1$s)"),
139                                 from_ascii(params_.length.asString()));
140                 break;
141         }
142         return message;
143 }
144
145
146 void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
147 {
148         switch (cmd.action()) {
149
150         case LFUN_INSET_MODIFY: {
151                 cur.recordUndo();
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_);
158                 break;
159         }
160
161         case LFUN_INSET_DIALOG_UPDATE:
162                 cur.bv().updateDialog("space", params2string(params()));
163                 break;
164
165         default:
166                 Inset::doDispatch(cur, cmd);
167                 break;
168         }
169 }
170
171
172 bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
173         FuncStatus & status) const
174 {
175         switch (cmd.action()) {
176         // we handle these
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);
183                 } else
184                         status.setEnabled(false);
185                 return true;
186
187         case LFUN_INSET_DIALOG_UPDATE:
188                 status.setEnabled(true);
189                 return true;
190         default:
191                 return Inset::getStatus(cur, cmd, status);
192         }
193 }
194
195
196 namespace {
197 int const arrow_size = 8;
198 }
199
200
201 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
202 {
203         if (isHfill()) {
204                 // The width for hfills is calculated externally in
205                 // TextMetrics::computeRowMetrics. The value of 5 is the
206                 // minimal value when the hfill is not active.
207                 dim = Dimension(5, 10, 10);
208                 return;
209         }
210
211         frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
212         dim.asc = fm.maxAscent();
213         dim.des = fm.maxDescent();
214         int const em = fm.em();
215
216         switch (params_.kind) {
217                 case InsetSpaceParams::THIN:
218                 case InsetSpaceParams::NEGTHIN:
219                         dim.wid = em / 6;
220                         break;
221                 case InsetSpaceParams::MEDIUM:
222                 case InsetSpaceParams::NEGMEDIUM:
223                         dim.wid = em / 4;
224                         break;
225                 case InsetSpaceParams::THICK:
226                 case InsetSpaceParams::NEGTHICK:
227                         dim.wid = em / 2;
228                         break;
229                 case InsetSpaceParams::PROTECTED:
230                 case InsetSpaceParams::VISIBLE:
231                 case InsetSpaceParams::NORMAL:
232                         dim.wid = fm.width(char_type(' '));
233                         break;
234                 case InsetSpaceParams::QUAD:
235                         dim.wid = em;
236                         break;
237                 case InsetSpaceParams::QQUAD:
238                         dim.wid = 2 * em;
239                         break;
240                 case InsetSpaceParams::ENSPACE:
241                 case InsetSpaceParams::ENSKIP:
242                         dim.wid = int(0.5 * em);
243                         break;
244                 case InsetSpaceParams::CUSTOM:
245                 case InsetSpaceParams::CUSTOM_PROTECTED: {
246                         int const w =
247                                 params_.length.len().inPixels(mi.base);
248                         int const minw = (w < 0) ? 3 * arrow_size : 4;
249                         dim.wid = max(minw, abs(w));
250                         break;
251                 }
252                 case InsetSpaceParams::HFILL:
253                 case InsetSpaceParams::HFILL_PROTECTED:
254                 case InsetSpaceParams::DOTFILL:
255                 case InsetSpaceParams::HRULEFILL:
256                 case InsetSpaceParams::LEFTARROWFILL:
257                 case InsetSpaceParams::RIGHTARROWFILL:
258                 case InsetSpaceParams::UPBRACEFILL:
259                 case InsetSpaceParams::DOWNBRACEFILL:
260                         // shut up compiler
261                         break;
262         }
263 }
264
265
266 void InsetSpace::draw(PainterInfo & pi, int x, int y) const
267 {
268         Dimension const dim = dimension(*pi.base.bv);
269
270         if (isHfill() || params_.length.len().value() < 0) {
271                 int const asc = theFontMetrics(pi.base.font).ascent('M');
272                 int const desc = theFontMetrics(pi.base.font).descent('M');
273                 // Pixel height divisible by 2 for prettier fill graphics:
274                 int const oddheight = (asc ^ desc) & 1;
275                 int const x0 = x + 1;
276                 int const x1 = x + dim.wid - 2;
277                 int const y0 = y + desc - 1;
278                 int const y1 = y - asc + oddheight - 1;
279                 int const y2 = (y0 + y1) / 2;
280                 int xoffset = (y0 - y1) / 2;
281
282                 // Two tests for very narrow insets
283                 if (xoffset > x1 - x0
284                      && (params_.kind == InsetSpaceParams::LEFTARROWFILL
285                          || params_.kind == InsetSpaceParams::RIGHTARROWFILL))
286                                 xoffset = x1 - x0;
287                 if (xoffset * 6 > (x1 - x0)
288                      && (params_.kind == InsetSpaceParams::UPBRACEFILL
289                          || params_.kind == InsetSpaceParams::DOWNBRACEFILL))
290                                 xoffset = (x1 - x0) / 6;
291
292                 int const x2 = x0 + xoffset;
293                 int const x3 = x1 - xoffset;
294                 int const xm = (x0 + x1) / 2;
295                 int const xml = xm - xoffset;
296                 int const xmr = xm + xoffset;
297
298                 if (params_.kind == InsetSpaceParams::HFILL) {
299                         pi.pain.line(x0, y1, x0, y0, Color_added_space);
300                         pi.pain.line(x0, y2, x1, y2, Color_added_space,
301                                 frontend::Painter::line_onoffdash);
302                         pi.pain.line(x1, y1, x1, y0, Color_added_space);
303                 } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
304                         pi.pain.line(x0, y1, x0, y0, Color_latex);
305                         pi.pain.line(x0, y2, x1, y2, Color_latex,
306                                 frontend::Painter::line_onoffdash);
307                         pi.pain.line(x1, y1, x1, y0, Color_latex);
308                 } else if (params_.kind == InsetSpaceParams::DOTFILL) {
309                         pi.pain.line(x0, y1, x0, y0, Color_special);
310                         pi.pain.line(x0, y0, x1, y0, Color_special,
311                                 frontend::Painter::line_onoffdash);
312                         pi.pain.line(x1, y1, x1, y0, Color_special);
313                 } else if (params_.kind == InsetSpaceParams::HRULEFILL) {
314                         pi.pain.line(x0, y1, x0, y0, Color_special);
315                         pi.pain.line(x0, y0, x1, y0, Color_special);
316                         pi.pain.line(x1, y1, x1, y0, Color_special);
317                 } else if (params_.kind == InsetSpaceParams::LEFTARROWFILL) {
318                         pi.pain.line(x2, y1 + 1 , x0 + 1, y2, Color_special);
319                         pi.pain.line(x0 + 1, y2 + 1 , x2, y0, Color_special);
320                         pi.pain.line(x0, y2 , x1, y2, Color_special);
321                 } else if (params_.kind == InsetSpaceParams::RIGHTARROWFILL) {
322                         pi.pain.line(x3 + 1, y1 + 1 , x1, y2, Color_special);
323                         pi.pain.line(x1, y2 + 1 , x3 + 1, y0, Color_special);
324                         pi.pain.line(x0, y2 , x1, y2, Color_special);
325                 } else if (params_.kind == InsetSpaceParams::UPBRACEFILL) {
326                         pi.pain.line(x0 + 1, y1 + 1 , x2, y2, Color_special);
327                         pi.pain.line(x2, y2 , xml, y2, Color_special);
328                         pi.pain.line(xml + 1, y2 + 1 , xm, y0, Color_special);
329                         pi.pain.line(xm + 1, y0 , xmr, y2 + 1, Color_special);
330                         pi.pain.line(xmr, y2 , x3, y2, Color_special);
331                         pi.pain.line(x3 + 1, y2 , x1, y1 + 1, Color_special);
332                 } else if (params_.kind == InsetSpaceParams::DOWNBRACEFILL) {
333                         pi.pain.line(x0 + 1, y0 , x2, y2 + 1, Color_special);
334                         pi.pain.line(x2, y2 , xml, y2, Color_special);
335                         pi.pain.line(xml + 1, y2 , xm, y1 + 1, Color_special);
336                         pi.pain.line(xm + 1, y1 + 1 , xmr, y2, Color_special);
337                         pi.pain.line(xmr, y2 , x3, y2, Color_special);
338                         pi.pain.line(x3 + 1, y2 + 1 , x1, y0, Color_special);
339                 } else if (params_.kind == InsetSpaceParams::CUSTOM) {
340                         pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_special);
341                         pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_special);
342                         pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_special);
343                         pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_special);
344                         pi.pain.line(x2, y2 , x3, y2, Color_special);
345                 } else if (params_.kind == InsetSpaceParams::CUSTOM_PROTECTED) {
346                         pi.pain.line(x0, y1 + 1 , x2 + 1, y2, Color_latex);
347                         pi.pain.line(x2 + 1, y2 + 1 , x0, y0, Color_latex);
348                         pi.pain.line(x1 + 1, y1 + 1 , x3, y2, Color_latex);
349                         pi.pain.line(x3, y2 + 1 , x1 + 1, y0, Color_latex);
350                         pi.pain.line(x2, y2 , x3, y2, Color_latex);
351                 }
352                 return;
353         }
354
355         int const w = dim.wid;
356         int const h = theFontMetrics(pi.base.font).ascent('x');
357         int xp[4], yp[4];
358
359         xp[0] = x;
360         yp[0] = y - max(h / 4, 1);
361         if (params_.kind == InsetSpaceParams::NORMAL ||
362             params_.kind == InsetSpaceParams::PROTECTED ||
363             params_.kind == InsetSpaceParams::VISIBLE) {
364                 xp[1] = x;     yp[1] = y;
365                 xp[2] = x + w; yp[2] = y;
366         } else {
367                 xp[1] = x;     yp[1] = y + max(h / 4, 1);
368                 xp[2] = x + w; yp[2] = y + max(h / 4, 1);
369         }
370         xp[3] = x + w;
371         yp[3] = y - max(h / 4, 1);
372
373         Color col = Color_special;
374         if (params_.kind == InsetSpaceParams::PROTECTED ||
375             params_.kind == InsetSpaceParams::ENSPACE ||
376             params_.kind == InsetSpaceParams::NEGTHIN ||
377             params_.kind == InsetSpaceParams::NEGMEDIUM ||
378             params_.kind == InsetSpaceParams::NEGTHICK ||
379             params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
380                 col = Color_latex;
381         else if (params_.kind == InsetSpaceParams::VISIBLE)
382                 col =  Color_foreground;
383
384         pi.pain.lines(xp, yp, 4, col);
385 }
386
387
388 void InsetSpaceParams::write(ostream & os) const
389 {
390         switch (kind) {
391         case InsetSpaceParams::NORMAL:
392                 os << "\\space{}";
393                 break;
394         case InsetSpaceParams::PROTECTED:
395                 os <<  "~";
396                 break;
397         case InsetSpaceParams::VISIBLE:
398                 os <<  "\\textvisiblespace{}";
399                 break;
400         case InsetSpaceParams::THIN:
401                 os <<  "\\thinspace{}";
402                 break;
403         case InsetSpaceParams::MEDIUM:
404                 os <<  "\\medspace{}";
405                 break;
406         case InsetSpaceParams::THICK:
407                 os <<  "\\thickspace{}";
408                 break;
409         case InsetSpaceParams::QUAD:
410                 os <<  "\\quad{}";
411                 break;
412         case InsetSpaceParams::QQUAD:
413                 os <<  "\\qquad{}";
414                 break;
415         case InsetSpaceParams::ENSPACE:
416                 os <<  "\\enspace{}";
417                 break;
418         case InsetSpaceParams::ENSKIP:
419                 os <<  "\\enskip{}";
420                 break;
421         case InsetSpaceParams::NEGTHIN:
422                 os <<  "\\negthinspace{}";
423                 break;
424         case InsetSpaceParams::NEGMEDIUM:
425                 os <<  "\\negmedspace{}";
426                 break;
427         case InsetSpaceParams::NEGTHICK:
428                 os <<  "\\negthickspace{}";
429                 break;
430         case InsetSpaceParams::HFILL:
431                 os <<  "\\hfill{}";
432                 break;
433         case InsetSpaceParams::HFILL_PROTECTED:
434                 os <<  "\\hspace*{\\fill}";
435                 break;
436         case InsetSpaceParams::DOTFILL:
437                 os <<  "\\dotfill{}";
438                 break;
439         case InsetSpaceParams::HRULEFILL:
440                 os <<  "\\hrulefill{}";
441                 break;
442         case InsetSpaceParams::LEFTARROWFILL:
443                 os <<  "\\leftarrowfill{}";
444                 break;
445         case InsetSpaceParams::RIGHTARROWFILL:
446                 os <<  "\\rightarrowfill{}";
447                 break;
448         case InsetSpaceParams::UPBRACEFILL:
449                 os <<  "\\upbracefill{}";
450                 break;
451         case InsetSpaceParams::DOWNBRACEFILL:
452                 os <<  "\\downbracefill{}";
453                 break;
454         case InsetSpaceParams::CUSTOM:
455                 os <<  "\\hspace{}";
456                 break;
457         case InsetSpaceParams::CUSTOM_PROTECTED:
458                 os <<  "\\hspace*{}";
459                 break;
460         }
461
462         if (!length.len().empty())
463                 os << "\n\\length " << length.asString();
464 }
465
466
467 void InsetSpaceParams::read(Lexer & lex)
468 {
469         lex.setContext("InsetSpaceParams::read");
470         string command;
471         lex >> command;
472
473         // The tests for math might be disabled after a file format change
474         if (command == "\\space{}")
475                 kind = InsetSpaceParams::NORMAL;
476         else if (command == "~")
477                 kind = InsetSpaceParams::PROTECTED;
478         else if (command == "\\textvisiblespace{}")
479                 kind = InsetSpaceParams::VISIBLE;
480         else if (command == "\\thinspace{}")
481                 kind = InsetSpaceParams::THIN;
482         else if (math && command == "\\medspace{}")
483                 kind = InsetSpaceParams::MEDIUM;
484         else if (math && command == "\\thickspace{}")
485                 kind = InsetSpaceParams::THICK;
486         else if (command == "\\quad{}")
487                 kind = InsetSpaceParams::QUAD;
488         else if (command == "\\qquad{}")
489                 kind = InsetSpaceParams::QQUAD;
490         else if (command == "\\enspace{}")
491                 kind = InsetSpaceParams::ENSPACE;
492         else if (command == "\\enskip{}")
493                 kind = InsetSpaceParams::ENSKIP;
494         else if (command == "\\negthinspace{}")
495                 kind = InsetSpaceParams::NEGTHIN;
496         else if (command == "\\negmedspace{}")
497                 kind = InsetSpaceParams::NEGMEDIUM;
498         else if (command == "\\negthickspace{}")
499                 kind = InsetSpaceParams::NEGTHICK;
500         else if (command == "\\hfill{}")
501                 kind = InsetSpaceParams::HFILL;
502         else if (command == "\\hspace*{\\fill}")
503                 kind = InsetSpaceParams::HFILL_PROTECTED;
504         else if (command == "\\dotfill{}")
505                 kind = InsetSpaceParams::DOTFILL;
506         else if (command == "\\hrulefill{}")
507                 kind = InsetSpaceParams::HRULEFILL;
508         else if (command == "\\hspace{}")
509                 kind = InsetSpaceParams::CUSTOM;
510         else if (command == "\\leftarrowfill{}")
511                 kind = InsetSpaceParams::LEFTARROWFILL;
512         else if (command == "\\rightarrowfill{}")
513                 kind = InsetSpaceParams::RIGHTARROWFILL;
514         else if (command == "\\upbracefill{}")
515                 kind = InsetSpaceParams::UPBRACEFILL;
516         else if (command == "\\downbracefill{}")
517                 kind = InsetSpaceParams::DOWNBRACEFILL;
518         else if (command == "\\hspace*{}")
519                 kind = InsetSpaceParams::CUSTOM_PROTECTED;
520         else
521                 lex.printError("InsetSpace: Unknown kind: `$$Token'");
522
523         if (lex.checkFor("\\length"))
524                 lex >> length;
525 }
526
527
528 void InsetSpace::write(ostream & os) const
529 {
530         os << "space ";
531         params_.write(os);
532 }
533
534
535 void InsetSpace::read(Lexer & lex)
536 {
537         params_.read(lex);
538         lex >> "\\end_inset";
539 }
540
541
542 void InsetSpace::latex(otexstream & os, OutputParams const & runparams) const
543 {
544         switch (params_.kind) {
545         case InsetSpaceParams::NORMAL:
546                 os << (runparams.free_spacing ? " " : "\\ ");
547                 break;
548         case InsetSpaceParams::PROTECTED:
549                 if (runparams.local_font &&
550                     runparams.local_font->language()->lang() == "polutonikogreek")
551                         // in babel's polutonikogreek, ~ is active
552                         os << (runparams.free_spacing ? " " : "\\nobreakspace{}");
553                 else
554                         os << (runparams.free_spacing ? ' ' : '~');
555                 break;
556         case InsetSpaceParams::VISIBLE:
557                 os << (runparams.free_spacing ? " " : "\\textvisiblespace{}");
558                 break;
559         case InsetSpaceParams::THIN:
560                 os << (runparams.free_spacing ? " " : "\\,");
561                 break;
562         case InsetSpaceParams::MEDIUM:
563                 os << (runparams.free_spacing ? " " : "\\:");
564                 break;
565         case InsetSpaceParams::THICK:
566                 os << (runparams.free_spacing ? " " : "\\;");
567                 break;
568         case InsetSpaceParams::QUAD:
569                 os << (runparams.free_spacing ? " " : "\\quad{}");
570                 break;
571         case InsetSpaceParams::QQUAD:
572                 os << (runparams.free_spacing ? " " : "\\qquad{}");
573                 break;
574         case InsetSpaceParams::ENSPACE:
575                 os << (runparams.free_spacing ? " " : "\\enspace{}");
576                 break;
577         case InsetSpaceParams::ENSKIP:
578                 os << (runparams.free_spacing ? " " : "\\enskip{}");
579                 break;
580         case InsetSpaceParams::NEGTHIN:
581                 os << (runparams.free_spacing ? " " : "\\negthinspace{}");
582                 break;
583         case InsetSpaceParams::NEGMEDIUM:
584                 os << (runparams.free_spacing ? " " : "\\negmedspace{}");
585                 break;
586         case InsetSpaceParams::NEGTHICK:
587                 os << (runparams.free_spacing ? " " : "\\negthickspace{}");
588                 break;
589         case InsetSpaceParams::HFILL:
590                 os << (runparams.free_spacing ? " " : "\\hfill{}");
591                 break;
592         case InsetSpaceParams::HFILL_PROTECTED:
593                 os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}");
594                 break;
595         case InsetSpaceParams::DOTFILL:
596                 os << (runparams.free_spacing ? " " : "\\dotfill{}");
597                 break;
598         case InsetSpaceParams::HRULEFILL:
599                 os << (runparams.free_spacing ? " " : "\\hrulefill{}");
600                 break;
601         case InsetSpaceParams::LEFTARROWFILL:
602                 os << (runparams.free_spacing ? " " : "\\leftarrowfill{}");
603                 break;
604         case InsetSpaceParams::RIGHTARROWFILL:
605                 os << (runparams.free_spacing ? " " : "\\rightarrowfill{}");
606                 break;
607         case InsetSpaceParams::UPBRACEFILL:
608                 os << (runparams.free_spacing ? " " : "\\upbracefill{}");
609                 break;
610         case InsetSpaceParams::DOWNBRACEFILL:
611                 os << (runparams.free_spacing ? " " : "\\downbracefill{}");
612                 break;
613         case InsetSpaceParams::CUSTOM:
614                 if (runparams.free_spacing)
615                         os << " ";
616                 else
617                         os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
618                 break;
619         case InsetSpaceParams::CUSTOM_PROTECTED:
620                 if (runparams.free_spacing)
621                         os << " ";
622                 else
623                         os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
624                 break;
625         }
626 }
627
628
629 int InsetSpace::plaintext(odocstringstream & os,
630         OutputParams const &, size_t) const
631 {
632         switch (params_.kind) {
633         case InsetSpaceParams::HFILL:
634         case InsetSpaceParams::HFILL_PROTECTED:
635                 os << "     ";
636                 return 5;
637         case InsetSpaceParams::DOTFILL:
638                 os << ".....";
639                 return 5;
640         case InsetSpaceParams::HRULEFILL:
641                 os << "_____";
642                 return 5;
643         case InsetSpaceParams::LEFTARROWFILL:
644                 os << "<----";
645                 return 5;
646         case InsetSpaceParams::RIGHTARROWFILL:
647                 os << "---->";
648                 return 5;
649         case InsetSpaceParams::UPBRACEFILL:
650                 os << "\\-v-/";
651                 return 5;
652         case InsetSpaceParams::DOWNBRACEFILL:
653                 os << "/-^-\\";
654                 return 5;
655         case InsetSpaceParams::VISIBLE:
656                 os.put(0x2423);
657                 return 1;
658         case InsetSpaceParams::ENSKIP:
659                 os.put(0x2002);
660                 return 1;
661         case InsetSpaceParams::ENSPACE:
662                 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
663                 os.put(0x2002);
664                 os.put(0x2060); // WORD JOINER, makes the breakable en space unbreakable
665                 return 3;
666         case InsetSpaceParams::QUAD:
667                 os.put(0x2003);
668                 return 1;
669         case InsetSpaceParams::QQUAD:
670                 os.put(0x2003);
671                 os.put(0x2003);
672                 return 2;
673         case InsetSpaceParams::THIN:
674                 os.put(0x202f);
675                 return 1;
676         case InsetSpaceParams::MEDIUM:
677                 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
678                 os.put(0x2005);
679                 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable medium space breakable
680                 return 1;
681         case InsetSpaceParams::THICK:
682                 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
683                 os.put(0x2004);
684                 os.put(0x200b); // ZERO WIDTH SPACE, makes the unbreakable thick space breakable
685                 return 1;
686         case InsetSpaceParams::PROTECTED:
687         case InsetSpaceParams::CUSTOM_PROTECTED:
688                 os.put(0x00a0);
689                 return 1;
690         case InsetSpaceParams::NEGTHIN:
691         case InsetSpaceParams::NEGMEDIUM:
692         case InsetSpaceParams::NEGTHICK:
693                 return 0;
694         default:
695                 os << ' ';
696                 return 1;
697         }
698 }
699
700
701 int InsetSpace::docbook(odocstream & os, OutputParams const &) const
702 {
703         switch (params_.kind) {
704         case InsetSpaceParams::NORMAL:
705                 os << " ";
706                 break;
707         case InsetSpaceParams::QUAD:
708                 os << "&emsp;";
709                 break;
710         case InsetSpaceParams::QQUAD:
711                 os << "&emsp;&emsp;";
712                 break;
713         case InsetSpaceParams::ENSKIP:
714                 os << "&ensp;";
715                 break;
716         case InsetSpaceParams::PROTECTED:
717                 os << "&nbsp;";
718                 break;
719         case InsetSpaceParams::VISIBLE:
720                 os << "&#x2423;";
721                 break;
722         case InsetSpaceParams::ENSPACE:
723                 os << "&#x2060;&ensp;&#x2060;";
724                 break;
725         case InsetSpaceParams::THIN:
726                 os << "&thinsp;";
727                 break;
728         case InsetSpaceParams::MEDIUM:
729                 os << "&emsp14;";
730                 break;
731         case InsetSpaceParams::THICK:
732                 os << "&emsp13;";
733                 break;
734         case InsetSpaceParams::NEGTHIN:
735         case InsetSpaceParams::NEGMEDIUM:
736         case InsetSpaceParams::NEGTHICK:
737                 // FIXME
738                 os << "&nbsp;";
739                 break;
740         case InsetSpaceParams::HFILL:
741         case InsetSpaceParams::HFILL_PROTECTED:
742                 os << '\n';
743                 break;
744         case InsetSpaceParams::DOTFILL:
745                 // FIXME
746                 os << '\n';
747                 break;
748         case InsetSpaceParams::HRULEFILL:
749                 // FIXME
750                 os << '\n';
751                 break;
752         case InsetSpaceParams::LEFTARROWFILL:
753         case InsetSpaceParams::RIGHTARROWFILL:
754         case InsetSpaceParams::UPBRACEFILL:
755         case InsetSpaceParams::DOWNBRACEFILL:
756         case InsetSpaceParams::CUSTOM:
757         case InsetSpaceParams::CUSTOM_PROTECTED:
758                 // FIXME
759                 os << '\n';
760                 break;
761         }
762         return 0;
763 }
764
765
766 docstring InsetSpace::xhtml(XHTMLStream & xs, OutputParams const &) const
767 {
768         string output;
769         switch (params_.kind) {
770         case InsetSpaceParams::NORMAL:
771                 output = " ";
772                 break;
773         case InsetSpaceParams::ENSKIP:
774                 output ="&ensp;";
775                 break;
776         case InsetSpaceParams::ENSPACE:
777                 output ="&#x2060;&ensp;&#x2060;";
778                 break;
779         case InsetSpaceParams::QQUAD:
780                 output ="&emsp;&emsp;";
781                 break;
782         case InsetSpaceParams::THICK:
783                 output ="&#x2004;";
784                 break;
785         case InsetSpaceParams::QUAD:
786                 output ="&emsp;";
787                 break;
788         case InsetSpaceParams::MEDIUM:
789                 output ="&#x2005;";
790                 break;
791         case InsetSpaceParams::THIN:
792                 output ="&thinsp;";
793                 break;
794         case InsetSpaceParams::PROTECTED:
795         case InsetSpaceParams::NEGTHIN:
796         case InsetSpaceParams::NEGMEDIUM:
797         case InsetSpaceParams::NEGTHICK:
798                 output ="&nbsp;";
799                 break;
800         // no XHTML entity, only unicode code for space character exists
801         case InsetSpaceParams::VISIBLE:
802                 output ="&#x2423;";
803                 break;
804         case InsetSpaceParams::HFILL:
805         case InsetSpaceParams::HFILL_PROTECTED:
806         case InsetSpaceParams::DOTFILL:
807         case InsetSpaceParams::HRULEFILL:
808         case InsetSpaceParams::LEFTARROWFILL:
809         case InsetSpaceParams::RIGHTARROWFILL:
810         case InsetSpaceParams::UPBRACEFILL:
811         case InsetSpaceParams::DOWNBRACEFILL:
812                 // FIXME XHTML
813                 // Can we do anything with those in HTML?
814                 break;
815         case InsetSpaceParams::CUSTOM:
816                 // FIXME XHTML
817                 // Probably we could do some sort of blank span?
818                 break;
819         case InsetSpaceParams::CUSTOM_PROTECTED:
820                 // FIXME XHTML
821                 // Probably we could do some sort of blank span?
822                 output ="&nbsp;";
823                 break;
824         }
825         // don't escape the entities!
826         xs << XHTMLStream::ESCAPE_NONE << from_ascii(output);
827         return docstring();
828 }
829
830
831 void InsetSpace::validate(LaTeXFeatures & features) const
832 {
833         if (params_.kind == InsetSpaceParams::NEGMEDIUM ||
834             params_.kind == InsetSpaceParams::NEGTHICK)
835                 features.require("amsmath");
836 }
837
838
839 void InsetSpace::toString(odocstream & os) const
840 {
841         odocstringstream ods;
842         plaintext(ods, OutputParams(0));
843         os << ods.str();
844 }
845
846
847 void InsetSpace::forOutliner(docstring & os, size_t const, bool const) const
848 {
849         // There's no need to be cute here.
850         os += " ";
851 }
852
853
854 bool InsetSpace::isHfill() const
855 {
856         return params_.kind == InsetSpaceParams::HFILL
857                 || params_.kind == InsetSpaceParams::HFILL_PROTECTED
858                 || params_.kind == InsetSpaceParams::DOTFILL
859                 || params_.kind == InsetSpaceParams::HRULEFILL
860                 || params_.kind == InsetSpaceParams::LEFTARROWFILL
861                 || params_.kind == InsetSpaceParams::RIGHTARROWFILL
862                 || params_.kind == InsetSpaceParams::UPBRACEFILL
863                 || params_.kind == InsetSpaceParams::DOWNBRACEFILL;
864 }
865
866
867 string InsetSpace::contextMenuName() const
868 {
869         return "context-space";
870 }
871
872
873 void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
874 {
875         params = InsetSpaceParams();
876         if (in.empty())
877                 return;
878
879         istringstream data(in);
880         Lexer lex;
881         lex.setStream(data);
882         lex.setContext("InsetSpace::string2params");
883         lex.next();
884         string const name = lex.getString();
885         if (name == "mathspace")
886                 params.math = true;
887         else {
888                 params.math = false;
889                 // we can try to read this even if the name is wrong
890                 LATTEST(name == "space");
891         }
892
893         // There are cases, such as when we are called via getStatus() from
894         // Dialog::canApply(), where we are just called with "space" rather
895         // than a full "space \type{}\n\\end_inset".
896         if (lex.isOK())
897                 params.read(lex);
898 }
899
900
901 string InsetSpace::params2string(InsetSpaceParams const & params)
902 {
903         ostringstream data;
904         if (params.math)
905                 data << "math";
906         data << "space" << ' ';
907         params.write(data);
908         return data.str();
909 }
910
911
912 } // namespace lyx