]> git.lyx.org Git - lyx.git/blob - src/insets/InsetSpecialChar.cpp
77792b973cd02e228b927d2f46e29d9d886fa4c4
[lyx.git] / src / insets / InsetSpecialChar.cpp
1 /**
2  * \file InsetSpecialChar.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  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "InsetSpecialChar.h"
16
17 #include "Dimension.h"
18 #include "Font.h"
19 #include "LaTeXFeatures.h"
20 #include "Lexer.h"
21 #include "MetricsInfo.h"
22 #include "output_xhtml.h"
23
24 #include "frontends/FontMetrics.h"
25 #include "frontends/Painter.h"
26
27 #include "support/debug.h"
28 #include "support/docstream.h"
29
30 using namespace std;
31
32 namespace lyx {
33
34
35 InsetSpecialChar::InsetSpecialChar(Kind k)
36         : Inset(0), kind_(k)
37 {}
38
39
40 InsetSpecialChar::Kind InsetSpecialChar::kind() const
41 {
42         return kind_;
43 }
44
45
46 void InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const
47 {
48         frontend::FontMetrics const & fm =
49                 theFontMetrics(mi.base.font);
50         dim.asc = fm.maxAscent();
51         dim.des = fm.maxDescent();
52
53         docstring s;
54         switch (kind_) {
55                 case LIGATURE_BREAK:
56                         s = from_ascii("|");
57                         break;
58                 case END_OF_SENTENCE:
59                         s = from_ascii(".");
60                         break;
61                 case LDOTS:
62                         s = from_ascii(". . .");
63                         break;
64                 case MENU_SEPARATOR:
65                         s = from_ascii(" x ");
66                         break;
67                 case HYPHENATION:
68                         s = from_ascii("-");
69                         break;
70                 case SLASH:
71                         s = from_ascii("/");
72                         break;
73                 case NOBREAKDASH:
74                         s = from_ascii("-");
75                         break;
76                 case PHRASE_LYX:
77                         s = from_ascii("LyX");
78                         break;
79                 case PHRASE_TEX:
80                         s = from_ascii("TeX");
81                         break;
82                 case PHRASE_LATEX2E:
83                         s = from_ascii("LaTeX2") + char_type(0x03b5);
84                         break;
85                 case PHRASE_LATEX:
86                         s = from_ascii("LaTeX");
87                         break;
88         }
89         dim.wid = fm.width(s);
90         if (kind_ == HYPHENATION && dim.wid > 5)
91                 dim.wid -= 2; // to make it look shorter
92         
93         setDimCache(mi, dim);
94 }
95
96
97 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
98 {
99         FontInfo font = pi.base.font;
100
101         switch (kind_) {
102         case HYPHENATION:
103         {
104                 font.setColor(Color_special);
105                 pi.pain.text(x, y, char_type('-'), font);
106                 break;
107         }
108         case LIGATURE_BREAK:
109         {
110                 font.setColor(Color_special);
111                 pi.pain.text(x, y, char_type('|'), font);
112                 break;
113         }
114         case END_OF_SENTENCE:
115         {
116                 font.setColor(Color_special);
117                 pi.pain.text(x, y, char_type('.'), font);
118                 break;
119         }
120         case LDOTS:
121         {
122                 font.setColor(Color_special);
123                 string ell = ". . . ";
124                 docstring dell(ell.begin(), ell.end());
125                 pi.pain.text(x, y, dell, font);
126                 break;
127         }
128         case MENU_SEPARATOR:
129         {
130                 frontend::FontMetrics const & fm =
131                         theFontMetrics(font);
132
133                 // A triangle the width and height of an 'x'
134                 int w = fm.width(char_type('x'));
135                 int ox = fm.width(char_type(' ')) + x;
136                 int h = fm.ascent(char_type('x'));
137                 int xp[4], yp[4];
138
139                 xp[0] = ox;     yp[0] = y;
140                 xp[1] = ox;     yp[1] = y - h;
141                 xp[2] = ox + w; yp[2] = y - h/2;
142                 xp[3] = ox;     yp[3] = y;
143
144                 pi.pain.lines(xp, yp, 4, Color_special);
145                 break;
146         }
147         case SLASH:
148         {
149                 font.setColor(Color_special);
150                 pi.pain.text(x, y, char_type('/'), font);
151                 break;
152         }
153         case NOBREAKDASH:
154         {
155                 font.setColor(Color_latex);
156                 pi.pain.text(x, y, char_type('-'), font);
157                 break;
158         }
159         case PHRASE_LYX:
160                 font.setColor(Color_special);
161                 pi.pain.text(x, y, from_ascii("LyX"), font);
162                 break;
163         case PHRASE_TEX:
164                 font.setColor(Color_special);
165                 pi.pain.text(x, y, from_ascii("TeX"), font);
166                 break;
167         case PHRASE_LATEX2E:
168                 font.setColor(Color_special);
169                 pi.pain.text(x, y, from_ascii("LaTeX2") + char_type(0x03b5), font);
170                 break;
171         case PHRASE_LATEX:
172                 font.setColor(Color_special);
173                 pi.pain.text(x, y, from_ascii("LaTeX"), font);
174                 break;
175         }
176 }
177
178
179 // In lyxf3 this will be just LaTeX
180 void InsetSpecialChar::write(ostream & os) const
181 {
182         string command;
183         switch (kind_) {
184         case HYPHENATION:
185                 command = "\\-";
186                 break;
187         case LIGATURE_BREAK:
188                 command = "\\textcompwordmark{}";
189                 break;
190         case END_OF_SENTENCE:
191                 command = "\\@.";
192                 break;
193         case LDOTS:
194                 command = "\\ldots{}";
195                 break;
196         case MENU_SEPARATOR:
197                 command = "\\menuseparator";
198                 break;
199         case SLASH:
200                 command = "\\slash{}";
201                 break;
202         case NOBREAKDASH:
203                 command = "\\nobreakdash-";
204                 break;
205         case PHRASE_LYX:
206                 command = "\\LyX";
207                 break;
208         case PHRASE_TEX:
209                 command = "\\TeX";
210                 break;
211         case PHRASE_LATEX2E:
212                 command = "\\LaTeX2e";
213                 break;
214         case PHRASE_LATEX:
215                 command = "\\LaTeX";
216                 break;
217         }
218         os << "\\SpecialChar " << command << "\n";
219 }
220
221
222 // This function will not be necessary when lyx3
223 void InsetSpecialChar::read(Lexer & lex)
224 {
225         lex.next();
226         string const command = lex.getString();
227
228         if (command == "\\-")
229                 kind_ = HYPHENATION;
230         else if (command == "\\textcompwordmark{}")
231                 kind_ = LIGATURE_BREAK;
232         else if (command == "\\@.")
233                 kind_ = END_OF_SENTENCE;
234         else if (command == "\\ldots{}")
235                 kind_ = LDOTS;
236         else if (command == "\\menuseparator")
237                 kind_ = MENU_SEPARATOR;
238         else if (command == "\\slash{}")
239                 kind_ = SLASH;
240         else if (command == "\\nobreakdash-")
241                 kind_ = NOBREAKDASH;
242         else if (command == "\\LyX")
243                 kind_ = PHRASE_LYX;
244         else if (command == "\\TeX")
245                 kind_ = PHRASE_TEX;
246         else if (command == "\\LaTeX2e")
247                 kind_ = PHRASE_LATEX2E;
248         else if (command == "\\LaTeX")
249                 kind_ = PHRASE_LATEX;
250         else
251                 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
252 }
253
254
255 void InsetSpecialChar::latex(otexstream & os,
256                              OutputParams const & rp) const
257 {
258         switch (kind_) {
259         case HYPHENATION:
260                 os << "\\-";
261                 break;
262         case LIGATURE_BREAK:
263                 os << "\\textcompwordmark{}";
264                 break;
265         case END_OF_SENTENCE:
266                 os << "\\@.";
267                 break;
268         case LDOTS:
269                 os << "\\ldots{}";
270                 break;
271         case MENU_SEPARATOR:
272                 if (rp.local_font->isRightToLeft())
273                         os << "\\lyxarrow*{}";
274                 else
275                         os << "\\lyxarrow{}";
276                 break;
277         case SLASH:
278                 os << "\\slash{}";
279                 break;
280         case NOBREAKDASH:
281                 if (rp.moving_arg)
282                         os << "\\protect";
283                 os << "\\nobreakdash-";
284                 break;
285         case PHRASE_LYX:
286                 if (rp.moving_arg)
287                         os << "\\protect";
288                 os << "\\LyX{}";
289                 break;
290         case PHRASE_TEX:
291                 if (rp.moving_arg)
292                         os << "\\protect";
293                 os << "\\TeX{}";
294                 break;
295         case PHRASE_LATEX2E:
296                 if (rp.moving_arg)
297                         os << "\\protect";
298                 os << "\\LaTeX2e{}";
299                 break;
300         case PHRASE_LATEX:
301                 if (rp.moving_arg)
302                         os << "\\protect";
303                 os << "\\LaTeX{}";
304                 break;
305         }
306 }
307
308
309 int InsetSpecialChar::plaintext(odocstringstream & os,
310         OutputParams const &, size_t) const
311 {
312         switch (kind_) {
313         case HYPHENATION:
314                 return 0;
315         case LIGATURE_BREAK:
316                 os.put(0x200c);
317                 return 1;
318         case END_OF_SENTENCE:
319                 os << '.';
320                 return 1;
321         case LDOTS:
322                 os.put(0x2026);
323                 return 1;
324         case MENU_SEPARATOR:
325                 os << "->";
326                 return 2;
327         case SLASH:
328                 os << '/';
329                 return 1;
330         case NOBREAKDASH:
331                 os.put(0x2011);
332                 return 1;
333         case PHRASE_LYX:
334                 os << "LyX";
335                 return 3;
336         case PHRASE_TEX:
337                 os << "TeX";
338                 return 3;
339         case PHRASE_LATEX2E:
340                 os << "LaTeX2";
341                 os.put(0x03b5);
342                 return 7;
343         case PHRASE_LATEX:
344                 os << "LaTeX";
345                 return 5;
346         }
347         return 0;
348 }
349
350
351 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
352 {
353         switch (kind_) {
354         case HYPHENATION:
355         case LIGATURE_BREAK:
356                 break;
357         case END_OF_SENTENCE:
358                 os << '.';
359                 break;
360         case LDOTS:
361                 os << "&hellip;";
362                 break;
363         case MENU_SEPARATOR:
364                 os << "&lyxarrow;";
365                 break;
366         case SLASH:
367                 os << '/';
368                 break;
369         case NOBREAKDASH:
370                 os << '-';
371                 break;
372         case PHRASE_LYX:
373                 os << "LyX";
374                 break;
375         case PHRASE_TEX:
376                 os << "TeX";
377                 break;
378         case PHRASE_LATEX2E:
379                 os << "LaTeX2";
380                 os.put(0x03b5);
381                 break;
382         case PHRASE_LATEX:
383                 os << "LaTeX";
384                 break;
385         }
386         return 0;
387 }
388
389
390 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
391 {
392         switch (kind_) {
393         case HYPHENATION:
394                 break;
395         case LIGATURE_BREAK:
396                 xs << XHTMLStream::ESCAPE_NONE << "&#8204;";
397                 break;
398         case END_OF_SENTENCE:
399                 xs << '.';
400                 break;
401         case LDOTS:
402                 xs << XHTMLStream::ESCAPE_NONE << "&hellip;";
403                 break;
404         case MENU_SEPARATOR:
405                 xs << XHTMLStream::ESCAPE_NONE << "&rArr;";
406                 break;
407         case SLASH:
408                 xs << XHTMLStream::ESCAPE_NONE << "&frasl;";
409                 break;
410         case NOBREAKDASH:
411                 xs << XHTMLStream::ESCAPE_NONE << "&#8209;";
412                 break;
413         case PHRASE_LYX:
414                 xs << "LyX";
415                 break;
416         case PHRASE_TEX:
417                 xs << "TeX";
418                 break;
419         case PHRASE_LATEX2E:
420                 xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "&#x3b5;";
421                 break;
422         case PHRASE_LATEX:
423                 xs << "LaTeX";
424                 break;
425         }
426         return docstring();
427 }
428
429
430 void InsetSpecialChar::toString(odocstream & os) const
431 {
432         switch (kind_) {
433         case LIGATURE_BREAK:
434                 // Do not output ZERO WIDTH NON JOINER here
435                 // Spell checker would choke on it.
436                 return;
437         default:
438                 break;
439         }
440         odocstringstream ods;
441         plaintext(ods, OutputParams(0));
442         os << ods.str();
443 }
444
445
446 void InsetSpecialChar::forOutliner(docstring & os, size_t) const
447 {
448         odocstringstream ods;
449         plaintext(ods, OutputParams(0));
450         os += ods.str();
451 }
452
453
454 void InsetSpecialChar::validate(LaTeXFeatures & features) const
455 {
456         if (kind_ == MENU_SEPARATOR)
457                 features.require("lyxarrow");
458         if (kind_ == NOBREAKDASH)
459                 features.require("amsmath");
460         if (kind_ == PHRASE_LYX)
461                 features.require("LyX");
462 }
463
464
465 bool InsetSpecialChar::isLetter() const
466 {
467         return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
468                 || kind_ == NOBREAKDASH;
469 }
470
471
472 bool InsetSpecialChar::isLineSeparator() const
473 {
474 #if 0
475         // this would be nice, but it does not work, since
476         // Paragraph::stripLeadingSpaces nukes the characters which
477         // have this property. I leave the code here, since it should
478         // eventually be made to work. (JMarc 20020327)
479         return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR
480                 || kind_ == SLASH;
481 #else
482         return false;
483 #endif
484 }
485
486
487 } // namespace lyx