]> git.lyx.org Git - lyx.git/blob - src/insets/InsetIPAMacro.cpp
Fix conflicting inset font defaults (bug #8874)
[lyx.git] / src / insets / InsetIPAMacro.cpp
1 /**
2  * \file InsetIPAMacro.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Spitzmüller
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetIPAMacro.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "Dimension.h"
18 #include "Encoding.h"
19 #include "Font.h"
20 #include "FuncRequest.h"
21 #include "FuncStatus.h"
22 #include "LaTeXFeatures.h"
23 #include "Lexer.h"
24 #include "MetricsInfo.h"
25 #include "output_xhtml.h"
26
27 #include "frontends/FontMetrics.h"
28 #include "frontends/Painter.h"
29
30 #include "support/debug.h"
31 #include "support/docstream.h"
32 #include "support/gettext.h"
33 #include "support/Translator.h"
34
35 using namespace std;
36
37 namespace lyx {
38
39 namespace {
40
41 typedef Translator<string, InsetIPADecoParams::Type> IPADecoTranslator;
42 typedef Translator<docstring, InsetIPADecoParams::Type> IPADecoTranslatorLoc;
43
44 IPADecoTranslator const init_ipadecotranslator()
45 {
46         IPADecoTranslator translator("toptiebar", InsetIPADecoParams::Toptiebar);
47         translator.addPair("bottomtiebar", InsetIPADecoParams::Bottomtiebar);
48         return translator;
49 }
50
51
52 IPADecoTranslatorLoc const init_ipadecotranslator_loc()
53 {
54         IPADecoTranslatorLoc translator(_("Top tie bar"), InsetIPADecoParams::Toptiebar);
55         translator.addPair(_("Bottom tie bar"), InsetIPADecoParams::Bottomtiebar);
56         return translator;
57 }
58
59
60 IPADecoTranslator const & ipadecotranslator()
61 {
62         static IPADecoTranslator decotranslator = init_ipadecotranslator();
63         return decotranslator;
64 }
65
66
67 IPADecoTranslatorLoc const & ipadecotranslator_loc()
68 {
69         static IPADecoTranslatorLoc translator = init_ipadecotranslator_loc();
70         return translator;
71 }
72
73
74 typedef Translator<string, InsetIPAChar::Kind> IPACharTranslator;
75
76 IPACharTranslator const init_ipachartranslator()
77 {
78         IPACharTranslator translator("\\tone{51}", InsetIPAChar::TONE_FALLING);
79         translator.addPair("\\tone{15}", InsetIPAChar::TONE_RISING);
80         translator.addPair("\\tone{45}", InsetIPAChar::TONE_HIGH_RISING);
81         translator.addPair("\\tone{12}", InsetIPAChar::TONE_LOW_RISING);
82         translator.addPair("\\tone{454}", InsetIPAChar::TONE_HIGH_RISING_FALLING);
83         return translator;
84 }
85
86
87 IPACharTranslator const & ipachartranslator()
88 {
89         static IPACharTranslator chartranslator = init_ipachartranslator();
90         return chartranslator;
91 }
92
93 } // anon
94
95
96 InsetIPADecoParams::InsetIPADecoParams()
97         : type(Bottomtiebar)
98 {}
99
100
101 void InsetIPADecoParams::write(ostream & os) const
102 {
103         string const label = ipadecotranslator().find(type);
104         os << "IPADeco " << label << "\n";
105 }
106
107
108 void InsetIPADecoParams::read(Lexer & lex)
109 {
110         string label;
111         lex >> label;
112         if (lex)
113                 type = ipadecotranslator().find(label);
114 }
115
116
117 /////////////////////////////////////////////////////////////////////
118 //
119 // InsetIPADeco
120 //
121 /////////////////////////////////////////////////////////////////////
122
123 InsetIPADeco::InsetIPADeco(Buffer * buf, string const & label)
124         : InsetCollapsable(buf)
125 {
126         setDrawFrame(true);
127         setFrameColor(Color_insetframe);
128         params_.type = ipadecotranslator().find(label);
129 }
130
131
132 InsetIPADeco::~InsetIPADeco()
133 {}
134
135
136 docstring InsetIPADeco::layoutName() const
137 {
138         return from_ascii("IPADeco:" + ipadecotranslator().find(params_.type));
139 }
140
141
142 void InsetIPADeco::metrics(MetricsInfo & mi, Dimension & dim) const
143 {
144         InsetText::metrics(mi, dim);
145         
146         if (params_.type == InsetIPADecoParams::Toptiebar) {
147                 // consider width of the inset label
148                 FontInfo font(getLayout().labelfont());
149                 font.realize(sane_font);
150                 font.decSize();
151                 font.decSize();
152                 int w = 0;
153                 int a = 0;
154                 int d = 0;
155                 docstring const label(1, char_type(0x2040));
156                 theFontMetrics(font).rectText(label, w, a, d);
157                 dim.asc += int(a * 0.5);
158         }
159         if (params_.type == InsetIPADecoParams::Bottomtiebar) {
160                 // consider width of the inset label
161                 FontInfo font(getLayout().labelfont());
162                 font.realize(sane_font);
163                 font.decSize();
164                 font.decSize();
165                 int w = 0;
166                 int a = 0;
167                 int d = 0;
168                 docstring const label(1, char_type(0x203f));
169                 theFontMetrics(font).rectText(label, w, a, d);
170                 dim.des += int(d * 1.5);
171         }
172
173         // cache the inset dimension
174         setDimCache(mi, dim);
175 }
176
177
178 void InsetIPADeco::draw(PainterInfo & pi, int x, int y) const
179 {
180         // draw the text
181         InsetCollapsable::draw(pi, x, y);
182
183         // draw the inset marker
184         drawMarkers(pi, x, y);
185
186         Dimension const dim = Inset::dimension(*pi.base.bv);
187
188         if (params_.type == InsetIPADecoParams::Toptiebar) {
189                 FontInfo font(getLayout().labelfont());
190                 font.realize(sane_font);
191                 font.decSize();
192                 font.decSize();
193                 int w = 0;
194                 int a = 0;
195                 int d = 0;
196                 int asc = dim.ascent();
197                 docstring const label(1, char_type(0x2040));
198                 theFontMetrics(font).rectText(label, w, a, d);
199                 int const ww = max(dim.wid, w);
200                 pi.pain.rectText(x + (ww - w) / 2, y - int(asc / 2.5),
201                         label, font, Color_none, Color_none);
202         }
203
204         if (params_.type == InsetIPADecoParams::Bottomtiebar) {
205                 FontInfo font(getLayout().labelfont());
206                 font.realize(sane_font);
207                 font.decSize();
208                 font.decSize();
209                 int w = 0;
210                 int a = 0;
211                 int d = 0;
212                 int desc = dim.descent();
213                 docstring const label(1, char_type(0x203f));
214                 theFontMetrics(font).rectText(label, w, a, d);
215                 int const ww = max(dim.wid, w);
216                 pi.pain.rectText(x + (ww - w) / 2, y + int(desc / 1.5),
217                         label, font, Color_none, Color_none);
218         }
219 }
220
221
222 void InsetIPADeco::write(ostream & os) const
223 {
224         params_.write(os);
225         InsetCollapsable::write(os);
226 }
227
228
229 void InsetIPADeco::read(Lexer & lex)
230 {
231         params_.read(lex);
232         InsetCollapsable::read(lex);
233 }
234
235
236 void InsetIPADeco::doDispatch(Cursor & cur, FuncRequest & cmd)
237 {
238         switch (cmd.action()) {
239         case LFUN_QUOTE_INSERT: {
240                 FuncRequest fr(LFUN_SELF_INSERT, "\"");
241                 InsetText::doDispatch(cur, fr);
242                 break;
243         }
244         default:
245                 InsetText::doDispatch(cur, cmd);
246                 break;
247         }
248 }
249
250
251 bool InsetIPADeco::getStatus(Cursor & cur, FuncRequest const & cmd,
252                 FuncStatus & flag) const
253 {
254         switch (cmd.action()) {
255         case LFUN_SCRIPT_INSERT: {
256                 if (cmd.argument() == "subscript") {
257                         flag.setEnabled(false);
258                         return true;
259                 }
260                 break;
261         }
262         case LFUN_IN_IPA:
263                 flag.setEnabled(true);
264                 return true;
265                 break;
266         default:
267                 break;
268         }
269         return InsetText::getStatus(cur, cmd, flag);
270 }
271
272
273 void InsetIPADeco::latex(otexstream & os, OutputParams const & runparams) const
274 {
275         if (params_.type == InsetIPADecoParams::Toptiebar)
276                 os << "\\texttoptiebar{";
277         else if (params_.type == InsetIPADecoParams::Bottomtiebar)
278                 os << "\\textbottomtiebar{";
279         InsetCollapsable::latex(os, runparams);
280         os << "}";
281 }
282
283
284 int InsetIPADeco::plaintext(odocstringstream & os,
285                             OutputParams const & runparams, size_t max_length) const
286 {
287         odocstringstream ods;
288         int h = (int)(InsetCollapsable::plaintext(ods, runparams, max_length) / 2);
289         docstring result = ods.str();
290         docstring const before = result.substr(0, h);
291         docstring const after = result.substr(h, result.size());
292         
293         if (params_.type == InsetIPADecoParams::Toptiebar) {
294                 os << before;
295                 os.put(0x0361);
296                 os << after;
297         }
298         else if (params_.type == InsetIPADecoParams::Bottomtiebar) {
299                 os << before;
300                 os.put(0x035c);
301                 os << after;
302         }
303         return result.size();
304 }
305
306
307 int InsetIPADeco::docbook(odocstream & os, OutputParams const & runparams) const
308 {
309         // FIXME: Any docbook option here?
310         return InsetCollapsable::docbook(os, runparams);
311 }
312
313
314 docstring InsetIPADeco::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
315 {
316         // FIXME: Like in plaintext, the combining characters "&#x361;" (toptiebar)
317         // or "&#x35c;" (bottomtiebar) would need to be inserted just in the mid
318         // of the text string. (How) can this be done with the xhtml stream?
319         return InsetCollapsable::xhtml(xs, runparams);
320 }
321
322
323 docstring InsetIPADeco::toolTip(BufferView const &, int, int) const
324 {
325         return ipadecotranslator_loc().find(params_.type);
326 }
327
328
329 string InsetIPADeco::params2string(InsetIPADecoParams const & params)
330 {
331         ostringstream data;
332         data << "IPADeco" << ' ';
333         params.write(data);
334         return data.str();
335 }
336
337
338 void InsetIPADeco::string2params(string const & in, InsetIPADecoParams & params)
339 {
340         params = InsetIPADecoParams();
341
342         if (in.empty())
343                 return;
344
345         istringstream data(in);
346         Lexer lex;
347         lex.setStream(data);
348         lex.setContext("InsetIPADeco::string2params");
349         lex >> "IPADeco" >> "toptiebar";
350
351         params.read(lex);
352 }
353
354
355 void InsetIPADeco::validate(LaTeXFeatures & features) const
356 {
357         features.require("tipa");
358         InsetText::validate(features);
359 }
360
361
362 bool InsetIPADeco::insetAllowed(InsetCode code) const
363 {
364         switch (code) {
365         // code that is allowed
366         case ERT_CODE:
367         case IPACHAR_CODE:
368         case SCRIPT_CODE:
369                 return true;
370         default:
371                 return false;
372         }
373 }
374
375 /////////////////////////////////////////////////////////////////////////
376 //
377 // InsetIPAChar
378 //
379 /////////////////////////////////////////////////////////////////////////
380
381
382 InsetIPAChar::InsetIPAChar(Kind k)
383         : Inset(0), kind_(k)
384 {}
385
386
387 InsetIPAChar::Kind InsetIPAChar::kind() const
388 {
389         return kind_;
390 }
391
392
393 void InsetIPAChar::metrics(MetricsInfo & mi, Dimension & dim) const
394 {
395         frontend::FontMetrics const & fm =
396                 theFontMetrics(mi.base.font);
397         dim.asc = fm.maxAscent();
398         dim.des = fm.maxDescent();
399
400         string s;
401         switch (kind_) {
402                 case TONE_FALLING:
403                 case TONE_RISING:
404                 case TONE_HIGH_RISING:
405                 case TONE_LOW_RISING:
406                 case TONE_HIGH_RISING_FALLING:
407                         s = "_";
408                         break;
409         }
410         docstring ds(s.begin(), s.end());
411         dim.wid = fm.width(ds);
412         setDimCache(mi, dim);
413 }
414
415
416 void InsetIPAChar::draw(PainterInfo & pi, int x, int y) const
417 {
418         FontInfo font = pi.base.font;
419         frontend::FontMetrics const & fm =
420                         theFontMetrics(font);
421
422         switch (kind_) {
423         case TONE_FALLING:
424         {
425                 int w = fm.width(char_type('-'));
426                 int h = fm.ascent(char_type('M'));
427                 int x2 = x + w;
428                 int y2 = y - h;
429
430                 pi.pain.line(x2, y2, x2, y, Color_foreground);
431                 pi.pain.line(x2, y, x, y2, Color_foreground);
432                 break;
433         }
434         case TONE_RISING:
435         {
436                 int w = fm.width(char_type('-'));
437                 int h = fm.ascent(char_type('M'));
438                 int x2 = x + w;
439                 int y2 = y - h;
440
441                 pi.pain.line(x2, y, x2, y2, Color_foreground);
442                 pi.pain.line(x2, y2, x, y, Color_foreground);
443                 break;
444         }
445         case TONE_HIGH_RISING:
446         {
447                 int w = fm.width(char_type('-'));
448                 int h = fm.ascent(char_type('M'));
449                 int x2 = x + w;
450                 int y2 = y - h;
451                 int y3 = y - int(h * 0.75);
452
453                 pi.pain.line(x2, y, x2, y2, Color_foreground);
454                 pi.pain.line(x2, y2, x, y3, Color_foreground);
455                 break;
456         }
457         case TONE_LOW_RISING:
458         {
459                 int w = fm.width(char_type('-'));
460                 int h = fm.ascent(char_type('M'));
461                 int x2 = x + w;
462                 int y2 = y - h;
463                 int y3 = y - int(h * 0.25);
464
465                 pi.pain.line(x2, y, x2, y2, Color_foreground);
466                 pi.pain.line(x2, y3, x, y, Color_foreground);
467                 break;
468         }
469         case TONE_HIGH_RISING_FALLING:
470         {
471                 int w = fm.width(char_type('-'));
472                 int h = fm.ascent(char_type('M'));
473                 int x2 = x + w;
474                 int y2 = y - h;
475                 int x3 = x + int(w * 0.5);
476                 int y3 = y - int(h * 0.75);
477
478                 pi.pain.line(x2, y, x2, y2, Color_foreground);
479                 pi.pain.line(x2, y3, x3, y2, Color_foreground);
480                 pi.pain.line(x3, y2, x, y3, Color_foreground);
481                 break;
482         }
483         }
484 }
485
486
487 void InsetIPAChar::write(ostream & os) const
488 {
489         string const command = ipachartranslator().find(kind_);
490         if (command.empty()) {
491                 LYXERR0("InsetIPAChar::write: Unknown type");
492                 return;
493         }
494         os << "\\IPAChar " << command << "\n";
495 }
496
497
498 void InsetIPAChar::read(Lexer & lex)
499 {
500         lex.next();
501         string const command = lex.getString();
502         kind_ = ipachartranslator().find(command);
503 }
504
505
506 void InsetIPAChar::latex(otexstream & os,
507                          OutputParams const &) const
508 {
509         string const command = ipachartranslator().find(kind_);
510         os << command;
511 }
512
513
514 int InsetIPAChar::plaintext(odocstringstream & os, OutputParams const &, size_t) const
515 {
516         switch (kind_) {
517         case TONE_FALLING:
518                 os.put(0x02e5);
519                 os.put(0x02e9);
520                 return 2;
521         case TONE_RISING:
522                 os.put(0x02e9);
523                 os.put(0x02e5);
524                 return 2;
525         case TONE_HIGH_RISING:
526                 os.put(0x02e7);
527                 os.put(0x02e5);
528                 return 2;
529         case TONE_LOW_RISING:
530                 os.put(0x02e9);
531                 os.put(0x02e7);
532                 return 2;
533         case TONE_HIGH_RISING_FALLING:
534                 os.put(0x02e8);
535                 os.put(0x02e5);
536                 os.put(0x02e8);
537                 return 3;
538         }
539         return 0;
540 }
541
542
543 int InsetIPAChar::docbook(odocstream & /*os*/, OutputParams const &) const
544 {
545         switch (kind_) {
546         // FIXME
547         LYXERR0("IPA tone macros not yet implemented with DocBook!");
548         case TONE_FALLING:
549         case TONE_RISING:
550         case TONE_HIGH_RISING:
551         case TONE_LOW_RISING:
552         case TONE_HIGH_RISING_FALLING:
553                 break;
554         }
555         return 0;
556 }
557
558
559 docstring InsetIPAChar::xhtml(XHTMLStream & xs, OutputParams const &) const
560 {
561         switch (kind_) {
562         case TONE_FALLING:
563                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e5;"
564                    << XHTMLStream::ESCAPE_NONE << "&#x2e9;";
565                 break;
566         case TONE_RISING:
567                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e9;"
568                    << XHTMLStream::ESCAPE_NONE << "&#x2e5;";
569                 break;
570         case TONE_HIGH_RISING:
571                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e7;"
572                    << XHTMLStream::ESCAPE_NONE << "&#x2e5;";
573                 break;
574         case TONE_LOW_RISING:
575                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e9;"
576                    << XHTMLStream::ESCAPE_NONE << "&#x2e7;";
577                 break;
578         case TONE_HIGH_RISING_FALLING:
579                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e8;"
580                    << XHTMLStream::ESCAPE_NONE << "&#x2e5;"
581                    << XHTMLStream::ESCAPE_NONE << "&#x2e8;";
582                 break;
583         }
584         return docstring();
585 }
586
587
588 void InsetIPAChar::toString(odocstream & os) const
589 {
590         odocstringstream ods;
591         plaintext(ods, OutputParams(0));
592         os << ods.str();
593 }
594
595
596 void InsetIPAChar::forToc(docstring & os, size_t) const
597 {
598         odocstringstream ods;
599         plaintext(ods, OutputParams(0));
600         os += ods.str();
601 }
602
603
604 void InsetIPAChar::validate(LaTeXFeatures & features) const
605 {
606         switch (kind_) {
607         case TONE_FALLING:
608         case TONE_RISING:
609         case TONE_HIGH_RISING:
610         case TONE_LOW_RISING:
611         case TONE_HIGH_RISING_FALLING:
612                 features.require("tone");
613                 break;
614         default:
615                 break;
616         }
617 }
618
619
620 bool InsetIPAChar::isLetter() const
621 {
622         return true;
623 }
624
625
626 bool InsetIPAChar::isLineSeparator() const
627 {
628         return false;
629 }
630
631
632 } // namespace lyx