📄 notepixmapfactory.cpp
字号:
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: *//* Rosegarden A MIDI and audio sequencer and musical notation editor. This program is Copyright 2000-2007 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 <kapplication.h>#include <klocale.h>#include <kstddirs.h>#include <kconfig.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/general/GUIPalette.h"#include "gui/general/PixmapFunctions.h"#include "gui/general/Spline.h"#include "gui/kdeext/KStartupLogo.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 <kglobal.h>#include <kmessagebox.h>#include <qbitmap.h>#include <qcolor.h>#include <qfile.h>#include <qfont.h>#include <qfontmetrics.h>#include <qimage.h>#include <qpainter.h>#include <qpen.h>#include <qpixmap.h>#include <qpointarray.h>#include <qpoint.h>#include <qrect.h>#include <qstring.h>#include <qwmatrix.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, QCanvasPixmap*>{ // nothing to add -- just so we can predeclare it in the header};const char* const NotePixmapFactory::defaultSerifFontFamily = "Times New Roman";const char* const NotePixmapFactory::defaultTimeSigFontFamily = "Century Schoolbook";NotePixmapFactory::NotePixmapFactory(std::string fontName, int size) : m_selected(false), m_shaded(false), m_tupletCountFont(defaultSerifFontFamily, 8, QFont::Bold), m_tupletCountFontMetrics(m_tupletCountFont), m_textMarkFont(defaultSerifFontFamily, 8, QFont::Bold, true), m_textMarkFontMetrics(m_textMarkFont), m_fingeringFont(defaultSerifFontFamily, 8, QFont::Bold), m_fingeringFontMetrics(m_fingeringFont), m_timeSigFont(defaultTimeSigFontFamily, 8, QFont::Bold), m_timeSigFontMetrics(m_timeSigFont), m_bigTimeSigFont(defaultTimeSigFontFamily, 12, QFont::Normal), m_bigTimeSigFontMetrics(m_bigTimeSigFont), m_ottavaFont(defaultSerifFontFamily, 8, QFont::Normal, true), m_ottavaFontMetrics(m_ottavaFont), 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, QFont::Normal, true), m_ottavaFontMetrics(m_ottavaFont), 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 = QFontMetrics(m_timeSigFont); m_bigTimeSigFont = npf.m_bigTimeSigFont; m_bigTimeSigFontMetrics = QFontMetrics(m_bigTimeSigFont); m_tupletCountFont = npf.m_tupletCountFont; m_tupletCountFontMetrics = QFontMetrics(m_tupletCountFont); m_textMarkFont = npf.m_textMarkFont; m_textMarkFontMetrics = QFontMetrics(m_textMarkFont); m_fingeringFont = npf.m_fingeringFont; m_fingeringFontMetrics = QFontMetrics(m_fingeringFont); m_ottavaFont = npf.m_ottavaFont; m_ottavaFontMetrics = QFontMetrics(m_ottavaFontMetrics); init(npf.m_font->getName(), npf.m_font->getSize()); m_dottedRestCache->clear(); m_textFontCache.clear(); } return *this;}voidNotePixmapFactory::init(std::string fontName, int size){ try { m_style = NoteStyleFactory::getStyle(NoteStyleFactory::DefaultStyle); } catch (NoteStyleFactory::StyleUnavailable u) { KStartupLogo::hideIfStillThere(); KMessageBox::error(0, i18n(strtoqstr(u.getMessage()))); 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 QFont timeSigFont(defaultTimeSigFontFamily), textFont(defaultSerifFontFamily); KConfig* config = kapp->config(); config->setGroup(NotationViewConfigGroup); m_timeSigFont = config->readFontEntry("timesigfont", &timeSigFont); m_timeSigFont.setBold(true); m_timeSigFont.setPixelSize(size * 5 / 2); m_timeSigFontMetrics = QFontMetrics(m_timeSigFont); m_bigTimeSigFont = config->readFontEntry("timesigfont", &timeSigFont); m_bigTimeSigFont.setPixelSize(size * 4 + 2); m_bigTimeSigFontMetrics = QFontMetrics(m_bigTimeSigFont); m_tupletCountFont = config->readFontEntry("textfont", &textFont); m_tupletCountFont.setBold(true); m_tupletCountFont.setPixelSize(size * 2); m_tupletCountFontMetrics = QFontMetrics(m_tupletCountFont); m_textMarkFont = config->readFontEntry("textfont", &textFont); m_textMarkFont.setBold(true); m_textMarkFont.setItalic(true); m_textMarkFont.setPixelSize(size * 2); m_textMarkFontMetrics = QFontMetrics(m_textMarkFont); m_fingeringFont = config->readFontEntry("textfont", &textFont); m_fingeringFont.setBold(true); m_fingeringFont.setPixelSize(size * 5 / 3); m_fingeringFontMetrics = QFontMetrics(m_fingeringFont); m_ottavaFont = config->readFontEntry("textfont", &textFont); m_ottavaFont.setPixelSize(size * 2); m_ottavaFontMetrics = QFontMetrics(m_ottavaFont);}NotePixmapFactory::~NotePixmapFactory(){ delete m_p; delete m_dottedRestCache;}std::stringNotePixmapFactory::getFontName() const{ return m_font->getName();}intNotePixmapFactory::getSize() const{ return m_font->getSize();}QPixmapNotePixmapFactory::toQPixmap(QCanvasPixmap* cp){ QPixmap p = *cp; delete cp; return p;}voidNotePixmapFactory::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}QCanvasPixmap*NotePixmapFactory::makeNotePixmap(const NotePixmapParameters ¶ms){ Profiler profiler("NotePixmapFactory::makeNotePixmap"); clock_t startTime = clock(); drawNoteAux(params, 0, 0, 0); QPoint hotspot(m_left, m_above + m_noteBodyHeight / 2); //#define ROSE_DEBUG_NOTE_PIXMAP_FACTORY#ifdef ROSE_DEBUG_NOTE_PIXMAP_FACTORY m_p->painter().setPen(Qt::red); m_p->painter().setBrush(Qt::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);}voidNotePixmapFactory::drawNote(const NotePixmapParameters ¶ms, QPainter &painter, int x, int y){ Profiler profiler("NotePixmapFactory::drawNote"); m_inPrinterMethod = true; drawNoteAux(params, &painter, x, y); m_inPrinterMethod = false;}voidNotePixmapFactory::drawNoteAux(const NotePixmapParameters ¶ms, QPainter *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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -