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