]> git.lyx.org Git - lyx.git/blob - src/insets/InsetIPAMacro.cpp
Update my email and status.
[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(odocstream & os,
285                             OutputParams const & runparams) const
286 {
287         odocstringstream ods;
288         int h = (int)(InsetCollapsable::plaintext(ods, runparams) / 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         if (!buffer_->params().useNonTeXFonts)
358                 features.require("tipa");
359         InsetText::validate(features);
360 }
361
362
363 bool InsetIPADeco::insetAllowed(InsetCode code) const
364 {
365         switch (code) {
366         // code that is allowed
367         case ERT_CODE:
368         case IPACHAR_CODE:
369         case SCRIPT_CODE:
370                 return true;
371         default:
372                 return false;
373         }
374 }
375
376 /////////////////////////////////////////////////////////////////////////
377 //
378 // InsetIPAChar
379 //
380 /////////////////////////////////////////////////////////////////////////
381
382
383 InsetIPAChar::InsetIPAChar(Kind k)
384         : Inset(0), kind_(k)
385 {}
386
387
388 InsetIPAChar::Kind InsetIPAChar::kind() const
389 {
390         return kind_;
391 }
392
393
394 void InsetIPAChar::metrics(MetricsInfo & mi, Dimension & dim) const
395 {
396         frontend::FontMetrics const & fm =
397                 theFontMetrics(mi.base.font);
398         dim.asc = fm.maxAscent();
399         dim.des = fm.maxDescent();
400
401         string s;
402         switch (kind_) {
403                 case TONE_FALLING:
404                 case TONE_RISING:
405                 case TONE_HIGH_RISING:
406                 case TONE_LOW_RISING:
407                 case TONE_HIGH_RISING_FALLING:
408                         s = "_";
409                         break;
410         }
411         docstring ds(s.begin(), s.end());
412         dim.wid = fm.width(ds);
413         setDimCache(mi, dim);
414 }
415
416
417 void InsetIPAChar::draw(PainterInfo & pi, int x, int y) const
418 {
419         FontInfo font = pi.base.font;
420         frontend::FontMetrics const & fm =
421                         theFontMetrics(font);
422
423         switch (kind_) {
424         case TONE_FALLING:
425         {
426                 int w = fm.width(char_type('-'));
427                 int h = fm.ascent(char_type('M'));
428                 int x2 = x + w;
429                 int y2 = y - h;
430
431                 pi.pain.line(x2, y2, x2, y, Color_foreground);
432                 pi.pain.line(x2, y, x, y2, Color_foreground);
433                 break;
434         }
435         case TONE_RISING:
436         {
437                 int w = fm.width(char_type('-'));
438                 int h = fm.ascent(char_type('M'));
439                 int x2 = x + w;
440                 int y2 = y - h;
441
442                 pi.pain.line(x2, y, x2, y2, Color_foreground);
443                 pi.pain.line(x2, y2, x, y, Color_foreground);
444                 break;
445         }
446         case TONE_HIGH_RISING:
447         {
448                 int w = fm.width(char_type('-'));
449                 int h = fm.ascent(char_type('M'));
450                 int x2 = x + w;
451                 int y2 = y - h;
452                 int y3 = y - int(h * 0.75);
453
454                 pi.pain.line(x2, y, x2, y2, Color_foreground);
455                 pi.pain.line(x2, y2, x, y3, Color_foreground);
456                 break;
457         }
458         case TONE_LOW_RISING:
459         {
460                 int w = fm.width(char_type('-'));
461                 int h = fm.ascent(char_type('M'));
462                 int x2 = x + w;
463                 int y2 = y - h;
464                 int y3 = y - int(h * 0.25);
465
466                 pi.pain.line(x2, y, x2, y2, Color_foreground);
467                 pi.pain.line(x2, y3, x, y, Color_foreground);
468                 break;
469         }
470         case TONE_HIGH_RISING_FALLING:
471         {
472                 int w = fm.width(char_type('-'));
473                 int h = fm.ascent(char_type('M'));
474                 int x2 = x + w;
475                 int y2 = y - h;
476                 int x3 = x + int(w * 0.5);
477                 int y3 = y - int(h * 0.75);
478
479                 pi.pain.line(x2, y, x2, y2, Color_foreground);
480                 pi.pain.line(x2, y3, x3, y2, Color_foreground);
481                 pi.pain.line(x3, y2, x, y3, Color_foreground);
482                 break;
483         }
484         }
485 }
486
487
488 void InsetIPAChar::write(ostream & os) const
489 {
490         string const command = ipachartranslator().find(kind_);
491         if (command.empty()) {
492                 LYXERR0("InsetIPAChar::write: Unknown type");
493                 return;
494         }
495         os << "\\IPAChar " << command << "\n";
496 }
497
498
499 void InsetIPAChar::read(Lexer & lex)
500 {
501         lex.next();
502         string const command = lex.getString();
503         kind_ = ipachartranslator().find(command);
504 }
505
506
507 void InsetIPAChar::latex(otexstream & os,
508                          OutputParams const &) const
509 {
510         string const command = ipachartranslator().find(kind_);
511         os << command;
512 }
513
514
515 int InsetIPAChar::plaintext(odocstream & os, OutputParams const &) const
516 {
517         switch (kind_) {
518         case TONE_FALLING:
519                 os.put(0x02e5);
520                 os.put(0x02e9);
521                 return 2;
522         case TONE_RISING:
523                 os.put(0x02e9);
524                 os.put(0x02e5);
525                 return 2;
526         case TONE_HIGH_RISING:
527                 os.put(0x02e7);
528                 os.put(0x02e5);
529                 return 2;
530         case TONE_LOW_RISING:
531                 os.put(0x02e9);
532                 os.put(0x02e7);
533                 return 2;
534         case TONE_HIGH_RISING_FALLING:
535                 os.put(0x02e8);
536                 os.put(0x02e5);
537                 os.put(0x02e8);
538                 return 3;
539         }
540         return 0;
541 }
542
543
544 int InsetIPAChar::docbook(odocstream & /*os*/, OutputParams const &) const
545 {
546         switch (kind_) {
547         // FIXME
548         LYXERR0("IPA tone macros not yet implemented with DocBook!");
549         case TONE_FALLING:
550         case TONE_RISING:
551         case TONE_HIGH_RISING:
552         case TONE_LOW_RISING:
553         case TONE_HIGH_RISING_FALLING:
554                 break;
555         }
556         return 0;
557 }
558
559
560 docstring InsetIPAChar::xhtml(XHTMLStream & xs, OutputParams const &) const
561 {
562         switch (kind_) {
563         case TONE_FALLING:
564                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e5;"
565                    << XHTMLStream::ESCAPE_NONE << "&#x2e9;";
566                 break;
567         case TONE_RISING:
568                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e9;"
569                    << XHTMLStream::ESCAPE_NONE << "&#x2e5;";
570                 break;
571         case TONE_HIGH_RISING:
572                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e7;"
573                    << XHTMLStream::ESCAPE_NONE << "&#x2e5;";
574                 break;
575         case TONE_LOW_RISING:
576                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e9;"
577                    << XHTMLStream::ESCAPE_NONE << "&#x2e7;";
578                 break;
579         case TONE_HIGH_RISING_FALLING:
580                 xs << XHTMLStream::ESCAPE_NONE << "&#x2e8;"
581                    << XHTMLStream::ESCAPE_NONE << "&#x2e5;"
582                    << XHTMLStream::ESCAPE_NONE << "&#x2e8;";
583                 break;
584         }
585         return docstring();
586 }
587
588
589 void InsetIPAChar::toString(odocstream & os) const
590 {
591         plaintext(os, OutputParams(0));
592 }
593
594
595 void InsetIPAChar::forToc(docstring & os, size_t) const
596 {
597         odocstringstream ods;
598         plaintext(ods, OutputParams(0));
599         os += ods.str();
600 }
601
602
603 void InsetIPAChar::validate(LaTeXFeatures & features) const
604 {
605         switch (kind_) {
606         case TONE_FALLING:
607         case TONE_RISING:
608         case TONE_HIGH_RISING:
609         case TONE_LOW_RISING:
610         case TONE_HIGH_RISING_FALLING:
611                 if (!buffer_->params().useNonTeXFonts)
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