2 * \file InsetIPAMacro.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Jürgen Spitzmüller
8 * Full author contact details are available in file CREDITS.
13 #include "InsetIPAMacro.h"
16 #include "BufferParams.h"
17 #include "Dimension.h"
20 #include "FuncRequest.h"
21 #include "FuncStatus.h"
22 #include "InsetLayout.h"
23 #include "LaTeXFeatures.h"
24 #include "MetricsInfo.h"
26 #include "texstream.h"
28 #include "frontends/FontMetrics.h"
29 #include "frontends/Painter.h"
31 #include "support/debug.h"
32 #include "support/docstream.h"
33 #include "support/gettext.h"
34 #include "support/Lexer.h"
35 #include "support/Translator.h"
45 typedef Translator<string, InsetIPADecoParams::Type> IPADecoTranslator;
46 typedef Translator<docstring, InsetIPADecoParams::Type> IPADecoTranslatorLoc;
48 IPADecoTranslator const init_ipadecotranslator()
50 IPADecoTranslator translator("toptiebar", InsetIPADecoParams::Toptiebar);
51 translator.addPair("bottomtiebar", InsetIPADecoParams::Bottomtiebar);
56 IPADecoTranslatorLoc const init_ipadecotranslator_loc()
58 IPADecoTranslatorLoc translator(_("Top tie bar"), InsetIPADecoParams::Toptiebar);
59 translator.addPair(_("Bottom tie bar"), InsetIPADecoParams::Bottomtiebar);
64 IPADecoTranslator const & ipadecotranslator()
66 static IPADecoTranslator const decotranslator =
67 init_ipadecotranslator();
68 return decotranslator;
72 IPADecoTranslatorLoc const & ipadecotranslator_loc()
74 static IPADecoTranslatorLoc const translator =
75 init_ipadecotranslator_loc();
80 typedef Translator<string, InsetIPAChar::Kind> IPACharTranslator;
82 IPACharTranslator const init_ipachartranslator()
84 IPACharTranslator translator("\\tone{51}", InsetIPAChar::TONE_FALLING);
85 translator.addPair("\\tone{15}", InsetIPAChar::TONE_RISING);
86 translator.addPair("\\tone{45}", InsetIPAChar::TONE_HIGH_RISING);
87 translator.addPair("\\tone{12}", InsetIPAChar::TONE_LOW_RISING);
88 translator.addPair("\\tone{454}", InsetIPAChar::TONE_HIGH_RISING_FALLING);
93 IPACharTranslator const & ipachartranslator()
95 static IPACharTranslator const chartranslator =
96 init_ipachartranslator();
97 return chartranslator;
103 InsetIPADecoParams::InsetIPADecoParams()
108 void InsetIPADecoParams::write(ostream & os) const
110 string const label = ipadecotranslator().find(type);
111 os << "IPADeco " << label << "\n";
115 void InsetIPADecoParams::read(Lexer & lex)
120 type = ipadecotranslator().find(label);
124 /////////////////////////////////////////////////////////////////////
128 /////////////////////////////////////////////////////////////////////
130 InsetIPADeco::InsetIPADeco(Buffer * buf, string const & label)
131 : InsetCollapsible(buf)
134 setFrameColor(Color_insetframe);
135 params_.type = ipadecotranslator().find(label);
139 InsetIPADeco::~InsetIPADeco()
143 docstring InsetIPADeco::layoutName() const
145 return from_ascii("IPADeco:" + ipadecotranslator().find(params_.type));
149 void InsetIPADeco::metrics(MetricsInfo & mi, Dimension & dim) const
151 InsetText::metrics(mi, dim);
153 if (params_.type == InsetIPADecoParams::Toptiebar) {
154 // consider width of the inset label
155 FontInfo font(getLayout().labelfont());
156 font.realize(sane_font);
162 docstring const label(1, char_type(0x2040));
163 theFontMetrics(font).rectText(label, w, a, d);
164 dim.asc += int(a * 0.5);
166 if (params_.type == InsetIPADecoParams::Bottomtiebar) {
167 // consider width of the inset label
168 FontInfo font(getLayout().labelfont());
169 font.realize(sane_font);
175 docstring const label(1, char_type(0x203f));
176 theFontMetrics(font).rectText(label, w, a, d);
177 dim.des += int(d * 1.5);
182 void InsetIPADeco::draw(PainterInfo & pi, int x, int y) const
185 InsetCollapsible::draw(pi, x, y);
187 // draw the inset marker
188 drawMarkers(pi, x, y);
190 Dimension const dim = dimension(*pi.base.bv);
192 if (params_.type == InsetIPADecoParams::Toptiebar) {
193 FontInfo font(getLayout().labelfont());
194 font.realize(sane_font);
200 int asc = dim.ascent();
201 docstring const label(1, char_type(0x2040));
202 theFontMetrics(font).rectText(label, w, a, d);
203 int const ww = max(dim.wid, w);
204 pi.pain.rectText(x + (ww - w) / 2, y - int(asc / 2.5),
205 label, font, Color_none, Color_none);
208 if (params_.type == InsetIPADecoParams::Bottomtiebar) {
209 FontInfo font(getLayout().labelfont());
210 font.realize(sane_font);
216 int desc = dim.descent();
217 docstring const label(1, char_type(0x203f));
218 theFontMetrics(font).rectText(label, w, a, d);
219 int const ww = max(dim.wid, w);
220 pi.pain.rectText(x + (ww - w) / 2, y + int(desc / 1.5),
221 label, font, Color_none, Color_none);
226 void InsetIPADeco::write(ostream & os) const
229 InsetCollapsible::write(os);
233 void InsetIPADeco::read(Lexer & lex)
236 InsetCollapsible::read(lex);
240 void InsetIPADeco::doDispatch(Cursor & cur, FuncRequest & cmd)
242 switch (cmd.action()) {
243 case LFUN_QUOTE_INSERT: {
244 FuncRequest fr(LFUN_SELF_INSERT, "\"");
245 InsetText::doDispatch(cur, fr);
249 InsetText::doDispatch(cur, cmd);
255 bool InsetIPADeco::getStatus(Cursor & cur, FuncRequest const & cmd,
256 FuncStatus & flag) const
258 switch (cmd.action()) {
259 case LFUN_SCRIPT_INSERT: {
260 if (cmd.argument() == "subscript") {
261 flag.setEnabled(false);
267 flag.setEnabled(true);
273 return InsetText::getStatus(cur, cmd, flag);
277 void InsetIPADeco::latex(otexstream & os, OutputParams const & runparams) const
279 if (params_.type == InsetIPADecoParams::Toptiebar)
280 os << "\\texttoptiebar{";
281 else if (params_.type == InsetIPADecoParams::Bottomtiebar)
282 os << "\\textbottomtiebar{";
283 InsetCollapsible::latex(os, runparams);
289 std::pair<docstring, docstring> splitPlainTextInHalves(
290 const InsetIPADeco * inset, OutputParams const & runparams,
291 size_t max_length = INT_MAX)
293 odocstringstream ods;
294 int h = inset->InsetCollapsible::plaintext(ods, runparams, max_length) / 2;
295 docstring result = ods.str();
296 docstring const before = result.substr(0, h);
297 docstring const after = result.substr(h, result.size());
298 return {before, after};
303 int InsetIPADeco::plaintext(odocstringstream & os,
304 OutputParams const & runparams, size_t max_length) const
308 tie(before, after) = splitPlainTextInHalves(this, runparams, max_length);
310 if (params_.type == InsetIPADecoParams::Toptiebar) {
315 else if (params_.type == InsetIPADecoParams::Bottomtiebar) {
320 return before.size() + after.size();
324 void InsetIPADeco::docbook(XMLStream & xs, OutputParams const & runparams) const
326 // The special combining character must be put in the middle, between the two other characters.
327 // It will not work if there is anything else than two pure characters, so going back to plaintext.
330 tie(before, after) = splitPlainTextInHalves(this, runparams);
332 xs << XMLStream::ESCAPE_NONE << before;
333 if (params_.type == InsetIPADecoParams::Toptiebar)
334 xs << XMLStream::ESCAPE_NONE << "͡";
335 else if (params_.type == InsetIPADecoParams::Bottomtiebar)
336 xs << XMLStream::ESCAPE_NONE << "͜";
337 xs << XMLStream::ESCAPE_NONE << after;
341 docstring InsetIPADeco::xhtml(XMLStream & xs, OutputParams const & runparams) const
343 // The DocBook encoding for this inset has no DocBook tag, but sheer XML (relying on a plaintext
344 // transformation of the inset).
345 docbook(xs, runparams);
350 docstring InsetIPADeco::toolTip(BufferView const &, int, int) const
352 return ipadecotranslator_loc().find(params_.type);
356 string InsetIPADeco::params2string(InsetIPADecoParams const & params)
359 data << "IPADeco" << ' ';
365 void InsetIPADeco::string2params(string const & in, InsetIPADecoParams & params)
367 params = InsetIPADecoParams();
372 istringstream data(in);
375 lex.setContext("InsetIPADeco::string2params");
376 lex >> "IPADeco" >> "toptiebar";
382 void InsetIPADeco::validate(LaTeXFeatures & features) const
384 features.require("tipa");
385 InsetText::validate(features);
389 bool InsetIPADeco::insetAllowed(InsetCode code) const
392 // code that is allowed
402 /////////////////////////////////////////////////////////////////////////
406 /////////////////////////////////////////////////////////////////////////
409 InsetIPAChar::InsetIPAChar(Kind k)
410 : Inset(nullptr), kind_(k)
414 InsetIPAChar::Kind InsetIPAChar::kind() const
420 void InsetIPAChar::metrics(MetricsInfo & mi, Dimension & dim) const
422 frontend::FontMetrics const & fm =
423 theFontMetrics(mi.base.font);
424 dim.asc = fm.maxAscent();
425 dim.des = fm.maxDescent();
431 case TONE_HIGH_RISING:
432 case TONE_LOW_RISING:
433 case TONE_HIGH_RISING_FALLING:
437 docstring ds(s.begin(), s.end());
438 dim.wid = fm.width(ds);
442 void InsetIPAChar::draw(PainterInfo & pi, int x, int y) const
444 FontInfo font = pi.base.font;
445 frontend::FontMetrics const & fm =
446 theFontMetrics(font);
451 int w = fm.width(char_type('-'));
452 int h = fm.ascent(char_type('M'));
456 pi.pain.line(x2, y2, x2, y, Color_foreground);
457 pi.pain.line(x2, y, x, y2, Color_foreground);
462 int w = fm.width(char_type('-'));
463 int h = fm.ascent(char_type('M'));
467 pi.pain.line(x2, y, x2, y2, Color_foreground);
468 pi.pain.line(x2, y2, x, y, Color_foreground);
471 case TONE_HIGH_RISING:
473 int w = fm.width(char_type('-'));
474 int h = fm.ascent(char_type('M'));
477 int y3 = y - int(h * 0.75);
479 pi.pain.line(x2, y, x2, y2, Color_foreground);
480 pi.pain.line(x2, y2, x, y3, Color_foreground);
483 case TONE_LOW_RISING:
485 int w = fm.width(char_type('-'));
486 int h = fm.ascent(char_type('M'));
489 int y3 = y - int(h * 0.25);
491 pi.pain.line(x2, y, x2, y2, Color_foreground);
492 pi.pain.line(x2, y3, x, y, Color_foreground);
495 case TONE_HIGH_RISING_FALLING:
497 int w = fm.width(char_type('-'));
498 int h = fm.ascent(char_type('M'));
501 int x3 = x + int(w * 0.5);
502 int y3 = y - int(h * 0.75);
504 pi.pain.line(x2, y, x2, y2, Color_foreground);
505 pi.pain.line(x2, y3, x3, y2, Color_foreground);
506 pi.pain.line(x3, y2, x, y3, Color_foreground);
513 void InsetIPAChar::write(ostream & os) const
515 string const command = ipachartranslator().find(kind_);
516 if (command.empty()) {
517 LYXERR0("InsetIPAChar::write: Unknown type");
520 os << "\\IPAChar " << command << "\n";
524 void InsetIPAChar::read(Lexer & lex)
527 string const command = lex.getString();
528 kind_ = ipachartranslator().find(command);
532 void InsetIPAChar::latex(otexstream & os,
533 OutputParams const &) const
535 string const command = ipachartranslator().find(kind_);
540 int InsetIPAChar::plaintext(odocstringstream & os, OutputParams const &, size_t) const
551 case TONE_HIGH_RISING:
555 case TONE_LOW_RISING:
559 case TONE_HIGH_RISING_FALLING:
570 std::string ipaCharToXMLEntity(InsetIPAChar::Kind kind) {
572 case InsetIPAChar::Kind::TONE_FALLING:
573 return "˥˩";
574 case InsetIPAChar::Kind::TONE_RISING:
575 return "˩˥";
576 case InsetIPAChar::Kind::TONE_HIGH_RISING:
577 return "˧˥";
578 case InsetIPAChar::Kind::TONE_LOW_RISING:
579 return "˩˧";
580 case InsetIPAChar::Kind::TONE_HIGH_RISING_FALLING:
581 return "˨˥˨";
588 void InsetIPAChar::docbook(XMLStream & xs, OutputParams const &) const
590 xs << XMLStream::ESCAPE_NONE << from_ascii(ipaCharToXMLEntity(kind()));
594 docstring InsetIPAChar::xhtml(XMLStream & xs, OutputParams const &) const
596 xs << XMLStream::ESCAPE_NONE << from_ascii(ipaCharToXMLEntity(kind()));
601 void InsetIPAChar::toString(odocstream & os) const
603 odocstringstream ods;
604 plaintext(ods, OutputParams(0));
609 void InsetIPAChar::forOutliner(docstring & os, size_t const, bool const) const
611 odocstringstream ods;
612 plaintext(ods, OutputParams(0));
617 void InsetIPAChar::validate(LaTeXFeatures & features) const
622 case TONE_HIGH_RISING:
623 case TONE_LOW_RISING:
624 case TONE_HIGH_RISING_FALLING:
625 features.require("tone");