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