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