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