mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-16 07:55:41 +00:00
615 lines
13 KiB
C++
615 lines
13 KiB
C++
|
/**
|
||
|
* \file InsetIPAMacro.cpp
|
||
|
* This file is part of LyX, the document processor.
|
||
|
* Licence details can be found in the file COPYING.
|
||
|
*
|
||
|
* \author Jürgen Spitzmüller
|
||
|
*
|
||
|
* Full author contact details are available in file CREDITS.
|
||
|
*/
|
||
|
|
||
|
#include <config.h>
|
||
|
|
||
|
#include "InsetIPAMacro.h"
|
||
|
|
||
|
#include "Buffer.h"
|
||
|
#include "BufferParams.h"
|
||
|
#include "Dimension.h"
|
||
|
#include "Encoding.h"
|
||
|
#include "Font.h"
|
||
|
#include "FuncRequest.h"
|
||
|
#include "FuncStatus.h"
|
||
|
#include "LaTeXFeatures.h"
|
||
|
#include "Lexer.h"
|
||
|
#include "MetricsInfo.h"
|
||
|
#include "output_xhtml.h"
|
||
|
|
||
|
#include "frontends/FontMetrics.h"
|
||
|
#include "frontends/Painter.h"
|
||
|
|
||
|
#include "support/debug.h"
|
||
|
#include "support/docstream.h"
|
||
|
#include "support/gettext.h"
|
||
|
#include "support/Translator.h"
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
namespace lyx {
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
typedef Translator<string, InsetIPADecoParams::Type> IPADecoTranslator;
|
||
|
typedef Translator<docstring, InsetIPADecoParams::Type> IPADecoTranslatorLoc;
|
||
|
|
||
|
IPADecoTranslator const init_ipadecotranslator()
|
||
|
{
|
||
|
IPADecoTranslator translator("toptiebar", InsetIPADecoParams::Toptiebar);
|
||
|
translator.addPair("bottomtiebar", InsetIPADecoParams::Bottomtiebar);
|
||
|
return translator;
|
||
|
}
|
||
|
|
||
|
|
||
|
IPADecoTranslatorLoc const init_ipadecotranslator_loc()
|
||
|
{
|
||
|
IPADecoTranslatorLoc translator(_("Top tie bar"), InsetIPADecoParams::Toptiebar);
|
||
|
translator.addPair(_("Bottom tie bar"), InsetIPADecoParams::Bottomtiebar);
|
||
|
return translator;
|
||
|
}
|
||
|
|
||
|
|
||
|
IPADecoTranslator const & ipadecotranslator()
|
||
|
{
|
||
|
static IPADecoTranslator decotranslator = init_ipadecotranslator();
|
||
|
return decotranslator;
|
||
|
}
|
||
|
|
||
|
|
||
|
IPADecoTranslatorLoc const & ipadecotranslator_loc()
|
||
|
{
|
||
|
static IPADecoTranslatorLoc translator = init_ipadecotranslator_loc();
|
||
|
return translator;
|
||
|
}
|
||
|
|
||
|
|
||
|
typedef Translator<string, InsetIPAChar::Kind> IPACharTranslator;
|
||
|
|
||
|
IPACharTranslator const init_ipachartranslator()
|
||
|
{
|
||
|
IPACharTranslator translator("\\tone{51}", InsetIPAChar::TONE_FALLING);
|
||
|
translator.addPair("\\tone{15}", InsetIPAChar::TONE_RISING);
|
||
|
translator.addPair("\\tone{45}", InsetIPAChar::TONE_HIGH_RISING);
|
||
|
translator.addPair("\\tone{12}", InsetIPAChar::TONE_LOW_RISING);
|
||
|
translator.addPair("\\tone{454}", InsetIPAChar::TONE_HIGH_RISING_FALLING);
|
||
|
return translator;
|
||
|
}
|
||
|
|
||
|
|
||
|
IPACharTranslator const & ipachartranslator()
|
||
|
{
|
||
|
static IPACharTranslator chartranslator = init_ipachartranslator();
|
||
|
return chartranslator;
|
||
|
}
|
||
|
|
||
|
} // anon
|
||
|
|
||
|
|
||
|
InsetIPADecoParams::InsetIPADecoParams()
|
||
|
: type(Bottomtiebar)
|
||
|
{}
|
||
|
|
||
|
|
||
|
void InsetIPADecoParams::write(ostream & os) const
|
||
|
{
|
||
|
string const label = ipadecotranslator().find(type);
|
||
|
os << "IPADeco " << label << "\n";
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADecoParams::read(Lexer & lex)
|
||
|
{
|
||
|
string label;
|
||
|
lex >> label;
|
||
|
if (lex)
|
||
|
type = ipadecotranslator().find(label);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// InsetIPADeco
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
InsetIPADeco::InsetIPADeco(Buffer * buf, string const & label)
|
||
|
: InsetCollapsable(buf)
|
||
|
{
|
||
|
setDrawFrame(true);
|
||
|
setFrameColor(Color_insetframe);
|
||
|
params_.type = ipadecotranslator().find(label);
|
||
|
}
|
||
|
|
||
|
|
||
|
InsetIPADeco::~InsetIPADeco()
|
||
|
{}
|
||
|
|
||
|
|
||
|
docstring InsetIPADeco::layoutName() const
|
||
|
{
|
||
|
return from_ascii("IPADeco:" + ipadecotranslator().find(params_.type));
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::metrics(MetricsInfo & mi, Dimension & dim) const
|
||
|
{
|
||
|
InsetText::metrics(mi, dim);
|
||
|
|
||
|
if (params_.type == InsetIPADecoParams::Toptiebar) {
|
||
|
// consider width of the inset label
|
||
|
FontInfo font(getLayout().labelfont());
|
||
|
font.realize(sane_font);
|
||
|
font.decSize();
|
||
|
font.decSize();
|
||
|
int w = 0;
|
||
|
int a = 0;
|
||
|
int d = 0;
|
||
|
docstring const label(1, char_type(0x2040));
|
||
|
theFontMetrics(font).rectText(label, w, a, d);
|
||
|
dim.asc += a * 0.5;
|
||
|
}
|
||
|
if (params_.type == InsetIPADecoParams::Bottomtiebar) {
|
||
|
// consider width of the inset label
|
||
|
FontInfo font(getLayout().labelfont());
|
||
|
font.realize(sane_font);
|
||
|
font.decSize();
|
||
|
font.decSize();
|
||
|
int w = 0;
|
||
|
int a = 0;
|
||
|
int d = 0;
|
||
|
docstring const label(1, char_type(0x203f));
|
||
|
theFontMetrics(font).rectText(label, w, a, d);
|
||
|
dim.des += d * 1.5;
|
||
|
}
|
||
|
|
||
|
// cache the inset dimension
|
||
|
setDimCache(mi, dim);
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::draw(PainterInfo & pi, int x, int y) const
|
||
|
{
|
||
|
// draw the text
|
||
|
InsetCollapsable::draw(pi, x, y);
|
||
|
|
||
|
// draw the inset marker
|
||
|
drawMarkers(pi, x, y);
|
||
|
|
||
|
Dimension const dim = Inset::dimension(*pi.base.bv);
|
||
|
|
||
|
if (params_.type == InsetIPADecoParams::Toptiebar) {
|
||
|
FontInfo font(getLayout().labelfont());
|
||
|
font.realize(sane_font);
|
||
|
font.decSize();
|
||
|
font.decSize();
|
||
|
int w = 0;
|
||
|
int a = 0;
|
||
|
int d = 0;
|
||
|
int asc = dim.ascent();
|
||
|
docstring const label(1, char_type(0x2040));
|
||
|
theFontMetrics(font).rectText(label, w, a, d);
|
||
|
int const ww = max(dim.wid, w);
|
||
|
pi.pain.rectText(x + (ww - w) / 2, y - (asc / 2.5),
|
||
|
label, font, Color_none, Color_none);
|
||
|
}
|
||
|
|
||
|
if (params_.type == InsetIPADecoParams::Bottomtiebar) {
|
||
|
FontInfo font(getLayout().labelfont());
|
||
|
font.realize(sane_font);
|
||
|
font.decSize();
|
||
|
font.decSize();
|
||
|
int w = 0;
|
||
|
int a = 0;
|
||
|
int d = 0;
|
||
|
int desc = dim.descent();
|
||
|
docstring const label(1, char_type(0x203f));
|
||
|
theFontMetrics(font).rectText(label, w, a, d);
|
||
|
int const ww = max(dim.wid, w);
|
||
|
pi.pain.rectText(x + (ww - w) / 2, y + (desc / 1.5),
|
||
|
label, font, Color_none, Color_none);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::write(ostream & os) const
|
||
|
{
|
||
|
params_.write(os);
|
||
|
InsetCollapsable::write(os);
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::read(Lexer & lex)
|
||
|
{
|
||
|
params_.read(lex);
|
||
|
InsetCollapsable::read(lex);
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::doDispatch(Cursor & cur, FuncRequest & cmd)
|
||
|
{
|
||
|
switch (cmd.action()) {
|
||
|
case LFUN_QUOTE_INSERT: {
|
||
|
FuncRequest fr(LFUN_SELF_INSERT, "\"");
|
||
|
InsetText::doDispatch(cur, fr);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
InsetText::doDispatch(cur, cmd);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool InsetIPADeco::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||
|
FuncStatus & flag) const
|
||
|
{
|
||
|
switch (cmd.action()) {
|
||
|
case LFUN_SCRIPT_INSERT: {
|
||
|
if (cmd.argument() == "subscript") {
|
||
|
flag.setEnabled(false);
|
||
|
return true;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case LFUN_IN_IPA:
|
||
|
flag.setEnabled(true);
|
||
|
return true;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return InsetText::getStatus(cur, cmd, flag);
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::latex(otexstream & os, OutputParams const & runparams) const
|
||
|
{
|
||
|
if (params_.type == InsetIPADecoParams::Toptiebar)
|
||
|
os << "\\texttoptiebar{";
|
||
|
else if (params_.type == InsetIPADecoParams::Bottomtiebar)
|
||
|
os << "\\textbottomtiebar{";
|
||
|
InsetCollapsable::latex(os, runparams);
|
||
|
os << "}";
|
||
|
}
|
||
|
|
||
|
|
||
|
int InsetIPADeco::plaintext(odocstream & os,
|
||
|
OutputParams const & runparams) const
|
||
|
{
|
||
|
// FIXME: Any plaintext option here?
|
||
|
return InsetCollapsable::plaintext(os, runparams);
|
||
|
}
|
||
|
|
||
|
|
||
|
int InsetIPADeco::docbook(odocstream & os, OutputParams const & runparams) const
|
||
|
{
|
||
|
// FIXME: Any docbook option here?
|
||
|
return InsetCollapsable::docbook(os, runparams);
|
||
|
}
|
||
|
|
||
|
|
||
|
docstring InsetIPADeco::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
|
||
|
{
|
||
|
// FIXME: Any xhtml option here?
|
||
|
return InsetCollapsable::xhtml(xs, runparams);
|
||
|
}
|
||
|
|
||
|
|
||
|
docstring InsetIPADeco::toolTip(BufferView const &, int, int) const
|
||
|
{
|
||
|
return ipadecotranslator_loc().find(params_.type);
|
||
|
}
|
||
|
|
||
|
|
||
|
string InsetIPADeco::params2string(InsetIPADecoParams const & params)
|
||
|
{
|
||
|
ostringstream data;
|
||
|
data << "IPADeco" << ' ';
|
||
|
params.write(data);
|
||
|
return data.str();
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::string2params(string const & in, InsetIPADecoParams & params)
|
||
|
{
|
||
|
params = InsetIPADecoParams();
|
||
|
|
||
|
if (in.empty())
|
||
|
return;
|
||
|
|
||
|
istringstream data(in);
|
||
|
Lexer lex;
|
||
|
lex.setStream(data);
|
||
|
lex.setContext("InsetIPADeco::string2params");
|
||
|
lex >> "IPADeco" >> "toptiebar";
|
||
|
|
||
|
params.read(lex);
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPADeco::validate(LaTeXFeatures & features) const
|
||
|
{
|
||
|
if (!buffer_->params().useNonTeXFonts)
|
||
|
features.require("tipa");
|
||
|
InsetText::validate(features);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool InsetIPADeco::insetAllowed(InsetCode code) const
|
||
|
{
|
||
|
switch (code) {
|
||
|
// code that is allowed
|
||
|
case ERT_CODE:
|
||
|
case IPACHAR_CODE:
|
||
|
case SCRIPT_CODE:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// InsetIPAChar
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
InsetIPAChar::InsetIPAChar(Kind k)
|
||
|
: Inset(0), kind_(k)
|
||
|
{}
|
||
|
|
||
|
|
||
|
InsetIPAChar::Kind InsetIPAChar::kind() const
|
||
|
{
|
||
|
return kind_;
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::metrics(MetricsInfo & mi, Dimension & dim) const
|
||
|
{
|
||
|
frontend::FontMetrics const & fm =
|
||
|
theFontMetrics(mi.base.font);
|
||
|
dim.asc = fm.maxAscent();
|
||
|
dim.des = fm.maxDescent();
|
||
|
|
||
|
string s;
|
||
|
switch (kind_) {
|
||
|
case TONE_FALLING:
|
||
|
case TONE_RISING:
|
||
|
case TONE_HIGH_RISING:
|
||
|
case TONE_LOW_RISING:
|
||
|
case TONE_HIGH_RISING_FALLING:
|
||
|
s = "_";
|
||
|
break;
|
||
|
}
|
||
|
docstring ds(s.begin(), s.end());
|
||
|
dim.wid = fm.width(ds);
|
||
|
setDimCache(mi, dim);
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::draw(PainterInfo & pi, int x, int y) const
|
||
|
{
|
||
|
FontInfo font = pi.base.font;
|
||
|
frontend::FontMetrics const & fm =
|
||
|
theFontMetrics(font);
|
||
|
|
||
|
switch (kind_) {
|
||
|
case TONE_FALLING:
|
||
|
{
|
||
|
int w = fm.width(char_type('-'));
|
||
|
int h = fm.ascent(char_type('M'));
|
||
|
int x2 = x + w;
|
||
|
int y2 = y - h;
|
||
|
|
||
|
pi.pain.line(x2, y2, x2, y, Color_foreground);
|
||
|
pi.pain.line(x2, y, x, y2, Color_foreground);
|
||
|
break;
|
||
|
}
|
||
|
case TONE_RISING:
|
||
|
{
|
||
|
int w = fm.width(char_type('-'));
|
||
|
int h = fm.ascent(char_type('M'));
|
||
|
int x2 = x + w;
|
||
|
int y2 = y - h;
|
||
|
|
||
|
pi.pain.line(x2, y, x2, y2, Color_foreground);
|
||
|
pi.pain.line(x2, y2, x, y, Color_foreground);
|
||
|
break;
|
||
|
}
|
||
|
case TONE_HIGH_RISING:
|
||
|
{
|
||
|
int w = fm.width(char_type('-'));
|
||
|
int h = fm.ascent(char_type('M'));
|
||
|
int x2 = x + w;
|
||
|
int y2 = y - h;
|
||
|
int y3 = y - (h * 0.75);
|
||
|
|
||
|
pi.pain.line(x2, y, x2, y2, Color_foreground);
|
||
|
pi.pain.line(x2, y2, x, y3, Color_foreground);
|
||
|
break;
|
||
|
}
|
||
|
case TONE_LOW_RISING:
|
||
|
{
|
||
|
int w = fm.width(char_type('-'));
|
||
|
int h = fm.ascent(char_type('M'));
|
||
|
int x2 = x + w;
|
||
|
int y2 = y - h;
|
||
|
int y3 = y - (h * 0.25);
|
||
|
|
||
|
pi.pain.line(x2, y, x2, y2, Color_foreground);
|
||
|
pi.pain.line(x2, y3, x, y, Color_foreground);
|
||
|
break;
|
||
|
}
|
||
|
case TONE_HIGH_RISING_FALLING:
|
||
|
{
|
||
|
int w = fm.width(char_type('-'));
|
||
|
int h = fm.ascent(char_type('M'));
|
||
|
int x2 = x + w;
|
||
|
int y2 = y - h;
|
||
|
int x3 = x + (w * 0.5);
|
||
|
int y3 = y - (h * 0.75);
|
||
|
|
||
|
pi.pain.line(x2, y, x2, y2, Color_foreground);
|
||
|
pi.pain.line(x2, y3, x3, y2, Color_foreground);
|
||
|
pi.pain.line(x3, y2, x, y3, Color_foreground);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::write(ostream & os) const
|
||
|
{
|
||
|
string const command = ipachartranslator().find(kind_);
|
||
|
if (command.empty()) {
|
||
|
LYXERR0("InsetIPAChar::write: Unknown type");
|
||
|
return;
|
||
|
}
|
||
|
os << "\\IPAChar " << command << "\n";
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::read(Lexer & lex)
|
||
|
{
|
||
|
lex.next();
|
||
|
string const command = lex.getString();
|
||
|
kind_ = ipachartranslator().find(command);
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::latex(otexstream & os,
|
||
|
OutputParams const &) const
|
||
|
{
|
||
|
string const command = ipachartranslator().find(kind_);
|
||
|
os << command;
|
||
|
}
|
||
|
|
||
|
|
||
|
int InsetIPAChar::plaintext(odocstream & os, OutputParams const &) const
|
||
|
{
|
||
|
switch (kind_) {
|
||
|
case TONE_FALLING:
|
||
|
os.put(0x02e5);
|
||
|
os.put(0x02e9);
|
||
|
return 2;
|
||
|
case TONE_RISING:
|
||
|
os.put(0x02e9);
|
||
|
os.put(0x02e5);
|
||
|
return 2;
|
||
|
case TONE_HIGH_RISING:
|
||
|
os.put(0x02e7);
|
||
|
os.put(0x02e5);
|
||
|
return 2;
|
||
|
case TONE_LOW_RISING:
|
||
|
os.put(0x02e9);
|
||
|
os.put(0x02e7);
|
||
|
return 2;
|
||
|
case TONE_HIGH_RISING_FALLING:
|
||
|
os.put(0x02e8);
|
||
|
os.put(0x02e5);
|
||
|
os.put(0x02e8);
|
||
|
return 3;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int InsetIPAChar::docbook(odocstream & /*os*/, OutputParams const &) const
|
||
|
{
|
||
|
switch (kind_) {
|
||
|
// FIXME
|
||
|
case TONE_FALLING:
|
||
|
case TONE_RISING:
|
||
|
case TONE_HIGH_RISING:
|
||
|
case TONE_LOW_RISING:
|
||
|
case TONE_HIGH_RISING_FALLING:
|
||
|
break;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
docstring InsetIPAChar::xhtml(XHTMLStream & xs, OutputParams const &) const
|
||
|
{
|
||
|
switch (kind_) {
|
||
|
case TONE_FALLING:
|
||
|
xs << XHTMLStream::ESCAPE_NONE << "˥"
|
||
|
<< XHTMLStream::ESCAPE_NONE << "˩";
|
||
|
break;
|
||
|
case TONE_RISING:
|
||
|
xs << XHTMLStream::ESCAPE_NONE << "˩"
|
||
|
<< XHTMLStream::ESCAPE_NONE << "˥";
|
||
|
break;
|
||
|
case TONE_HIGH_RISING:
|
||
|
xs << XHTMLStream::ESCAPE_NONE << "˧"
|
||
|
<< XHTMLStream::ESCAPE_NONE << "˥";
|
||
|
break;
|
||
|
case TONE_LOW_RISING:
|
||
|
xs << XHTMLStream::ESCAPE_NONE << "˩"
|
||
|
<< XHTMLStream::ESCAPE_NONE << "˧";
|
||
|
break;
|
||
|
case TONE_HIGH_RISING_FALLING:
|
||
|
xs << XHTMLStream::ESCAPE_NONE << "˨"
|
||
|
<< XHTMLStream::ESCAPE_NONE << "˥"
|
||
|
<< XHTMLStream::ESCAPE_NONE << "˨";
|
||
|
break;
|
||
|
}
|
||
|
return docstring();
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::toString(odocstream & os) const
|
||
|
{
|
||
|
plaintext(os, OutputParams(0));
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::forToc(docstring & os, size_t) const
|
||
|
{
|
||
|
odocstringstream ods;
|
||
|
plaintext(ods, OutputParams(0));
|
||
|
os += ods.str();
|
||
|
}
|
||
|
|
||
|
|
||
|
void InsetIPAChar::validate(LaTeXFeatures & features) const
|
||
|
{
|
||
|
switch (kind_) {
|
||
|
case TONE_FALLING:
|
||
|
case TONE_RISING:
|
||
|
case TONE_HIGH_RISING:
|
||
|
case TONE_LOW_RISING:
|
||
|
case TONE_HIGH_RISING_FALLING:
|
||
|
if (!buffer_->params().useNonTeXFonts)
|
||
|
features.require("tone");
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool InsetIPAChar::isLetter() const
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool InsetIPAChar::isLineSeparator() const
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
} // namespace lyx
|