]> git.lyx.org Git - features.git/blob - src/insets/InsetSpace.cpp
lexer cosmetics
[features.git] / src / insets / InsetSpace.cpp
1 /**
2  * \file InsetSpace.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup Nielsen
7  * \author Jean-Marc Lasgouttes
8  * \author Lars Gullik Bjønnes
9  * \author Jürgen Spitzmüller
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "InsetSpace.h"
17
18 #include "BufferView.h"
19 #include "Cursor.h"
20 #include "Dimension.h"
21 #include "FuncRequest.h"
22 #include "FuncStatus.h"
23 #include "Length.h"
24 #include "Lexer.h"
25 #include "MetricsInfo.h"
26 #include "OutputParams.h"
27
28 #include "support/debug.h"
29 #include "support/docstream.h"
30 #include "support/gettext.h"
31 #include "support/lstrings.h"
32
33 #include "frontends/Application.h"
34 #include "frontends/FontMetrics.h"
35 #include "frontends/Painter.h"
36
37 using namespace std;
38
39 namespace lyx {
40
41
42 InsetSpace::InsetSpace(InsetSpaceParams const & params)
43         : params_(params)
44 {}
45
46
47 InsetSpaceParams::Kind InsetSpace::kind() const
48 {
49         return params_.kind;
50 }
51
52
53 Length InsetSpace::length() const
54 {
55         return params_.length;
56 }
57
58
59 InsetSpace::~InsetSpace()
60 {
61         hideDialogs("space", this);
62 }
63
64
65 docstring InsetSpace::toolTip(BufferView const &, int, int) const
66 {
67         docstring message;
68         switch (params_.kind) {
69         case InsetSpaceParams::NORMAL:
70                 message = _("Interword Space");
71                 break;
72         case InsetSpaceParams::PROTECTED:
73                 message = _("Protected Space");
74                 break;
75         case InsetSpaceParams::THIN:
76                 message = _("Thin Space");
77                 break;
78         case InsetSpaceParams::QUAD:
79                 message = _("Quad Space");
80                 break;
81         case InsetSpaceParams::QQUAD:
82                 message = _("QQuad Space");
83                 break;
84         case InsetSpaceParams::ENSPACE:
85                 message = _("Enspace");
86                 break;
87         case InsetSpaceParams::ENSKIP:
88                 message = _("Enskip");
89                 break;
90         case InsetSpaceParams::NEGTHIN:
91                 message = _("Negative Thin Space");
92                 break;
93         case InsetSpaceParams::HFILL:
94                 message = _("Horizontal Fill");
95                 break;
96         case InsetSpaceParams::HFILL_PROTECTED:
97                 message = _("Protected Horizontal Fill");
98                 break;
99         case InsetSpaceParams::DOTFILL:
100                 message = _("Horizontal Fill (Dots)");
101                 break;
102         case InsetSpaceParams::HRULEFILL:
103                 message = _("Horizontal Fill (Rule)");
104                 break;
105         case InsetSpaceParams::CUSTOM:
106                 message = support::bformat(_("Horizontal Space (%1$s)"),
107                                 params_.length.asDocstring());
108                 break;
109         case InsetSpaceParams::CUSTOM_PROTECTED:
110                 message = support::bformat(_("Protected Horizontal Space (%1$s)"),
111                                 params_.length.asDocstring());
112                 break;
113         }
114         return message;
115 }
116
117
118 void InsetSpace::doDispatch(Cursor & cur, FuncRequest & cmd)
119 {
120         switch (cmd.action) {
121
122         case LFUN_INSET_MODIFY: {
123                 string2params(to_utf8(cmd.argument()), params_);
124                 break;
125         }
126
127         case LFUN_MOUSE_RELEASE:
128                 if (!cur.selection() && cmd.button() == mouse_button::button1)
129                         cur.bv().showDialog("space", params2string(params()), this);
130                 break;
131
132         default:
133                 Inset::doDispatch(cur, cmd);
134                 break;
135         }
136 }
137
138
139 bool InsetSpace::getStatus(Cursor & cur, FuncRequest const & cmd,
140         FuncStatus & status) const
141 {
142         switch (cmd.action) {
143         // we handle these
144         case LFUN_INSET_MODIFY:
145                 if (cmd.getArg(0) == "space") {
146                         InsetSpaceParams params;
147                         string2params(to_utf8(cmd.argument()), params);
148                         status.setOnOff(params_.kind == params.kind);
149                 } else {
150                         status.enabled(true);
151                 }
152                 return true;
153         default:
154                 return Inset::getStatus(cur, cmd, status);
155         }
156 }
157
158
159 void InsetSpace::edit(Cursor & cur, bool, EntryDirection)
160 {
161         cur.bv().showDialog("space", params2string(params()), this);
162 }
163
164
165 void InsetSpace::metrics(MetricsInfo & mi, Dimension & dim) const
166 {
167         if (isStretchableSpace()) {
168                 // The metrics for this kinds are calculated externally in
169                 // \c TextMetrics::computeRowMetrics. Those are dummy value:
170                 dim = Dimension(10, 10, 10);
171                 return;
172         }
173
174         frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
175         dim.asc = fm.maxAscent();
176         dim.des = fm.maxDescent();
177
178         switch (params_.kind) {
179                 case InsetSpaceParams::THIN:
180                 case InsetSpaceParams::NEGTHIN:
181                         dim.wid = fm.width(char_type('M')) / 6;
182                         break;
183                 case InsetSpaceParams::PROTECTED:
184                 case InsetSpaceParams::NORMAL:
185                         dim.wid = fm.width(char_type(' '));
186                         break;
187                 case InsetSpaceParams::QUAD:
188                         dim.wid = fm.width(char_type('M'));
189                         break;
190                 case InsetSpaceParams::QQUAD:
191                         dim.wid = 2 * fm.width(char_type('M'));
192                         break;
193                 case InsetSpaceParams::ENSPACE:
194                 case InsetSpaceParams::ENSKIP:
195                         dim.wid = int(0.5 * fm.width(char_type('M')));
196                         break;
197                 case InsetSpaceParams::CUSTOM:
198                 case InsetSpaceParams::CUSTOM_PROTECTED:
199                         dim.wid = params_.length.inBP();
200                         break;
201                 case InsetSpaceParams::HFILL:
202                 case InsetSpaceParams::HFILL_PROTECTED:
203                 case InsetSpaceParams::DOTFILL:
204                 case InsetSpaceParams::HRULEFILL:
205                         // shut up compiler
206                         break;
207         }
208         // Cache the inset dimension.
209         setDimCache(mi, dim);
210 }
211
212
213 void InsetSpace::draw(PainterInfo & pi, int x, int y) const
214 {
215         Dimension const dim = dimension(*pi.base.bv);
216
217         if (isStretchableSpace()) {
218                 int const asc = theFontMetrics(pi.base.font).ascent('M');
219                 int const desc = theFontMetrics(pi.base.font).descent('M');
220                 int const x0 = x + 1;
221                 int const x1 = x + dim.wid - 2;
222                 int const y0 = y + desc;
223                 int const y1 = y - asc;
224                 int const y2 = y - asc / 2;
225
226                 if (params_.kind == InsetSpaceParams::HFILL) {
227                         pi.pain.line(x0, y1, x0, y0, Color_added_space);
228                         pi.pain.line(x0, y2 , x1, y2, Color_added_space,
229                                 frontend::Painter::line_onoffdash);
230                         pi.pain.line(x1, y1, x1, y0, Color_added_space);
231                 } else if (params_.kind == InsetSpaceParams::HFILL_PROTECTED) {
232                         pi.pain.line(x0, y1, x0, y0, Color_latex);
233                         pi.pain.line(x0, y2 , x1, y2, Color_latex,
234                                 frontend::Painter::line_onoffdash);
235                         pi.pain.line(x1, y1, x1, y0, Color_latex);
236                 } else if (params_.kind == InsetSpaceParams::DOTFILL) {
237                         pi.pain.line(x0, y1, x0, y0, Color_special);
238                         pi.pain.line(x0, y, x1, y, Color_special,
239                                 frontend::Painter::line_onoffdash);
240                         pi.pain.line(x1, y1, x1, y0, Color_special);
241                 } if (params_.kind == InsetSpaceParams::HRULEFILL) {
242                         pi.pain.line(x0, y1, x0, y0, Color_special);
243                         pi.pain.line(x0, y, x1, y, Color_special);
244                         pi.pain.line(x1, y1, x1, y0, Color_special);
245                 }
246                 return;
247         }
248
249         int const w = dim.wid;
250         int const h = theFontMetrics(pi.base.font).ascent('x');
251         int xp[4], yp[4];
252
253         xp[0] = x;
254         yp[0] = y - max(h / 4, 1);
255         if (params_.kind == InsetSpaceParams::NORMAL ||
256             params_.kind == InsetSpaceParams::PROTECTED) {
257                 xp[1] = x;     yp[1] = y;
258                 xp[2] = x + w; yp[2] = y;
259         } else {
260                 xp[1] = x;     yp[1] = y + max(h / 4, 1);
261                 xp[2] = x + w; yp[2] = y + max(h / 4, 1);
262         }
263         xp[3] = x + w;
264         yp[3] = y - max(h / 4, 1);
265
266         if (params_.kind == InsetSpaceParams::PROTECTED ||
267             params_.kind == InsetSpaceParams::ENSPACE ||
268             params_.kind == InsetSpaceParams::NEGTHIN ||
269             params_.kind == InsetSpaceParams::CUSTOM_PROTECTED)
270                 pi.pain.lines(xp, yp, 4, Color_latex);
271         else
272                 pi.pain.lines(xp, yp, 4, Color_special);
273 }
274
275
276 void InsetSpaceParams::write(ostream & os) const
277 {
278         string command;
279         switch (kind) {
280         case InsetSpaceParams::NORMAL:
281                 os << "\\space{}";
282                 break;
283         case InsetSpaceParams::PROTECTED:
284                 os <<  "~";
285                 break;
286         case InsetSpaceParams::THIN:
287                 os <<  "\\thinspace{}";
288                 break;
289         case InsetSpaceParams::QUAD:
290                 os <<  "\\quad{}";
291                 break;
292         case InsetSpaceParams::QQUAD:
293                 os <<  "\\qquad{}";
294                 break;
295         case InsetSpaceParams::ENSPACE:
296                 os <<  "\\enspace{}";
297                 break;
298         case InsetSpaceParams::ENSKIP:
299                 os <<  "\\enskip{}";
300                 break;
301         case InsetSpaceParams::NEGTHIN:
302                 os <<  "\\negthinspace{}";
303                 break;
304         case InsetSpaceParams::HFILL:
305                 os <<  "\\hfill{}";
306                 break;
307         case InsetSpaceParams::HFILL_PROTECTED:
308                 os <<  "\\hspace*{\\fill}";
309                 break;
310         case InsetSpaceParams::DOTFILL:
311                 os <<  "\\dotfill{}";
312                 break;
313         case InsetSpaceParams::HRULEFILL:
314                 os <<  "\\hrulefill{}";
315                 break;
316         case InsetSpaceParams::CUSTOM:
317                 os <<  "\\hspace{}";
318                 break;
319         case InsetSpaceParams::CUSTOM_PROTECTED:
320                 os <<  "\\hspace*{}";
321                 break;
322         }
323         
324         if (!length.empty())
325                 os << "\n\\length " << length.asString();
326 }
327
328
329 void InsetSpaceParams::read(Lexer & lex)
330 {
331         lex.setContext("InsetSpaceParams::read");
332         string command;
333         lex >> command;
334
335         if (command == "\\space{}")
336                 kind = InsetSpaceParams::NORMAL;
337         else if (command == "~")
338                 kind = InsetSpaceParams::PROTECTED;
339         else if (command == "\\thinspace{}")
340                 kind = InsetSpaceParams::THIN;
341         else if (command == "\\quad{}")
342                 kind = InsetSpaceParams::QUAD;
343         else if (command == "\\qquad{}")
344                 kind = InsetSpaceParams::QQUAD;
345         else if (command == "\\enspace{}")
346                 kind = InsetSpaceParams::ENSPACE;
347         else if (command == "\\enskip{}")
348                 kind = InsetSpaceParams::ENSKIP;
349         else if (command == "\\negthinspace{}")
350                 kind = InsetSpaceParams::NEGTHIN;
351         else if (command == "\\hfill{}")
352                 kind = InsetSpaceParams::HFILL;
353         else if (command == "\\hspace*{\\fill}")
354                 kind = InsetSpaceParams::HFILL_PROTECTED;
355         else if (command == "\\dotfill{}")
356                 kind = InsetSpaceParams::DOTFILL;
357         else if (command == "\\hrulefill{}")
358                 kind = InsetSpaceParams::HRULEFILL;
359         else if (command == "\\hspace{}")
360                 kind = InsetSpaceParams::CUSTOM;
361         else if (command == "\\hspace*{}")
362                 kind = InsetSpaceParams::CUSTOM_PROTECTED;
363         else
364                 lex.printError("InsetSpace: Unknown kind: `$$Token'");
365
366         if (lex.checkFor("\\length"))
367                 lex >> length;
368         lex >> "\\end_inset";
369 }
370
371
372 void InsetSpace::write(ostream & os) const
373 {
374         os << "Space ";
375         params_.write(os);
376 }
377
378
379 void InsetSpace::read(Lexer & lex)
380 {
381         params_.read(lex);
382 }
383
384
385 int InsetSpace::latex(odocstream & os, OutputParams const & runparams) const
386 {
387         switch (params_.kind) {
388         case InsetSpaceParams::NORMAL:
389                 os << (runparams.free_spacing ? " " : "\\ ");
390                 break;
391         case InsetSpaceParams::PROTECTED:
392                 os << (runparams.free_spacing ? ' ' : '~');
393                 break;
394         case InsetSpaceParams::THIN:
395                 os << (runparams.free_spacing ? " " : "\\,");
396                 break;
397         case InsetSpaceParams::QUAD:
398                 os << (runparams.free_spacing ? " " : "\\quad{}");
399                 break;
400         case InsetSpaceParams::QQUAD:
401                 os << (runparams.free_spacing ? " " : "\\qquad{}");
402                 break;
403         case InsetSpaceParams::ENSPACE:
404                 os << (runparams.free_spacing ? " " : "\\enspace{}");
405                 break;
406         case InsetSpaceParams::ENSKIP:
407                 os << (runparams.free_spacing ? " " : "\\enskip{}");
408                 break;
409         case InsetSpaceParams::NEGTHIN:
410                 os << (runparams.free_spacing ? " " : "\\negthinspace{}");
411                 break;
412         case InsetSpaceParams::HFILL:
413                 os << (runparams.free_spacing ? " " : "\\hfill{}");
414                 break;
415         case InsetSpaceParams::HFILL_PROTECTED:
416                 os << (runparams.free_spacing ? " " : "\\hspace*{\\fill}");
417                 break;
418         case InsetSpaceParams::DOTFILL:
419                 os << (runparams.free_spacing ? " " : "\\dotfill{}");
420                 break;
421         case InsetSpaceParams::HRULEFILL:
422                 os << (runparams.free_spacing ? " " : "\\hrulefill{}");
423                 break;
424         case InsetSpaceParams::CUSTOM:
425                 if (runparams.free_spacing)
426                         os << " ";
427                 else
428                         os << "\\hspace{" << from_ascii(params_.length.asLatexString()) << "}";
429                 break;
430         case InsetSpaceParams::CUSTOM_PROTECTED:
431                 if (runparams.free_spacing)
432                         os << " ";
433                 else
434                         os << "\\hspace*{" << from_ascii(params_.length.asLatexString()) << "}";
435                 break;
436         }
437         return 0;
438 }
439
440
441 int InsetSpace::plaintext(odocstream & os, OutputParams const &) const
442 {
443         switch (params_.kind) {
444         case InsetSpaceParams::HFILL:
445         case InsetSpaceParams::HFILL_PROTECTED:
446                 os << "     ";
447                 return 5;
448         case InsetSpaceParams::DOTFILL:
449                 os << ".....";
450                 return 5;
451         case InsetSpaceParams::HRULEFILL:
452                 os << "_____";
453                 return 5;
454         default:
455                 os << ' ';
456                 return 1;
457         }
458 }
459
460
461 int InsetSpace::docbook(odocstream & os, OutputParams const &) const
462 {
463         switch (params_.kind) {
464         case InsetSpaceParams::NORMAL:
465         case InsetSpaceParams::QUAD:
466         case InsetSpaceParams::QQUAD:
467         case InsetSpaceParams::ENSKIP:
468                 os << " ";
469                 break;
470         case InsetSpaceParams::PROTECTED:
471         case InsetSpaceParams::ENSPACE:
472         case InsetSpaceParams::THIN:
473         case InsetSpaceParams::NEGTHIN:
474                 os << "&nbsp;";
475                 break;
476         case InsetSpaceParams::HFILL:
477         case InsetSpaceParams::HFILL_PROTECTED:
478                 os << '\n';
479         case InsetSpaceParams::DOTFILL:
480                 // FIXME
481                 os << '\n';
482         case InsetSpaceParams::HRULEFILL:
483                 // FIXME
484                 os << '\n';
485         case InsetSpaceParams::CUSTOM:
486         case InsetSpaceParams::CUSTOM_PROTECTED:
487                 // FIXME
488                 os << '\n';
489         }
490         return 0;
491 }
492
493
494 void InsetSpace::textString(odocstream & os) const
495 {
496         plaintext(os, OutputParams(0));
497 }
498
499
500 bool InsetSpace::isStretchableSpace() const
501 {
502         return params_.kind == InsetSpaceParams::HFILL
503                 || params_.kind == InsetSpaceParams::HFILL_PROTECTED
504                 || params_.kind == InsetSpaceParams::DOTFILL
505                 || params_.kind == InsetSpaceParams::HRULEFILL;
506 }
507
508
509 docstring InsetSpace::contextMenu(BufferView const &, int, int) const
510 {
511         return from_ascii("context-space");
512 }
513
514
515 void InsetSpace::string2params(string const & in, InsetSpaceParams & params)
516 {
517         params = InsetSpaceParams();
518         if (in.empty())
519                 return;
520
521         istringstream data(in);
522         Lexer lex;
523         lex.setStream(data);
524         lex.setContext("InsetSpace::string2params");
525         lex >> "space";
526
527         params.read(lex);
528 }
529
530
531 string InsetSpace::params2string(InsetSpaceParams const & params)
532 {
533         ostringstream data;
534         data << "space" << ' ';
535         params.write(data);
536         return data.str();
537 }
538
539
540 } // namespace lyx