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