You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1089 lines
32 KiB
1089 lines
32 KiB
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
|
|
|
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
|
|
#include "NoteFontMap.h"
|
|
#include "misc/Debug.h"
|
|
|
|
#include <tdelocale.h>
|
|
#include <kstddirs.h>
|
|
#include "misc/Strings.h"
|
|
#include "base/Exception.h"
|
|
#include "SystemFont.h"
|
|
#include <tdeglobal.h>
|
|
#include <tqfile.h>
|
|
#include <tqfileinfo.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqregexp.h>
|
|
#include <tqstring.h>
|
|
#include <tqstringlist.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
NoteFontMap::NoteFontMap(std::string name) :
|
|
m_name(name),
|
|
m_smooth(false),
|
|
m_srcDirectory(name),
|
|
m_characterDestination(0),
|
|
m_hotspotCharName(""),
|
|
m_errorString(i18n("unknown error")),
|
|
m_ok(true)
|
|
{
|
|
m_fontDirectory = TDEGlobal::dirs()->findResource("appdata", "fonts/");
|
|
|
|
TQString mapFileName;
|
|
|
|
TQString mapFileMixedName = TQString("%1/mappings/%2.xml")
|
|
.arg(m_fontDirectory)
|
|
.arg(strtoqstr(name));
|
|
|
|
TQFileInfo mapFileMixedInfo(mapFileMixedName);
|
|
|
|
if (!mapFileMixedInfo.isReadable()) {
|
|
|
|
TQString lowerName = strtoqstr(name).lower();
|
|
lowerName.replace(TQRegExp(" "), "_");
|
|
TQString mapFileLowerName = TQString("%1/mappings/%2.xml")
|
|
.arg(m_fontDirectory)
|
|
.arg(lowerName);
|
|
|
|
TQFileInfo mapFileLowerInfo(mapFileLowerName);
|
|
|
|
if (!mapFileLowerInfo.isReadable()) {
|
|
if (mapFileLowerName != mapFileMixedName) {
|
|
throw MappingFileReadFailed
|
|
(qstrtostr(i18n("Can't open font mapping file %1 or %2").
|
|
arg(mapFileMixedName).arg(mapFileLowerName)));
|
|
} else {
|
|
throw MappingFileReadFailed
|
|
(qstrtostr(i18n("Can't open font mapping file %1").
|
|
arg(mapFileMixedName)));
|
|
}
|
|
} else {
|
|
mapFileName = mapFileLowerName;
|
|
}
|
|
} else {
|
|
mapFileName = mapFileMixedName;
|
|
}
|
|
|
|
TQFile mapFile(mapFileName);
|
|
|
|
TQXmlInputSource source(mapFile);
|
|
TQXmlSimpleReader reader;
|
|
reader.setContentHandler(this);
|
|
reader.setErrorHandler(this);
|
|
bool ok = reader.parse(source);
|
|
mapFile.close();
|
|
|
|
if (!ok) {
|
|
throw MappingFileReadFailed(qstrtostr(m_errorString));
|
|
}
|
|
}
|
|
|
|
NoteFontMap::~NoteFontMap()
|
|
{
|
|
for (SystemFontMap::iterator i = m_systemFontCache.begin();
|
|
i != m_systemFontCache.end(); ++i) {
|
|
delete i->second;
|
|
}
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::characters(TQString &chars)
|
|
{
|
|
if (!m_characterDestination)
|
|
return true;
|
|
*m_characterDestination += qstrtostr(chars);
|
|
return true;
|
|
}
|
|
|
|
int
|
|
NoteFontMap::toSize(int baseSize, double factor, bool limitAtOne)
|
|
{
|
|
double dsize = factor * baseSize;
|
|
dsize += 0.5;
|
|
if (limitAtOne && dsize < 1.0)
|
|
dsize = 1.0;
|
|
return int(dsize);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::startElement(const TQString &, const TQString &,
|
|
const TQString &qName,
|
|
const TQXmlAttributes &attributes)
|
|
{
|
|
TQString lcName = qName.lower();
|
|
m_characterDestination = 0;
|
|
|
|
// The element names are actually unique within the whole file;
|
|
// we don't bother checking we're in the right context. Leave that
|
|
// to the DTD, when we have one.
|
|
|
|
if (lcName == "rosegarden-font-encoding") {
|
|
|
|
TQString s;
|
|
|
|
s = attributes.value("name");
|
|
if (!s.isNull()) {
|
|
m_name = qstrtostr(s);
|
|
m_srcDirectory = m_name;
|
|
}
|
|
|
|
} else if (lcName == "font-information") {
|
|
|
|
TQString s;
|
|
|
|
s = attributes.value("origin");
|
|
if (!s.isNull())
|
|
m_origin = qstrtostr(s);
|
|
|
|
s = attributes.value("copyright");
|
|
if (!s.isNull())
|
|
m_copyright = qstrtostr(s);
|
|
|
|
s = attributes.value("mapped-by");
|
|
if (!s.isNull())
|
|
m_mappedBy = qstrtostr(s);
|
|
|
|
s = attributes.value("type");
|
|
if (!s.isNull())
|
|
m_type = qstrtostr(s);
|
|
|
|
s = attributes.value("autocrop");
|
|
if (!s.isNull()) {
|
|
std::cerr << "Warning: autocrop attribute in note font mapping file is no longer supported\n(all fonts are now always autocropped)" << std::endl;
|
|
}
|
|
|
|
s = attributes.value("smooth");
|
|
if (!s.isNull())
|
|
m_smooth = (s.lower() == "true");
|
|
|
|
} else if (lcName == "font-sizes") {
|
|
}
|
|
else if (lcName == "font-size") {
|
|
|
|
TQString s = attributes.value("note-height");
|
|
if (!s) {
|
|
m_errorString = "note-height is a required attribute of font-size";
|
|
return false;
|
|
}
|
|
int noteHeight = s.toInt();
|
|
|
|
SizeData &sizeData = m_sizes[noteHeight];
|
|
|
|
s = attributes.value("staff-line-thickness");
|
|
if (!s.isNull())
|
|
sizeData.setStaffLineThickness(s.toInt());
|
|
|
|
s = attributes.value("leger-line-thickness");
|
|
if (!s.isNull())
|
|
sizeData.setLegerLineThickness(s.toInt());
|
|
|
|
s = attributes.value("stem-thickness");
|
|
if (!s.isNull())
|
|
sizeData.setStemThickness(s.toInt());
|
|
|
|
s = attributes.value("beam-thickness");
|
|
if (!s.isNull())
|
|
sizeData.setBeamThickness(s.toInt());
|
|
|
|
s = attributes.value("stem-length");
|
|
if (!s.isNull())
|
|
sizeData.setStemLength(s.toInt());
|
|
|
|
s = attributes.value("flag-spacing");
|
|
if (!s.isNull())
|
|
sizeData.setFlagSpacing(s.toInt());
|
|
|
|
s = attributes.value("border-x");
|
|
if (!s.isNull()) {
|
|
std::cerr << "Warning: border-x attribute in note font mapping file is no longer supported\n(use hotspot-x for note head or flag)" << std::endl;
|
|
}
|
|
|
|
s = attributes.value("border-y");
|
|
if (!s.isNull()) {
|
|
std::cerr << "Warning: border-y attribute in note font mapping file is no longer supported" << std::endl;
|
|
}
|
|
|
|
int fontId = 0;
|
|
s = attributes.value("font-id");
|
|
if (!s.isNull())
|
|
fontId = s.toInt();
|
|
|
|
s = attributes.value("font-height");
|
|
if (!s.isNull())
|
|
sizeData.setFontHeight(fontId, s.toInt());
|
|
|
|
} else if (lcName == "font-scale") {
|
|
|
|
double fontHeight = -1.0;
|
|
double beamThickness = -1.0;
|
|
double stemLength = -1.0;
|
|
double flagSpacing = -1.0;
|
|
double staffLineThickness = -1.0;
|
|
double legerLineThickness = -1.0;
|
|
double stemThickness = -1.0;
|
|
|
|
TQString s;
|
|
|
|
s = attributes.value("font-height");
|
|
if (!s.isNull())
|
|
fontHeight = qstrtodouble(s);
|
|
else {
|
|
m_errorString = "font-height is a required attribute of font-scale";
|
|
return false;
|
|
}
|
|
|
|
s = attributes.value("staff-line-thickness");
|
|
if (!s.isNull())
|
|
staffLineThickness = qstrtodouble(s);
|
|
|
|
s = attributes.value("leger-line-thickness");
|
|
if (!s.isNull())
|
|
legerLineThickness = qstrtodouble(s);
|
|
|
|
s = attributes.value("stem-thickness");
|
|
if (!s.isNull())
|
|
stemThickness = qstrtodouble(s);
|
|
|
|
s = attributes.value("beam-thickness");
|
|
if (!s.isNull())
|
|
beamThickness = qstrtodouble(s);
|
|
|
|
s = attributes.value("stem-length");
|
|
if (!s.isNull())
|
|
stemLength = qstrtodouble(s);
|
|
|
|
s = attributes.value("flag-spacing");
|
|
if (!s.isNull())
|
|
flagSpacing = qstrtodouble(s);
|
|
|
|
int fontId = 0;
|
|
s = attributes.value("font-id");
|
|
if (!s.isNull())
|
|
fontId = s.toInt();
|
|
|
|
//!!! need to be able to calculate max size -- checkFont needs
|
|
//to take a size argument; unfortunately TQt doesn't seem to be
|
|
//able to report to us when a scalable font was loaded in the
|
|
//wrong size, so large sizes might be significantly inaccurate
|
|
//as it just stops scaling up any further at somewhere around
|
|
//120px. We could test whether the metric for the black
|
|
//notehead is noticeably smaller than the notehead should be,
|
|
//and reject if so? [update -- no, that doesn't work either,
|
|
//TQt just returns the correct metric even if drawing the
|
|
//incorrect size]
|
|
|
|
for (int sz = 1; sz <= 30; sz += (sz == 1 ? 1 : 2)) {
|
|
|
|
SizeData & sizeData = m_sizes[sz];
|
|
unsigned int temp;
|
|
|
|
if (sizeData.getStaffLineThickness(temp) == false &&
|
|
staffLineThickness >= 0.0)
|
|
sizeData.setStaffLineThickness(toSize(sz, staffLineThickness, true));
|
|
|
|
if (sizeData.getLegerLineThickness(temp) == false &&
|
|
legerLineThickness >= 0.0)
|
|
sizeData.setLegerLineThickness(toSize(sz, legerLineThickness, true));
|
|
|
|
if (sizeData.getStemThickness(temp) == false &&
|
|
stemThickness >= 0.0)
|
|
sizeData.setStemThickness(toSize(sz, stemThickness, true));
|
|
|
|
if (sizeData.getBeamThickness(temp) == false &&
|
|
beamThickness >= 0.0)
|
|
sizeData.setBeamThickness(toSize(sz, beamThickness, true));
|
|
|
|
if (sizeData.getStemLength(temp) == false &&
|
|
stemLength >= 0.0)
|
|
sizeData.setStemLength(toSize(sz, stemLength, true));
|
|
|
|
if (sizeData.getFlagSpacing(temp) == false &&
|
|
flagSpacing >= 0.0)
|
|
sizeData.setFlagSpacing(toSize(sz, flagSpacing, true));
|
|
|
|
if (sizeData.getFontHeight(fontId, temp) == false)
|
|
sizeData.setFontHeight(fontId, toSize(sz, fontHeight, true));
|
|
}
|
|
|
|
} else if (lcName == "font-symbol-map") {
|
|
}
|
|
else if (lcName == "src-directory") {
|
|
|
|
TQString d = attributes.value("name");
|
|
if (!d) {
|
|
m_errorString = "name is a required attribute of src-directory";
|
|
return false;
|
|
}
|
|
|
|
m_srcDirectory = qstrtostr(d);
|
|
|
|
} else if (lcName == "codebase") {
|
|
|
|
int bn = 0, fn = 0;
|
|
bool ok;
|
|
TQString base = attributes.value("base");
|
|
if (!base) {
|
|
m_errorString = "base is a required attribute of codebase";
|
|
return false;
|
|
}
|
|
bn = base.toInt(&ok);
|
|
if (!ok || bn < 0) {
|
|
m_errorString =
|
|
TQString("invalid base attribute \"%1\" (must be integer >= 0)").
|
|
arg(base);
|
|
return false;
|
|
}
|
|
|
|
TQString fontId = attributes.value("font-id");
|
|
if (!fontId) {
|
|
m_errorString = "font-id is a required attribute of codebase";
|
|
return false;
|
|
}
|
|
fn = fontId.stripWhiteSpace().toInt(&ok);
|
|
if (!ok || fn < 0) {
|
|
m_errorString =
|
|
TQString("invalid font-id attribute \"%1\" (must be integer >= 0)").
|
|
arg(fontId);
|
|
return false;
|
|
}
|
|
|
|
m_bases[fn] = bn;
|
|
|
|
} else if (lcName == "symbol") {
|
|
|
|
TQString symbolName = attributes.value("name");
|
|
if (!symbolName) {
|
|
m_errorString = "name is a required attribute of symbol";
|
|
return false;
|
|
}
|
|
SymbolData symbolData;
|
|
|
|
TQString src = attributes.value("src");
|
|
TQString code = attributes.value("code");
|
|
TQString glyph = attributes.value("glyph");
|
|
|
|
int icode = -1;
|
|
bool ok = false;
|
|
if (!code.isNull()) {
|
|
icode = code.stripWhiteSpace().toInt(&ok);
|
|
if (!ok || icode < 0) {
|
|
m_errorString =
|
|
TQString("invalid code attribute \"%1\" (must be integer >= 0)").
|
|
arg(code);
|
|
return false;
|
|
}
|
|
symbolData.setCode(icode);
|
|
}
|
|
|
|
int iglyph = -1;
|
|
ok = false;
|
|
if (!glyph.isNull()) {
|
|
iglyph = glyph.stripWhiteSpace().toInt(&ok);
|
|
if (!ok || iglyph < 0) {
|
|
m_errorString =
|
|
TQString("invalid glyph attribute \"%1\" (must be integer >= 0)").
|
|
arg(glyph);
|
|
return false;
|
|
}
|
|
symbolData.setGlyph(iglyph);
|
|
}
|
|
|
|
if (!src && icode < 0 && iglyph < 0) {
|
|
m_errorString = "symbol must have either src, code, or glyph attribute";
|
|
return false;
|
|
}
|
|
if (!src.isNull())
|
|
symbolData.setSrc(qstrtostr(src));
|
|
|
|
TQString inversionSrc = attributes.value("inversion-src");
|
|
if (!inversionSrc.isNull())
|
|
symbolData.setInversionSrc(qstrtostr(inversionSrc));
|
|
|
|
TQString inversionCode = attributes.value("inversion-code");
|
|
if (!inversionCode.isNull()) {
|
|
icode = inversionCode.stripWhiteSpace().toInt(&ok);
|
|
if (!ok || icode < 0) {
|
|
m_errorString =
|
|
TQString("invalid inversion code attribute \"%1\" (must be integer >= 0)").
|
|
arg(inversionCode);
|
|
return false;
|
|
}
|
|
symbolData.setInversionCode(icode);
|
|
}
|
|
|
|
TQString inversionGlyph = attributes.value("inversion-glyph");
|
|
if (!inversionGlyph.isNull()) {
|
|
iglyph = inversionGlyph.stripWhiteSpace().toInt(&ok);
|
|
if (!ok || iglyph < 0) {
|
|
m_errorString =
|
|
TQString("invalid inversion glyph attribute \"%1\" (must be integer >= 0)").
|
|
arg(inversionGlyph);
|
|
return false;
|
|
}
|
|
symbolData.setInversionGlyph(iglyph);
|
|
}
|
|
|
|
TQString fontId = attributes.value("font-id");
|
|
if (!fontId.isNull()) {
|
|
int n = fontId.stripWhiteSpace().toInt(&ok);
|
|
if (!ok || n < 0) {
|
|
m_errorString =
|
|
TQString("invalid font-id attribute \"%1\" (must be integer >= 0)").
|
|
arg(fontId);
|
|
return false;
|
|
}
|
|
symbolData.setFontId(n);
|
|
}
|
|
|
|
m_data[qstrtostr(symbolName.upper())] = symbolData;
|
|
|
|
} else if (lcName == "font-hotspots") {
|
|
}
|
|
else if (lcName == "hotspot") {
|
|
|
|
TQString s = attributes.value("name");
|
|
if (!s) {
|
|
m_errorString = "name is a required attribute of hotspot";
|
|
return false;
|
|
}
|
|
m_hotspotCharName = qstrtostr(s.upper());
|
|
|
|
} else if (lcName == "scaled") {
|
|
|
|
if (m_hotspotCharName == "") {
|
|
m_errorString = "scaled-element must be in hotspot-element";
|
|
return false;
|
|
}
|
|
|
|
TQString s = attributes.value("x");
|
|
double x = -1.0;
|
|
if (!s.isNull())
|
|
x = qstrtodouble(s);
|
|
|
|
s = attributes.value("y");
|
|
if (!s) {
|
|
m_errorString = "y is a required attribute of scaled";
|
|
return false;
|
|
}
|
|
double y = qstrtodouble(s);
|
|
|
|
HotspotDataMap::iterator i = m_hotspots.find(m_hotspotCharName);
|
|
if (i == m_hotspots.end()) {
|
|
m_hotspots[m_hotspotCharName] = HotspotData();
|
|
i = m_hotspots.find(m_hotspotCharName);
|
|
}
|
|
|
|
i->second.setScaledHotspot(x, y);
|
|
|
|
} else if (lcName == "fixed") {
|
|
|
|
if (m_hotspotCharName == "") {
|
|
m_errorString = "fixed-element must be in hotspot-element";
|
|
return false;
|
|
}
|
|
|
|
TQString s = attributes.value("x");
|
|
int x = 0;
|
|
if (!s.isNull())
|
|
x = s.toInt();
|
|
|
|
s = attributes.value("y");
|
|
int y = 0;
|
|
if (!s.isNull())
|
|
y = s.toInt();
|
|
|
|
HotspotDataMap::iterator i = m_hotspots.find(m_hotspotCharName);
|
|
if (i == m_hotspots.end()) {
|
|
m_hotspots[m_hotspotCharName] = HotspotData();
|
|
i = m_hotspots.find(m_hotspotCharName);
|
|
}
|
|
|
|
i->second.addHotspot(0, x, y);
|
|
|
|
} else if (lcName == "when") {
|
|
|
|
if (m_hotspotCharName == "") {
|
|
m_errorString = "when-element must be in hotspot-element";
|
|
return false;
|
|
}
|
|
|
|
TQString s = attributes.value("note-height");
|
|
if (!s) {
|
|
m_errorString = "note-height is a required attribute of when";
|
|
return false;
|
|
}
|
|
int noteHeight = s.toInt();
|
|
|
|
s = attributes.value("x");
|
|
int x = 0;
|
|
if (!s.isNull())
|
|
x = s.toInt();
|
|
|
|
s = attributes.value("y");
|
|
if (!s) {
|
|
m_errorString = "y is a required attribute of when";
|
|
return false;
|
|
}
|
|
int y = s.toInt();
|
|
|
|
HotspotDataMap::iterator i = m_hotspots.find(m_hotspotCharName);
|
|
if (i == m_hotspots.end()) {
|
|
m_hotspots[m_hotspotCharName] = HotspotData();
|
|
i = m_hotspots.find(m_hotspotCharName);
|
|
}
|
|
|
|
i->second.addHotspot(noteHeight, x, y);
|
|
|
|
} else if (lcName == "font-requirements") {
|
|
}
|
|
else if (lcName == "font-requirement") {
|
|
|
|
TQString id = attributes.value("font-id");
|
|
int n = -1;
|
|
bool ok = false;
|
|
if (!id.isNull()) {
|
|
n = id.stripWhiteSpace().toInt(&ok);
|
|
if (!ok) {
|
|
m_errorString =
|
|
TQString("invalid font-id attribute \"%1\" (must be integer >= 0)").
|
|
arg(id);
|
|
return false;
|
|
}
|
|
} else {
|
|
m_errorString = "font-id is a required attribute of font-requirement";
|
|
return false;
|
|
}
|
|
|
|
TQString name = attributes.value("name");
|
|
TQString names = attributes.value("names");
|
|
|
|
if (!name.isNull()) {
|
|
if (!names.isNull()) {
|
|
m_errorString = "font-requirement may have name or names attribute, but not both";
|
|
return false;
|
|
}
|
|
|
|
SystemFont *font = SystemFont::loadSystemFont
|
|
(SystemFontSpec(name, 12));
|
|
|
|
if (font) {
|
|
m_systemFontNames[n] = name;
|
|
delete font;
|
|
} else {
|
|
std::cerr << TQString("Warning: Unable to load font \"%1\"").arg(name).ascii() << std::endl;
|
|
m_ok = false;
|
|
}
|
|
|
|
} else if (!names.isNull()) {
|
|
|
|
bool have = false;
|
|
TQStringList list = TQStringList::split(",", names, false);
|
|
for (TQStringList::Iterator i = list.begin(); i != list.end(); ++i) {
|
|
SystemFont *font = SystemFont::loadSystemFont
|
|
(SystemFontSpec(*i, 12));
|
|
if (font) {
|
|
m_systemFontNames[n] = *i;
|
|
have = true;
|
|
delete font;
|
|
break;
|
|
}
|
|
}
|
|
if (!have) {
|
|
std::cerr << TQString("Warning: Unable to load any of the fonts in \"%1\"").
|
|
arg(names).ascii() << std::endl;
|
|
m_ok = false;
|
|
}
|
|
|
|
} else {
|
|
m_errorString = "font-requirement must have either name or names attribute";
|
|
return false;
|
|
}
|
|
|
|
TQString s = attributes.value("strategy").lower();
|
|
SystemFont::Strategy strategy = SystemFont::PreferGlyphs;
|
|
|
|
if (!s.isNull()) {
|
|
if (s == "prefer-glyphs")
|
|
strategy = SystemFont::PreferGlyphs;
|
|
else if (s == "prefer-codes")
|
|
strategy = SystemFont::PreferCodes;
|
|
else if (s == "only-glyphs")
|
|
strategy = SystemFont::OnlyGlyphs;
|
|
else if (s == "only-codes")
|
|
strategy = SystemFont::OnlyCodes;
|
|
else {
|
|
std::cerr << "Warning: Unknown strategy value " << s.ascii()
|
|
<< " (known values are prefer-glyphs, prefer-codes,"
|
|
<< " only-glyphs, only-codes)" << std::endl;
|
|
}
|
|
}
|
|
|
|
m_systemFontStrategies[n] = strategy;
|
|
|
|
} else {
|
|
}
|
|
|
|
if (m_characterDestination)
|
|
*m_characterDestination = "";
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::error(const TQXmlParseException& exception)
|
|
{
|
|
m_errorString = TQString("%1 at line %2, column %3: %4")
|
|
.arg(exception.message())
|
|
.arg(exception.lineNumber())
|
|
.arg(exception.columnNumber())
|
|
.arg(m_errorString);
|
|
return TQXmlDefaultHandler::error(exception);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::fatalError(const TQXmlParseException& exception)
|
|
{
|
|
m_errorString = TQString("%1 at line %2, column %3: %4")
|
|
.arg(exception.message())
|
|
.arg(exception.lineNumber())
|
|
.arg(exception.columnNumber())
|
|
.arg(m_errorString);
|
|
return TQXmlDefaultHandler::fatalError(exception);
|
|
}
|
|
|
|
std::set<int>
|
|
NoteFontMap::getSizes() const
|
|
{
|
|
std::set<int> sizes;
|
|
|
|
for (SizeDataMap::const_iterator i = m_sizes.begin();
|
|
i != m_sizes.end(); ++i) {
|
|
sizes.insert(i->first);
|
|
}
|
|
|
|
return sizes;
|
|
}
|
|
|
|
std::set<CharName>
|
|
NoteFontMap::getCharNames() const
|
|
{
|
|
std::set<CharName> names;
|
|
|
|
for (SymbolDataMap::const_iterator i = m_data.begin();
|
|
i != m_data.end(); ++i) {
|
|
names.insert(i->first);
|
|
}
|
|
|
|
return names;
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::checkFile(int size, std::string &src) const
|
|
{
|
|
TQString pixmapFileMixedName = TQString("%1/%2/%3/%4.xpm")
|
|
.arg(m_fontDirectory)
|
|
.arg(strtoqstr(m_srcDirectory))
|
|
.arg(size)
|
|
.arg(strtoqstr(src));
|
|
|
|
TQFileInfo pixmapFileMixedInfo(pixmapFileMixedName);
|
|
|
|
if (!pixmapFileMixedInfo.isReadable()) {
|
|
|
|
TQString pixmapFileLowerName = TQString("%1/%2/%3/%4.xpm")
|
|
.arg(m_fontDirectory)
|
|
.arg(strtoqstr(m_srcDirectory).lower())
|
|
.arg(size)
|
|
.arg(strtoqstr(src));
|
|
|
|
TQFileInfo pixmapFileLowerInfo(pixmapFileLowerName);
|
|
|
|
if (!pixmapFileLowerInfo.isReadable()) {
|
|
if (pixmapFileMixedName != pixmapFileLowerName) {
|
|
std::cerr << "Warning: Unable to open pixmap file "
|
|
<< pixmapFileMixedName.ascii() << " or " << pixmapFileLowerName.ascii()
|
|
<< std::endl;
|
|
} else {
|
|
std::cerr << "Warning: Unable to open pixmap file "
|
|
<< pixmapFileMixedName.ascii() << std::endl;
|
|
}
|
|
return false;
|
|
} else {
|
|
src = qstrtostr(pixmapFileLowerName);
|
|
}
|
|
} else {
|
|
src = qstrtostr(pixmapFileMixedName);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::hasInversion(int, CharName charName) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
return i->second.hasInversion();
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getSrc(int size, CharName charName, std::string &src) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
|
|
src = i->second.getSrc();
|
|
if (src == "")
|
|
return false;
|
|
return checkFile(size, src);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getInversionSrc(int size, CharName charName, std::string &src) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
|
|
if (!i->second.hasInversion())
|
|
return false;
|
|
src = i->second.getInversionSrc();
|
|
if (src == "")
|
|
return false;
|
|
return checkFile(size, src);
|
|
}
|
|
|
|
SystemFont *
|
|
NoteFontMap::getSystemFont(int size, CharName charName, int &charBase)
|
|
const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
|
|
SizeDataMap::const_iterator si = m_sizes.find(size);
|
|
if (si == m_sizes.end())
|
|
return false;
|
|
|
|
int fontId = i->second.getFontId();
|
|
|
|
unsigned int fontHeight = 0;
|
|
if (!si->second.getFontHeight(fontId, fontHeight)) {
|
|
if (fontId == 0 || !si->second.getFontHeight(0, fontHeight)) {
|
|
fontHeight = size;
|
|
}
|
|
}
|
|
|
|
SystemFontNameMap::const_iterator fni = m_systemFontNames.find(fontId);
|
|
if (fontId < 0 || fni == m_systemFontNames.end())
|
|
return false;
|
|
TQString fontName = fni->second;
|
|
|
|
CharBaseMap::const_iterator bi = m_bases.find(fontId);
|
|
if (bi == m_bases.end())
|
|
charBase = 0;
|
|
else
|
|
charBase = bi->second;
|
|
|
|
SystemFontSpec spec(fontName, fontHeight);
|
|
SystemFontMap::const_iterator fi = m_systemFontCache.find(spec);
|
|
if (fi != m_systemFontCache.end()) {
|
|
return fi->second;
|
|
}
|
|
|
|
SystemFont *font = SystemFont::loadSystemFont(spec);
|
|
if (!font)
|
|
return 0;
|
|
m_systemFontCache[spec] = font;
|
|
|
|
NOTATION_DEBUG << "NoteFontMap::getFont: loaded font " << fontName
|
|
<< " at pixel size " << fontHeight << endl;
|
|
|
|
return font;
|
|
}
|
|
|
|
SystemFont::Strategy
|
|
NoteFontMap::getStrategy(int, CharName charName) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return SystemFont::PreferGlyphs;
|
|
|
|
int fontId = i->second.getFontId();
|
|
SystemFontStrategyMap::const_iterator si =
|
|
m_systemFontStrategies.find(fontId);
|
|
|
|
if (si != m_systemFontStrategies.end()) {
|
|
return si->second;
|
|
}
|
|
|
|
return SystemFont::PreferGlyphs;
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getCode(int, CharName charName, int &code) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
|
|
code = i->second.getCode();
|
|
return (code >= 0);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getInversionCode(int, CharName charName, int &code) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
|
|
code = i->second.getInversionCode();
|
|
return (code >= 0);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getGlyph(int, CharName charName, int &glyph) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
|
|
glyph = i->second.getGlyph();
|
|
return (glyph >= 0);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getInversionGlyph(int, CharName charName, int &glyph) const
|
|
{
|
|
SymbolDataMap::const_iterator i = m_data.find(charName);
|
|
if (i == m_data.end())
|
|
return false;
|
|
|
|
glyph = i->second.getInversionGlyph();
|
|
return (glyph >= 0);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getStaffLineThickness(int size, unsigned int &thickness) const
|
|
{
|
|
SizeDataMap::const_iterator i = m_sizes.find(size);
|
|
if (i == m_sizes.end())
|
|
return false;
|
|
|
|
return i->second.getStaffLineThickness(thickness);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getLegerLineThickness(int size, unsigned int &thickness) const
|
|
{
|
|
SizeDataMap::const_iterator i = m_sizes.find(size);
|
|
if (i == m_sizes.end())
|
|
return false;
|
|
|
|
return i->second.getLegerLineThickness(thickness);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getStemThickness(int size, unsigned int &thickness) const
|
|
{
|
|
SizeDataMap::const_iterator i = m_sizes.find(size);
|
|
if (i == m_sizes.end())
|
|
return false;
|
|
|
|
return i->second.getStemThickness(thickness);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getBeamThickness(int size, unsigned int &thickness) const
|
|
{
|
|
SizeDataMap::const_iterator i = m_sizes.find(size);
|
|
if (i == m_sizes.end())
|
|
return false;
|
|
|
|
return i->second.getBeamThickness(thickness);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getStemLength(int size, unsigned int &length) const
|
|
{
|
|
SizeDataMap::const_iterator i = m_sizes.find(size);
|
|
if (i == m_sizes.end())
|
|
return false;
|
|
|
|
return i->second.getStemLength(length);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getFlagSpacing(int size, unsigned int &spacing) const
|
|
{
|
|
SizeDataMap::const_iterator i = m_sizes.find(size);
|
|
if (i == m_sizes.end())
|
|
return false;
|
|
|
|
return i->second.getFlagSpacing(spacing);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::getHotspot(int size, CharName charName, int width, int height,
|
|
int &x, int &y) const
|
|
{
|
|
HotspotDataMap::const_iterator i = m_hotspots.find(charName);
|
|
if (i == m_hotspots.end())
|
|
return false;
|
|
return i->second.getHotspot(size, width, height, x, y);
|
|
}
|
|
|
|
bool
|
|
NoteFontMap::HotspotData::getHotspot(int size, int width, int height,
|
|
int &x, int &y) const
|
|
{
|
|
DataMap::const_iterator i = m_data.find(size);
|
|
if (i == m_data.end()) {
|
|
i = m_data.find(0); // fixed-pixel hotspot
|
|
x = 0;
|
|
if (m_scaled.first >= 0) {
|
|
x = toSize(width, m_scaled.first, false);
|
|
} else {
|
|
if (i != m_data.end()) {
|
|
x = i->second.first;
|
|
}
|
|
}
|
|
if (m_scaled.second >= 0) {
|
|
y = toSize(height, m_scaled.second, false);
|
|
return true;
|
|
} else {
|
|
if (i != m_data.end()) {
|
|
y = i->second.second;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
x = i->second.first;
|
|
y = i->second.second;
|
|
return true;
|
|
}
|
|
|
|
TQStringList
|
|
NoteFontMap::getSystemFontNames() const
|
|
{
|
|
TQStringList names;
|
|
for (SystemFontNameMap::const_iterator i = m_systemFontNames.begin();
|
|
i != m_systemFontNames.end(); ++i) {
|
|
names.append(i->second);
|
|
}
|
|
return names;
|
|
}
|
|
|
|
void
|
|
NoteFontMap::dump() const
|
|
{
|
|
// debug code
|
|
|
|
std::cout << "Font data:\nName: " << getName() << "\nOrigin: " << getOrigin()
|
|
<< "\nCopyright: " << getCopyright() << "\nMapped by: "
|
|
<< getMappedBy() << "\nType: " << getType()
|
|
<< "\nSmooth: " << isSmooth() << std::endl;
|
|
|
|
std::set<int> sizes = getSizes();
|
|
std::set<CharName> names = getCharNames();
|
|
|
|
for (std::set<int>::iterator sizei = sizes.begin(); sizei != sizes.end();
|
|
++sizei) {
|
|
|
|
std::cout << "\nSize: " << *sizei << "\n" << std::endl;
|
|
|
|
unsigned int t = 0;
|
|
|
|
if (getStaffLineThickness(*sizei, t)) {
|
|
std::cout << "Staff line thickness: " << t << std::endl;
|
|
}
|
|
|
|
if (getLegerLineThickness(*sizei, t)) {
|
|
std::cout << "Leger line thickness: " << t << std::endl;
|
|
}
|
|
|
|
if (getStemThickness(*sizei, t)) {
|
|
std::cout << "Stem thickness: " << t << std::endl;
|
|
}
|
|
|
|
if (getBeamThickness(*sizei, t)) {
|
|
std::cout << "Beam thickness: " << t << std::endl;
|
|
}
|
|
|
|
if (getStemLength(*sizei, t)) {
|
|
std::cout << "Stem length: " << t << std::endl;
|
|
}
|
|
|
|
if (getFlagSpacing(*sizei, t)) {
|
|
std::cout << "Flag spacing: " << t << std::endl;
|
|
}
|
|
|
|
for (std::set<CharName>::iterator namei = names.begin();
|
|
namei != names.end(); ++namei) {
|
|
|
|
std::cout << "\nCharacter: " << namei->c_str() << std::endl;
|
|
|
|
std::string s;
|
|
int x, y, c;
|
|
|
|
if (getSrc(*sizei, *namei, s)) {
|
|
std::cout << "Src: " << s << std::endl;
|
|
}
|
|
|
|
if (getInversionSrc(*sizei, *namei, s)) {
|
|
std::cout << "Inversion src: " << s << std::endl;
|
|
}
|
|
|
|
if (getCode(*sizei, *namei, c)) {
|
|
std::cout << "Code: " << c << std::endl;
|
|
}
|
|
|
|
if (getInversionCode(*sizei, *namei, c)) {
|
|
std::cout << "Inversion code: " << c << std::endl;
|
|
}
|
|
|
|
if (getGlyph(*sizei, *namei, c)) {
|
|
std::cout << "Glyph: " << c << std::endl;
|
|
}
|
|
|
|
if (getInversionGlyph(*sizei, *namei, c)) {
|
|
std::cout << "Inversion glyph: " << c << std::endl;
|
|
}
|
|
|
|
if (getHotspot(*sizei, *namei, 1, 1, x, y)) {
|
|
std::cout << "Hot spot: (" << x << "," << y << ")" << std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|