]> git.lyx.org Git - lyx.git/blob - src/insets/InsetSpecialChar.cpp
Better TOC output for XHTML, per Rob and Pavel.
[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         string s;
54         switch (kind_) {
55                 case LIGATURE_BREAK:
56                         s = "|";
57                         break;
58                 case END_OF_SENTENCE:
59                         s = ".";
60                         break;
61                 case LDOTS:
62                         s = ". . .";
63                         break;
64                 case MENU_SEPARATOR:
65                         s = " x ";
66                         break;
67                 case HYPHENATION:
68                         s = "-";
69                         break;
70                 case SLASH:
71                         s = "/";
72                         break;
73                 case NOBREAKDASH:
74                         s = "-";
75                         break;
76         }
77         docstring ds(s.begin(), s.end());
78         dim.wid = fm.width(ds);
79         if (kind_ == HYPHENATION && dim.wid > 5)
80                 dim.wid -= 2; // to make it look shorter
81         
82         setDimCache(mi, dim);
83 }
84
85
86 void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const
87 {
88         FontInfo font = pi.base.font;
89
90         switch (kind_) {
91         case HYPHENATION:
92         {
93                 font.setColor(Color_special);
94                 pi.pain.text(x, y, char_type('-'), font);
95                 break;
96         }
97         case LIGATURE_BREAK:
98         {
99                 font.setColor(Color_special);
100                 pi.pain.text(x, y, char_type('|'), font);
101                 break;
102         }
103         case END_OF_SENTENCE:
104         {
105                 font.setColor(Color_special);
106                 pi.pain.text(x, y, char_type('.'), font);
107                 break;
108         }
109         case LDOTS:
110         {
111                 font.setColor(Color_special);
112                 string ell = ". . . ";
113                 docstring dell(ell.begin(), ell.end());
114                 pi.pain.text(x, y, dell, font);
115                 break;
116         }
117         case MENU_SEPARATOR:
118         {
119                 frontend::FontMetrics const & fm =
120                         theFontMetrics(font);
121
122                 // A triangle the width and height of an 'x'
123                 int w = fm.width(char_type('x'));
124                 int ox = fm.width(char_type(' ')) + x;
125                 int h = fm.ascent(char_type('x'));
126                 int xp[4], yp[4];
127
128                 xp[0] = ox;     yp[0] = y;
129                 xp[1] = ox;     yp[1] = y - h;
130                 xp[2] = ox + w; yp[2] = y - h/2;
131                 xp[3] = ox;     yp[3] = y;
132
133                 pi.pain.lines(xp, yp, 4, Color_special);
134                 break;
135         }
136         case SLASH:
137         {
138                 font.setColor(Color_special);
139                 pi.pain.text(x, y, char_type('/'), font);
140                 break;
141         }
142         case NOBREAKDASH:
143         {
144                 font.setColor(Color_latex);
145                 pi.pain.text(x, y, char_type('-'), font);
146                 break;
147         }
148         }
149 }
150
151
152 // In lyxf3 this will be just LaTeX
153 void InsetSpecialChar::write(ostream & os) const
154 {
155         string command;
156         switch (kind_) {
157         case HYPHENATION:
158                 command = "\\-";
159                 break;
160         case LIGATURE_BREAK:
161                 command = "\\textcompwordmark{}";
162                 break;
163         case END_OF_SENTENCE:
164                 command = "\\@.";
165                 break;
166         case LDOTS:
167                 command = "\\ldots{}";
168                 break;
169         case MENU_SEPARATOR:
170                 command = "\\menuseparator";
171                 break;
172         case SLASH:
173                 command = "\\slash{}";
174                 break;
175         case NOBREAKDASH:
176                 command = "\\nobreakdash-";
177                 break;
178         }
179         os << "\\SpecialChar " << command << "\n";
180 }
181
182
183 // This function will not be necessary when lyx3
184 void InsetSpecialChar::read(Lexer & lex)
185 {
186         lex.next();
187         string const command = lex.getString();
188
189         if (command == "\\-")
190                 kind_ = HYPHENATION;
191         else if (command == "\\textcompwordmark{}")
192                 kind_ = LIGATURE_BREAK;
193         else if (command == "\\@.")
194                 kind_ = END_OF_SENTENCE;
195         else if (command == "\\ldots{}")
196                 kind_ = LDOTS;
197         else if (command == "\\menuseparator")
198                 kind_ = MENU_SEPARATOR;
199         else if (command == "\\slash{}")
200                 kind_ = SLASH;
201         else if (command == "\\nobreakdash-")
202                 kind_ = NOBREAKDASH;
203         else
204                 lex.printError("InsetSpecialChar: Unknown kind: `$$Token'");
205 }
206
207
208 void InsetSpecialChar::latex(otexstream & os,
209                              OutputParams const & rp) const
210 {
211         switch (kind_) {
212         case HYPHENATION:
213                 os << "\\-";
214                 break;
215         case LIGATURE_BREAK:
216                 os << "\\textcompwordmark{}";
217                 break;
218         case END_OF_SENTENCE:
219                 os << "\\@.";
220                 break;
221         case LDOTS:
222                 os << "\\ldots{}";
223                 break;
224         case MENU_SEPARATOR:
225                 if (rp.local_font->isRightToLeft())
226                         os << "\\lyxarrow*{}";
227                 else
228                         os << "\\lyxarrow{}";
229                 break;
230         case SLASH:
231                 os << "\\slash{}";
232                 break;
233         case NOBREAKDASH:
234                 if (rp.moving_arg)
235                         os << "\\protect";
236                 os << "\\nobreakdash-";
237                 break;
238         }
239 }
240
241
242 int InsetSpecialChar::plaintext(odocstream & os, OutputParams const &) const
243 {
244         switch (kind_) {
245         case HYPHENATION:
246         case LIGATURE_BREAK:
247                 return 0;
248         case END_OF_SENTENCE:
249                 os << '.';
250                 return 1;
251         case LDOTS:
252                 os << "...";
253                 return 3;
254         case MENU_SEPARATOR:
255                 os << "->";
256                 return 2;
257         case SLASH:
258                 os << '/';
259                 return 1;
260         case NOBREAKDASH:
261                 os << '-';
262                 return 1;
263         }
264         return 0;
265 }
266
267
268 int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const
269 {
270         switch (kind_) {
271         case HYPHENATION:
272         case LIGATURE_BREAK:
273                 break;
274         case END_OF_SENTENCE:
275                 os << '.';
276                 break;
277         case LDOTS:
278                 os << "...";
279                 break;
280         case MENU_SEPARATOR:
281                 os << "&lyxarrow;";
282                 break;
283         case SLASH:
284                 os << '/';
285                 break;
286         case NOBREAKDASH:
287                 os << '-';
288                 break;
289         }
290         return 0;
291 }
292
293
294 docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const
295 {
296         switch (kind_) {
297         case HYPHENATION:
298         case LIGATURE_BREAK:
299                 break;
300         case END_OF_SENTENCE:
301                 xs << '.';
302                 break;
303         case LDOTS:
304                 xs << XHTMLStream::ESCAPE_NONE << "&hellip;";
305                 break;
306         case MENU_SEPARATOR:
307                 xs << XHTMLStream::ESCAPE_NONE << "&rArr;";
308                 break;
309         case SLASH:
310                 xs << XHTMLStream::ESCAPE_NONE << "&frasl;";
311                 break;
312         case NOBREAKDASH:
313                 xs << '-';
314                 break;
315         }
316         return docstring();
317 }
318
319
320 void InsetSpecialChar::toString(odocstream & os) const
321 {
322         plaintext(os, OutputParams(0));
323 }
324
325
326 void InsetSpecialChar::forToc(docstring & os, size_t) const
327 {
328         odocstringstream ods;
329         plaintext(ods, OutputParams(0));
330         os += ods.str();
331 }
332
333
334 void InsetSpecialChar::validate(LaTeXFeatures & features) const
335 {
336         if (kind_ == MENU_SEPARATOR)
337                 features.require("lyxarrow");
338         if (kind_ == NOBREAKDASH)
339                 features.require("amsmath");
340 }
341
342
343 bool InsetSpecialChar::isLetter() const
344 {
345         return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK
346                 || kind_ == NOBREAKDASH;
347 }
348
349
350 bool InsetSpecialChar::isLineSeparator() const
351 {
352 #if 0
353         // this would be nice, but it does not work, since
354         // Paragraph::stripLeadingSpaces nukes the characters which
355         // have this property. I leave the code here, since it should
356         // eventually be made to work. (JMarc 20020327)
357         return kind_ == HYPHENATION || kind_ == MENU_SEPARATOR
358                 || kind_ == SLASH;
359 #else
360         return false;
361 #endif
362 }
363
364
365 } // namespace lyx