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