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.
3688 lines
114 KiB
3688 lines
114 KiB
/*
|
|
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 <cmath>
|
|
#include "NotePixmapFactory.h"
|
|
#include "misc/Debug.h"
|
|
#include "base/NotationRules.h"
|
|
#include <tdeapplication.h>
|
|
|
|
#include <tdelocale.h>
|
|
#include <kstddirs.h>
|
|
#include <tdeconfig.h>
|
|
#include "misc/Strings.h"
|
|
#include "document/ConfigGroups.h"
|
|
#include "base/Exception.h"
|
|
#include "base/NotationTypes.h"
|
|
#include "base/Profiler.h"
|
|
#include "gui/editors/guitar/Fingering.h"
|
|
#include "gui/editors/guitar/FingeringBox.h"
|
|
#include "gui/editors/guitar/NoteSymbols.h"
|
|
#include "gui/editors/notation/TrackHeader.h"
|
|
#include "gui/general/GUIPalette.h"
|
|
#include "gui/general/PixmapFunctions.h"
|
|
#include "gui/general/Spline.h"
|
|
#include "gui/kdeext/TDEStartupLogo.h"
|
|
#include "NotationStrings.h"
|
|
#include "NotationView.h"
|
|
#include "NoteCharacter.h"
|
|
#include "NoteCharacterNames.h"
|
|
#include "NoteFontFactory.h"
|
|
#include "NoteFont.h"
|
|
#include "NotePixmapParameters.h"
|
|
#include "NotePixmapPainter.h"
|
|
#include "NoteStyleFactory.h"
|
|
#include "NoteStyle.h"
|
|
#include <tdeglobal.h>
|
|
#include <tdemessagebox.h>
|
|
#include <tqbitmap.h>
|
|
#include <tqcolor.h>
|
|
#include <tqfile.h>
|
|
#include <tqfont.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <tqimage.h>
|
|
#include <tqpainter.h>
|
|
#include <tqpen.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqpointarray.h>
|
|
#include <tqpoint.h>
|
|
#include <tqrect.h>
|
|
#include <tqstring.h>
|
|
#include <tqwmatrix.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
using namespace Accidentals;
|
|
|
|
static clock_t drawBeamsTime = 0;
|
|
static clock_t makeNotesTime = 0;
|
|
static int drawBeamsCount = 0;
|
|
static int drawBeamsBeamCount = 0;
|
|
|
|
class NotePixmapCache : public std::map<CharName, TQCanvasPixmap*>
|
|
{
|
|
// nothing to add -- just so we can predeclare it in the header
|
|
};
|
|
|
|
const char* const NotePixmapFactory::defaultSerifFontFamily = "Bitstream Vera Serif";
|
|
const char* const NotePixmapFactory::defaultSansSerifFontFamily = "Bitstream Vera Sans";
|
|
const char* const NotePixmapFactory::defaultTimeSigFontFamily = "Bitstream Vera Serif";
|
|
|
|
NotePixmapFactory::NotePixmapFactory(std::string fontName, int size) :
|
|
m_selected(false),
|
|
m_shaded(false),
|
|
m_tupletCountFont(defaultSerifFontFamily, 8, TQFont::Bold),
|
|
m_tupletCountFontMetrics(m_tupletCountFont),
|
|
m_textMarkFont(defaultSerifFontFamily, 8, TQFont::Bold, true),
|
|
m_textMarkFontMetrics(m_textMarkFont),
|
|
m_fingeringFont(defaultSerifFontFamily, 8, TQFont::Bold),
|
|
m_fingeringFontMetrics(m_fingeringFont),
|
|
m_timeSigFont(defaultTimeSigFontFamily, 8, TQFont::Bold),
|
|
m_timeSigFontMetrics(m_timeSigFont),
|
|
m_bigTimeSigFont(defaultTimeSigFontFamily, 12, TQFont::Normal),
|
|
m_bigTimeSigFontMetrics(m_bigTimeSigFont),
|
|
m_ottavaFont(defaultSerifFontFamily, 8, TQFont::Normal, true),
|
|
m_ottavaFontMetrics(m_ottavaFont),
|
|
m_clefOttavaFont(defaultSerifFontFamily, 8, TQFont::Normal),
|
|
m_clefOttavaFontMetrics(m_ottavaFont),
|
|
m_trackHeaderFont(defaultSansSerifFontFamily, 10, TQFont::Normal),
|
|
m_trackHeaderFontMetrics(m_trackHeaderFont),
|
|
m_trackHeaderBoldFont(defaultSansSerifFontFamily, 10, TQFont::Bold),
|
|
m_trackHeaderBoldFontMetrics(m_trackHeaderBoldFont),
|
|
m_generatedPixmap(0),
|
|
m_generatedMask(0),
|
|
m_generatedWidth( -1),
|
|
m_generatedHeight( -1),
|
|
m_inPrinterMethod(false),
|
|
m_p(new NotePixmapPainter()),
|
|
m_dottedRestCache(new NotePixmapCache)
|
|
{
|
|
init(fontName, size);
|
|
}
|
|
|
|
NotePixmapFactory::NotePixmapFactory(const NotePixmapFactory &npf) :
|
|
m_selected(false),
|
|
m_shaded(false),
|
|
m_tupletCountFont(npf.m_tupletCountFont),
|
|
m_tupletCountFontMetrics(m_tupletCountFont),
|
|
m_textMarkFont(npf.m_textMarkFont),
|
|
m_textMarkFontMetrics(m_textMarkFont),
|
|
m_fingeringFont(npf.m_fingeringFont),
|
|
m_fingeringFontMetrics(m_fingeringFont),
|
|
m_timeSigFont(npf.m_timeSigFont),
|
|
m_timeSigFontMetrics(m_timeSigFont),
|
|
m_bigTimeSigFont(npf.m_bigTimeSigFont),
|
|
m_bigTimeSigFontMetrics(m_bigTimeSigFont),
|
|
m_ottavaFont(defaultSerifFontFamily, 8, TQFont::Normal, true),
|
|
m_ottavaFontMetrics(m_ottavaFont),
|
|
m_clefOttavaFont(defaultSerifFontFamily, 8, TQFont::Normal),
|
|
m_clefOttavaFontMetrics(m_ottavaFont),
|
|
m_trackHeaderFont(defaultSansSerifFontFamily, 10, TQFont::Normal),
|
|
m_trackHeaderFontMetrics(m_trackHeaderFont),
|
|
m_trackHeaderBoldFont(defaultSansSerifFontFamily, 10, TQFont::Bold),
|
|
m_trackHeaderBoldFontMetrics(m_trackHeaderBoldFont),
|
|
m_generatedPixmap(0),
|
|
m_generatedMask(0),
|
|
m_generatedWidth( -1),
|
|
m_generatedHeight( -1),
|
|
m_inPrinterMethod(false),
|
|
m_p(new NotePixmapPainter()),
|
|
m_dottedRestCache(new NotePixmapCache)
|
|
{
|
|
init(npf.m_font->getName(), npf.m_font->getSize());
|
|
}
|
|
|
|
NotePixmapFactory &
|
|
NotePixmapFactory::operator=(const NotePixmapFactory &npf)
|
|
{
|
|
if (&npf != this) {
|
|
m_selected = npf.m_selected;
|
|
m_shaded = npf.m_shaded;
|
|
m_timeSigFont = npf.m_timeSigFont;
|
|
m_timeSigFontMetrics = TQFontMetrics(m_timeSigFont);
|
|
m_bigTimeSigFont = npf.m_bigTimeSigFont;
|
|
m_bigTimeSigFontMetrics = TQFontMetrics(m_bigTimeSigFont);
|
|
m_tupletCountFont = npf.m_tupletCountFont;
|
|
m_tupletCountFontMetrics = TQFontMetrics(m_tupletCountFont);
|
|
m_textMarkFont = npf.m_textMarkFont;
|
|
m_textMarkFontMetrics = TQFontMetrics(m_textMarkFont);
|
|
m_fingeringFont = npf.m_fingeringFont;
|
|
m_fingeringFontMetrics = TQFontMetrics(m_fingeringFont);
|
|
m_ottavaFont = npf.m_ottavaFont;
|
|
m_ottavaFontMetrics = TQFontMetrics(m_ottavaFont);
|
|
m_clefOttavaFont = npf.m_clefOttavaFont;
|
|
m_clefOttavaFontMetrics = TQFontMetrics(m_clefOttavaFont);
|
|
m_trackHeaderFont = npf.m_trackHeaderFont;
|
|
m_trackHeaderFontMetrics = TQFontMetrics(m_trackHeaderFont);
|
|
m_trackHeaderBoldFont = npf.m_trackHeaderBoldFont;
|
|
m_trackHeaderBoldFontMetrics = TQFontMetrics(m_trackHeaderBoldFont);
|
|
init(npf.m_font->getName(), npf.m_font->getSize());
|
|
m_dottedRestCache->clear();
|
|
m_textFontCache.clear();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::init(std::string fontName, int size)
|
|
{
|
|
try {
|
|
m_style = NoteStyleFactory::getStyle(NoteStyleFactory::DefaultStyle);
|
|
} catch (NoteStyleFactory::StyleUnavailable u) {
|
|
TDEStartupLogo::hideIfStillThere();
|
|
KMessageBox::error(0, i18n(strtoqstr(u.getMessage()).ascii()));
|
|
throw;
|
|
}
|
|
|
|
int origSize = size;
|
|
|
|
if (fontName != "") {
|
|
try {
|
|
if (size < 0)
|
|
size = NoteFontFactory::getDefaultSize(fontName);
|
|
m_font = NoteFontFactory::getFont(fontName, size);
|
|
} catch (Exception f) {
|
|
fontName = "";
|
|
// fall through
|
|
}
|
|
}
|
|
|
|
if (fontName == "") { // either because it was passed in or because read failed
|
|
try {
|
|
fontName = NoteFontFactory::getDefaultFontName();
|
|
size = origSize;
|
|
if (size < 0)
|
|
size = NoteFontFactory::getDefaultSize(fontName);
|
|
m_font = NoteFontFactory::getFont(fontName, size);
|
|
} catch (Exception f) { // already reported
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// Resize the fonts, because the original constructor used point
|
|
// sizes only and we want pixels
|
|
TQFont timeSigFont(defaultTimeSigFontFamily),
|
|
textFont(defaultSerifFontFamily);
|
|
TDEConfig* config = kapp->config();
|
|
config->setGroup(NotationViewConfigGroup);
|
|
|
|
m_timeSigFont = config->readFontEntry("timesigfont", &timeSigFont);
|
|
m_timeSigFont.setBold(true);
|
|
m_timeSigFont.setPixelSize(size * 5 / 2);
|
|
m_timeSigFontMetrics = TQFontMetrics(m_timeSigFont);
|
|
|
|
m_bigTimeSigFont = config->readFontEntry("timesigfont", &timeSigFont);
|
|
m_bigTimeSigFont.setPixelSize(size * 4 + 2);
|
|
m_bigTimeSigFontMetrics = TQFontMetrics(m_bigTimeSigFont);
|
|
|
|
m_tupletCountFont = config->readFontEntry("textfont", &textFont);
|
|
m_tupletCountFont.setBold(true);
|
|
m_tupletCountFont.setPixelSize(size * 2);
|
|
m_tupletCountFontMetrics = TQFontMetrics(m_tupletCountFont);
|
|
|
|
m_textMarkFont = config->readFontEntry("textfont", &textFont);
|
|
m_textMarkFont.setBold(true);
|
|
m_textMarkFont.setItalic(true);
|
|
m_textMarkFont.setPixelSize(size * 2);
|
|
m_textMarkFontMetrics = TQFontMetrics(m_textMarkFont);
|
|
|
|
m_fingeringFont = config->readFontEntry("textfont", &textFont);
|
|
m_fingeringFont.setBold(true);
|
|
m_fingeringFont.setPixelSize(size * 5 / 3);
|
|
m_fingeringFontMetrics = TQFontMetrics(m_fingeringFont);
|
|
|
|
m_ottavaFont = config->readFontEntry("textfont", &textFont);
|
|
m_ottavaFont.setPixelSize(size * 2);
|
|
m_ottavaFontMetrics = TQFontMetrics(m_ottavaFont);
|
|
|
|
m_clefOttavaFont = config->readFontEntry("textfont", &textFont);
|
|
m_clefOttavaFont.setPixelSize(getLineSpacing() * 3 / 2);
|
|
m_clefOttavaFontMetrics = TQFontMetrics(m_clefOttavaFont);
|
|
|
|
m_trackHeaderFont = config->readFontEntry("sansfont", &m_trackHeaderFont);
|
|
m_trackHeaderFont.setPixelSize(12);
|
|
m_trackHeaderFontMetrics = TQFontMetrics(m_trackHeaderFont);
|
|
|
|
m_trackHeaderBoldFont = m_trackHeaderFont;
|
|
m_trackHeaderBoldFont.setBold(true);
|
|
m_trackHeaderBoldFontMetrics = TQFontMetrics(m_trackHeaderBoldFont);
|
|
}
|
|
|
|
NotePixmapFactory::~NotePixmapFactory()
|
|
{
|
|
delete m_p;
|
|
delete m_dottedRestCache;
|
|
}
|
|
|
|
std::string
|
|
NotePixmapFactory::getFontName() const
|
|
{
|
|
return m_font->getName();
|
|
}
|
|
|
|
int
|
|
NotePixmapFactory::getSize() const
|
|
{
|
|
return m_font->getSize();
|
|
}
|
|
|
|
TQPixmap
|
|
NotePixmapFactory::toTQPixmap(TQCanvasPixmap* cp)
|
|
{
|
|
TQPixmap p = *cp;
|
|
delete cp;
|
|
return p;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::dumpStats(std::ostream &s)
|
|
{
|
|
#ifdef DUMP_STATS
|
|
s << "NotePixmapFactory: total times since last stats dump:\n"
|
|
<< "makeNotePixmap: "
|
|
<< (makeNotesTime * 1000 / CLOCKS_PER_SEC) << "ms\n"
|
|
<< "drawBeams: "
|
|
<< (drawBeamsTime * 1000 / CLOCKS_PER_SEC) << "ms"
|
|
<< " (drew " << drawBeamsCount << " individual points in " << drawBeamsBeamCount << " beams)"
|
|
<< endl;
|
|
makeNotesTime = 0;
|
|
drawBeamsTime = 0;
|
|
drawBeamsCount = 0;
|
|
drawBeamsBeamCount = 0;
|
|
#endif
|
|
|
|
(void)s; // avoid warnings
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeNotePixmap(const NotePixmapParameters ¶ms)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeNotePixmap");
|
|
clock_t startTime = clock();
|
|
|
|
drawNoteAux(params, 0, 0, 0);
|
|
|
|
TQPoint hotspot(m_left, m_above + m_noteBodyHeight / 2);
|
|
|
|
//#define ROSE_DEBUG_NOTE_PIXMAP_FACTORY
|
|
#ifdef ROSE_DEBUG_NOTE_PIXMAP_FACTORY
|
|
|
|
m_p->painter().setPen(TQt::red);
|
|
m_p->painter().setBrush(TQt::red);
|
|
|
|
m_p->drawLine(0, 0, 0, m_generatedHeight - 1);
|
|
m_p->drawLine(m_generatedWidth - 1, 0,
|
|
m_generatedWidth - 1,
|
|
m_generatedHeight - 1);
|
|
|
|
{
|
|
int hsx = hotspot.x();
|
|
int hsy = hotspot.y();
|
|
m_p->drawLine(hsx - 2, hsy - 2, hsx + 2, hsy + 2);
|
|
m_p->drawLine(hsx - 2, hsy + 2, hsx + 2, hsy - 2);
|
|
}
|
|
#endif
|
|
|
|
clock_t endTime = clock();
|
|
makeNotesTime += (endTime - startTime);
|
|
|
|
return makeCanvasPixmap(hotspot);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawNote(const NotePixmapParameters ¶ms,
|
|
TQPainter &painter, int x, int y)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::drawNote");
|
|
m_inPrinterMethod = true;
|
|
drawNoteAux(params, &painter, x, y);
|
|
m_inPrinterMethod = false;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawNoteAux(const NotePixmapParameters ¶ms,
|
|
TQPainter *painter, int x, int y)
|
|
{
|
|
NoteFont::CharacterType charType = m_inPrinterMethod ? NoteFont::Printer : NoteFont::Screen;
|
|
|
|
bool drawFlag = params.m_drawFlag;
|
|
|
|
if (params.m_beamed)
|
|
drawFlag = false;
|
|
|
|
// A note pixmap is formed of note head, stem, flags,
|
|
// accidentals, dots and beams. Assume the note head first, then
|
|
// do the rest of the calculations left to right, ie accidentals,
|
|
// stem, flags, dots, beams
|
|
|
|
m_noteBodyWidth = getNoteBodyWidth(params.m_noteType);
|
|
m_noteBodyHeight = getNoteBodyHeight(params.m_noteType);
|
|
|
|
// Spacing surrounding the note head. For top and bottom, we
|
|
// adjust this according to the discrepancy between the nominal
|
|
// and actual heights of the note head pixmap. For left and
|
|
// right, we use the hotspot x coordinate of the head.
|
|
int temp;
|
|
if (!m_font->getHotspot(m_style->getNoteHeadCharName(params.m_noteType).first,
|
|
m_borderX, temp))
|
|
m_borderX = 0;
|
|
|
|
if (params.m_noteType == Note::Minim && params.m_stemGoesUp)
|
|
m_borderX++;
|
|
int actualNoteBodyHeight =
|
|
m_font->getHeight(m_style->getNoteHeadCharName(params.m_noteType).first);
|
|
|
|
m_left = m_right = m_borderX;
|
|
m_above = m_borderY = (actualNoteBodyHeight - m_noteBodyHeight) / 2;
|
|
m_below = (actualNoteBodyHeight - m_noteBodyHeight) - m_above;
|
|
|
|
// NOTATION_DEBUG << "actualNoteBodyHeight: " << actualNoteBodyHeight
|
|
// << ", noteBodyHeight: " << m_noteBodyHeight << ", borderX: "
|
|
// << m_borderX << ", borderY: "
|
|
// << m_borderY << endl;
|
|
|
|
bool isStemmed = m_style->hasStem(params.m_noteType);
|
|
int flagCount = m_style->getFlagCount(params.m_noteType);
|
|
int slashCount = params.m_slashes;
|
|
if (!slashCount)
|
|
slashCount = m_style->getSlashCount(params.m_noteType);
|
|
|
|
if (params.m_accidental != NoAccidental) {
|
|
makeRoomForAccidental(params.m_accidental,
|
|
params.m_cautionary,
|
|
params.m_accidentalShift,
|
|
params.m_accidentalExtra);
|
|
}
|
|
|
|
NoteCharacter dot(getCharacter(NoteCharacterNames::DOT, PlainColour, charType));
|
|
int dotWidth = dot.getWidth();
|
|
if (dotWidth < getNoteBodyWidth() / 2)
|
|
dotWidth = getNoteBodyWidth() / 2;
|
|
|
|
int stemLength = getStemLength(params);
|
|
|
|
if (params.m_marks.size() > 0) {
|
|
makeRoomForMarks(isStemmed, params, stemLength);
|
|
}
|
|
|
|
if (params.m_legerLines != 0) {
|
|
makeRoomForLegerLines(params);
|
|
}
|
|
|
|
if (slashCount > 0) {
|
|
m_left = std::max(m_left, m_noteBodyWidth / 2);
|
|
m_right = std::max(m_right, m_noteBodyWidth / 2);
|
|
}
|
|
|
|
if (params.m_tupletCount > 0) {
|
|
makeRoomForTuplingLine(params);
|
|
}
|
|
|
|
m_right = std::max(m_right, params.m_dots * dotWidth + dotWidth / 2);
|
|
if (params.m_dotShifted) {
|
|
m_right += m_noteBodyWidth;
|
|
}
|
|
if (params.m_onLine) {
|
|
m_above = std::max(m_above, dot.getHeight() / 2);
|
|
}
|
|
|
|
if (params.m_shifted) {
|
|
if (params.m_stemGoesUp) {
|
|
m_right += m_noteBodyWidth;
|
|
} else {
|
|
m_left = std::max(m_left, m_noteBodyWidth);
|
|
}
|
|
}
|
|
|
|
bool tieAbove = params.m_tieAbove;
|
|
if (!params.m_tiePositionExplicit) {
|
|
tieAbove = !params.m_stemGoesUp;
|
|
}
|
|
|
|
if (params.m_tied) {
|
|
m_right = std::max(m_right, params.m_tieLength);
|
|
if (!tieAbove) {
|
|
m_below = std::max(m_below, m_noteBodyHeight * 2);
|
|
} else {
|
|
m_above = std::max(m_above, m_noteBodyHeight * 2);
|
|
}
|
|
}
|
|
|
|
TQPoint startPoint, endPoint;
|
|
if (isStemmed && params.m_drawStem) {
|
|
makeRoomForStemAndFlags(drawFlag ? flagCount : 0, stemLength, params,
|
|
startPoint, endPoint);
|
|
}
|
|
|
|
if (isStemmed && params.m_drawStem && params.m_beamed) {
|
|
makeRoomForBeams(params);
|
|
}
|
|
|
|
// for all other calculations we use the nominal note-body height
|
|
// (same as the gap between staff lines), but here we want to know
|
|
// if the pixmap itself is taller than that
|
|
/*!!!
|
|
int actualNoteBodyHeight = m_font->getHeight
|
|
(m_style->getNoteHeadCharName(params.m_noteType).first);
|
|
// - 2*m_origin.y();
|
|
if (actualNoteBodyHeight > m_noteBodyHeight) {
|
|
m_below = std::max(m_below, actualNoteBodyHeight - m_noteBodyHeight);
|
|
}
|
|
*/
|
|
if (painter) {
|
|
painter->save();
|
|
m_p->beginExternal(painter);
|
|
// NOTATION_DEBUG << "Translate: (" << x << "," << y << ")" << endl;
|
|
painter->translate(x - m_left, y - m_above - m_noteBodyHeight / 2);
|
|
} else {
|
|
createPixmapAndMask(m_noteBodyWidth + m_left + m_right,
|
|
m_noteBodyHeight + m_above + m_below);
|
|
}
|
|
|
|
if (params.m_tupletCount > 0) {
|
|
drawTuplingLine(params);
|
|
}
|
|
|
|
if (isStemmed && params.m_drawStem && drawFlag) {
|
|
drawFlags(flagCount, params, startPoint, endPoint);
|
|
}
|
|
|
|
if (params.m_accidental != NoAccidental) {
|
|
drawAccidental(params.m_accidental, params.m_cautionary);
|
|
}
|
|
|
|
NoteStyle::CharNameRec charNameRec
|
|
(m_style->getNoteHeadCharName(params.m_noteType));
|
|
CharName charName = charNameRec.first;
|
|
bool inverted = charNameRec.second;
|
|
NoteCharacter body = getCharacter
|
|
(charName,
|
|
params.m_highlighted ? HighlightedColour :
|
|
params.m_quantized ? QuantizedColour :
|
|
params.m_trigger ? TriggerColour :
|
|
params.m_inRange ? PlainColour : OutRangeColour,
|
|
inverted);
|
|
|
|
TQPoint bodyLocation(m_left - m_borderX,
|
|
m_above - m_borderY + getStaffLineThickness() / 2);
|
|
if (params.m_shifted) {
|
|
if (params.m_stemGoesUp) {
|
|
bodyLocation.rx() += m_noteBodyWidth;
|
|
} else {
|
|
bodyLocation.rx() -= m_noteBodyWidth - 1;
|
|
}
|
|
}
|
|
|
|
m_p->drawNoteCharacter(bodyLocation.x(), bodyLocation.y(), body);
|
|
|
|
if (params.m_dots > 0) {
|
|
|
|
int x = m_left + m_noteBodyWidth + dotWidth / 2;
|
|
int y = m_above + m_noteBodyHeight / 2 - dot.getHeight() / 2;
|
|
|
|
if (params.m_onLine)
|
|
y -= m_noteBodyHeight / 2;
|
|
|
|
if (params.m_shifted)
|
|
x += m_noteBodyWidth;
|
|
else if (params.m_dotShifted)
|
|
x += m_noteBodyWidth;
|
|
|
|
for (int i = 0; i < params.m_dots; ++i) {
|
|
m_p->drawNoteCharacter(x, y, dot);
|
|
x += dotWidth;
|
|
}
|
|
}
|
|
|
|
if (isStemmed && params.m_drawStem) {
|
|
|
|
if (flagCount > 0 && !drawFlag && params.m_beamed) {
|
|
drawBeams(endPoint, params, flagCount);
|
|
}
|
|
|
|
if (slashCount > 0) {
|
|
drawSlashes(startPoint, params, slashCount);
|
|
}
|
|
|
|
if (m_selected)
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
else
|
|
m_p->painter().setPen(TQt::black);
|
|
|
|
// If we draw stems after beams, instead of beams after stems,
|
|
// beam anti-aliasing won't damage stems but we have to shorten the
|
|
// stems slightly first so that the stems don't extend all the way
|
|
// through the beam into the anti-aliased region on the
|
|
// other side of the beam that faces away from the note-heads.
|
|
int shortening;
|
|
if (flagCount > 0 && !drawFlag && params.m_beamed)
|
|
shortening = 2;
|
|
else
|
|
shortening = 0;
|
|
drawStem(params, startPoint, endPoint, shortening);
|
|
}
|
|
|
|
if (params.m_marks.size() > 0) {
|
|
drawMarks(isStemmed, params, stemLength);
|
|
}
|
|
|
|
if (params.m_legerLines != 0) {
|
|
drawLegerLines(params);
|
|
}
|
|
|
|
if (params.m_tied) {
|
|
drawTie(tieAbove, params.m_tieLength, dotWidth * params.m_dots);
|
|
}
|
|
|
|
if (painter) {
|
|
painter->restore();
|
|
}
|
|
}
|
|
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeNoteHaloPixmap(const NotePixmapParameters ¶ms)
|
|
{
|
|
int nbh0 = getNoteBodyHeight();
|
|
int nbh = getNoteBodyHeight(params.m_noteType);
|
|
int nbw0 = getNoteBodyHeight();
|
|
int nbw = getNoteBodyWidth(params.m_noteType);
|
|
|
|
createPixmapAndMask(nbw + nbw0, nbh + nbh0);
|
|
drawNoteHalo(0, 0, nbw + nbw0, nbh + nbh0);
|
|
|
|
return makeCanvasPixmap(TQPoint(nbw0 / 2, nbh0));
|
|
}
|
|
|
|
|
|
void
|
|
NotePixmapFactory::drawNoteHalo(int x, int y, int w, int h) {
|
|
|
|
m_p->painter().setPen(TQPen(TQColor(GUIPalette::CollisionHaloHue,
|
|
GUIPalette::CollisionHaloSaturation,
|
|
255, TQColor::Hsv), 1));
|
|
m_p->painter().setBrush(TQColor(GUIPalette::CollisionHaloHue,
|
|
GUIPalette::CollisionHaloSaturation,
|
|
255, TQColor::Hsv));
|
|
m_p->drawEllipse(x, y, w, h);
|
|
}
|
|
|
|
|
|
|
|
int
|
|
NotePixmapFactory::getStemLength(const NotePixmapParameters ¶ms) const
|
|
{
|
|
if (params.m_beamed && params.m_stemLength >= 0) {
|
|
return params.m_stemLength;
|
|
}
|
|
|
|
int stemLength = getStemLength();
|
|
|
|
int flagCount = m_style->getFlagCount(params.m_noteType);
|
|
int slashCount = params.m_slashes;
|
|
bool stemUp = params.m_stemGoesUp;
|
|
int nbh = m_noteBodyHeight;
|
|
|
|
if (flagCount > 2) {
|
|
stemLength += getLineSpacing() * (flagCount - 2);
|
|
}
|
|
|
|
int width = 0, height = 0;
|
|
|
|
if (flagCount > 0) {
|
|
|
|
if (!stemUp)
|
|
stemLength += nbh / 2;
|
|
|
|
if (m_font->getDimensions(m_style->getFlagCharName(flagCount),
|
|
width, height)) {
|
|
|
|
stemLength = std::max(stemLength, height);
|
|
|
|
} else if (m_font->getDimensions(m_style->getPartialFlagCharName(true),
|
|
width, height) ||
|
|
m_font->getDimensions(m_style->getPartialFlagCharName(false),
|
|
width, height)) {
|
|
|
|
unsigned int flagSpace = m_noteBodyHeight;
|
|
(void)m_font->getFlagSpacing(flagSpace);
|
|
|
|
stemLength = std::max(stemLength,
|
|
height + (flagCount - 1) * (int)flagSpace);
|
|
}
|
|
}
|
|
|
|
if (slashCount > 3 && flagCount < 3) {
|
|
stemLength += (slashCount - 3) * (nbh / 2);
|
|
}
|
|
|
|
if (params.m_stemLength >= 0) {
|
|
if (flagCount == 0)
|
|
return params.m_stemLength;
|
|
stemLength = std::max(stemLength, params.m_stemLength);
|
|
}
|
|
|
|
return stemLength;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::makeRoomForAccidental(Accidental a,
|
|
bool cautionary, int shift, bool extra)
|
|
{
|
|
// General observation: where we're only using a character to
|
|
// determine its dimensions, we should (for the moment) just
|
|
// request it in screen mode, because it may be quicker and we
|
|
// don't need to render it, and the dimensions are the same.
|
|
NoteCharacter ac
|
|
(m_font->getCharacter(m_style->getAccidentalCharName(a)));
|
|
|
|
TQPoint ah(m_font->getHotspot(m_style->getAccidentalCharName(a)));
|
|
|
|
m_left += ac.getWidth() + (m_noteBodyWidth / 4 - m_borderX);
|
|
|
|
if (shift > 0) {
|
|
if (extra) {
|
|
// The extra flag indicates that the first shift is to get
|
|
// out of the way of a note head, thus has to move
|
|
// possibly further, or at least a different amount. So
|
|
// replace the first shift with a different one.
|
|
--shift;
|
|
m_left += m_noteBodyWidth - m_noteBodyWidth / 5;
|
|
}
|
|
if (shift > 0) {
|
|
// The amount we shift for each accidental is the greater
|
|
// of the probable shift for that accidental and the
|
|
// probable shift for a sharp, on the assumption (usually
|
|
// true in classical notation) that the sharp is the
|
|
// widest accidental and that we may have other
|
|
// accidentals possibly including sharps on other notes in
|
|
// this chord that we can't know about here.
|
|
int step = ac.getWidth() - ah.x();
|
|
if (a != Accidentals::Sharp) {
|
|
NoteCharacter acSharp
|
|
(m_font->getCharacter(m_style->getAccidentalCharName
|
|
(Accidentals::Sharp)));
|
|
TQPoint ahSharp
|
|
(m_font->getHotspot(m_style->getAccidentalCharName
|
|
(Accidentals::Sharp)));
|
|
step = std::max(step, acSharp.getWidth() - ahSharp.x());
|
|
}
|
|
m_left += shift * step;
|
|
}
|
|
}
|
|
|
|
if (cautionary)
|
|
m_left += m_noteBodyWidth;
|
|
|
|
int above = ah.y() - m_noteBodyHeight / 2;
|
|
int below = (ac.getHeight() - ah.y()) -
|
|
(m_noteBodyHeight - m_noteBodyHeight / 2); // subtract in case it's odd
|
|
|
|
if (above > 0)
|
|
m_above = std::max(m_above, above);
|
|
if (below > 0)
|
|
m_below = std::max(m_below, below);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawAccidental(Accidental a, bool cautionary)
|
|
{
|
|
NoteCharacter ac = getCharacter
|
|
(m_style->getAccidentalCharName(a), PlainColour, false);
|
|
|
|
TQPoint ah(m_font->getHotspot(m_style->getAccidentalCharName(a)));
|
|
|
|
int ax = 0;
|
|
|
|
if (cautionary) {
|
|
ax += m_noteBodyWidth / 2;
|
|
int bl = ac.getHeight() * 2 / 3;
|
|
int by = m_above + m_noteBodyHeight / 2 - bl / 2;
|
|
drawBracket(bl, true, false, m_noteBodyWidth*3 / 8, by);
|
|
drawBracket(bl, false, false, ac.getWidth() + m_noteBodyWidth*5 / 8, by);
|
|
}
|
|
|
|
m_p->drawNoteCharacter(ax, m_above + m_noteBodyHeight / 2 - ah.y(), ac);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::makeRoomForMarks(bool isStemmed,
|
|
const NotePixmapParameters ¶ms,
|
|
int stemLength)
|
|
{
|
|
int height = 0, width = 0;
|
|
int gap = m_noteBodyHeight / 5 + 1;
|
|
|
|
std::vector<Mark> normalMarks = params.getNormalMarks();
|
|
std::vector<Mark> aboveMarks = params.getAboveMarks();
|
|
|
|
for (std::vector<Mark>::iterator i = normalMarks.begin();
|
|
i != normalMarks.end(); ++i) {
|
|
|
|
if (!Marks::isTextMark(*i)) {
|
|
|
|
NoteCharacter character(m_font->getCharacter(m_style->getMarkCharName(*i)));
|
|
height += character.getHeight() + gap;
|
|
if (character.getWidth() > width)
|
|
width = character.getWidth();
|
|
|
|
} else {
|
|
// Inefficient to do this here _and_ in drawMarks, but
|
|
// text marks are not all that common
|
|
TQString text = strtoqstr(Marks::getTextFromMark(*i));
|
|
TQRect bounds = m_textMarkFontMetrics.boundingRect(text);
|
|
height += bounds.height() + gap;
|
|
if (bounds.width() > width)
|
|
width = bounds.width();
|
|
}
|
|
}
|
|
|
|
if (height > 0) {
|
|
if (isStemmed && params.m_stemGoesUp) {
|
|
m_below += height + 1;
|
|
} else {
|
|
m_above += height + 1;
|
|
}
|
|
}
|
|
|
|
height = 0;
|
|
|
|
if (params.m_safeVertDistance > 0 && !aboveMarks.empty()) {
|
|
m_above = std::max(m_above, params.m_safeVertDistance);
|
|
}
|
|
|
|
for (std::vector<Mark>::iterator i = aboveMarks.begin();
|
|
i != aboveMarks.end(); ++i) {
|
|
|
|
if (!Marks::isFingeringMark(*i)) {
|
|
|
|
Mark m(*i);
|
|
|
|
if (m == Marks::TrillLine)
|
|
m = Marks::LongTrill;
|
|
|
|
if (m == Marks::LongTrill) {
|
|
m_right = std::max(m_right, params.m_width);
|
|
}
|
|
|
|
NoteCharacter character(m_font->getCharacter(m_style->getMarkCharName(m)));
|
|
height += character.getHeight() + gap;
|
|
if (character.getWidth() > width)
|
|
width = character.getWidth();
|
|
|
|
} else {
|
|
|
|
// Inefficient to do this here _and_ in drawMarks
|
|
TQString text = strtoqstr(Marks::getFingeringFromMark(*i));
|
|
TQRect bounds = m_fingeringFontMetrics.boundingRect(text);
|
|
height += bounds.height() + gap + 3;
|
|
if (bounds.width() > width)
|
|
width = bounds.width();
|
|
}
|
|
}
|
|
|
|
if (height > 0) {
|
|
if (isStemmed && params.m_stemGoesUp && params.m_safeVertDistance == 0) {
|
|
m_above += stemLength + height + 1;
|
|
} else {
|
|
m_above += height + 1;
|
|
}
|
|
}
|
|
|
|
m_left = std::max(m_left, width / 2 - m_noteBodyWidth / 2);
|
|
m_right = std::max(m_right, width / 2 - m_noteBodyWidth / 2);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawMarks(bool isStemmed,
|
|
const NotePixmapParameters ¶ms,
|
|
int stemLength)
|
|
{
|
|
int gap = m_noteBodyHeight / 5 + 1;
|
|
int dy = gap;
|
|
|
|
std::vector<Mark> normalMarks = params.getNormalMarks();
|
|
std::vector<Mark> aboveMarks = params.getAboveMarks();
|
|
|
|
bool normalMarksAreAbove = !(isStemmed && params.m_stemGoesUp);
|
|
|
|
for (std::vector<Mark>::iterator i = normalMarks.begin();
|
|
i != normalMarks.end(); ++i) {
|
|
|
|
if (!Marks::isTextMark(*i)) {
|
|
|
|
NoteCharacter character = getCharacter
|
|
(m_style->getMarkCharName(*i), PlainColour,
|
|
!normalMarksAreAbove);
|
|
|
|
int x = m_left + m_noteBodyWidth / 2 - character.getWidth() / 2;
|
|
int y = (normalMarksAreAbove ?
|
|
(m_above - dy - character.getHeight() - 1) :
|
|
(m_above + m_noteBodyHeight + m_borderY * 2 + dy));
|
|
|
|
m_p->drawNoteCharacter(x, y, character);
|
|
dy += character.getHeight() + gap;
|
|
|
|
} else {
|
|
|
|
TQString text = strtoqstr(Marks::getTextFromMark(*i));
|
|
TQRect bounds = m_textMarkFontMetrics.boundingRect(text);
|
|
|
|
m_p->painter().setFont(m_textMarkFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(m_textMarkFont);
|
|
|
|
int x = m_left + m_noteBodyWidth / 2 - bounds.width() / 2;
|
|
int y = (normalMarksAreAbove ?
|
|
(m_above - dy - 3) :
|
|
(m_above + m_noteBodyHeight + m_borderY * 2 + dy + bounds.height() + 1));
|
|
|
|
m_p->drawText(x, y, text);
|
|
dy += bounds.height() + gap;
|
|
}
|
|
}
|
|
|
|
if (!normalMarksAreAbove)
|
|
dy = gap;
|
|
if (params.m_safeVertDistance > 0) {
|
|
if (normalMarksAreAbove) {
|
|
dy = std::max(dy, params.m_safeVertDistance);
|
|
} else {
|
|
dy = params.m_safeVertDistance;
|
|
}
|
|
} else if (isStemmed && params.m_stemGoesUp) {
|
|
dy += stemLength;
|
|
}
|
|
|
|
for (std::vector<Mark>::iterator i = aboveMarks.begin();
|
|
i != aboveMarks.end(); ++i) {
|
|
|
|
if (m_selected)
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
else
|
|
m_p->painter().setPen(TQt::black);
|
|
if (!Marks::isFingeringMark(*i)) {
|
|
|
|
int x = m_left + m_noteBodyWidth / 2;
|
|
int y = m_above - dy - 1;
|
|
|
|
if (*i != Marks::TrillLine) {
|
|
|
|
NoteCharacter character
|
|
(getCharacter
|
|
(m_style->getMarkCharName(*i), PlainColour,
|
|
false));
|
|
|
|
x -= character.getWidth() / 2;
|
|
y -= character.getHeight();
|
|
|
|
m_p->drawNoteCharacter(x, y, character);
|
|
|
|
y += character.getHeight() / 2;
|
|
x += character.getWidth();
|
|
|
|
dy += character.getHeight() + gap;
|
|
|
|
} else {
|
|
|
|
NoteCharacter character
|
|
(getCharacter
|
|
(m_style->getMarkCharName(Marks::Trill), PlainColour,
|
|
false));
|
|
y -= character.getHeight() / 2;
|
|
dy += character.getHeight() + gap;
|
|
}
|
|
|
|
if (*i == Marks::LongTrill ||
|
|
*i == Marks::TrillLine) {
|
|
NoteCharacter extension;
|
|
if (getCharacter(NoteCharacterNames::TRILL_LINE, extension,
|
|
PlainColour, false)) {
|
|
x += extension.getHotspot().x();
|
|
while (x < m_left + params.m_width - extension.getWidth()) {
|
|
x -= extension.getHotspot().x();
|
|
m_p->drawNoteCharacter(x, y, extension);
|
|
x += extension.getWidth();
|
|
}
|
|
}
|
|
if (*i == Marks::TrillLine)
|
|
dy += extension.getHeight() + gap;
|
|
}
|
|
|
|
} else {
|
|
TQString text = strtoqstr(Marks::getFingeringFromMark(*i));
|
|
TQRect bounds = m_fingeringFontMetrics.boundingRect(text);
|
|
|
|
m_p->painter().setFont(m_fingeringFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(m_fingeringFont);
|
|
|
|
int x = m_left + m_noteBodyWidth / 2 - bounds.width() / 2;
|
|
int y = m_above - dy - 3;
|
|
|
|
m_p->drawText(x, y, text);
|
|
dy += bounds.height() + gap;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::makeRoomForLegerLines(const NotePixmapParameters ¶ms)
|
|
{
|
|
if (params.m_legerLines < 0 || params.m_restOutsideStave) {
|
|
m_above = std::max(m_above,
|
|
(m_noteBodyHeight + 1) *
|
|
( -params.m_legerLines / 2));
|
|
}
|
|
if (params.m_legerLines > 0 || params.m_restOutsideStave) {
|
|
m_below = std::max(m_below,
|
|
(m_noteBodyHeight + 1) *
|
|
(params.m_legerLines / 2));
|
|
}
|
|
if (params.m_legerLines != 0) {
|
|
m_left = std::max(m_left, m_noteBodyWidth / 5 + 1);
|
|
m_right = std::max(m_right, m_noteBodyWidth / 5 + 1);
|
|
}
|
|
if (params.m_restOutsideStave) {
|
|
m_above += 1;
|
|
m_left = std::max(m_left, m_noteBodyWidth * 3 + 1);
|
|
m_right = std::max(m_right, m_noteBodyWidth * 3 + 1);
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawLegerLines(const NotePixmapParameters ¶ms)
|
|
{
|
|
int x0, x1, y;
|
|
|
|
if (params.m_legerLines == 0)
|
|
return ;
|
|
|
|
if (params.m_restOutsideStave) {
|
|
if (m_selected)
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
else
|
|
m_p->painter().setPen(TQt::black);
|
|
}
|
|
x0 = m_left - m_noteBodyWidth / 5 - 1;
|
|
x1 = m_left + m_noteBodyWidth + m_noteBodyWidth / 5 /* + 1 */;
|
|
|
|
if (params.m_shifted) {
|
|
if (params.m_stemGoesUp) {
|
|
x0 += m_noteBodyWidth;
|
|
x1 += m_noteBodyWidth;
|
|
} else {
|
|
x0 -= m_noteBodyWidth;
|
|
x1 -= m_noteBodyWidth;
|
|
}
|
|
}
|
|
|
|
int offset = m_noteBodyHeight + getStaffLineThickness();
|
|
int legerLines = params.m_legerLines;
|
|
bool below = (legerLines < 0);
|
|
|
|
if (below) {
|
|
legerLines = -legerLines;
|
|
offset = -offset;
|
|
}
|
|
|
|
if (params.m_restOutsideStave)
|
|
y = m_above;
|
|
else {
|
|
if (!below) { // note above staff
|
|
if (legerLines % 2) { // note is between lines
|
|
y = m_above + m_noteBodyHeight;
|
|
} else { // note is on a line
|
|
y = m_above + m_noteBodyHeight / 2 - getStaffLineThickness() / 2;
|
|
}
|
|
} else { // note below staff
|
|
if (legerLines % 2) { // note is between lines
|
|
y = m_above - getStaffLineThickness();
|
|
} else { // note is on a line
|
|
y = m_above + m_noteBodyHeight / 2;
|
|
}
|
|
}
|
|
}
|
|
if (params.m_restOutsideStave) {
|
|
NOTATION_DEBUG << "draw leger lines: " << legerLines << " lines, below "
|
|
<< below
|
|
<< ", note body height " << m_noteBodyHeight
|
|
<< ", thickness " << getLegerLineThickness()
|
|
<< " (staff line " << getStaffLineThickness() << ")"
|
|
<< ", offset " << offset << endl;
|
|
}
|
|
|
|
// NOTATION_DEBUG << "draw leger lines: " << legerLines << " lines, below "
|
|
// << below
|
|
// << ", note body height " << m_noteBodyHeight
|
|
// << ", thickness " << getLegerLineThickness()
|
|
// << " (staff line " << getStaffLineThickness() << ")"
|
|
// << ", offset " << offset << endl;
|
|
|
|
// bool first = true;
|
|
|
|
if (getLegerLineThickness() > getStaffLineThickness()) {
|
|
y -= (getLegerLineThickness() - getStaffLineThickness() + 1) / 2;
|
|
}
|
|
|
|
for (int i = legerLines - 1; i >= 0; --i) {
|
|
if (i % 2) {
|
|
// NOTATION_DEBUG << "drawing leger line at y = " << y << endl;
|
|
for (int j = 0; j < getLegerLineThickness(); ++j) {
|
|
m_p->drawLine(x0, y + j, x1, y + j);
|
|
}
|
|
y += offset;
|
|
// if (first) {
|
|
// x0 += getStemThickness();
|
|
// x1 -= getStemThickness();
|
|
// first = false;
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::makeRoomForStemAndFlags(int flagCount, int stemLength,
|
|
const NotePixmapParameters ¶ms,
|
|
TQPoint &s0, TQPoint &s1)
|
|
{
|
|
// The coordinates we set in s0 and s1 are relative to (m_above, m_left)
|
|
|
|
if (params.m_stemGoesUp) {
|
|
m_above = std::max
|
|
(m_above, stemLength - m_noteBodyHeight / 2);
|
|
} else {
|
|
m_below = std::max
|
|
(m_below, stemLength - m_noteBodyHeight / 2 + 1);
|
|
}
|
|
|
|
if (flagCount > 0) {
|
|
if (params.m_stemGoesUp) {
|
|
int width = 0, height = 0;
|
|
if (!m_font->getDimensions
|
|
(m_style->getFlagCharName(flagCount), width, height)) {
|
|
width = m_font->getWidth(m_style->getPartialFlagCharName(false));
|
|
}
|
|
m_right += width;
|
|
}
|
|
}
|
|
|
|
unsigned int stemThickness = getStemThickness();
|
|
|
|
NoteStyle::HFixPoint hfix;
|
|
NoteStyle::VFixPoint vfix;
|
|
m_style->getStemFixPoints(params.m_noteType, hfix, vfix);
|
|
|
|
switch (hfix) {
|
|
|
|
case NoteStyle::Normal:
|
|
case NoteStyle::Reversed:
|
|
if (params.m_stemGoesUp ^ (hfix == NoteStyle::Reversed)) {
|
|
s0.setX(m_noteBodyWidth - stemThickness);
|
|
} else {
|
|
s0.setX(0);
|
|
}
|
|
break;
|
|
|
|
case NoteStyle::Central:
|
|
if (params.m_stemGoesUp ^ (hfix == NoteStyle::Reversed)) {
|
|
s0.setX(m_noteBodyWidth / 2 + 1);
|
|
} else {
|
|
s0.setX(m_noteBodyWidth / 2);
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (vfix) {
|
|
|
|
case NoteStyle::Near:
|
|
case NoteStyle::Far:
|
|
if (params.m_stemGoesUp ^ (vfix == NoteStyle::Far)) {
|
|
s0.setY(0);
|
|
} else {
|
|
s0.setY(m_noteBodyHeight);
|
|
}
|
|
if (vfix == NoteStyle::Near) {
|
|
stemLength -= m_noteBodyHeight / 2;
|
|
} else {
|
|
stemLength += m_noteBodyHeight / 2;
|
|
}
|
|
break;
|
|
|
|
case NoteStyle::Middle:
|
|
if (params.m_stemGoesUp) {
|
|
s0.setY(m_noteBodyHeight * 3 / 8);
|
|
} else {
|
|
s0.setY(m_noteBodyHeight * 5 / 8);
|
|
}
|
|
stemLength -= m_noteBodyHeight / 8;
|
|
break;
|
|
}
|
|
|
|
if (params.m_stemGoesUp) {
|
|
s1.setY(s0.y() - stemLength + getStaffLineThickness());
|
|
} else {
|
|
s1.setY(s0.y() + stemLength);
|
|
}
|
|
|
|
s1.setX(s0.x());
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawFlags(int flagCount,
|
|
const NotePixmapParameters ¶ms,
|
|
const TQPoint &, const TQPoint &s1)
|
|
{
|
|
if (flagCount < 1)
|
|
return ;
|
|
|
|
NoteCharacter flagChar;
|
|
bool found = getCharacter(m_style->getFlagCharName(flagCount),
|
|
flagChar,
|
|
PlainColour,
|
|
!params.m_stemGoesUp);
|
|
|
|
if (!found) {
|
|
|
|
// Handle fonts that don't have all the flags in separate characters
|
|
|
|
found = getCharacter(m_style->getPartialFlagCharName(false),
|
|
flagChar,
|
|
PlainColour,
|
|
!params.m_stemGoesUp);
|
|
|
|
if (!found) {
|
|
std::cerr << "Warning: NotePixmapFactory::drawFlags: No way to draw note with " << flagCount << " flags in this font!?" << std::endl;
|
|
return ;
|
|
}
|
|
|
|
TQPoint hotspot = flagChar.getHotspot();
|
|
|
|
NoteCharacter oneFlagChar;
|
|
bool foundOne =
|
|
(flagCount > 1 ?
|
|
getCharacter(m_style->getPartialFlagCharName(true),
|
|
oneFlagChar,
|
|
PlainColour,
|
|
!params.m_stemGoesUp) : false);
|
|
|
|
unsigned int flagSpace = m_noteBodyHeight;
|
|
(void)m_font->getFlagSpacing(flagSpace);
|
|
|
|
for (int flag = 0; flag < flagCount; ++flag) {
|
|
|
|
// use flag_1 in preference to flag_0 for the final flag, so
|
|
// as to end with a flourish
|
|
if (flag == flagCount - 1 && foundOne)
|
|
flagChar = oneFlagChar;
|
|
|
|
int y = m_above + s1.y();
|
|
if (params.m_stemGoesUp)
|
|
y += flag * flagSpace;
|
|
else
|
|
y -= (flag * flagSpace) + flagChar.getHeight();
|
|
|
|
if (!m_inPrinterMethod) {
|
|
|
|
m_p->end();
|
|
|
|
// Super-slow
|
|
|
|
PixmapFunctions::drawPixmapMasked(*m_generatedPixmap,
|
|
*m_generatedMask,
|
|
m_left + s1.x() - hotspot.x(),
|
|
y,
|
|
*flagChar.getPixmap());
|
|
|
|
m_p->begin(m_generatedPixmap, m_generatedMask);
|
|
|
|
} else {
|
|
|
|
// No problem with mask here
|
|
m_p->drawNoteCharacter(m_left + s1.x() - hotspot.x(),
|
|
y,
|
|
flagChar);
|
|
}
|
|
}
|
|
|
|
} else { // the normal case
|
|
|
|
TQPoint hotspot = flagChar.getHotspot();
|
|
|
|
int y = m_above + s1.y();
|
|
if (!params.m_stemGoesUp)
|
|
y -= flagChar.getHeight();
|
|
|
|
m_p->drawNoteCharacter(m_left + s1.x() - hotspot.x(), y, flagChar);
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawStem(const NotePixmapParameters ¶ms,
|
|
const TQPoint &s0, const TQPoint &s1,
|
|
int shortening)
|
|
{
|
|
if (params.m_stemGoesUp)
|
|
shortening = -shortening;
|
|
for (int i = 0; i < getStemThickness(); ++i) {
|
|
m_p->drawLine(m_left + s0.x() + i, m_above + s0.y(),
|
|
m_left + s1.x() + i, m_above + s1.y() - shortening);
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::makeRoomForBeams(const NotePixmapParameters ¶ms)
|
|
{
|
|
int beamSpacing = (int)(params.m_width * params.m_gradient);
|
|
|
|
if (params.m_stemGoesUp) {
|
|
|
|
beamSpacing = -beamSpacing;
|
|
if (beamSpacing < 0)
|
|
beamSpacing = 0;
|
|
m_above += beamSpacing + 2;
|
|
|
|
// allow a bit extra in case the h fixpoint is non-normal
|
|
m_right = std::max(m_right, params.m_width + m_noteBodyWidth);
|
|
|
|
} else {
|
|
|
|
if (beamSpacing < 0)
|
|
beamSpacing = 0;
|
|
m_below += beamSpacing + 2;
|
|
|
|
m_right = std::max(m_right, params.m_width);
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawShallowLine(int x0, int y0, int x1, int y1,
|
|
int thickness, bool smooth)
|
|
{
|
|
if (!smooth || m_inPrinterMethod || (y0 == y1)) {
|
|
|
|
if (!m_inPrinterMethod) {
|
|
if (m_selected)
|
|
m_p->painter().setBrush(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
else
|
|
m_p->painter().setBrush(TQt::black);
|
|
}
|
|
if (thickness < 4) {
|
|
for (int i = 0; i < thickness; ++i) {
|
|
m_p->drawLine(x0, y0 + i, x1, y1 + i);
|
|
}
|
|
} else {
|
|
Profiler profiler("NotePixmapFactory::drawShallowLine(polygon)");
|
|
TQPointArray qp(4);
|
|
qp.setPoint(0, x0, y0);
|
|
qp.setPoint(1, x0, y0 + thickness);
|
|
qp.setPoint(2, x1, y1 + thickness);
|
|
qp.setPoint(3, x1, y1);
|
|
m_p->drawPolygon(qp);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
Profiler profiler("NotePixmapFactory::drawShallowLine(points)");
|
|
|
|
int dv = y1 - y0;
|
|
int dh = x1 - x0;
|
|
|
|
static std::vector<TQColor> colours, selectedColours;
|
|
if (colours.size() == 0) {
|
|
int h, s, v;
|
|
TQColor c = GUIPalette::getColour(GUIPalette::SelectedElement);
|
|
c.hsv(&h, &s, &v);
|
|
for (int step = 0; step < 256; step += (step == 0 ? 63 : 64)) {
|
|
colours.push_back(TQColor( -1, 0, step, TQColor::Hsv));
|
|
selectedColours.push_back(TQColor(h, 255 - step, v, TQColor::Hsv));
|
|
}
|
|
}
|
|
|
|
int cx = x0, cy = y0;
|
|
|
|
int inc = 1;
|
|
|
|
if (dv < 0) {
|
|
dv = -dv;
|
|
inc = -1;
|
|
}
|
|
|
|
int g = 2 * dv - dh;
|
|
int dg1 = 2 * (dv - dh);
|
|
int dg2 = 2 * dv;
|
|
|
|
int segment = (dg2 - dg1) / 4;
|
|
|
|
while (cx < x1) {
|
|
|
|
if (g > 0) {
|
|
g += dg1;
|
|
cy += inc;
|
|
} else {
|
|
g += dg2;
|
|
}
|
|
|
|
int quartile = segment ? ((dg2 - g) / segment) : 0;
|
|
if (quartile < 0)
|
|
quartile = 0;
|
|
if (quartile > 3)
|
|
quartile = 3;
|
|
if (inc > 0)
|
|
quartile = 4 - quartile;
|
|
/*
|
|
NOTATION_DEBUG
|
|
<< "x = " << cx << ", y = " << cy
|
|
<< ", g = " << g << ", dg1 = " << dg1 << ", dg2 = " << dg2
|
|
<< ", seg = " << segment << ", q = " << quartile << endl;
|
|
*/
|
|
// I don't know enough about TQt to be sure of this, but I
|
|
// suspect this may be some of the most inefficient code ever
|
|
// written:
|
|
|
|
int off = 0;
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(selectedColours[quartile]);
|
|
} else {
|
|
m_p->painter().setPen(colours[quartile]);
|
|
}
|
|
|
|
m_p->drawPoint(cx, cy);
|
|
drawBeamsCount ++;
|
|
|
|
if (thickness > 1) {
|
|
if (m_selected) {
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
} else {
|
|
m_p->painter().setPen(TQt::black);
|
|
}
|
|
}
|
|
|
|
while (++off < thickness) {
|
|
m_p->drawPoint(cx, cy + off);
|
|
drawBeamsCount ++;
|
|
}
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(selectedColours[4 - quartile]);
|
|
} else {
|
|
m_p->painter().setPen(colours[4 - quartile]);
|
|
}
|
|
|
|
m_p->drawPoint(cx, cy + off);
|
|
drawBeamsCount ++;
|
|
|
|
++cx;
|
|
}
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawBeams(const TQPoint &s1,
|
|
const NotePixmapParameters ¶ms,
|
|
int beamCount)
|
|
{
|
|
clock_t startTime = clock();
|
|
|
|
// draw beams: first we draw all the beams common to both ends of
|
|
// the section, then we draw beams for those that appear at the
|
|
// end only
|
|
|
|
int startY = m_above + s1.y(), startX = m_left + s1.x();
|
|
int commonBeamCount = std::min(beamCount, params.m_nextBeamCount);
|
|
|
|
unsigned int thickness;
|
|
(void)m_font->getBeamThickness(thickness);
|
|
|
|
int width = params.m_width;
|
|
double grad = params.m_gradient;
|
|
bool smooth = m_font->isSmooth();
|
|
int spacing = getLineSpacing();
|
|
|
|
int sign = (params.m_stemGoesUp ? 1 : -1);
|
|
|
|
if (!params.m_stemGoesUp)
|
|
startY -= thickness;
|
|
|
|
if (!smooth)
|
|
startY -= sign;
|
|
else if (grad > -0.01 && grad < 0.01)
|
|
startY -= sign;
|
|
|
|
if (m_inPrinterMethod) {
|
|
startX += getStemThickness() / 2;
|
|
}
|
|
|
|
for (int j = 0; j < commonBeamCount; ++j) {
|
|
int y = sign * j * spacing;
|
|
drawShallowLine(startX, startY + y, startX + width,
|
|
startY + (int)(width*grad) + y,
|
|
thickness, smooth);
|
|
drawBeamsBeamCount ++;
|
|
}
|
|
|
|
int partWidth = width / 3;
|
|
if (partWidth < 2)
|
|
partWidth = 2;
|
|
else if (partWidth > m_noteBodyWidth)
|
|
partWidth = m_noteBodyWidth;
|
|
|
|
if (params.m_thisPartialBeams) {
|
|
for (int j = commonBeamCount; j < beamCount; ++j) {
|
|
int y = sign * j * spacing;
|
|
drawShallowLine(startX, startY + y, startX + partWidth,
|
|
startY + (int)(partWidth*grad) + y,
|
|
thickness, smooth);
|
|
drawBeamsBeamCount ++;
|
|
}
|
|
}
|
|
|
|
if (params.m_nextPartialBeams) {
|
|
startX += width - partWidth;
|
|
startY += (int)((width - partWidth) * grad);
|
|
|
|
for (int j = commonBeamCount; j < params.m_nextBeamCount; ++j) {
|
|
int y = sign * j * spacing;
|
|
drawShallowLine(startX, startY + y, startX + partWidth,
|
|
startY + (int)(partWidth*grad) + y,
|
|
thickness, smooth);
|
|
drawBeamsBeamCount ++;
|
|
}
|
|
}
|
|
|
|
clock_t endTime = clock();
|
|
drawBeamsTime += (endTime - startTime);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawSlashes(const TQPoint &s0,
|
|
const NotePixmapParameters ¶ms,
|
|
int slashCount)
|
|
{
|
|
unsigned int thickness;
|
|
(void)m_font->getBeamThickness(thickness);
|
|
thickness = thickness * 3 / 4;
|
|
if (thickness < 1)
|
|
thickness = 1;
|
|
|
|
int gap = thickness - 1;
|
|
if (gap < 1)
|
|
gap = 1;
|
|
|
|
bool smooth = m_font->isSmooth();
|
|
|
|
int width = m_noteBodyWidth * 4 / 5;
|
|
int sign = (params.m_stemGoesUp ? -1 : 1);
|
|
|
|
int offset =
|
|
(slashCount == 1 ? m_noteBodyHeight * 2 :
|
|
slashCount == 2 ? m_noteBodyHeight * 3 / 2 :
|
|
m_noteBodyHeight);
|
|
int y = m_above + s0.y() + sign * (offset + thickness / 2);
|
|
|
|
for (int i = 0; i < slashCount; ++i) {
|
|
int yoff = width / 2;
|
|
drawShallowLine(m_left + s0.x() - width / 2, y + yoff / 2,
|
|
m_left + s0.x() + width / 2 + getStemThickness(), y - yoff / 2,
|
|
thickness, smooth);
|
|
y += sign * (thickness + gap);
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::makeRoomForTuplingLine(const NotePixmapParameters ¶ms)
|
|
{
|
|
int lineSpacing =
|
|
(int)(params.m_tuplingLineWidth * params.m_tuplingLineGradient);
|
|
int th = m_tupletCountFontMetrics.height();
|
|
|
|
if (params.m_tuplingLineY < 0) {
|
|
|
|
lineSpacing = -lineSpacing;
|
|
if (lineSpacing < 0)
|
|
lineSpacing = 0;
|
|
m_above = std::max(m_above, -params.m_tuplingLineY + th / 2);
|
|
m_above += lineSpacing + 1;
|
|
|
|
} else {
|
|
|
|
if (lineSpacing < 0)
|
|
lineSpacing = 0;
|
|
m_below = std::max(m_below, params.m_tuplingLineY + th / 2);
|
|
m_below += lineSpacing + 1;
|
|
}
|
|
|
|
m_right = std::max(m_right, params.m_tuplingLineWidth);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawTuplingLine(const NotePixmapParameters ¶ms)
|
|
{
|
|
int thickness = getStaffLineThickness() * 3 / 2;
|
|
int countSpace = thickness * 2;
|
|
|
|
TQString count;
|
|
count.setNum(params.m_tupletCount);
|
|
TQRect cr = m_tupletCountFontMetrics.boundingRect(count);
|
|
|
|
int tlw = params.m_tuplingLineWidth;
|
|
int indent = m_noteBodyWidth / 2;
|
|
|
|
if (tlw < (cr.width() + countSpace * 2 + m_noteBodyWidth * 2)) {
|
|
tlw += m_noteBodyWidth - 1;
|
|
indent = 0;
|
|
}
|
|
|
|
int w = (tlw - cr.width()) / 2 - countSpace;
|
|
|
|
int startX = m_left + indent;
|
|
int endX = startX + w;
|
|
|
|
int startY = params.m_tuplingLineY + m_above + getLineSpacing() / 2;
|
|
int endY = startY + (int)(params.m_tuplingLineGradient * w);
|
|
|
|
if (startY == endY)
|
|
++thickness;
|
|
|
|
int tickOffset = getLineSpacing() / 2;
|
|
if (params.m_tuplingLineY >= 0)
|
|
tickOffset = -tickOffset;
|
|
|
|
// NOTATION_DEBUG << "adjusted params.m_tuplingLineWidth = "
|
|
// << tlw
|
|
// << ", cr.width = " << cr.width()
|
|
// << ", tickOffset = " << tickOffset << endl;
|
|
// NOTATION_DEBUG << "line: (" << startX << "," << startY << ") -> ("
|
|
// << endX << "," << endY << ")" << endl;
|
|
|
|
bool smooth = m_font->isSmooth();
|
|
|
|
if (!params.m_tuplingLineFollowsBeam) {
|
|
m_p->drawLine(startX, startY, startX, startY + tickOffset);
|
|
drawShallowLine(startX, startY, endX, endY, thickness, smooth);
|
|
}
|
|
|
|
m_p->painter().setFont(m_tupletCountFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(m_tupletCountFont);
|
|
|
|
int textX = endX + countSpace;
|
|
int textY = endY + cr.height() / 2;
|
|
// NOTATION_DEBUG << "text: (" << textX << "," << textY << ")" << endl;
|
|
|
|
m_p->drawText(textX, textY, count);
|
|
|
|
startX += tlw - w;
|
|
endX = startX + w;
|
|
|
|
startY += (int)(params.m_tuplingLineGradient * (tlw - w));
|
|
endY = startY + (int)(params.m_tuplingLineGradient * w);
|
|
|
|
// NOTATION_DEBUG << "line: (" << startX << "," << startY << ") -> ("
|
|
// << endX << "," << endY << ")" << endl;
|
|
|
|
if (!params.m_tuplingLineFollowsBeam) {
|
|
drawShallowLine(startX, startY, endX, endY, thickness, smooth);
|
|
m_p->drawLine(endX, endY, endX, endY + tickOffset);
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawTie(bool above, int length, int shift)
|
|
{
|
|
#ifdef NASTY_OLD_FLAT_TIE_CODE
|
|
|
|
int tieThickness = getStaffLineThickness() * 2;
|
|
int tieCurve = m_font->getSize() * 2 / 3;
|
|
int height = tieCurve + tieThickness;
|
|
int x = m_left + m_noteBodyWidth;
|
|
int y = (above ? m_above - height - tieCurve / 2 :
|
|
m_above + m_noteBodyHeight + tieCurve / 2 + 1);
|
|
int i;
|
|
|
|
length -= m_noteBodyWidth;
|
|
if (length < tieCurve * 2)
|
|
length = tieCurve * 2;
|
|
if (length < m_noteBodyWidth * 3) {
|
|
length += m_noteBodyWidth - 2;
|
|
x -= m_noteBodyWidth / 2 - 1;
|
|
}
|
|
|
|
for (i = 0; i < tieThickness; ++i) {
|
|
|
|
if (above) {
|
|
|
|
m_p->drawArc
|
|
(x, y + i, tieCurve*2, tieCurve*2, 90*16, 70*16);
|
|
|
|
m_p->drawLine
|
|
(x + tieCurve, y + i, x + length - tieCurve - 2, y + i);
|
|
|
|
m_p->drawArc
|
|
(x + length - 2*tieCurve - 1, y + i,
|
|
tieCurve*2, tieCurve*2, 20*16, 70*16);
|
|
|
|
} else {
|
|
|
|
m_p->drawArc
|
|
(x, y + i - tieCurve, tieCurve*2, tieCurve*2, 200*16, 70*16);
|
|
|
|
m_p->drawLine
|
|
(x + tieCurve, y + height - i - 1,
|
|
x + length - tieCurve - 2, y + height - i - 1);
|
|
|
|
m_p->drawArc
|
|
(x + length - 2*tieCurve - 1, y + i - tieCurve,
|
|
tieCurve*2, tieCurve*2, 270*16, 70*16);
|
|
}
|
|
}
|
|
#else
|
|
|
|
int origLength = length;
|
|
|
|
int x = m_left + m_noteBodyWidth + m_noteBodyWidth / 4 + shift;
|
|
length = origLength - m_noteBodyWidth - m_noteBodyWidth / 3 - shift;
|
|
|
|
// if the length is short, move the tie a bit closer to both notes
|
|
if (length < m_noteBodyWidth*2) {
|
|
x = m_left + m_noteBodyWidth + shift;
|
|
length = origLength - m_noteBodyWidth - shift;
|
|
}
|
|
|
|
if (length < m_noteBodyWidth) {
|
|
length = m_noteBodyWidth;
|
|
}
|
|
|
|
// We can't request a smooth slur here, because that always involves
|
|
// creating a new pixmap
|
|
|
|
TQPoint hotspot;
|
|
drawSlurAux(length, 0, above, false, true, false, hotspot,
|
|
&m_p->painter(),
|
|
x,
|
|
above ? m_above : m_above + m_noteBodyHeight);
|
|
// above ? m_above - m_noteBodyHeight/2 :
|
|
// m_above + m_noteBodyHeight + m_noteBodyHeight/2);
|
|
|
|
#endif
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeRestPixmap(const NotePixmapParameters ¶ms)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeRestPixmap");
|
|
|
|
CharName charName(m_style->getRestCharName(params.m_noteType,
|
|
params.m_restOutsideStave));
|
|
// Check whether the font has the glyph for this charName;
|
|
// if not, substitute a rest-on-stave glyph for a rest-outside-stave glyph,
|
|
// and vice-versa.
|
|
NoteCharacter character;
|
|
if (!getCharacter(charName, character, PlainColour, false))
|
|
charName = m_style->getRestCharName(params.m_noteType,
|
|
!params.m_restOutsideStave);
|
|
|
|
bool encache = false;
|
|
|
|
if (params.m_tupletCount == 0 && !m_selected && !m_shaded &&
|
|
!params.m_restOutsideStave) {
|
|
|
|
if (params.m_dots == 0) {
|
|
return getCharacter(charName, PlainColour, false).getCanvasPixmap();
|
|
} else {
|
|
NotePixmapCache::iterator ci(m_dottedRestCache->find(charName));
|
|
if (ci != m_dottedRestCache->end())
|
|
return new TQCanvasPixmap
|
|
(*ci->second, TQPoint(ci->second->offsetX(),
|
|
ci->second->offsetY()));
|
|
else
|
|
encache = true;
|
|
}
|
|
}
|
|
|
|
TQPoint hotspot(m_font->getHotspot(charName));
|
|
drawRestAux(params, hotspot, 0, 0, 0);
|
|
|
|
TQCanvasPixmap* canvasMap = makeCanvasPixmap(hotspot);
|
|
if (encache) {
|
|
m_dottedRestCache->insert(std::pair<CharName, TQCanvasPixmap*>
|
|
(charName, new TQCanvasPixmap
|
|
(*canvasMap, hotspot)));
|
|
}
|
|
return canvasMap;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawRest(const NotePixmapParameters ¶ms,
|
|
TQPainter &painter, int x, int y)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::drawRest");
|
|
m_inPrinterMethod = true;
|
|
TQPoint hotspot; // unused
|
|
drawRestAux(params, hotspot, &painter, x, y);
|
|
m_inPrinterMethod = false;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawRestAux(const NotePixmapParameters ¶ms,
|
|
TQPoint &hotspot, TQPainter *painter, int x, int y)
|
|
{
|
|
CharName charName(m_style->getRestCharName(params.m_noteType,
|
|
params.m_restOutsideStave));
|
|
NoteCharacter character = getCharacter(charName,
|
|
params.m_quantized ? QuantizedColour :
|
|
PlainColour,
|
|
false);
|
|
|
|
NoteCharacter dot = getCharacter(NoteCharacterNames::DOT, PlainColour, false);
|
|
|
|
int dotWidth = dot.getWidth();
|
|
if (dotWidth < getNoteBodyWidth() / 2)
|
|
dotWidth = getNoteBodyWidth() / 2;
|
|
|
|
m_above = m_left = 0;
|
|
m_below = dot.getHeight() / 2; // for dotted shallow rests like semibreve
|
|
m_right = dotWidth / 2 + dotWidth * params.m_dots;
|
|
m_noteBodyWidth = character.getWidth();
|
|
m_noteBodyHeight = character.getHeight();
|
|
|
|
if (params.m_tupletCount)
|
|
makeRoomForTuplingLine(params);
|
|
|
|
// we'll adjust this for tupling line after drawing rest character:
|
|
hotspot = m_font->getHotspot(charName);
|
|
|
|
if (params.m_restOutsideStave &&
|
|
(charName == NoteCharacterNames::MULTI_REST ||
|
|
charName == NoteCharacterNames::MULTI_REST_ON_STAFF)) {
|
|
makeRoomForLegerLines(params);
|
|
}
|
|
if (painter) {
|
|
painter->save();
|
|
m_p->beginExternal(painter);
|
|
painter->translate(x - m_left, y - m_above - hotspot.y());
|
|
} else {
|
|
createPixmapAndMask(m_noteBodyWidth + m_left + m_right,
|
|
m_noteBodyHeight + m_above + m_below);
|
|
}
|
|
|
|
m_p->drawNoteCharacter(m_left, m_above, character);
|
|
|
|
if (params.m_tupletCount)
|
|
drawTuplingLine(params);
|
|
|
|
hotspot.setX(m_left);
|
|
hotspot.setY(m_above + hotspot.y());
|
|
|
|
int restY = hotspot.y() - dot.getHeight() - getStaffLineThickness();
|
|
if (params.m_noteType == Note::Semibreve ||
|
|
params.m_noteType == Note::Breve) {
|
|
restY += getLineSpacing();
|
|
}
|
|
|
|
for (int i = 0; i < params.m_dots; ++i) {
|
|
int x = m_left + m_noteBodyWidth + i * dotWidth + dotWidth / 2;
|
|
m_p->drawNoteCharacter(x, restY, dot);
|
|
}
|
|
|
|
if (params.m_restOutsideStave &&
|
|
(charName == NoteCharacterNames::MULTI_REST ||
|
|
charName == NoteCharacterNames::MULTI_REST_ON_STAFF)) {
|
|
drawLegerLines(params);
|
|
}
|
|
|
|
if (painter) {
|
|
painter->restore();
|
|
}
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeClefPixmap(const Clef &clef)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeClefPixmap");
|
|
NoteCharacter plain = getCharacter(m_style->getClefCharName(clef),
|
|
PlainColour, false);
|
|
|
|
int oct = clef.getOctaveOffset();
|
|
if (oct == 0)
|
|
return plain.getCanvasPixmap();
|
|
|
|
// fix #1522784 and use 15 rather than 16 for double octave offset
|
|
int adjustedOctave = (8 * (oct < 0 ? -oct : oct));
|
|
if (adjustedOctave > 8)
|
|
adjustedOctave--;
|
|
else if (adjustedOctave < 8)
|
|
adjustedOctave++;
|
|
|
|
TQString text = TQString("%1").arg(adjustedOctave);
|
|
TQRect rect = m_clefOttavaFontMetrics.boundingRect(text);
|
|
|
|
createPixmapAndMask(plain.getWidth(),
|
|
plain.getHeight() + rect.height());
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
}
|
|
|
|
m_p->drawNoteCharacter(0, oct < 0 ? 0 : rect.height(), plain);
|
|
|
|
m_p->painter().setFont(m_clefOttavaFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(m_clefOttavaFont);
|
|
|
|
m_p->drawText(plain.getWidth() / 2 - rect.width() / 2,
|
|
oct < 0 ? plain.getHeight() + rect.height() - 1 :
|
|
rect.height(), text);
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
TQPoint hotspot(plain.getHotspot());
|
|
if (oct > 0) hotspot.setY(hotspot.y() + rect.height());
|
|
return makeCanvasPixmap(hotspot, true);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makePedalDownPixmap()
|
|
{
|
|
return getCharacter(NoteCharacterNames::PEDAL_MARK, PlainColour, false)
|
|
.getCanvasPixmap();
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makePedalUpPixmap()
|
|
{
|
|
return getCharacter(NoteCharacterNames::PEDAL_UP_MARK, PlainColour, false)
|
|
.getCanvasPixmap();
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeUnknownPixmap()
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeUnknownPixmap");
|
|
return getCharacter(NoteCharacterNames::UNKNOWN, PlainColour, false)
|
|
.getCanvasPixmap();
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeToolbarPixmap(const char *name, bool menuSize)
|
|
{
|
|
TQString pixmapDir = TDEGlobal::dirs()->findResource("appdata", "pixmaps/");
|
|
TQString fileBase = pixmapDir + "/toolbar/";
|
|
if (menuSize) fileBase += "menu-";
|
|
fileBase += name;
|
|
if (TQFile(fileBase + ".png").exists()) {
|
|
return new TQCanvasPixmap(fileBase + ".png");
|
|
} else if (TQFile(fileBase + ".xpm").exists()) {
|
|
return new TQCanvasPixmap(fileBase + ".xpm");
|
|
} else if (menuSize) {
|
|
return makeToolbarPixmap(name, false);
|
|
} else {
|
|
// this will fail, but we don't want to return a null pointer
|
|
return new TQCanvasPixmap(fileBase + ".png");
|
|
}
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeNoteMenuPixmap(timeT duration,
|
|
timeT &errorReturn)
|
|
{
|
|
Note nearestNote = Note::getNearestNote(duration);
|
|
bool triplet = false;
|
|
errorReturn = 0;
|
|
|
|
if (nearestNote.getDuration() != duration) {
|
|
Note tripletNote = Note::getNearestNote(duration * 3 / 2);
|
|
if (tripletNote.getDuration() == duration * 3 / 2) {
|
|
nearestNote = tripletNote;
|
|
triplet = true;
|
|
} else {
|
|
errorReturn = duration - nearestNote.getDuration();
|
|
}
|
|
}
|
|
|
|
TQString noteName = NotationStrings::getReferenceName(nearestNote);
|
|
if (triplet)
|
|
noteName = "3-" + noteName;
|
|
noteName = "menu-" + noteName;
|
|
return makeToolbarPixmap(noteName.ascii());
|
|
}
|
|
|
|
TQCanvasPixmap *
|
|
NotePixmapFactory::makeMarkMenuPixmap(Mark mark)
|
|
{
|
|
if (mark == Marks::Sforzando ||
|
|
mark == Marks::Rinforzando) {
|
|
return makeToolbarPixmap(mark.c_str());
|
|
} else {
|
|
NoteFont *font = 0;
|
|
try {
|
|
font = NoteFontFactory::getFont
|
|
(NoteFontFactory::getDefaultFontName(), 6);
|
|
} catch (Exception) {
|
|
font = NoteFontFactory::getFont
|
|
(NoteFontFactory::getDefaultFontName(),
|
|
NoteFontFactory::getDefaultSize(NoteFontFactory::getDefaultFontName()));
|
|
}
|
|
NoteCharacter character = font->getCharacter
|
|
(NoteStyleFactory::getStyle(NoteStyleFactory::DefaultStyle)->
|
|
getMarkCharName(mark));
|
|
return character.getCanvasPixmap();
|
|
}
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeKeyPixmap(const Key &key,
|
|
const Clef &clef,
|
|
Key previousKey)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeKeyPixmap");
|
|
|
|
std::vector<int> ah0 = previousKey.getAccidentalHeights(clef);
|
|
std::vector<int> ah1 = key.getAccidentalHeights(clef);
|
|
|
|
int cancelCount = 0;
|
|
if (key.isSharp() != previousKey.isSharp())
|
|
cancelCount = ah0.size();
|
|
else if (ah1.size() < ah0.size())
|
|
cancelCount = ah0.size() - ah1.size();
|
|
|
|
CharName keyCharName;
|
|
if (key.isSharp())
|
|
keyCharName = NoteCharacterNames::SHARP;
|
|
else
|
|
keyCharName = NoteCharacterNames::FLAT;
|
|
|
|
NoteCharacter keyCharacter;
|
|
NoteCharacter cancelCharacter;
|
|
|
|
keyCharacter = getCharacter(keyCharName, PlainColour, false);
|
|
if (cancelCount > 0) {
|
|
cancelCharacter = getCharacter(NoteCharacterNames::NATURAL, PlainColour, false);
|
|
}
|
|
|
|
int x = 0;
|
|
int lw = getLineSpacing();
|
|
int keyDelta = keyCharacter.getWidth() - keyCharacter.getHotspot().x();
|
|
|
|
int cancelDelta = 0;
|
|
int between = 0;
|
|
if (cancelCount > 0) {
|
|
cancelDelta = cancelCharacter.getWidth() + cancelCharacter.getWidth() / 3;
|
|
between = cancelCharacter.getWidth();
|
|
}
|
|
|
|
createPixmapAndMask(keyDelta * ah1.size() + cancelDelta * cancelCount + between +
|
|
keyCharacter.getWidth() / 4, lw * 8 + 1);
|
|
|
|
if (key.isSharp() != previousKey.isSharp()) {
|
|
|
|
// cancellation first
|
|
|
|
for (int i = 0; i < cancelCount; ++i) {
|
|
|
|
int h = ah0[ah0.size() - cancelCount + i];
|
|
int y = (lw * 2) + ((8 - h) * lw) / 2 - cancelCharacter.getHotspot().y();
|
|
|
|
m_p->drawNoteCharacter(x, y, cancelCharacter);
|
|
|
|
x += cancelDelta;
|
|
}
|
|
|
|
if (cancelCount > 0) {
|
|
x += between;
|
|
}
|
|
}
|
|
|
|
for (unsigned int i = 0; i < ah1.size(); ++i) {
|
|
|
|
int h = ah1[i];
|
|
int y = (lw * 2) + ((8 - h) * lw) / 2 - keyCharacter.getHotspot().y();
|
|
|
|
m_p->drawNoteCharacter(x, y, keyCharacter);
|
|
|
|
x += keyDelta;
|
|
}
|
|
|
|
if (key.isSharp() == previousKey.isSharp()) {
|
|
|
|
// cancellation afterwards
|
|
|
|
if (cancelCount > 0) {
|
|
x += between;
|
|
}
|
|
|
|
for (int i = 0; i < cancelCount; ++i) {
|
|
|
|
int h = ah0[ah0.size() - cancelCount + i];
|
|
int y = (lw * 2) + ((8 - h) * lw) / 2 - cancelCharacter.getHotspot().y();
|
|
|
|
m_p->drawNoteCharacter(x, y, cancelCharacter);
|
|
|
|
x += cancelDelta;
|
|
}
|
|
}
|
|
|
|
return makeCanvasPixmap(m_pointZero);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeClefDisplayPixmap(const Clef &clef)
|
|
{
|
|
TQCanvasPixmap* clefPixmap = makeClefPixmap(clef);
|
|
|
|
int lw = getLineSpacing();
|
|
int width = clefPixmap->width() + 6 * getNoteBodyWidth();
|
|
|
|
createPixmapAndMask(width, lw * 10 + 1);
|
|
|
|
int h = clef.getAxisHeight();
|
|
int y = (lw * 3) + ((8 - h) * lw) / 2;
|
|
int x = 3 * getNoteBodyWidth();
|
|
m_p->drawPixmap(x, y - clefPixmap->offsetY(), *clefPixmap);
|
|
|
|
for (h = 0; h <= 8; h += 2) {
|
|
y = (lw * 3) + ((8 - h) * lw) / 2;
|
|
m_p->drawLine(x / 2, y, m_generatedWidth - x / 2 - 1, y);
|
|
}
|
|
|
|
delete clefPixmap;
|
|
|
|
return makeCanvasPixmap(m_pointZero);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeKeyDisplayPixmap(const Key &key, const Clef &clef)
|
|
{
|
|
std::vector<int> ah = key.getAccidentalHeights(clef);
|
|
|
|
CharName charName = (key.isSharp() ?
|
|
NoteCharacterNames::SHARP :
|
|
NoteCharacterNames::FLAT);
|
|
|
|
TQCanvasPixmap* clefPixmap = makeClefPixmap(clef);
|
|
TQPixmap accidentalPixmap(*m_font->getCharacter(charName).getPixmap());
|
|
TQPoint hotspot(m_font->getHotspot(charName));
|
|
|
|
int lw = getLineSpacing();
|
|
int delta = accidentalPixmap.width() - hotspot.x();
|
|
int maxDelta = getAccidentalWidth(Sharp);
|
|
int width = clefPixmap->width() + 5 * maxDelta + 7 * maxDelta;
|
|
int x = clefPixmap->width() + 5 * maxDelta / 2;
|
|
|
|
createPixmapAndMask(width, lw * 10 + 1);
|
|
|
|
int h = clef.getAxisHeight();
|
|
int y = (lw * 3) + ((8 - h) * lw) / 2;
|
|
m_p->drawPixmap(2 * maxDelta, y - clefPixmap->offsetY(), *clefPixmap);
|
|
|
|
for (unsigned int i = 0; i < ah.size(); ++i) {
|
|
|
|
h = ah[i];
|
|
y = (lw * 3) + ((8 - h) * lw) / 2 - hotspot.y();
|
|
|
|
m_p->drawPixmap(x, y, accidentalPixmap);
|
|
|
|
x += delta;
|
|
}
|
|
|
|
for (h = 0; h <= 8; h += 2) {
|
|
y = (lw * 3) + ((8 - h) * lw) / 2;
|
|
m_p->drawLine(maxDelta, y, m_generatedWidth - 2*maxDelta - 1, y);
|
|
}
|
|
|
|
delete clefPixmap;
|
|
return makeCanvasPixmap(m_pointZero);
|
|
}
|
|
|
|
int
|
|
NotePixmapFactory::getClefAndKeyWidth(const Key &key, const Clef &clef)
|
|
{
|
|
std::vector<int> ah = key.getAccidentalHeights(clef);
|
|
Accidental accidental = key.isSharp() ? Sharp : Flat;
|
|
NoteCharacter plain = getCharacter(m_style->getClefCharName(clef),
|
|
PlainColour, false);
|
|
|
|
int clefWidth = plain.getWidth();
|
|
int accWidth = getAccidentalWidth(accidental);
|
|
int maxDelta = getAccidentalWidth(Sharp);
|
|
|
|
int width = clefWidth + 2 * maxDelta + ah.size() * accWidth;
|
|
|
|
return width;
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeTrackHeaderPixmap(
|
|
int width, int height, TrackHeader *header)
|
|
{
|
|
|
|
height -= 4; // Make room to the label frame :
|
|
// 4 = 2 * (margin + lineWidth)
|
|
|
|
createPixmapAndMask(width, height);
|
|
|
|
int lw = getLineSpacing();
|
|
int h;
|
|
TQColor colour;
|
|
int maxDelta = getAccidentalWidth(Sharp);
|
|
|
|
// Staff Y position inside the whole header
|
|
int offset = (height - 10 * lw -1) / 2;
|
|
|
|
// Draw staff lines
|
|
m_p->painter().setPen(TQPen(TQt::black, getStaffLineThickness()));
|
|
for (h = 0; h <= 8; h += 2) {
|
|
int y = (lw * 3) + ((8 - h) * lw) / 2;
|
|
m_p->drawLine(maxDelta/2, y + offset, m_generatedWidth - maxDelta/2, y + offset);
|
|
}
|
|
|
|
if (header->isAClefToDraw()) {
|
|
const Clef &clef = header->getClef();
|
|
// TODO : use colours from GUIPalette
|
|
colour = header->isClefInconsistent() ? TQt::red : TQt::black;
|
|
|
|
int hue, sat, val;
|
|
colour.getHsv(&hue, &sat, &val);
|
|
NoteCharacter clefChar = m_font->getCharacterColoured
|
|
(m_style->getClefCharName(clef),
|
|
hue, val, NoteFont::Screen, false);
|
|
|
|
// Draw clef
|
|
h = clef.getAxisHeight();
|
|
int y = (lw * 3) + ((8 - h) * lw) / 2;
|
|
m_p->drawNoteCharacter(maxDelta,
|
|
y - clefChar.getHotspot().y() + offset, clefChar);
|
|
|
|
// If necessary, write 8 or 15 above or under the clef
|
|
int oct = clef.getOctaveOffset();
|
|
if (oct != 0) {
|
|
|
|
int adjustedOctave = (8 * (oct < 0 ? -oct : oct));
|
|
if (adjustedOctave > 8)
|
|
adjustedOctave--;
|
|
else if (adjustedOctave < 8)
|
|
adjustedOctave++;
|
|
|
|
TQString text = TQString("%1").arg(adjustedOctave);
|
|
TQRect rect = m_clefOttavaFontMetrics.boundingRect(text);
|
|
|
|
m_p->painter().setPen(colour);
|
|
|
|
m_p->painter().setFont(m_clefOttavaFont);
|
|
// m_p->maskPainter().setFont(m_clefOttavaFont);
|
|
int xpos = maxDelta + clefChar.getWidth() / 2 - rect.width() / 2;
|
|
int ypos = y - clefChar.getHotspot().y() + offset
|
|
+ (oct < 0 ? clefChar.getHeight() + rect.height() - 1 : - rect.height() / 3);
|
|
m_p->drawText(xpos, ypos, text);
|
|
}
|
|
|
|
// TODO : use colours from GUIPalette
|
|
colour = header->isKeyInconsistent() ? TQt::red : TQt::black;
|
|
|
|
|
|
// Draw the key signature if any
|
|
|
|
const Key &key = header->getKey();
|
|
std::vector<int> ah = key.getAccidentalHeights(clef);
|
|
|
|
CharName charName = key.isSharp() ?
|
|
NoteCharacterNames::SHARP :
|
|
NoteCharacterNames::FLAT;
|
|
|
|
colour.getHsv(&hue, &sat, &val);
|
|
NoteCharacter accident = m_font->getCharacterColoured(charName,
|
|
hue, val, NoteFont::Screen, false);
|
|
|
|
TQPoint hotspot(m_font->getHotspot(charName));
|
|
int delta = accident.getWidth() - hotspot.x();
|
|
|
|
int x = clefChar.getWidth() + maxDelta;
|
|
for (unsigned int i = 0; i < ah.size(); ++i) {
|
|
h = ah[i];
|
|
y = (lw * 3) + ((8 - h) * lw) / 2 - hotspot.y() + offset;
|
|
m_p->drawNoteCharacter(x, y, accident);
|
|
|
|
x += delta;
|
|
}
|
|
|
|
}
|
|
|
|
m_p->painter().setFont(m_trackHeaderFont);
|
|
// m_p->maskPainter().setFont(m_trackHeaderFont);
|
|
|
|
TQString text;
|
|
TQString textLine;
|
|
|
|
int charHeight = m_trackHeaderFontMetrics.height();
|
|
int charWidth = m_trackHeaderFontMetrics.maxWidth();
|
|
|
|
const TQString transposeText = header->getTransposeText();
|
|
TQRect bounds = m_trackHeaderBoldFontMetrics.boundingRect(transposeText);
|
|
int transposeWidth = bounds.width();
|
|
|
|
|
|
// Write upper text (track name and track label)
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
text = header->getUpperText();
|
|
int numberOfTextLines = header->getNumberOfTextLines();
|
|
|
|
for (int l=1; l<=numberOfTextLines; l++) {
|
|
int upperTextY = charHeight + (l - 1) * getTrackHeaderTextLineSpacing();
|
|
if (l == numberOfTextLines) {
|
|
int transposeSpace = transposeWidth ? transposeWidth + charWidth / 4 : 0;
|
|
textLine = getOneLine(text, width - transposeSpace - charWidth / 2);
|
|
if (!text.isEmpty()) {
|
|
// String too long : cut it and replace last character by dots
|
|
int len = textLine.length();
|
|
if (len > 1) textLine.replace(len - 1, 1, i18n("..."));
|
|
}
|
|
} else {
|
|
textLine = getOneLine(text, width - charWidth / 2);
|
|
}
|
|
if (textLine.isEmpty()) break;
|
|
m_p->drawText(charWidth / 4, upperTextY, textLine);
|
|
}
|
|
|
|
|
|
// Write transposition text
|
|
|
|
// TODO : use colours from GUIPalette
|
|
colour = header->isTransposeInconsistent() ? TQt::red : TQt::black;
|
|
m_p->painter().setFont(m_trackHeaderBoldFont);
|
|
// m_p->maskPainter().setFont(m_trackHeaderBoldFont);
|
|
m_p->painter().setPen(colour);
|
|
|
|
m_p->drawText(width - transposeWidth - charWidth / 4,
|
|
charHeight
|
|
+ (numberOfTextLines - 1) * getTrackHeaderTextLineSpacing(),
|
|
transposeText);
|
|
|
|
|
|
// Write lower text (segment label)
|
|
|
|
// TODO : use colours from GUIPalette
|
|
colour = header->isLabelInconsistent() ? TQt::red : TQt::black;
|
|
m_p->painter().setFont(m_trackHeaderFont);
|
|
// m_p->maskPainter().setFont(m_trackHeaderFont);
|
|
|
|
m_p->painter().setPen(colour);
|
|
text = header->getLowerText();
|
|
|
|
for (int l=1; l<=numberOfTextLines; l++) {
|
|
int lowerTextY = m_generatedHeight - 4 // -4 : adjust
|
|
- (numberOfTextLines - l) * getTrackHeaderTextLineSpacing();
|
|
|
|
TQString textLine = getOneLine(text, width - charWidth / 2);
|
|
if (textLine.isEmpty()) break;
|
|
|
|
if ((l == numberOfTextLines) && !text.isEmpty()) {
|
|
// String too long : cut it and replace last character by dots
|
|
int len = textLine.length();
|
|
if (len > 1) textLine.replace(len - 1, 1, i18n("..."));
|
|
}
|
|
|
|
m_p->drawText(charWidth / 4, lowerTextY, textLine);
|
|
}
|
|
|
|
return makeCanvasPixmap(m_pointZero, true);
|
|
}
|
|
|
|
int
|
|
NotePixmapFactory::getTrackHeaderNTL(int height)
|
|
{
|
|
int clefMaxHeight = 12 * getLineSpacing();
|
|
int textLineHeight = getTrackHeaderTextLineSpacing();
|
|
int numberOfLines = ((height - clefMaxHeight) / 2) / textLineHeight;
|
|
return (numberOfLines > 0) ? numberOfLines : 1;
|
|
}
|
|
|
|
int
|
|
NotePixmapFactory::getTrackHeaderTextWidth(TQString str)
|
|
{
|
|
TQRect bounds = m_trackHeaderFontMetrics.boundingRect(str);
|
|
return bounds.width();
|
|
}
|
|
|
|
int
|
|
NotePixmapFactory::getTrackHeaderTextLineSpacing()
|
|
{
|
|
// 3/2 is some arbitrary line spacing
|
|
return m_trackHeaderFont.pixelSize() * 3 / 2;
|
|
}
|
|
|
|
TQString
|
|
NotePixmapFactory::getOneLine(TQString &text, int width)
|
|
{
|
|
TQString str;
|
|
int n;
|
|
|
|
// Immediately stop if string is empty or only contains white spaces ...
|
|
if (text.stripWhiteSpace().isEmpty()) return TQString("");
|
|
|
|
// ... or if width is too small.
|
|
if (width < m_trackHeaderFontMetrics.boundingRect(text.left(1)).width())
|
|
return TQString("");
|
|
|
|
// Get a first approx. string length
|
|
int totalLength = text.length();
|
|
n = totalLength * width / getTrackHeaderTextWidth(text) + 1;
|
|
if (n > totalLength) n = totalLength;
|
|
|
|
// Verify string size is less than width then correct it if necessary
|
|
while (((getTrackHeaderTextWidth(text.left(n))) > width) && n) n--;
|
|
|
|
if (n == 0) {
|
|
str = text;
|
|
text = TQString("");
|
|
} else {
|
|
str = text.left(n);
|
|
text.remove(0, n);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makePitchDisplayPixmap(int p, const Clef &clef,
|
|
bool useSharps)
|
|
{
|
|
NotationRules rules;
|
|
|
|
Pitch pitch(p);
|
|
Accidental accidental(pitch.getAccidental(useSharps));
|
|
NotePixmapParameters params(Note::Crotchet, 0, accidental);
|
|
|
|
TQCanvasPixmap* clefPixmap = makeClefPixmap(clef);
|
|
|
|
int lw = getLineSpacing();
|
|
int width = getClefWidth(Clef::Bass) + 10 * getNoteBodyWidth();
|
|
|
|
int h = pitch.getHeightOnStaff(clef, useSharps);
|
|
params.setStemGoesUp(rules.isStemUp(h));
|
|
|
|
if (h < -1)
|
|
params.setStemLength(lw * (4 - h) / 2);
|
|
else if (h > 9)
|
|
params.setStemLength(lw * (h - 4) / 2);
|
|
if (h > 8)
|
|
params.setLegerLines(h - 8);
|
|
else if (h < 0)
|
|
params.setLegerLines(h);
|
|
|
|
params.setIsOnLine(h % 2 == 0);
|
|
params.setSelected(m_selected);
|
|
|
|
TQCanvasPixmap *notePixmap = makeNotePixmap(params);
|
|
|
|
int pixmapHeight = lw * 12 + 1;
|
|
int yoffset = lw * 3;
|
|
if (h > 12) {
|
|
pixmapHeight += 6 * lw;
|
|
yoffset += 6 * lw;
|
|
} else if (h < -4) {
|
|
pixmapHeight += 6 * lw;
|
|
}
|
|
|
|
createPixmapAndMask(width, pixmapHeight);
|
|
|
|
int x =
|
|
getClefWidth(Clef::Bass) + 5 * getNoteBodyWidth() -
|
|
getAccidentalWidth(accidental);
|
|
int y = yoffset + ((8 - h) * lw) / 2 - notePixmap->offsetY();
|
|
m_p->drawPixmap(x, y, *notePixmap);
|
|
|
|
h = clef.getAxisHeight();
|
|
x = 3 * getNoteBodyWidth();
|
|
y = yoffset + ((8 - h) * lw) / 2;
|
|
m_p->drawPixmap(x, y - clefPixmap->offsetY(), *clefPixmap);
|
|
|
|
for (h = 0; h <= 8; h += 2) {
|
|
y = yoffset + ((8 - h) * lw) / 2;
|
|
m_p->drawLine(x / 2, y, m_generatedWidth - x / 2, y);
|
|
}
|
|
|
|
delete clefPixmap;
|
|
delete notePixmap;
|
|
|
|
return makeCanvasPixmap(m_pointZero);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makePitchDisplayPixmap(int p, const Clef &clef,
|
|
int octave, int step)
|
|
{
|
|
NotationRules rules;
|
|
|
|
Pitch pitch(step, octave, p, 0);
|
|
Accidental accidental = pitch.getDisplayAccidental(Key("C major"));
|
|
NotePixmapParameters params(Note::Crotchet, 0, accidental);
|
|
|
|
TQCanvasPixmap* clefPixmap = makeClefPixmap(clef);
|
|
|
|
int lw = getLineSpacing();
|
|
int width = getClefWidth(Clef::Bass) + 10 * getNoteBodyWidth();
|
|
|
|
int h = pitch.getHeightOnStaff
|
|
(clef,
|
|
Key("C major"));
|
|
params.setStemGoesUp(rules.isStemUp(h));
|
|
|
|
if (h < -1)
|
|
params.setStemLength(lw * (4 - h) / 2);
|
|
else if (h > 9)
|
|
params.setStemLength(lw * (h - 4) / 2);
|
|
if (h > 8)
|
|
params.setLegerLines(h - 8);
|
|
else if (h < 0)
|
|
params.setLegerLines(h);
|
|
|
|
params.setIsOnLine(h % 2 == 0);
|
|
params.setSelected(m_selected);
|
|
|
|
TQCanvasPixmap *notePixmap = makeNotePixmap(params);
|
|
|
|
int pixmapHeight = lw * 12 + 1;
|
|
int yoffset = lw * 3;
|
|
if (h > 12) {
|
|
pixmapHeight += 6 * lw;
|
|
yoffset += 6 * lw;
|
|
} else if (h < -4) {
|
|
pixmapHeight += 6 * lw;
|
|
}
|
|
|
|
createPixmapAndMask(width, pixmapHeight);
|
|
|
|
int x =
|
|
getClefWidth(Clef::Bass) + 5 * getNoteBodyWidth() -
|
|
getAccidentalWidth(accidental);
|
|
int y = yoffset + ((8 - h) * lw) / 2 - notePixmap->offsetY();
|
|
m_p->drawPixmap(x, y, *notePixmap);
|
|
|
|
h = clef.getAxisHeight();
|
|
x = 3 * getNoteBodyWidth();
|
|
y = yoffset + ((8 - h) * lw) / 2;
|
|
m_p->drawPixmap(x, y - clefPixmap->offsetY(), *clefPixmap);
|
|
|
|
for (h = 0; h <= 8; h += 2) {
|
|
y = yoffset + ((8 - h) * lw) / 2;
|
|
m_p->drawLine(x / 2, y, m_generatedWidth - x / 2, y);
|
|
}
|
|
|
|
delete clefPixmap;
|
|
delete notePixmap;
|
|
|
|
return makeCanvasPixmap(m_pointZero);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeHairpinPixmap(int length, bool isCrescendo)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeHairpinPixmap");
|
|
drawHairpinAux(length, isCrescendo, 0, 0, 0);
|
|
return makeCanvasPixmap(TQPoint(0, m_generatedHeight / 2));
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawHairpin(int length, bool isCrescendo,
|
|
TQPainter &painter, int x, int y)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::drawHairpin");
|
|
m_inPrinterMethod = true;
|
|
drawHairpinAux(length, isCrescendo, &painter, x, y);
|
|
m_inPrinterMethod = false;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawHairpinAux(int length, bool isCrescendo,
|
|
TQPainter *painter, int x, int y)
|
|
{
|
|
int nbh = getNoteBodyHeight();
|
|
int nbw = getNoteBodyWidth();
|
|
|
|
int height = (int)(((double)nbh / (double)(nbw * 40)) * length) + nbh;
|
|
int thickness = getStaffLineThickness() * 3 / 2;
|
|
|
|
// NOTATION_DEBUG << "NotePixmapFactory::makeHairpinPixmap: mapped length " << length << " to height " << height << " (nbh = " << nbh << ", nbw = " << nbw << ")" << endl;
|
|
|
|
if (height < nbh)
|
|
height = nbh;
|
|
if (height > nbh*2)
|
|
height = nbh * 2;
|
|
|
|
height += thickness - 1;
|
|
|
|
if (painter) {
|
|
painter->save();
|
|
m_p->beginExternal(painter);
|
|
painter->translate(x, y - height / 2);
|
|
} else {
|
|
createPixmapAndMask(length, height);
|
|
}
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
}
|
|
|
|
int left = 1, right = length - 2 * nbw / 3 + 1;
|
|
|
|
bool smooth = m_font->isSmooth();
|
|
|
|
if (isCrescendo) {
|
|
drawShallowLine(left, height / 2 - 1,
|
|
right, height - thickness - 1, thickness, smooth);
|
|
drawShallowLine(left, height / 2 - 1, right, 0, thickness, smooth);
|
|
} else {
|
|
drawShallowLine(left, 0, right, height / 2 - 1, thickness, smooth);
|
|
drawShallowLine(left, height - thickness - 1,
|
|
right, height / 2 - 1, thickness, smooth);
|
|
}
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
|
|
if (painter) {
|
|
painter->restore();
|
|
}
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeSlurPixmap(int length, int dy, bool above, bool phrasing)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeSlurPixmap");
|
|
|
|
//!!! could remove "height > 5" requirement if we did a better job of
|
|
// sizing so that any horizontal part was rescaled down to exactly
|
|
// 1 pixel wide instead of blurring
|
|
bool smooth = m_font->isSmooth() && getNoteBodyHeight() > 5;
|
|
TQPoint hotspot;
|
|
if (length < getNoteBodyWidth()*2)
|
|
length = getNoteBodyWidth() * 2;
|
|
drawSlurAux(length, dy, above, smooth, false, phrasing, hotspot, 0, 0, 0);
|
|
|
|
m_p->end();
|
|
|
|
if (smooth) {
|
|
|
|
TQImage i = m_generatedPixmap->convertToImage();
|
|
if (i.depth() == 1)
|
|
i = i.convertDepth(32);
|
|
i = i.smoothScale(i.width() / 2, i.height() / 2);
|
|
|
|
delete m_generatedPixmap;
|
|
delete m_generatedMask;
|
|
TQPixmap newPixmap(i);
|
|
TQCanvasPixmap *p = new TQCanvasPixmap(newPixmap, hotspot);
|
|
p->setMask(PixmapFunctions::generateMask(newPixmap,
|
|
TQt::white.rgb()));
|
|
return p;
|
|
|
|
} else {
|
|
|
|
TQCanvasPixmap *p = new TQCanvasPixmap(*m_generatedPixmap, hotspot);
|
|
p->setMask(PixmapFunctions::generateMask(*m_generatedPixmap,
|
|
TQt::white.rgb()));
|
|
delete m_generatedPixmap;
|
|
delete m_generatedMask;
|
|
return p;
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawSlur(int length, int dy, bool above, bool phrasing,
|
|
TQPainter &painter, int x, int y)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::drawSlur");
|
|
TQPoint hotspot;
|
|
m_inPrinterMethod = true;
|
|
if (length < getNoteBodyWidth()*2)
|
|
length = getNoteBodyWidth() * 2;
|
|
drawSlurAux(length, dy, above, false, false, phrasing, hotspot, &painter, x, y);
|
|
m_inPrinterMethod = false;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawSlurAux(int length, int dy, bool above,
|
|
bool smooth, bool flat, bool phrasing,
|
|
TQPoint &hotspot, TQPainter *painter, int x, int y)
|
|
{
|
|
TQWMatrix::TransformationMode mode = TQWMatrix::transformationMode();
|
|
TQWMatrix::setTransformationMode(TQWMatrix::Points);
|
|
|
|
int thickness = getStaffLineThickness() * 2;
|
|
if (phrasing)
|
|
thickness = thickness * 3 / 4;
|
|
int nbh = getNoteBodyHeight(), nbw = getNoteBodyWidth();
|
|
|
|
// Experiment with rotating the painter rather than the control points.
|
|
double theta = 0;
|
|
bool rotate = false;
|
|
if (dy != 0) {
|
|
// We have opposite (dy) and adjacent (length).
|
|
theta = atan(double(dy) / double(length)) * 180.0 / M_PI;
|
|
// NOTATION_DEBUG << "slur: dy is " << dy << ", length " << length << ", rotating through " << theta << endl;
|
|
rotate = true;
|
|
}
|
|
|
|
// draw normal slur for very slopey phrasing slur:
|
|
if (theta < -5 || theta > 5)
|
|
phrasing = false;
|
|
|
|
int y0 = 0, my = 0;
|
|
|
|
float noteLengths = float(length) / nbw;
|
|
if (noteLengths < 1)
|
|
noteLengths = 1;
|
|
|
|
my = int(0 - nbh * sqrt(noteLengths) / 2);
|
|
if (flat)
|
|
my = my * 2 / 3;
|
|
else if (phrasing)
|
|
my = my * 3 / 4;
|
|
if (!above)
|
|
my = -my;
|
|
|
|
bool havePixmap = false;
|
|
TQPoint topLeft, bottomRight;
|
|
|
|
if (smooth)
|
|
thickness += 2;
|
|
|
|
for (int i = 0; i < thickness; ++i) {
|
|
|
|
Spline::PointList pl;
|
|
|
|
if (!phrasing) {
|
|
pl.push_back(TQPoint(length / 6, my));
|
|
pl.push_back(TQPoint(length - length / 6, my));
|
|
} else {
|
|
pl.push_back(TQPoint(abs(my) / 4, my / 3));
|
|
pl.push_back(TQPoint(length / 6, my));
|
|
|
|
if (theta > 1) {
|
|
pl.push_back(TQPoint(length * 3 / 8, my * 3 / 2));
|
|
} else if (theta < -1) {
|
|
pl.push_back(TQPoint(length * 5 / 8, my * 3 / 2));
|
|
} else {
|
|
pl.push_back(TQPoint(length / 2, my * 4 / 3));
|
|
}
|
|
|
|
pl.push_back(TQPoint(length - length / 6, my));
|
|
pl.push_back(TQPoint(length - abs(my) / 4, my / 3));
|
|
}
|
|
|
|
Spline::PointList *polyPoints = Spline::calculate
|
|
(TQPoint(0, y0), TQPoint(length - 1, y0), pl, topLeft, bottomRight);
|
|
|
|
if (!havePixmap) {
|
|
int width = bottomRight.x() - topLeft.x();
|
|
int height = bottomRight.y() - topLeft.y() + thickness - 1 + abs(dy);
|
|
hotspot = TQPoint(0, -topLeft.y() + (dy < 0 ? -dy : 0));
|
|
|
|
// NOTATION_DEBUG << "slur: bottomRight (" << bottomRight.x() << "," << bottomRight.y() << "), topLeft (" << topLeft.x() << "," << topLeft.y() << "), width " << width << ", height " << height << ", hotspot (" << hotspot.x() << "," << hotspot.y() << "), dy " << dy << ", thickness " << thickness << endl;
|
|
|
|
if (painter) {
|
|
|
|
// This conditional is because we're also called with
|
|
// a painter arg from non-printer drawTie. It's a big
|
|
// hack.
|
|
|
|
if (m_inPrinterMethod) {
|
|
painter->save();
|
|
m_p->beginExternal(painter);
|
|
painter->translate(x, y);
|
|
if (rotate)
|
|
painter->rotate(theta);
|
|
} else {
|
|
m_p->painter().save();
|
|
m_p->maskPainter().save();
|
|
m_p->painter().translate(x, y);
|
|
m_p->maskPainter().translate(x, y);
|
|
if (rotate) {
|
|
m_p->painter().rotate(theta);
|
|
m_p->maskPainter().rotate(theta);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
createPixmapAndMask(smooth ? width*2 + 1 : width,
|
|
smooth ? height*2 + thickness*2 : height + thickness,
|
|
width, height);
|
|
|
|
TQWMatrix m;
|
|
if (smooth)
|
|
m.translate(2 * hotspot.x(), 2 * hotspot.y());
|
|
else
|
|
m.translate(hotspot.x(), hotspot.y());
|
|
m.rotate(theta);
|
|
m_p->painter().setWorldMatrix(m);
|
|
m_p->maskPainter().setWorldMatrix(m);
|
|
}
|
|
|
|
if (m_selected)
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
else if (m_shaded) {
|
|
m_p->painter().setPen(TQt::gray);
|
|
}
|
|
havePixmap = true;
|
|
}
|
|
/*
|
|
for (int j = 0; j < pl.size(); ++j) {
|
|
if (smooth) {
|
|
m_p->drawPoint(pl[j].x()*2, pl[j].y()*2);
|
|
} else {
|
|
m_p->drawPoint(pl[j].x(), pl[j].y());
|
|
}
|
|
}
|
|
*/
|
|
int ppc = polyPoints->size();
|
|
TQPointArray qp(ppc);
|
|
|
|
for (int j = 0; j < ppc; ++j) {
|
|
qp.setPoint(j, (*polyPoints)[j].x(), (*polyPoints)[j].y());
|
|
}
|
|
|
|
delete polyPoints;
|
|
|
|
if (!smooth || (i > 0 && i < thickness - 1)) {
|
|
if (smooth) {
|
|
for (int j = 0; j < ppc; ++j) {
|
|
qp.setPoint(j, qp.point(j).x()*2, qp.point(j).y()*2);
|
|
}
|
|
m_p->drawPolyline(qp);
|
|
for (int j = 0; j < ppc; ++j) {
|
|
qp.setPoint(j, qp.point(j).x(), qp.point(j).y() + 1);
|
|
}
|
|
m_p->drawPolyline(qp);
|
|
} else {
|
|
m_p->drawPolyline(qp);
|
|
}
|
|
}
|
|
|
|
if (above) {
|
|
++my;
|
|
if (i % 2)
|
|
++y0;
|
|
} else {
|
|
--my;
|
|
if (i % 2)
|
|
--y0;
|
|
}
|
|
}
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(TQt::black);
|
|
}
|
|
|
|
TQWMatrix::setTransformationMode(mode);
|
|
|
|
if (painter) {
|
|
painter->restore();
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().restore();
|
|
}
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeOttavaPixmap(int length, int octavesUp)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeOttavaPixmap");
|
|
m_inPrinterMethod = false;
|
|
drawOttavaAux(length, octavesUp, 0, 0, 0);
|
|
return makeCanvasPixmap(TQPoint(0, m_generatedHeight - 1));
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawOttava(int length, int octavesUp,
|
|
TQPainter &painter, int x, int y)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::drawOttava");
|
|
m_inPrinterMethod = true;
|
|
drawOttavaAux(length, octavesUp, &painter, x, y);
|
|
m_inPrinterMethod = false;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawOttavaAux(int length, int octavesUp,
|
|
TQPainter *painter, int x, int y)
|
|
{
|
|
int height = m_ottavaFontMetrics.height();
|
|
int backpedal = 0;
|
|
TQString label;
|
|
TQRect r;
|
|
|
|
if (octavesUp == 2 || octavesUp == -2) {
|
|
label = "15ma ";
|
|
backpedal = m_ottavaFontMetrics.width("15") / 2;
|
|
} else {
|
|
label = "8va ";
|
|
backpedal = m_ottavaFontMetrics.width("8") / 2;
|
|
}
|
|
|
|
int width = length + backpedal;
|
|
|
|
if (painter) {
|
|
painter->save();
|
|
m_p->beginExternal(painter);
|
|
painter->translate(x - backpedal, y - height);
|
|
} else {
|
|
NOTATION_DEBUG << "NotePixmapFactory::drawOttavaAux: making pixmap and mask " << width << "x" << height << endl;
|
|
createPixmapAndMask(width, height);
|
|
}
|
|
|
|
int thickness = getStemThickness();
|
|
TQPen pen(TQt::black, thickness, TQt::DotLine);
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
pen.setColor(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
} else if (m_shaded) {
|
|
m_p->painter().setPen(TQt::gray);
|
|
pen.setColor(TQt::gray);
|
|
}
|
|
|
|
m_p->painter().setFont(m_ottavaFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(m_ottavaFont);
|
|
|
|
m_p->drawText(0, m_ottavaFontMetrics.ascent(), label);
|
|
|
|
m_p->painter().setPen(pen);
|
|
// if (!m_inPrinterMethod) m_p->maskPainter().setPen(pen);
|
|
|
|
int x0 = m_ottavaFontMetrics.width(label) + thickness;
|
|
int x1 = width - thickness;
|
|
int y0 = m_ottavaFontMetrics.ascent() * 2 / 3 - thickness / 2;
|
|
int y1 = (octavesUp < 0 ? 0 : m_ottavaFontMetrics.ascent());
|
|
|
|
NOTATION_DEBUG << "NotePixmapFactory::drawOttavaAux: drawing " << x0 << "," << y0 << " to " << x1 << "," << y0 << ", thickness " << thickness << endl;
|
|
|
|
m_p->drawLine(x0, y0, x1, y0);
|
|
|
|
pen.setStyle(TQt::SolidLine);
|
|
m_p->painter().setPen(pen);
|
|
// if (!m_inPrinterMethod) m_p->maskPainter().setPen(pen);
|
|
|
|
NOTATION_DEBUG << "NotePixmapFactory::drawOttavaAux: drawing " << x1 << "," << y0 << " to " << x1 << "," << y1 << ", thickness " << thickness << endl;
|
|
|
|
m_p->drawLine(x1, y0, x1, y1);
|
|
|
|
m_p->painter().setPen(TQPen());
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setPen(TQPen());
|
|
|
|
if (painter) {
|
|
painter->restore();
|
|
}
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawBracket(int length, bool left, bool curly, int x, int y)
|
|
{
|
|
// curly mode not yet implemented
|
|
|
|
int thickness = getStemThickness() * 2;
|
|
|
|
int m1 = length / 6;
|
|
int m2 = length - length / 6 - 1;
|
|
|
|
int off0 = 0, moff = 0;
|
|
|
|
int nbh = getNoteBodyHeight(), nbw = getNoteBodyWidth();
|
|
float noteLengths = float(length) / nbw;
|
|
if (noteLengths < 1)
|
|
noteLengths = 1;
|
|
moff = int(nbh * sqrt(noteLengths) / 2);
|
|
moff = moff * 2 / 3;
|
|
|
|
if (left)
|
|
moff = -moff;
|
|
|
|
TQPoint topLeft, bottomRight;
|
|
|
|
for (int i = 0; i < thickness; ++i) {
|
|
|
|
Spline::PointList pl;
|
|
pl.push_back(TQPoint((int)moff, m1));
|
|
pl.push_back(TQPoint((int)moff, m2));
|
|
/*
|
|
NOTATION_DEBUG << "bracket spline controls: " << moff << "," << m1
|
|
<< ", " << moff << "," << m2 << "; end points "
|
|
<< off0 << ",0, " << off0 << "," << length-1
|
|
<< endl;
|
|
*/
|
|
Spline::PointList *polyPoints = Spline::calculate
|
|
(TQPoint(off0, 0), TQPoint(off0, length - 1), pl, topLeft, bottomRight);
|
|
|
|
int ppc = polyPoints->size();
|
|
TQPointArray qp(ppc);
|
|
/*
|
|
NOTATION_DEBUG << "bracket spline polypoints: " << endl;
|
|
for (int j = 0; j < ppc; ++j) {
|
|
NOTATION_DEBUG << (*polyPoints)[j].x() << "," << (*polyPoints)[j].y() << endl;
|
|
}
|
|
*/
|
|
|
|
for (int j = 0; j < ppc; ++j) {
|
|
qp.setPoint(j, x + (*polyPoints)[j].x(), y + (*polyPoints)[j].y());
|
|
}
|
|
|
|
delete polyPoints;
|
|
|
|
m_p->drawPolyline(qp);
|
|
|
|
if (!left) {
|
|
++moff;
|
|
if (i % 2)
|
|
++off0;
|
|
} else {
|
|
--moff;
|
|
if (i % 2)
|
|
--off0;
|
|
}
|
|
}
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeTimeSigPixmap(const TimeSignature& sig)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeTimeSigPixmap");
|
|
|
|
if (sig.isCommon()) {
|
|
|
|
NoteCharacter character;
|
|
|
|
CharName charName;
|
|
if (sig.getNumerator() == 2) {
|
|
charName = NoteCharacterNames::CUT_TIME;
|
|
} else {
|
|
charName = NoteCharacterNames::COMMON_TIME;
|
|
}
|
|
|
|
if (getCharacter(charName, character, PlainColour, false)) {
|
|
createPixmapAndMask(character.getWidth(), character.getHeight());
|
|
m_p->drawNoteCharacter(0, 0, character);
|
|
return makeCanvasPixmap(TQPoint(0, character.getHeight() / 2));
|
|
}
|
|
|
|
TQString c("c");
|
|
TQRect r = m_bigTimeSigFontMetrics.boundingRect(c);
|
|
|
|
int dy = getLineSpacing() / 4;
|
|
createPixmapAndMask(r.width(), r.height() + dy*2);
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
} else if (m_shaded) {
|
|
m_p->painter().setPen(TQt::gray);
|
|
}
|
|
|
|
m_p->painter().setFont(m_bigTimeSigFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(m_bigTimeSigFont);
|
|
|
|
m_p->drawText(0, r.height() + dy, c);
|
|
|
|
if (sig.getNumerator() == 2) { // cut common
|
|
|
|
int x = r.width() * 3 / 5 - getStemThickness();
|
|
|
|
for (int i = 0; i < getStemThickness() * 2; ++i, ++x) {
|
|
m_p->drawLine(x, 0, x, r.height() + dy*2 - 1);
|
|
}
|
|
}
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
return makeCanvasPixmap(TQPoint(0, r.height() / 2 + dy));
|
|
|
|
} else {
|
|
|
|
int numerator = sig.getNumerator(),
|
|
denominator = sig.getDenominator();
|
|
|
|
TQString numS, denomS;
|
|
|
|
numS.setNum(numerator);
|
|
denomS.setNum(denominator);
|
|
|
|
NoteCharacter character;
|
|
if (getCharacter(m_style->getTimeSignatureDigitName(0), character,
|
|
PlainColour, false)) {
|
|
|
|
// if the 0 digit exists, we assume 1-9 also all exist
|
|
// and all have the same width
|
|
|
|
int numW = character.getWidth() * numS.length();
|
|
int denomW = character.getWidth() * denomS.length();
|
|
|
|
int width = std::max(numW, denomW);
|
|
int height = getLineSpacing() * 4 - getStaffLineThickness();
|
|
|
|
createPixmapAndMask(width, height);
|
|
|
|
for (unsigned int i = 0; i < numS.length(); ++i) {
|
|
int x = width - (width - numW) / 2 - (i + 1) * character.getWidth();
|
|
int y = height / 4 - (character.getHeight() / 2);
|
|
NoteCharacter charCharacter = getCharacter
|
|
(m_style->getTimeSignatureDigitName(numerator % 10),
|
|
PlainColour, false);
|
|
m_p->drawNoteCharacter(x, y, charCharacter);
|
|
numerator /= 10;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < denomS.length(); ++i) {
|
|
int x = width - (width - denomW) / 2 - (i + 1) * character.getWidth();
|
|
int y = height - height / 4 - (character.getHeight() / 2);
|
|
NoteCharacter charCharacter = getCharacter
|
|
(m_style->getTimeSignatureDigitName(denominator % 10),
|
|
PlainColour, false);
|
|
m_p->drawNoteCharacter(x, y, charCharacter);
|
|
denominator /= 10;
|
|
}
|
|
|
|
return makeCanvasPixmap(TQPoint(0, height / 2));
|
|
}
|
|
|
|
TQRect numR = m_timeSigFontMetrics.boundingRect(numS);
|
|
TQRect denomR = m_timeSigFontMetrics.boundingRect(denomS);
|
|
int width = std::max(numR.width(), denomR.width()) + 2;
|
|
int x;
|
|
|
|
createPixmapAndMask(width, denomR.height() * 2 + getNoteBodyHeight());
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
} else if (m_shaded) {
|
|
m_p->painter().setPen(TQt::gray);
|
|
}
|
|
|
|
m_p->painter().setFont(m_timeSigFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(m_timeSigFont);
|
|
|
|
x = (width - numR.width()) / 2 - 1;
|
|
m_p->drawText(x, denomR.height(), numS);
|
|
|
|
x = (width - denomR.width()) / 2 - 1;
|
|
m_p->drawText(x, denomR.height() * 2 + (getNoteBodyHeight() / 2) - 1, denomS);
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
|
|
return makeCanvasPixmap(TQPoint(0, denomR.height() +
|
|
(getNoteBodyHeight() / 4) - 1),
|
|
true);
|
|
}
|
|
}
|
|
|
|
int NotePixmapFactory::getTimeSigWidth(const TimeSignature &sig) const
|
|
{
|
|
if (sig.isCommon()) {
|
|
|
|
TQRect r(m_bigTimeSigFontMetrics.boundingRect("c"));
|
|
return r.width() + 2;
|
|
|
|
} else {
|
|
|
|
int numerator = sig.getNumerator(),
|
|
denominator = sig.getDenominator();
|
|
|
|
TQString numS, denomS;
|
|
|
|
numS.setNum(numerator);
|
|
denomS.setNum(denominator);
|
|
|
|
TQRect numR = m_timeSigFontMetrics.boundingRect(numS);
|
|
TQRect denomR = m_timeSigFontMetrics.boundingRect(denomS);
|
|
int width = std::max(numR.width(), denomR.width()) + 2;
|
|
|
|
return width;
|
|
}
|
|
}
|
|
|
|
TQFont
|
|
NotePixmapFactory::getTextFont(const Text &text) const
|
|
{
|
|
std::string type(text.getTextType());
|
|
TextFontCache::iterator i = m_textFontCache.find(type.c_str());
|
|
if (i != m_textFontCache.end())
|
|
return i->second;
|
|
|
|
/*
|
|
* Text types:
|
|
*
|
|
* UnspecifiedType: Nothing known, use small roman
|
|
* StaffName: Large roman, to left of start of staff
|
|
* ChordName: Not normally shown in score, use small roman
|
|
* KeyName: Not normally shown in score, use small roman
|
|
* Lyric: Small roman, below staff and dynamic texts
|
|
* Chord: Small bold roman, above staff
|
|
* Dynamic: Small italic, below staff
|
|
* Direction: Large roman, above staff (by barline?)
|
|
* LocalDirection: Small bold italic, below staff (by barline?)
|
|
* Tempo: Large bold roman, above staff
|
|
* LocalTempo: Small bold roman, above staff
|
|
* Annotation: Very small sans-serif, in a yellow box
|
|
* LilyPondDirective: Very small sans-serif, in a green box
|
|
*/
|
|
|
|
int weight = TQFont::Normal;
|
|
bool italic = false;
|
|
bool large = false;
|
|
bool tiny = false;
|
|
bool serif = true;
|
|
|
|
if (type == Text::Tempo ||
|
|
type == Text::LocalTempo ||
|
|
type == Text::LocalDirection ||
|
|
type == Text::Chord) {
|
|
weight = TQFont::Bold;
|
|
}
|
|
|
|
if (type == Text::Dynamic ||
|
|
type == Text::LocalDirection) {
|
|
italic = true;
|
|
}
|
|
|
|
if (type == Text::StaffName ||
|
|
type == Text::Direction ||
|
|
type == Text::Tempo) {
|
|
large = true;
|
|
}
|
|
|
|
if (type == Text::Annotation ||
|
|
type == Text::LilyPondDirective) {
|
|
serif = false;
|
|
tiny = true;
|
|
}
|
|
|
|
TDEConfig* config = kapp->config();
|
|
|
|
TQFont textFont;
|
|
|
|
if (serif) {
|
|
textFont = TQFont(defaultSerifFontFamily);
|
|
textFont = config->readFontEntry("textfont", &textFont);
|
|
} else {
|
|
textFont = TQFont(defaultSansSerifFontFamily);
|
|
textFont = config->readFontEntry("sansfont", &textFont);
|
|
}
|
|
|
|
textFont.setStyleStrategy(TQFont::StyleStrategy(TQFont::PreferDefault |
|
|
TQFont::PreferMatch));
|
|
|
|
int size;
|
|
if (large)
|
|
size = (getLineSpacing() * 7) / 2;
|
|
else if (tiny)
|
|
size = (getLineSpacing() * 4) / 3;
|
|
else if (serif)
|
|
size = (getLineSpacing() * 2);
|
|
else
|
|
size = (getLineSpacing() * 3) / 2;
|
|
|
|
textFont.setPixelSize(size);
|
|
textFont.setStyleHint(serif ? TQFont::Serif : TQFont::SansSerif);
|
|
textFont.setWeight(weight);
|
|
textFont.setItalic(italic);
|
|
|
|
NOTATION_DEBUG << "NotePixmapFactory::getTextFont: requested size " << size
|
|
<< " for type " << type << endl;
|
|
|
|
NOTATION_DEBUG << "NotePixmapFactory::getTextFont: returning font '"
|
|
<< TQString(textFont.toString()).ascii() << "' for type " << type.c_str()
|
|
<< " text : " << text.getText().c_str() << endl;
|
|
|
|
m_textFontCache[type.c_str()] = textFont;
|
|
return textFont;
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeTextPixmap(const Text &text)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::makeTextPixmap");
|
|
|
|
std::string type(text.getTextType());
|
|
|
|
if (type == Text::Annotation ||
|
|
type == Text::LilyPondDirective) {
|
|
return makeAnnotationPixmap(text, (type == Text::LilyPondDirective));
|
|
}
|
|
|
|
drawTextAux(text, 0, 0, 0);
|
|
return makeCanvasPixmap(TQPoint(2, 2), true);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeGuitarChordPixmap(const Guitar::Fingering &fingering,
|
|
int x,
|
|
int y)
|
|
{
|
|
using namespace Guitar;
|
|
Profiler profiler("NotePixmapFactory::makeGuitarChordPixmap");
|
|
|
|
int guitarChordWidth = getLineSpacing() * 6;
|
|
int guitarChordHeight = getLineSpacing() * 6;
|
|
|
|
createPixmapAndMask(guitarChordWidth, guitarChordHeight);
|
|
|
|
if (m_selected) {
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
m_p->painter().setBrush(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
} else {
|
|
m_p->painter().setPen(TQt::black);
|
|
m_p->painter().setBrush(TQt::black);
|
|
}
|
|
|
|
Guitar::NoteSymbols ns(Guitar::Fingering::DEFAULT_NB_STRINGS, FingeringBox::DEFAULT_NB_DISPLAYED_FRETS);
|
|
Guitar::NoteSymbols::drawFingeringPixmap(fingering, ns, &(m_p->painter()));
|
|
|
|
return makeCanvasPixmap(TQPoint (x, y), true);
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawText(const Text &text,
|
|
TQPainter &painter, int x, int y)
|
|
{
|
|
Profiler profiler("NotePixmapFactory::drawText");
|
|
|
|
// NOTATION_DEBUG << "NotePixmapFactory::drawText() " << text.getText().c_str()
|
|
// << " - type : " << text.getTextType().c_str() << endl;
|
|
|
|
std::string type(text.getTextType());
|
|
|
|
if (type == Text::Annotation ||
|
|
type == Text::LilyPondDirective) {
|
|
TQCanvasPixmap *map = makeAnnotationPixmap(text, (type == Text::LilyPondDirective));
|
|
painter.drawPixmap(x, y, *map);
|
|
return ;
|
|
}
|
|
|
|
m_inPrinterMethod = true;
|
|
drawTextAux(text, &painter, x, y);
|
|
m_inPrinterMethod = false;
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::drawTextAux(const Text &text,
|
|
TQPainter *painter, int x, int y)
|
|
{
|
|
TQString s(strtoqstr(text.getText()));
|
|
TQFont textFont(getTextFont(text));
|
|
TQFontMetrics textMetrics(textFont);
|
|
|
|
int offset = 2;
|
|
int width = textMetrics.width(s) + 2 * offset;
|
|
int height = textMetrics.height() + 2 * offset;
|
|
|
|
if (painter) {
|
|
painter->save();
|
|
m_p->beginExternal(painter);
|
|
painter->translate(x - offset, y - offset);
|
|
} else {
|
|
createPixmapAndMask(width, height);
|
|
}
|
|
|
|
if (m_selected)
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
else if (m_shaded)
|
|
m_p->painter().setPen(TQt::gray);
|
|
|
|
m_p->painter().setFont(textFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(textFont);
|
|
|
|
m_p->drawText(offset, textMetrics.ascent() + offset, s);
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
|
|
if (painter) {
|
|
painter->restore();
|
|
}
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeAnnotationPixmap(const Text &text)
|
|
{
|
|
return makeAnnotationPixmap(text, false);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeAnnotationPixmap(const Text &text, const bool isLilyPondDirective)
|
|
{
|
|
TQString s(strtoqstr(text.getText()));
|
|
|
|
TQFont textFont(getTextFont(text));
|
|
TQFontMetrics textMetrics(textFont);
|
|
|
|
int annotationWidth = getLineSpacing() * 16;
|
|
int annotationHeight = getLineSpacing() * 6;
|
|
|
|
int topGap = getLineSpacing() / 4 + 1;
|
|
int bottomGap = getLineSpacing() / 3 + 1;
|
|
int sideGap = getLineSpacing() / 4 + 1;
|
|
|
|
TQRect r = textMetrics.boundingRect
|
|
(0, 0, annotationWidth, annotationHeight, TQt::WordBreak, s);
|
|
|
|
int pixmapWidth = r.width() + sideGap * 2;
|
|
int pixmapHeight = r.height() + topGap + bottomGap;
|
|
|
|
createPixmapAndMask(pixmapWidth, pixmapHeight);
|
|
|
|
if (m_selected)
|
|
m_p->painter().setPen(GUIPalette::getColour(GUIPalette::SelectedElement));
|
|
else if (m_shaded)
|
|
m_p->painter().setPen(TQt::gray);
|
|
|
|
m_p->painter().setFont(textFont);
|
|
if (!m_inPrinterMethod)
|
|
m_p->maskPainter().setFont(textFont);
|
|
|
|
if (isLilyPondDirective) {
|
|
m_p->painter().setBrush(GUIPalette::getColour(GUIPalette::TextLilyPondDirectiveBackground));
|
|
} else {
|
|
m_p->painter().setBrush(GUIPalette::getColour(GUIPalette::TextAnnotationBackground));
|
|
}
|
|
|
|
m_p->drawRect(0, 0, pixmapWidth, pixmapHeight);
|
|
|
|
m_p->painter().setBrush(TQt::black);
|
|
m_p->painter().drawText(TQRect(sideGap, topGap,
|
|
annotationWidth + sideGap,
|
|
pixmapHeight - bottomGap),
|
|
TQt::WordBreak, s);
|
|
|
|
/* unnecessary following the rectangle draw
|
|
m_pm.drawText(TQRect(sideGap, topGap,
|
|
annotationWidth + sideGap, annotationHeight + topGap),
|
|
TQt::WordBreak, s);
|
|
*/
|
|
|
|
return makeCanvasPixmap(TQPoint(0, 0));
|
|
}
|
|
|
|
void
|
|
NotePixmapFactory::createPixmapAndMask(int width, int height,
|
|
int maskWidth, int maskHeight)
|
|
{
|
|
if (maskWidth < 0)
|
|
maskWidth = width;
|
|
if (maskHeight < 0)
|
|
maskHeight = height;
|
|
|
|
m_generatedWidth = width;
|
|
m_generatedHeight = height;
|
|
m_generatedPixmap = new TQPixmap(width, height);
|
|
m_generatedMask = new TQBitmap(maskWidth, maskHeight);
|
|
|
|
static unsigned long total = 0;
|
|
total += width * height;
|
|
// NOTATION_DEBUG << "createPixmapAndMask: " << width << "x" << height << " (" << (width*height) << " px, " << total << " total)" << endl;
|
|
|
|
// clear up pixmap and mask
|
|
m_generatedPixmap->fill();
|
|
m_generatedMask->fill(TQt::color0);
|
|
|
|
// initiate painting
|
|
m_p->begin(m_generatedPixmap, m_generatedMask);
|
|
|
|
m_p->painter().setPen(TQt::black);
|
|
m_p->painter().setBrush(TQt::black);
|
|
m_p->maskPainter().setPen(TQt::white);
|
|
m_p->maskPainter().setBrush(TQt::white);
|
|
}
|
|
|
|
TQCanvasPixmap*
|
|
NotePixmapFactory::makeCanvasPixmap(TQPoint hotspot, bool generateMask)
|
|
{
|
|
m_p->end();
|
|
|
|
TQCanvasPixmap* p = new TQCanvasPixmap(*m_generatedPixmap, hotspot);
|
|
|
|
if (generateMask) {
|
|
p->setMask(PixmapFunctions::generateMask(*p));
|
|
} else {
|
|
p->setMask(*m_generatedMask);
|
|
}
|
|
|
|
delete m_generatedPixmap;
|
|
delete m_generatedMask;
|
|
return p;
|
|
}
|
|
|
|
NoteCharacter
|
|
NotePixmapFactory::getCharacter(CharName name, ColourType type, bool inverted)
|
|
{
|
|
NoteCharacter ch;
|
|
getCharacter(name, ch, type, inverted);
|
|
return ch;
|
|
}
|
|
|
|
bool
|
|
NotePixmapFactory::getCharacter(CharName name, NoteCharacter &ch,
|
|
ColourType type, bool inverted)
|
|
{
|
|
NoteFont::CharacterType charType =
|
|
m_inPrinterMethod ? NoteFont::Printer : NoteFont::Screen;
|
|
|
|
if (m_selected) {
|
|
return m_font->getCharacterColoured
|
|
(name,
|
|
GUIPalette::SelectedElementHue,
|
|
GUIPalette::SelectedElementMinValue,
|
|
ch, charType, inverted);
|
|
}
|
|
|
|
if (m_shaded) {
|
|
return m_font->getCharacterShaded(name, ch, charType, inverted);
|
|
}
|
|
|
|
switch (type) {
|
|
|
|
case PlainColour:
|
|
return m_font->getCharacter(name, ch, charType, inverted);
|
|
|
|
case QuantizedColour:
|
|
return m_font->getCharacterColoured
|
|
(name,
|
|
GUIPalette::QuantizedNoteHue,
|
|
GUIPalette::QuantizedNoteMinValue,
|
|
ch, charType, inverted);
|
|
|
|
case HighlightedColour:
|
|
return m_font->getCharacterColoured
|
|
(name,
|
|
GUIPalette::HighlightedElementHue,
|
|
GUIPalette::HighlightedElementMinValue,
|
|
ch, charType, inverted);
|
|
|
|
case TriggerColour:
|
|
return m_font->getCharacterColoured
|
|
(name,
|
|
GUIPalette::TriggerNoteHue,
|
|
GUIPalette::TriggerNoteMinValue,
|
|
ch, charType, inverted);
|
|
|
|
case OutRangeColour:
|
|
return m_font->getCharacterColoured
|
|
(name,
|
|
GUIPalette::OutRangeNoteHue,
|
|
GUIPalette::OutRangeNoteMinValue,
|
|
ch, charType, inverted);
|
|
}
|
|
|
|
return m_font->getCharacter(name, ch, charType, inverted);
|
|
}
|
|
|
|
TQPoint
|
|
NotePixmapFactory::m_pointZero;
|
|
|
|
|
|
int NotePixmapFactory::getNoteBodyWidth(Note::Type type)
|
|
const
|
|
{
|
|
CharName charName(m_style->getNoteHeadCharName(type).first);
|
|
int hx, hy;
|
|
if (!m_font->getHotspot(charName, hx, hy))
|
|
hx = 0;
|
|
return m_font->getWidth(charName) - hx * 2;
|
|
}
|
|
|
|
int NotePixmapFactory::getNoteBodyHeight(Note::Type )
|
|
const
|
|
{
|
|
// this is by definition
|
|
return m_font->getSize();
|
|
}
|
|
|
|
int NotePixmapFactory::getLineSpacing() const
|
|
{
|
|
return m_font->getSize() + getStaffLineThickness();
|
|
}
|
|
|
|
int NotePixmapFactory::getAccidentalWidth(const Accidental &a,
|
|
int shift, bool extraShift) const
|
|
{
|
|
if (a == Accidentals::NoAccidental)
|
|
return 0;
|
|
int w = m_font->getWidth(m_style->getAccidentalCharName(a));
|
|
if (!shift)
|
|
return w;
|
|
else {
|
|
int sw = w;
|
|
if (extraShift) {
|
|
--shift;
|
|
w += getNoteBodyWidth() + getStemThickness();
|
|
}
|
|
w += shift *
|
|
(sw - m_font->getHotspot(m_style->getAccidentalCharName(a)).x());
|
|
}
|
|
return w;
|
|
}
|
|
|
|
int NotePixmapFactory::getAccidentalHeight(const Accidental &a) const
|
|
{
|
|
return m_font->getHeight(m_style->getAccidentalCharName(a));
|
|
}
|
|
|
|
int NotePixmapFactory::getStemLength() const
|
|
{
|
|
unsigned int l = 1;
|
|
(void)m_font->getStemLength(l);
|
|
return l;
|
|
}
|
|
|
|
int NotePixmapFactory::getStemThickness() const
|
|
{
|
|
unsigned int i = 1;
|
|
(void)m_font->getStemThickness(i);
|
|
return i;
|
|
}
|
|
|
|
int NotePixmapFactory::getStaffLineThickness() const
|
|
{
|
|
unsigned int i;
|
|
(void)m_font->getStaffLineThickness(i);
|
|
return i;
|
|
}
|
|
|
|
int NotePixmapFactory::getLegerLineThickness() const
|
|
{
|
|
unsigned int i;
|
|
(void)m_font->getLegerLineThickness(i);
|
|
return i;
|
|
}
|
|
|
|
int NotePixmapFactory::getDotWidth() const
|
|
{
|
|
return m_font->getWidth(NoteCharacterNames::DOT);
|
|
}
|
|
|
|
int NotePixmapFactory::getClefWidth(const Clef &clef) const
|
|
{
|
|
return m_font->getWidth(m_style->getClefCharName(clef.getClefType()));
|
|
}
|
|
|
|
int NotePixmapFactory::getBarMargin() const
|
|
{
|
|
return getNoteBodyWidth() * 2;
|
|
}
|
|
|
|
int NotePixmapFactory::getRestWidth(const Note &restType) const
|
|
{
|
|
return m_font->getWidth(m_style->getRestCharName(restType.getNoteType(),
|
|
false)) // small inaccuracy!
|
|
+ (restType.getDots() * getDotWidth());
|
|
}
|
|
|
|
int NotePixmapFactory::getKeyWidth(const Key &key,
|
|
Key previousKey) const
|
|
{
|
|
std::vector<int> ah0 = previousKey.getAccidentalHeights(Clef());
|
|
std::vector<int> ah1 = key.getAccidentalHeights(Clef());
|
|
|
|
int cancelCount = 0;
|
|
if (key.isSharp() != previousKey.isSharp())
|
|
cancelCount = ah0.size();
|
|
else if (ah1.size() < ah0.size())
|
|
cancelCount = ah0.size() - ah1.size();
|
|
|
|
CharName keyCharName;
|
|
if (key.isSharp())
|
|
keyCharName = NoteCharacterNames::SHARP;
|
|
else
|
|
keyCharName = NoteCharacterNames::FLAT;
|
|
|
|
NoteCharacter keyCharacter;
|
|
NoteCharacter cancelCharacter;
|
|
|
|
keyCharacter = m_font->getCharacter(keyCharName);
|
|
if (cancelCount > 0) {
|
|
cancelCharacter = m_font->getCharacter(NoteCharacterNames::NATURAL);
|
|
}
|
|
|
|
//int x = 0;
|
|
//int lw = getLineSpacing();
|
|
int keyDelta = keyCharacter.getWidth() - keyCharacter.getHotspot().x();
|
|
|
|
int cancelDelta = 0;
|
|
int between = 0;
|
|
if (cancelCount > 0) {
|
|
cancelDelta = cancelCharacter.getWidth() + cancelCharacter.getWidth() / 3;
|
|
between = cancelCharacter.getWidth();
|
|
}
|
|
|
|
return (keyDelta * ah1.size() + cancelDelta * cancelCount + between +
|
|
keyCharacter.getWidth() / 4);
|
|
}
|
|
|
|
int NotePixmapFactory::getTextWidth(const Text &text) const
|
|
{
|
|
TQFontMetrics metrics(getTextFont(text));
|
|
return metrics.boundingRect(strtoqstr(text.getText())).width() + 4;
|
|
}
|
|
|
|
}
|