2012-05-26 14:26:10 +02:00
|
|
|
|
//=============================================================================
|
|
|
|
|
// MuseScore
|
|
|
|
|
// Music Composition & Notation
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2002-2011 Werner Schweer
|
|
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License version 2
|
|
|
|
|
// as published by the Free Software Foundation and appearing in
|
|
|
|
|
// the file LICENCE.GPL
|
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
|
|
#include "figuredbass.h"
|
|
|
|
|
#include "score.h"
|
|
|
|
|
#include "note.h"
|
|
|
|
|
#include "measure.h"
|
|
|
|
|
#include "system.h"
|
|
|
|
|
#include "segment.h"
|
2013-05-13 18:49:17 +02:00
|
|
|
|
#include "chord.h"
|
|
|
|
|
#include "rest.h"
|
|
|
|
|
#include "score.h"
|
2013-11-11 16:53:03 +01:00
|
|
|
|
#include "sym.h"
|
2014-04-09 16:09:21 +02:00
|
|
|
|
#include "xml.h"
|
2013-05-13 18:49:17 +02:00
|
|
|
|
|
2014-07-06 01:56:30 +02:00
|
|
|
|
// trying to do without it
|
|
|
|
|
//#include <QQmlEngine>
|
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
|
namespace Ms {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2015-10-25 00:38:39 +02:00
|
|
|
|
static constexpr qreal FB_CONTLINE_HEIGHT = 0.875; // the % of font EM to raise the cont. line at
|
|
|
|
|
// (0 = top of font; 1 = bottom of font)
|
|
|
|
|
static constexpr qreal FB_CONTLINE_LEFT_PADDING = 0.1875; // (3/16sp) the blank space at the left of a cont. line (in sp)
|
|
|
|
|
static constexpr qreal FB_CONTLINE_OVERLAP = 0.125; // (1/8sp) the overlap of an extended cont. line (in sp)
|
|
|
|
|
static constexpr qreal FB_CONTLINE_THICKNESS = 0.09375; // (3/32sp) the thickness of a cont. line (in sp)
|
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// the array of configured fonts
|
|
|
|
|
static QList<FiguredBassFont> g_FBFonts;
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// F I G U R E D B A S S I T E M
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// used for indexed access to parenthesis chars
|
|
|
|
|
// (these is no normAccidToChar[], as accidentals may use mult. chars in normalized display):
|
2014-05-23 08:24:41 +02:00
|
|
|
|
const QChar FiguredBassItem::normParenthToChar[int(FiguredBassItem::Parenthesis::NUMOF)] =
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{ 0, '(', ')', '[', ']'};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FiguredBassItem::FiguredBassItem(Score* s, int l)
|
2012-08-01 19:06:20 +02:00
|
|
|
|
: Element(s), ord(l)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
2014-05-22 22:21:56 +02:00
|
|
|
|
_prefix = _suffix = Modifier::NONE;
|
2012-08-10 20:50:27 +02:00
|
|
|
|
_digit = FBIDigitNone;
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[0] = parenth[1] = parenth[2] = parenth[3] = parenth[4] = Parenthesis::NONE;
|
2014-05-23 09:49:22 +02:00
|
|
|
|
_contLine = ContLine::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FiguredBassItem::FiguredBassItem(const FiguredBassItem& item)
|
2012-08-01 19:06:20 +02:00
|
|
|
|
: Element(item)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
|
|
|
|
ord = item.ord;
|
2012-08-10 20:50:27 +02:00
|
|
|
|
_prefix = item._prefix;
|
|
|
|
|
_digit = item._digit;
|
|
|
|
|
_suffix = item._suffix;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
parenth[0] = item.parenth[0];
|
|
|
|
|
parenth[1] = item.parenth[1];
|
|
|
|
|
parenth[2] = item.parenth[2];
|
|
|
|
|
parenth[3] = item.parenth[3];
|
|
|
|
|
parenth[4] = item.parenth[4];
|
2012-08-10 20:50:27 +02:00
|
|
|
|
_contLine = item._contLine;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
textWidth = item.textWidth;
|
2012-08-01 19:06:20 +02:00
|
|
|
|
_displayText= item._displayText;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FiguredBassItem::~FiguredBassItem()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem parse()
|
|
|
|
|
//
|
|
|
|
|
// converts a string into a property-based representation, if possible;
|
|
|
|
|
// return true on success | false if the string is non-conformant
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool FiguredBassItem::parse(QString& str)
|
|
|
|
|
{
|
|
|
|
|
int retVal;
|
|
|
|
|
|
|
|
|
|
parseParenthesis(str, 0);
|
|
|
|
|
retVal = parsePrefixSuffix(str, true); // prefix
|
|
|
|
|
if(retVal == -1)
|
|
|
|
|
return false;
|
|
|
|
|
parseParenthesis(str, 1);
|
|
|
|
|
retVal = parseDigit(str); // digit
|
|
|
|
|
if(retVal == -1)
|
|
|
|
|
return false;
|
|
|
|
|
parseParenthesis(str, 2);
|
|
|
|
|
retVal = parsePrefixSuffix(str, false); // suffix
|
|
|
|
|
if(retVal == -1)
|
|
|
|
|
return false;
|
|
|
|
|
parseParenthesis(str, 3);
|
|
|
|
|
// check for a possible cont. line symbol(s)
|
2014-05-23 09:49:22 +02:00
|
|
|
|
_contLine = ContLine::NONE; // contLine
|
2013-02-12 16:00:05 +01:00
|
|
|
|
if(str[0] == '-' || str[0] == '_') { // 1 symbol: simple continuation
|
2014-05-23 09:49:22 +02:00
|
|
|
|
_contLine = ContLine::SIMPLE;
|
2013-02-12 16:00:05 +01:00
|
|
|
|
str.remove(0, 1);
|
|
|
|
|
}
|
|
|
|
|
while(str[0] == '-' || str[0] == '_') { // more than 1 symbol: extended continuation
|
2014-05-23 09:49:22 +02:00
|
|
|
|
_contLine = ContLine::EXTENDED;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.remove(0, 1);
|
|
|
|
|
}
|
|
|
|
|
parseParenthesis(str, 4);
|
|
|
|
|
|
2013-02-12 16:00:05 +01:00
|
|
|
|
// remove useless parentheses, moving external parentheses toward central digit element
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(_prefix == Modifier::NONE && parenth[1] == Parenthesis::NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
parenth[1] = parenth[0];
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[0] = Parenthesis::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(_digit == FBIDigitNone && parenth[2] == Parenthesis::NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
parenth[2] = parenth[1];
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[1] = Parenthesis::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if(_contLine == ContLine::NONE && parenth[3] == Parenthesis::NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
parenth[3] = parenth[4];
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[4] = Parenthesis::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(_suffix == Modifier::NONE && parenth[2] == Parenthesis::NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
parenth[2] = parenth[3];
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[3] = Parenthesis::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// some checks:
|
|
|
|
|
// if some extra input, str is not conformant
|
|
|
|
|
if(str.size())
|
|
|
|
|
return false;
|
|
|
|
|
// can't have BOTH prefix and suffix
|
|
|
|
|
// prefix, digit, suffix and cont.line cannot be ALL empty
|
|
|
|
|
// suffix cannot combine with empty digit
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if( (_prefix != Modifier::NONE && _suffix != Modifier::NONE)
|
2014-05-23 09:49:22 +02:00
|
|
|
|
|| (_prefix == Modifier::NONE && _digit == FBIDigitNone && _suffix == Modifier::NONE && _contLine == ContLine::NONE)
|
2014-05-22 22:21:56 +02:00
|
|
|
|
|| ( (_suffix == Modifier::CROSS || _suffix == Modifier::BACKSLASH || _suffix == Modifier::SLASH)
|
2012-08-10 20:50:27 +02:00
|
|
|
|
&& _digit == FBIDigitNone) )
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem parsePrefixSuffix()
|
|
|
|
|
//
|
|
|
|
|
// scans str to extract prefix or suffix properties. Stops at the first char which cannot fit.
|
|
|
|
|
// Fitting chars are removed from str. DOES NOT generate any display text
|
|
|
|
|
//
|
|
|
|
|
// returns the number of QChar's read from str or -1 if prefix / suffix has an illegal format
|
|
|
|
|
// (no prefix / suffix at all IS legal)
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
int FiguredBassItem::parsePrefixSuffix(QString& str, bool bPrefix)
|
|
|
|
|
{
|
2012-08-11 01:15:22 +02:00
|
|
|
|
Modifier * dest = bPrefix ? &_prefix : &_suffix;
|
|
|
|
|
bool done = false;
|
|
|
|
|
int size = str.size();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str = str.trimmed();
|
|
|
|
|
|
2014-05-22 22:21:56 +02:00
|
|
|
|
*dest = Modifier::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
while(str.size()) {
|
|
|
|
|
switch(str.at(0).unicode())
|
|
|
|
|
{
|
|
|
|
|
case 'b':
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(*dest != Modifier::NONE) {
|
|
|
|
|
if(*dest == Modifier::FLAT) // FLAT may double a previous FLAT
|
|
|
|
|
*dest = Modifier::DOUBLEFLAT;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else
|
|
|
|
|
return -1; // but no other combination is acceptable
|
|
|
|
|
}
|
2015-03-02 16:44:49 +01:00
|
|
|
|
else
|
|
|
|
|
*dest = Modifier::FLAT;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(*dest != Modifier::NONE) // cannot combine with any other accidental
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return -1;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
*dest = Modifier::NATURAL;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
case '#':
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(*dest != Modifier::NONE) {
|
|
|
|
|
if(*dest == Modifier::SHARP) // SHARP may double a preivous SHARP
|
|
|
|
|
*dest = Modifier::DOUBLESHARP;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else
|
|
|
|
|
return -1; // but no other combination is acceptable
|
|
|
|
|
}
|
2015-03-02 16:44:49 +01:00
|
|
|
|
else
|
|
|
|
|
*dest = Modifier::SHARP;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
case '+':
|
2013-02-10 07:01:31 +01:00
|
|
|
|
// accept '+' as both a prefix and a suffix for harmony notation
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(*dest != Modifier::NONE) // cannot combine with any other accidental
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return -1;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
*dest = Modifier::CROSS;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
2013-02-10 07:01:31 +01:00
|
|
|
|
// '\\' and '/' go into the suffix
|
2012-05-26 14:26:10 +02:00
|
|
|
|
case '\\':
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(_suffix != Modifier::NONE) // cannot combine with any other accidental
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return -1;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
_suffix = Modifier::BACKSLASH;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
case '/':
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(_suffix != Modifier::NONE) // cannot combine with any other accidental
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return -1;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
_suffix = Modifier::SLASH;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
2012-08-10 20:50:27 +02:00
|
|
|
|
default: // any other char: no longer in prefix/suffix
|
2012-05-26 14:26:10 +02:00
|
|
|
|
done = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(done)
|
|
|
|
|
break;
|
|
|
|
|
str.remove(0,1); // 'eat' the char and continue
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 20:50:27 +02:00
|
|
|
|
return size - str.size(); // return how many chars we had read into prefix/suffix
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem parseDigit()
|
|
|
|
|
//
|
|
|
|
|
// scans str to extract digit properties. Stops at the first char which cannot belong to digit part.
|
|
|
|
|
// Fitting chars are removed from str. DOES NOT generate any display text
|
|
|
|
|
//
|
|
|
|
|
// returns the number of QChar's read from str or -1 if no legal digit can be constructed
|
|
|
|
|
// (no digit at all IS legal)
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
int FiguredBassItem::parseDigit(QString& str)
|
|
|
|
|
{
|
|
|
|
|
int size = str.size();
|
|
|
|
|
str = str.trimmed();
|
|
|
|
|
|
2012-08-10 20:50:27 +02:00
|
|
|
|
_digit = FBIDigitNone;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
while(str.size()) {
|
2014-06-11 11:34:36 +02:00
|
|
|
|
// any digit acceptable
|
|
|
|
|
if(str[0] >= '0' && str[0] <= '9') {
|
|
|
|
|
if (_digit == FBIDigitNone)
|
|
|
|
|
_digit = 0;
|
|
|
|
|
_digit = _digit*10 + (str[0].unicode() - '0');
|
|
|
|
|
str.remove(0, 1);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
// anything else: no longer in digit part
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return size - str.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem parseParenthesis()
|
|
|
|
|
//
|
|
|
|
|
// scans str to extract a (possible) parenthesis, stores its code into parenth[parenthIdx]
|
|
|
|
|
// and removes it from str. Only looks at first str char.
|
|
|
|
|
//
|
|
|
|
|
// returns the number of QChar's read from str (actually 0 or 1).
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
int FiguredBassItem::parseParenthesis(QString& str, int parenthIdx)
|
|
|
|
|
{
|
|
|
|
|
int c = str[0].unicode();
|
2014-05-23 08:24:41 +02:00
|
|
|
|
Parenthesis code = Parenthesis::NONE;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
switch(c)
|
|
|
|
|
{
|
|
|
|
|
case '(':
|
2014-05-23 08:24:41 +02:00
|
|
|
|
code = Parenthesis::ROUNDOPEN;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
case ')':
|
2014-05-23 08:24:41 +02:00
|
|
|
|
code = Parenthesis::ROUNDCLOSED;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
case '[':
|
2014-05-23 08:24:41 +02:00
|
|
|
|
code =Parenthesis::SQUAREDOPEN;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
case ']':
|
2014-05-23 08:24:41 +02:00
|
|
|
|
code = Parenthesis::SQUAREDCLOSED;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
parenth[parenthIdx] = code;
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(code != Parenthesis::NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.remove(0, 1);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem normalizedText()
|
|
|
|
|
//
|
|
|
|
|
// returns a string with the normalized text, i.e. the text displayed while editing;
|
|
|
|
|
// this is a standard textual representation of the item properties
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
QString FiguredBassItem::normalizedText() const
|
|
|
|
|
{
|
|
|
|
|
QString str = QString();
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[0] != Parenthesis::NONE)
|
|
|
|
|
str.append(normParenthToChar[int(parenth[0])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(_prefix != Modifier::NONE) {
|
2012-08-10 20:50:27 +02:00
|
|
|
|
switch(_prefix)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::FLAT:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('b');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::NATURAL:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('h');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::SHARP:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('#');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::CROSS:
|
2013-02-10 07:01:31 +01:00
|
|
|
|
str.append('+');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::DOUBLEFLAT:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append("bb");
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::DOUBLESHARP:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append("##");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[1] != Parenthesis::NONE)
|
|
|
|
|
str.append(normParenthToChar[int(parenth[1])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
// digit
|
2012-08-10 20:50:27 +02:00
|
|
|
|
if(_digit != FBIDigitNone)
|
2014-06-11 11:34:36 +02:00
|
|
|
|
str.append(QString::number(_digit));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[2] != Parenthesis::NONE)
|
|
|
|
|
str.append(normParenthToChar[int(parenth[2])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
// suffix
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(_suffix != Modifier::NONE) {
|
2012-08-10 20:50:27 +02:00
|
|
|
|
switch(_suffix)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::FLAT:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('b');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::NATURAL:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('h');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::SHARP:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('#');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::CROSS:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('+');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::BACKSLASH:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('\\');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::SLASH:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('/');
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::DOUBLEFLAT:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append("bb");
|
|
|
|
|
break;
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::DOUBLESHARP:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append("##");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[3] != Parenthesis::NONE)
|
|
|
|
|
str.append(normParenthToChar[int(parenth[3])]);
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if(_contLine > ContLine::NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
str.append('_');
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if (_contLine > ContLine::SIMPLE)
|
2013-02-12 16:00:05 +01:00
|
|
|
|
str.append('_');
|
|
|
|
|
}
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[4] != Parenthesis::NONE)
|
|
|
|
|
str.append(normParenthToChar[int(parenth[4])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem write()
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBassItem::write(Xml& xml) const
|
|
|
|
|
{
|
|
|
|
|
xml.stag("FiguredBassItem");
|
|
|
|
|
xml.tagE(QString("brackets b0=\"%1\" b1=\"%2\" b2=\"%3\" b3=\"%4\" b4=\"%5\"")
|
2014-05-23 08:24:41 +02:00
|
|
|
|
.arg(int(parenth[0])) .arg(int(parenth[1])) .arg(int(parenth[2])) .arg(int(parenth[3])) .arg(int(parenth[4])) );
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(_prefix != Modifier::NONE)
|
|
|
|
|
xml.tag(QString("prefix"), int(_prefix));
|
2012-08-10 20:50:27 +02:00
|
|
|
|
if(_digit != FBIDigitNone)
|
|
|
|
|
xml.tag(QString("digit"), _digit);
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(_suffix != Modifier::NONE)
|
|
|
|
|
xml.tag(QString("suffix"), int(_suffix));
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if(_contLine != ContLine::NONE)
|
|
|
|
|
xml.tag("continuationLine", int(_contLine));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
xml.etag();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem read()
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
|
void FiguredBassItem::read(XmlReader& e)
|
|
|
|
|
{
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
|
|
|
|
|
if (tag == "brackets") {
|
|
|
|
|
parenth[0] = (Parenthesis)e.intAttribute("b0");
|
|
|
|
|
parenth[1] = (Parenthesis)e.intAttribute("b1");
|
|
|
|
|
parenth[2] = (Parenthesis)e.intAttribute("b2");
|
|
|
|
|
parenth[3] = (Parenthesis)e.intAttribute("b3");
|
|
|
|
|
parenth[4] = (Parenthesis)e.intAttribute("b4");
|
2013-01-20 01:05:45 +01:00
|
|
|
|
e.readNext();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
|
else if (tag == "prefix")
|
|
|
|
|
_prefix = (Modifier)(e.readInt());
|
|
|
|
|
else if (tag == "digit")
|
|
|
|
|
_digit = e.readInt();
|
|
|
|
|
else if (tag == "suffix")
|
|
|
|
|
_suffix = (Modifier)(e.readInt());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if(tag == "continuationLine")
|
2013-02-12 16:00:05 +01:00
|
|
|
|
_contLine = (ContLine)(e.readInt());
|
2013-01-11 18:10:18 +01:00
|
|
|
|
else if (!Element::readProperties(e))
|
|
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem layout()
|
|
|
|
|
// creates the display text (set as element text) and computes
|
|
|
|
|
// the horiz. offset needed to align the right part as well as the vert. offset
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBassItem::layout()
|
|
|
|
|
{
|
|
|
|
|
qreal h, w, x, x1, x2, y;
|
|
|
|
|
|
2012-08-01 19:06:20 +02:00
|
|
|
|
// contruct font metrics
|
|
|
|
|
int fontIdx = 0;
|
|
|
|
|
QFont f(g_FBFonts.at(fontIdx).family);
|
2015-10-25 00:38:39 +02:00
|
|
|
|
|
|
|
|
|
// font size in pixels, scaled according to spatium()
|
|
|
|
|
// (use the same font selection as used in draw() below)
|
2015-11-16 14:24:47 +01:00
|
|
|
|
qreal m = score()->styleD(StyleIdx::figuredBassFontSize);
|
|
|
|
|
m *= spatium() / SPATIUM20; // make spatium dependent
|
2015-10-25 00:38:39 +02:00
|
|
|
|
f.setPixelSize(lrint(m));
|
|
|
|
|
/* USING POINTS RATHER PIXELS MAKES FOR COARSER STEPS IN Qt ROUNDING TO INTEGER FONT SIZES
|
2012-08-02 18:41:29 +02:00
|
|
|
|
// font size in points, scaled according to spatium()
|
2015-11-16 14:24:47 +01:00
|
|
|
|
qreal m = score()->styleD(StyleIdx::figuredBassFontSize) * spatium() / SPATIUM20;
|
2012-08-01 19:06:20 +02:00
|
|
|
|
f.setPointSizeF(m);
|
2015-10-25 00:38:39 +02:00
|
|
|
|
*/
|
2012-08-01 19:06:20 +02:00
|
|
|
|
QFontMetrics fm(f);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
QString str = QString();
|
2013-11-11 15:11:28 +01:00
|
|
|
|
x = symWidth(SymId::noteheadBlack) * .5;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
x1 = x2 = 0.0;
|
|
|
|
|
|
|
|
|
|
// create display text
|
|
|
|
|
int font = 0;
|
2014-05-26 15:31:36 +02:00
|
|
|
|
int style = score()->styleI(StyleIdx::figuredBassStyle);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[0] != Parenthesis::NONE)
|
|
|
|
|
str.append(g_FBFonts.at(font).displayParenthesis[int(parenth[0])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
// prefix
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(_prefix != Modifier::NONE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// if no digit, the string created so far 'hangs' to the left of the note
|
2012-08-10 20:50:27 +02:00
|
|
|
|
if(_digit == FBIDigitNone)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
x1 = fm.width(str);
|
2014-05-22 22:21:56 +02:00
|
|
|
|
str.append(g_FBFonts.at(font).displayAccidental[int(_prefix)]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// if no digit, the string from here onward 'hangs' to the right of the note
|
2012-08-10 20:50:27 +02:00
|
|
|
|
if(_digit == FBIDigitNone)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
x2 = fm.width(str);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[1] != Parenthesis::NONE)
|
|
|
|
|
str.append(g_FBFonts.at(font).displayParenthesis[int(parenth[1])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
// digit
|
2012-08-10 20:50:27 +02:00
|
|
|
|
if(_digit != FBIDigitNone) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// if some digit, the string created so far 'hangs' to the left of the note
|
|
|
|
|
x1 = fm.width(str);
|
2014-06-11 11:34:36 +02:00
|
|
|
|
// if suffix is a combining shape, combine it with digit (multi-digit numbers cannot be combined)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// unless there is a parenthesis in between
|
2014-06-11 11:34:36 +02:00
|
|
|
|
if( (_digit < 10)
|
|
|
|
|
&& (_suffix == Modifier::CROSS || _suffix == Modifier::BACKSLASH || _suffix == Modifier::SLASH)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
&& parenth[2] == Parenthesis::NONE)
|
2014-05-22 22:21:56 +02:00
|
|
|
|
str.append(g_FBFonts.at(font).displayDigit[style][_digit][int(_suffix)-(int(Modifier::CROSS)-1)]);
|
2014-06-11 11:34:36 +02:00
|
|
|
|
// if several digits or no shape combination, convert _digit to font styled chars
|
|
|
|
|
else {
|
|
|
|
|
QString digits = QString();
|
|
|
|
|
int digit = _digit;
|
|
|
|
|
while (true) {
|
|
|
|
|
digits.prepend(g_FBFonts.at(font).displayDigit[style][(digit % 10)][0]);
|
|
|
|
|
digit /= 10;
|
|
|
|
|
if (digit == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
str.append(digits);
|
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// if some digit, the string from here onward 'hangs' to the right of the note
|
|
|
|
|
x2 = fm.width(str);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[2] != Parenthesis::NONE)
|
|
|
|
|
str.append(g_FBFonts.at(font).displayParenthesis[int(parenth[2])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
// suffix
|
|
|
|
|
// append only if non-combining shape or cannot combine (no digit or parenthesis in between)
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if( _suffix != Modifier::NONE
|
|
|
|
|
&& ( (_suffix != Modifier::CROSS && _suffix != Modifier::BACKSLASH && _suffix != Modifier::SLASH)
|
2012-08-10 20:50:27 +02:00
|
|
|
|
|| _digit == FBIDigitNone
|
2014-05-23 08:24:41 +02:00
|
|
|
|
|| parenth[2] != Parenthesis::NONE) )
|
2014-05-22 22:21:56 +02:00
|
|
|
|
str.append(g_FBFonts.at(font).displayAccidental[int(_suffix)]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[3] != Parenthesis::NONE)
|
|
|
|
|
str.append(g_FBFonts.at(font).displayParenthesis[int(parenth[3])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2012-08-01 19:06:20 +02:00
|
|
|
|
setDisplayText(str); // this text will be displayed
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2013-02-12 16:00:05 +01:00
|
|
|
|
if (str.size()) // if some text
|
|
|
|
|
x = x - (x1+x2) * 0.5; // position the text so that [x1<-->x2] is centered below the note
|
|
|
|
|
else // if no text (but possibly a line)
|
|
|
|
|
x = 0; // start at note left margin
|
2013-02-10 13:34:08 +01:00
|
|
|
|
// vertical position
|
2012-05-26 14:26:10 +02:00
|
|
|
|
h = fm.lineSpacing();
|
2014-05-26 15:31:36 +02:00
|
|
|
|
h *= score()->styleD(StyleIdx::figuredBassLineHeight);
|
|
|
|
|
if (score()->styleI(StyleIdx::figuredBassAlignment) == 0) // top alignment: stack down from first item
|
2013-02-10 13:34:08 +01:00
|
|
|
|
y = h * ord;
|
|
|
|
|
else // bottom alignment: stack up from last item
|
|
|
|
|
y = -h * (figuredBass()->numOfItems() - ord);
|
|
|
|
|
setPos(x, y);
|
2013-02-12 16:00:05 +01:00
|
|
|
|
// determine bbox from text width
|
|
|
|
|
// w = fm.width(str);
|
|
|
|
|
w = fm.boundingRect(str).width();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
textWidth = w;
|
2013-02-12 16:00:05 +01:00
|
|
|
|
// if there is a cont.line, extend width to cover the whole FB element duration line
|
2012-05-26 14:26:10 +02:00
|
|
|
|
int lineLen;
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if(_contLine != ContLine::NONE && (lineLen=figuredBass()->lineLength(0)) > w)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
w = lineLen;
|
2013-01-02 09:29:17 +01:00
|
|
|
|
bbox().setRect(0, 0, w, h);
|
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// FiguredBassItem draw()
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBassItem::draw(QPainter* painter) const
|
|
|
|
|
{
|
2015-10-25 00:38:39 +02:00
|
|
|
|
int font = 0;
|
|
|
|
|
qreal _spatium = spatium();
|
2012-07-24 01:46:12 +02:00
|
|
|
|
// set font from general style
|
|
|
|
|
QFont f(g_FBFonts.at(font).family);
|
|
|
|
|
#ifdef USE_GLYPHS
|
|
|
|
|
f.setHintingPreference(QFont::PreferVerticalHinting);
|
|
|
|
|
#endif
|
2012-08-02 18:41:29 +02:00
|
|
|
|
// font size in pixels, scaled according to spatium()
|
2015-10-25 00:38:39 +02:00
|
|
|
|
// (use the same font selection as used in layout() above)
|
2015-11-16 14:24:47 +01:00
|
|
|
|
qreal m = score()->styleD(StyleIdx::figuredBassFontSize);
|
|
|
|
|
m *= spatium() / SPATIUM20; // make spatium dependent
|
2012-07-24 01:46:12 +02:00
|
|
|
|
f.setPixelSize(lrint(m));
|
2015-10-25 00:38:39 +02:00
|
|
|
|
/* USING POINTS RATHER PIXELS MAKES FOR COARSER STEPS IN Qt ROUNDING TO INTEGER FONT SIZES
|
|
|
|
|
// font size in points, scaled according to spatium()
|
2015-11-16 14:24:47 +01:00
|
|
|
|
qreal m = score()->styleD(StyleIdx::figuredBassFontSize) * spatium() / SPATIUM20;
|
2015-10-25 00:38:39 +02:00
|
|
|
|
f.setPointSizeF(m);
|
|
|
|
|
*/
|
2012-07-24 01:46:12 +02:00
|
|
|
|
painter->setFont(f);
|
|
|
|
|
painter->setBrush(Qt::NoBrush);
|
2015-10-25 00:38:39 +02:00
|
|
|
|
QPen pen(figuredBass()->curColor(), FB_CONTLINE_THICKNESS * _spatium, Qt::SolidLine, Qt::RoundCap);
|
|
|
|
|
painter->setPen(pen);
|
2012-08-01 19:06:20 +02:00
|
|
|
|
painter->drawText(bbox(), Qt::TextDontClip | Qt::AlignLeft | Qt::AlignTop, displayText());
|
2012-07-24 01:46:12 +02:00
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// continuation line
|
2013-02-12 16:00:05 +01:00
|
|
|
|
qreal lineEndX = 0.0;
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if (_contLine > ContLine::NONE) {
|
2013-03-01 13:42:05 +01:00
|
|
|
|
qreal lineStartX = textWidth; // by default, line starts right after text
|
2013-02-12 16:00:05 +01:00
|
|
|
|
if (lineStartX > 0.0)
|
2015-10-25 00:38:39 +02:00
|
|
|
|
lineStartX += _spatium * FB_CONTLINE_LEFT_PADDING; // if some text, give some room after it
|
|
|
|
|
lineEndX = figuredBass()->printedLineLength(); // by default, line ends with item duration
|
2013-03-01 13:42:05 +01:00
|
|
|
|
if(lineEndX - lineStartX < 1.0) // if line length < 1 sp, ignore it
|
|
|
|
|
lineEndX = 0.0;
|
|
|
|
|
|
|
|
|
|
// if extended cont.line and no closing parenthesis: look at next FB element
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if (_contLine > ContLine::SIMPLE && parenth[4] == Parenthesis::NONE) {
|
2013-02-12 16:00:05 +01:00
|
|
|
|
FiguredBass * nextFB;
|
|
|
|
|
// if there is a contiguous FB element
|
|
|
|
|
if ( (nextFB=figuredBass()->nextFiguredBass()) != 0) {
|
|
|
|
|
// retrieve the X position (in page coords) of a possible cont. line of nextFB
|
|
|
|
|
// on the same line of 'this'
|
|
|
|
|
QPointF pgPos = pagePos();
|
|
|
|
|
qreal nextContPageX = nextFB->additionalContLineX(pgPos.y());
|
|
|
|
|
// if an additional cont. line has been found, extend up to its initial X coord
|
|
|
|
|
if (nextContPageX > 0)
|
2015-10-25 00:38:39 +02:00
|
|
|
|
lineEndX = nextContPageX - pgPos.x() + _spatium*FB_CONTLINE_OVERLAP;
|
|
|
|
|
// with a little bit of overlap
|
2013-03-01 13:42:05 +01:00
|
|
|
|
else
|
2015-10-25 00:38:39 +02:00
|
|
|
|
lineEndX = figuredBass()->lineLength(0); // if none found, draw to the duration end
|
2013-02-12 16:00:05 +01:00
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2013-03-01 13:42:05 +01:00
|
|
|
|
// if some line, draw it
|
|
|
|
|
if (lineEndX > 0.0) {
|
2015-10-25 00:38:39 +02:00
|
|
|
|
qreal h = bbox().height() * FB_CONTLINE_HEIGHT;
|
2013-03-01 13:42:05 +01:00
|
|
|
|
painter->drawLine(lineStartX, h, lineEndX - ipos().x(), h);
|
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2012-07-24 01:46:12 +02:00
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// closing cont.line parenthesis
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(parenth[4] != Parenthesis::NONE) {
|
2013-02-12 16:00:05 +01:00
|
|
|
|
int x = lineEndX > 0.0 ? lineEndX : textWidth;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
painter->drawText(QRectF(x, 0, bbox().width(), bbox().height()), Qt::AlignLeft | Qt::AlignTop,
|
2014-05-23 08:24:41 +02:00
|
|
|
|
g_FBFonts.at(font).displayParenthesis[int(parenth[4])]);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 20:50:27 +02:00
|
|
|
|
//---------------------------------------------------------
|
2012-08-11 01:15:22 +02:00
|
|
|
|
// PROPERTY METHODS
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
QVariant FiguredBassItem::getProperty(P_ID propertyId) const
|
|
|
|
|
{
|
|
|
|
|
switch(propertyId) {
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPREFIX:
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return int(_prefix);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBDIGIT:
|
2012-08-11 01:15:22 +02:00
|
|
|
|
return _digit;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBSUFFIX:
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return int(_suffix);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBCONTINUATIONLINE:
|
2014-05-23 09:49:22 +02:00
|
|
|
|
return int(_contLine);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS1:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return int(parenth[0]);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS2:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return int(parenth[1]);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS3:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return int(parenth[2]);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS4:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return int(parenth[3]);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS5:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return int(parenth[4]);
|
2012-08-11 01:15:22 +02:00
|
|
|
|
default:
|
|
|
|
|
return Element::getProperty(propertyId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FiguredBassItem::setProperty(P_ID propertyId, const QVariant& v)
|
|
|
|
|
{
|
|
|
|
|
score()->addRefresh(canvasBoundingRect());
|
|
|
|
|
int val = v.toInt();
|
|
|
|
|
switch(propertyId) {
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPREFIX:
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(val < int(Modifier::NONE) || val >= int(Modifier::NUMOF))
|
2012-08-11 01:15:22 +02:00
|
|
|
|
return false;
|
|
|
|
|
_prefix = (Modifier)val;
|
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBDIGIT:
|
2012-08-11 01:15:22 +02:00
|
|
|
|
if(val < 1 || val > 9)
|
|
|
|
|
return false;
|
|
|
|
|
_digit = val;
|
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBSUFFIX:
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(val < int(Modifier::NONE) || val >= int(Modifier::NUMOF))
|
2012-08-11 01:15:22 +02:00
|
|
|
|
return false;
|
|
|
|
|
_suffix = (Modifier)val;
|
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBCONTINUATIONLINE:
|
2013-02-12 16:00:05 +01:00
|
|
|
|
_contLine = (ContLine)val;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS1:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(val < int(Parenthesis::NONE) || val >= int(Parenthesis::NUMOF))
|
2012-08-14 14:58:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
parenth[0] = (Parenthesis)val;
|
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS2:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(val < int(Parenthesis::NONE) || val >= int(Parenthesis::NUMOF))
|
2012-08-14 14:58:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
parenth[1] = (Parenthesis)val;
|
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS3:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(val < int(Parenthesis::NONE) || val >= int(Parenthesis::NUMOF))
|
2012-08-14 14:58:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
parenth[2] = (Parenthesis)val;
|
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS4:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(val < int(Parenthesis::NONE) || val >= int(Parenthesis::NUMOF))
|
2012-08-14 14:58:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
parenth[3] = (Parenthesis)val;
|
|
|
|
|
break;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPARENTHESIS5:
|
2014-05-23 08:24:41 +02:00
|
|
|
|
if(val < int(Parenthesis::NONE) || val >= int(Parenthesis::NUMOF))
|
2012-08-14 14:58:43 +02:00
|
|
|
|
return false;
|
|
|
|
|
parenth[4] = (Parenthesis)val;
|
|
|
|
|
break;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
default:
|
|
|
|
|
return Element::setProperty(propertyId, v);
|
|
|
|
|
}
|
|
|
|
|
score()->setLayoutAll(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant FiguredBassItem::propertyDefault(P_ID id) const
|
|
|
|
|
{
|
|
|
|
|
switch(id) {
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBPREFIX:
|
|
|
|
|
case P_ID::FBSUFFIX:
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return int(Modifier::NONE);
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBDIGIT:
|
2012-08-11 01:15:22 +02:00
|
|
|
|
return FBIDigitNone;
|
2014-05-26 18:18:01 +02:00
|
|
|
|
case P_ID::FBCONTINUATIONLINE:
|
2012-08-11 01:15:22 +02:00
|
|
|
|
return false;
|
|
|
|
|
default:
|
|
|
|
|
return Element::propertyDefault(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// UNDOABLE PROPERTY SETTERS
|
2012-08-10 20:50:27 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2012-08-11 01:15:22 +02:00
|
|
|
|
void FiguredBassItem::undoSetPrefix(Modifier pref)
|
2012-08-10 20:50:27 +02:00
|
|
|
|
{
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(pref <= Modifier::CROSS) {
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBPREFIX, (int)pref);
|
2012-08-12 13:39:25 +02:00
|
|
|
|
// if setting some prefix and there is a suffix already, clear suffix
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(pref != Modifier::NONE && _suffix != Modifier::NONE)
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBSUFFIX, int(Modifier::NONE));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
2012-08-12 13:39:25 +02:00
|
|
|
|
}
|
2012-08-10 20:50:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FiguredBassItem::undoSetDigit(int digit)
|
|
|
|
|
{
|
2012-08-14 14:58:43 +02:00
|
|
|
|
if(digit >= 0 && digit <= 9) {
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBDIGIT, digit);
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
|
|
|
|
}
|
2012-08-10 20:50:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 01:15:22 +02:00
|
|
|
|
void FiguredBassItem::undoSetSuffix(Modifier suff)
|
2012-08-10 20:50:27 +02:00
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBSUFFIX, int(suff));
|
2012-08-12 13:39:25 +02:00
|
|
|
|
// if setting some suffix and there is a prefix already, clear prefix
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if(suff != Modifier::NONE && _prefix != Modifier::NONE)
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBPREFIX, int(Modifier::NONE));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
2012-08-10 20:50:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-23 09:49:22 +02:00
|
|
|
|
void FiguredBassItem::undoSetContLine(ContLine val)
|
2012-08-10 20:50:27 +02:00
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBCONTINUATIONLINE, int(val));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FiguredBassItem::undoSetParenth1(Parenthesis par)
|
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBPARENTHESIS1, int(par));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
|
|
|
|
}
|
|
|
|
|
void FiguredBassItem::undoSetParenth2(Parenthesis par)
|
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBPARENTHESIS2, int(par));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
|
|
|
|
}
|
|
|
|
|
void FiguredBassItem::undoSetParenth3(Parenthesis par)
|
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBPARENTHESIS3, int(par));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
|
|
|
|
}
|
|
|
|
|
void FiguredBassItem::undoSetParenth4(Parenthesis par)
|
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBPARENTHESIS4, int(par));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
|
|
|
|
}
|
|
|
|
|
void FiguredBassItem::undoSetParenth5(Parenthesis par)
|
|
|
|
|
{
|
2014-05-26 18:18:01 +02:00
|
|
|
|
score()->undoChangeProperty(this, P_ID::FBPARENTHESIS5, int(par));
|
2012-08-14 14:58:43 +02:00
|
|
|
|
layout(); // re-generate displayText
|
2012-08-10 20:50:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 01:15:22 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// MusicXML I/O
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Convert MusicXML prefix/suffix to Modifier
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
FiguredBassItem::Modifier FiguredBassItem::MusicXML2Modifier(const QString prefix) const
|
2012-08-10 20:50:27 +02:00
|
|
|
|
{
|
2012-08-11 01:15:22 +02:00
|
|
|
|
if (prefix == "sharp")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::SHARP;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (prefix == "flat")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::FLAT;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (prefix == "natural")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::NATURAL;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (prefix == "double-sharp")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::DOUBLESHARP;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (prefix == "flat-flat")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::DOUBLEFLAT;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (prefix == "sharp-sharp")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::DOUBLESHARP;
|
2015-01-03 10:58:53 +01:00
|
|
|
|
else if (prefix == "cross")
|
|
|
|
|
return Modifier::CROSS;
|
|
|
|
|
else if (prefix == "backslash")
|
|
|
|
|
return Modifier::BACKSLASH;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (prefix == "slash")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::SLASH;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else
|
2014-05-22 22:21:56 +02:00
|
|
|
|
return Modifier::NONE;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Convert Modifier to MusicXML prefix/suffix
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
QString FiguredBassItem::Modifier2MusicXML(FiguredBassItem::Modifier prefix) const
|
|
|
|
|
{
|
|
|
|
|
switch (prefix) {
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::NONE: return "";
|
|
|
|
|
case Modifier::DOUBLEFLAT: return "flat-flat";
|
|
|
|
|
case Modifier::FLAT: return "flat";
|
|
|
|
|
case Modifier::NATURAL: return "natural";
|
|
|
|
|
case Modifier::SHARP: return "sharp";
|
|
|
|
|
case Modifier::DOUBLESHARP: return "double-sharp";
|
2015-01-03 10:58:53 +01:00
|
|
|
|
case Modifier::CROSS: return "cross";
|
|
|
|
|
case Modifier::BACKSLASH: return "backslash";
|
2014-05-22 22:21:56 +02:00
|
|
|
|
case Modifier::SLASH: return "slash";
|
|
|
|
|
case Modifier::NUMOF: return ""; // prevent gcc "‘FBINumOfAccid’ not handled in switch" warning
|
2012-08-11 01:15:22 +02:00
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Read MusicXML
|
|
|
|
|
//
|
|
|
|
|
// Set the FiguredBassItem state based on the MusicXML <figure> node de.
|
|
|
|
|
// In MusicXML, parentheses is set to "yes" or "no" for the figured-bass
|
|
|
|
|
// node instead of for each individual <figure> node.
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2013-01-17 11:33:11 +01:00
|
|
|
|
#if 0
|
2015-01-03 10:58:53 +01:00
|
|
|
|
void FiguredBassItem::readMusicXML(XmlReader& e, bool paren)
|
2012-08-11 01:15:22 +02:00
|
|
|
|
{
|
|
|
|
|
// read the <figure> node de
|
2013-01-11 18:10:18 +01:00
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
const QStringRef& tag(e.name());
|
2015-01-03 10:58:53 +01:00
|
|
|
|
if (tag == "figure-number") {
|
2012-08-11 01:15:22 +02:00
|
|
|
|
// MusicXML spec states figure-number is a number
|
|
|
|
|
// MuseScore can only handle single digit
|
2013-01-11 18:10:18 +01:00
|
|
|
|
int iVal = e.readInt();
|
2012-08-11 01:15:22 +02:00
|
|
|
|
if (1 <= iVal && iVal <= 9)
|
|
|
|
|
_digit = iVal;
|
|
|
|
|
}
|
|
|
|
|
else if (tag == "prefix")
|
2013-01-11 18:10:18 +01:00
|
|
|
|
_prefix = MusicXML2Modifier(e.readElementText());
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (tag == "suffix")
|
2013-01-11 18:10:18 +01:00
|
|
|
|
_suffix = MusicXML2Modifier(e.readElementText());
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
|
e.unknown();
|
2012-08-11 01:15:22 +02:00
|
|
|
|
}
|
|
|
|
|
// set parentheses
|
|
|
|
|
if (paren) {
|
|
|
|
|
// parenthesis open
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if (_prefix != Modifier::NONE)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[0] = Parenthesis::ROUNDOPEN; // before prefix
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (_digit != FBIDigitNone)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[1] = Parenthesis::ROUNDOPEN; // before digit
|
2014-05-22 22:21:56 +02:00
|
|
|
|
else if (_suffix != Modifier::NONE)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[2] = Parenthesis::ROUNDOPEN; // before suffix
|
2012-08-11 01:15:22 +02:00
|
|
|
|
// parenthesis close
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if (_suffix != Modifier::NONE)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[3] = Parenthesis::ROUNDCLOSED; // after suffix
|
2012-08-11 01:15:22 +02:00
|
|
|
|
else if (_digit != FBIDigitNone)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[2] = Parenthesis::ROUNDCLOSED; // after digit
|
2014-05-22 22:21:56 +02:00
|
|
|
|
else if (_prefix != Modifier::NONE)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
parenth[1] = Parenthesis::ROUNDCLOSED; // after prefix
|
2012-08-11 01:15:22 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-01-17 11:33:11 +01:00
|
|
|
|
#endif
|
2012-08-11 01:15:22 +02:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Write MusicXML
|
2015-01-03 10:58:53 +01:00
|
|
|
|
//
|
|
|
|
|
// Writes the portion within the <figure> tag.
|
2015-02-20 15:57:24 +01:00
|
|
|
|
//
|
2015-01-03 10:58:53 +01:00
|
|
|
|
// NOTE: Both MuseScore and MusicXML provide two ways of altering the (temporal) length of a
|
|
|
|
|
// figured bass object: extension lines and duration. The convention is that an EXTENSION is
|
|
|
|
|
// used if the figure lasts LONGER than the note (i.e., it "extends" to the following notes),
|
|
|
|
|
// whereas DURATION is used if the figure lasts SHORTER than the note (e.g., when notating a
|
|
|
|
|
// figure change under a note). However, MuseScore does not restrict durations in this way,
|
|
|
|
|
// allowing them to act as extensions themselves. As a result, a few more branches are
|
|
|
|
|
// required in the decision tree to handle everything correctly.
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBassItem::writeMusicXML(Xml& xml, bool isOriginalFigure, int crEndTick, int fbEndTick) const
|
2012-08-11 01:15:22 +02:00
|
|
|
|
{
|
|
|
|
|
xml.stag("figure");
|
2015-01-03 10:58:53 +01:00
|
|
|
|
|
|
|
|
|
// The first figure of each group is the "original" figure. Practically, it is one inserted manually
|
|
|
|
|
// by the user, rather than automatically by the "duration" extend method.
|
|
|
|
|
if (isOriginalFigure) {
|
2013-01-01 14:36:49 +01:00
|
|
|
|
QString strPrefix = Modifier2MusicXML(_prefix);
|
|
|
|
|
if (strPrefix != "")
|
|
|
|
|
xml.tag("prefix", strPrefix);
|
|
|
|
|
if (_digit != FBIDigitNone)
|
|
|
|
|
xml.tag("figure-number", _digit);
|
|
|
|
|
QString strSuffix = Modifier2MusicXML(_suffix);
|
|
|
|
|
if (strSuffix != "")
|
|
|
|
|
xml.tag("suffix", strSuffix);
|
2015-01-03 10:58:53 +01:00
|
|
|
|
|
|
|
|
|
// Check if the figure ends before or at the same time as the current note. Otherwise, the figure
|
|
|
|
|
// extends to the next note, and so carries an extension type "start" by definition.
|
|
|
|
|
if (fbEndTick <= crEndTick) {
|
|
|
|
|
if (_contLine == ContLine::SIMPLE)
|
|
|
|
|
xml.tagE("extend type=\"stop\" ");
|
|
|
|
|
else if (_contLine == ContLine::EXTENDED) {
|
|
|
|
|
bool hasFigure = (strPrefix != "" || _digit != FBIDigitNone || strSuffix != "");
|
|
|
|
|
if (hasFigure)
|
|
|
|
|
xml.tagE("extend type=\"start\" ");
|
|
|
|
|
else
|
|
|
|
|
xml.tagE("extend type=\"continue\" ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
xml.tagE("extend type=\"start\" ");
|
2013-01-01 14:36:49 +01:00
|
|
|
|
}
|
2015-01-03 10:58:53 +01:00
|
|
|
|
// If the figure is not "original", it must have been created using the "duration" feature of figured bass.
|
|
|
|
|
// In other words, the original figure belongs to a previous note rather than the current note.
|
|
|
|
|
else {
|
|
|
|
|
if (crEndTick < fbEndTick)
|
|
|
|
|
xml.tagE("extend type=\"continue\" ");
|
|
|
|
|
else
|
|
|
|
|
xml.tagE("extend type=\"stop\" ");
|
2013-01-01 14:36:49 +01:00
|
|
|
|
}
|
2012-08-11 01:15:22 +02:00
|
|
|
|
xml.etag();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// startsWithParenthesis
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool FiguredBassItem::startsWithParenthesis() const
|
|
|
|
|
{
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if (_prefix != Modifier::NONE)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return (parenth[0] != Parenthesis::NONE);
|
2012-08-11 01:15:22 +02:00
|
|
|
|
if (_digit != FBIDigitNone)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return (parenth[1] != Parenthesis::NONE);
|
2014-05-22 22:21:56 +02:00
|
|
|
|
if (_suffix != Modifier::NONE)
|
2014-05-23 08:24:41 +02:00
|
|
|
|
return (parenth[2] != Parenthesis::NONE);
|
2012-08-11 01:15:22 +02:00
|
|
|
|
return false;
|
2012-08-10 20:50:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// F I G U R E D B A S S
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
FiguredBass::FiguredBass(Score* s)
|
|
|
|
|
: Text(s)
|
|
|
|
|
{
|
2014-05-22 10:10:58 +02:00
|
|
|
|
setFlag(ElementFlag::ON_STAFF, true);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
setOnNote(true);
|
2014-05-30 10:13:29 +02:00
|
|
|
|
setTextStyleType(TextStyleType::FIGURED_BASS);
|
2014-05-26 15:31:36 +02:00
|
|
|
|
TextStyle st("Figured Bass", g_FBFonts[0].family, score()->styleD(StyleIdx::figuredBassFontSize),
|
2014-06-02 12:16:45 +02:00
|
|
|
|
false, false, false, AlignmentFlags::LEFT | AlignmentFlags::TOP, QPointF(0, score()->styleD(StyleIdx::figuredBassYOffset)), OffsetType::SPATIUM);
|
2012-08-10 01:24:19 +02:00
|
|
|
|
st.setSizeIsSpatiumDependent(true);
|
|
|
|
|
setTextStyle(st);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
setTicks(0);
|
|
|
|
|
items.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FiguredBass::FiguredBass(const FiguredBass& fb)
|
|
|
|
|
: Text(fb)
|
|
|
|
|
{
|
|
|
|
|
setOnNote(fb.onNote());
|
|
|
|
|
setTicks(fb.ticks());
|
2015-12-24 15:11:35 +01:00
|
|
|
|
for (auto i : fb.items) { // deep copy is needed
|
|
|
|
|
FiguredBassItem* fbi = new FiguredBassItem(*i);
|
|
|
|
|
fbi->setParent(this);
|
|
|
|
|
items.push_back(fbi);
|
|
|
|
|
}
|
2015-02-20 15:57:24 +01:00
|
|
|
|
// items = fb.items;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FiguredBass::~FiguredBass()
|
|
|
|
|
{
|
2014-04-21 00:46:40 +02:00
|
|
|
|
for (FiguredBassItem* item : items)
|
|
|
|
|
delete item;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// write
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBass::write(Xml& xml) const
|
|
|
|
|
{
|
2014-08-15 17:20:20 +02:00
|
|
|
|
if (!xml.canWrite(this))
|
|
|
|
|
return;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
xml.stag("FiguredBass");
|
|
|
|
|
if(!onNote())
|
|
|
|
|
xml.tag("onNote", onNote());
|
|
|
|
|
if (ticks() > 0)
|
|
|
|
|
xml.tag("ticks", ticks());
|
2014-06-11 10:46:35 +02:00
|
|
|
|
// if unparseable items, write full text data
|
|
|
|
|
if (items.size() < 1)
|
|
|
|
|
Text::writeProperties(xml, true);
|
|
|
|
|
else {
|
|
|
|
|
if (textStyleType() != TextStyleType::FIGURED_BASS)
|
|
|
|
|
// if all items parsed and not unstiled, we simply have a special style: write it
|
2013-08-10 00:36:15 +02:00
|
|
|
|
xml.tag("style", textStyle().name());
|
2014-06-11 10:46:35 +02:00
|
|
|
|
for(FiguredBassItem* item : items)
|
|
|
|
|
item->write(xml);
|
|
|
|
|
Element::writeProperties(xml);
|
2013-02-22 19:59:52 +01:00
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
xml.etag();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// read
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
|
void FiguredBass::read(XmlReader& e)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
|
QString normalizedText;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
int idx = 0;
|
2013-01-11 18:10:18 +01:00
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
const QStringRef& tag(e.name());
|
|
|
|
|
if (tag == "ticks")
|
|
|
|
|
setTicks(e.readInt());
|
2013-02-22 19:59:52 +01:00
|
|
|
|
else if (tag == "onNote")
|
2013-01-11 18:10:18 +01:00
|
|
|
|
setOnNote(e.readInt() != 0l);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "FiguredBassItem") {
|
|
|
|
|
FiguredBassItem * pItem = new FiguredBassItem(score(), idx++);
|
|
|
|
|
pItem->setTrack(track());
|
|
|
|
|
pItem->setParent(this);
|
|
|
|
|
pItem->read(e);
|
2014-04-21 00:46:40 +02:00
|
|
|
|
items.push_back(pItem);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// add item normalized text
|
|
|
|
|
if(!normalizedText.isEmpty())
|
|
|
|
|
normalizedText.append('\n');
|
|
|
|
|
normalizedText.append(pItem->normalizedText());
|
|
|
|
|
}
|
2013-08-10 00:36:15 +02:00
|
|
|
|
// else if (tag == "style")
|
|
|
|
|
// setTextStyleType(e.readElementText());
|
2013-02-22 19:59:52 +01:00
|
|
|
|
else if (!Text::readProperties(e))
|
2013-01-11 18:10:18 +01:00
|
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2014-03-14 11:30:19 +01:00
|
|
|
|
// if items could be parsed set normalized text
|
2014-06-11 10:46:35 +02:00
|
|
|
|
if (items.size() > 0)
|
2015-04-27 12:59:30 +02:00
|
|
|
|
setXmlText(normalizedText); // this is the text to show while editing
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// layout
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBass::layout()
|
|
|
|
|
{
|
2014-05-26 15:31:36 +02:00
|
|
|
|
qreal yOff = score()->styleD(StyleIdx::figuredBassYOffset);
|
2014-03-28 01:23:44 +01:00
|
|
|
|
qreal _sp = spatium();
|
2013-02-22 19:59:52 +01:00
|
|
|
|
// if 'our' style, force 'our' style data from FiguredBass parameters
|
2014-05-30 10:13:29 +02:00
|
|
|
|
if(textStyleType() == TextStyleType::FIGURED_BASS) {
|
2014-05-26 15:31:36 +02:00
|
|
|
|
TextStyle st("Figured Bass", g_FBFonts[0].family, score()->styleD(StyleIdx::figuredBassFontSize),
|
2014-06-02 12:16:45 +02:00
|
|
|
|
false, false, false, AlignmentFlags::LEFT | AlignmentFlags::TOP, QPointF(0, yOff),
|
2014-05-27 08:28:53 +02:00
|
|
|
|
OffsetType::SPATIUM);
|
2013-02-22 19:59:52 +01:00
|
|
|
|
st.setSizeIsSpatiumDependent(true);
|
|
|
|
|
setTextStyle(st);
|
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
2014-03-28 01:23:44 +01:00
|
|
|
|
// if in edit mode or if style has been changed,
|
|
|
|
|
// do nothing else, keeping default laying out and formatting
|
2014-06-11 10:46:35 +02:00
|
|
|
|
if(editMode() || items.size() < 1 || textStyleType() != TextStyleType::FIGURED_BASS) {
|
2014-03-28 01:23:44 +01:00
|
|
|
|
Text::layout();
|
2013-02-22 19:59:52 +01:00
|
|
|
|
return;
|
2014-03-28 01:23:44 +01:00
|
|
|
|
}
|
2013-08-10 00:36:15 +02:00
|
|
|
|
|
2014-03-28 01:23:44 +01:00
|
|
|
|
// VERTICAL POSITION:
|
|
|
|
|
yOff *= _sp; // convert spatium value to raster units
|
|
|
|
|
setPos(QPointF(0.0, yOff));
|
|
|
|
|
|
|
|
|
|
// BOUNDING BOX and individual item layout (if requried)
|
|
|
|
|
createLayout(); // prepare structs and data expected by Text methods
|
|
|
|
|
// if element could be parsed into items, layout each element
|
|
|
|
|
if(items.size() > 0) {
|
|
|
|
|
layoutLines();
|
|
|
|
|
bbox().setRect(0, 0, _lineLenghts.at(0), 0);
|
|
|
|
|
// layout each item and enlarge bbox to include items bboxes
|
2014-04-21 00:46:40 +02:00
|
|
|
|
for(FiguredBassItem* item : items) {
|
|
|
|
|
item->layout();
|
|
|
|
|
addbbox(item->bbox().translated(item->pos()));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-28 01:23:44 +01:00
|
|
|
|
adjustReadPos();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// layoutLines
|
|
|
|
|
//
|
|
|
|
|
// lays out the duration indicator line(s), filling the _lineLengths array
|
2014-03-28 01:23:44 +01:00
|
|
|
|
// and the length of printed lines (used by continuation lines)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBass::layoutLines()
|
|
|
|
|
{
|
2015-12-23 16:44:02 +01:00
|
|
|
|
if(_ticks <= 0 || segment() == nullptr) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
NoLen:
|
2014-03-28 01:23:44 +01:00
|
|
|
|
_lineLenghts.resize(1); // be sure to always have
|
|
|
|
|
_lineLenghts[0] = 0; // at least 1 item in array
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2013-03-01 13:42:05 +01:00
|
|
|
|
|
|
|
|
|
ChordRest * lastCR; // the last ChordRest of this
|
2012-05-26 14:26:10 +02:00
|
|
|
|
Segment * nextSegm; // the Segment beyond this' segment
|
|
|
|
|
int nextTick = segment()->tick() + _ticks; // the tick beyond this' duration
|
|
|
|
|
|
|
|
|
|
// locate the measure containing the last tick of this; it is either:
|
|
|
|
|
// the same measure containing nextTick, if nextTick is not the first tick of a measure
|
|
|
|
|
// (and line should stop right before it)
|
|
|
|
|
// or the previous measure, if nextTick is the first tick of a measure
|
|
|
|
|
// (and line should stop before any measure terminal segment (bar, clef, ...) )
|
|
|
|
|
Measure* m = score()->tick2measure(nextTick-1);
|
|
|
|
|
if (m != 0) {
|
|
|
|
|
// locate the first segment (of ANY type) right after this' last tick
|
2014-06-25 11:46:10 +02:00
|
|
|
|
for (nextSegm = m->first(Segment::Type::All); nextSegm; ) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
if(nextSegm->tick() >= nextTick)
|
|
|
|
|
break;
|
2012-08-03 15:54:02 +02:00
|
|
|
|
nextSegm = nextSegm->next();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2013-03-01 13:42:05 +01:00
|
|
|
|
// locate the last ChordRest of this
|
|
|
|
|
if (nextSegm)
|
|
|
|
|
lastCR = nextSegm->prev1()->nextChordRest(track(), true);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
if (m == 0 || nextSegm == 0) {
|
2014-03-25 13:33:47 +01:00
|
|
|
|
qDebug("FiguredBass layout: no segment found for tick %d", nextTick);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
goto NoLen;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-01 13:42:05 +01:00
|
|
|
|
// get length of printed lines from horiz. page position of lastCR
|
|
|
|
|
// (enter a bit 'into' the ChordRest for clarity)
|
2014-08-20 18:42:50 +02:00
|
|
|
|
_printedLineLength = lastCR ? lastCR->pageX() - pageX() + 1.5*spatium() : 3 * spatium();
|
2013-03-01 13:42:05 +01:00
|
|
|
|
|
|
|
|
|
// get duration indicator line(s) from page position of nextSegm
|
2016-02-04 11:27:47 +01:00
|
|
|
|
const QList<System*>& systems = score()->systems();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
System* s1 = segment()->measure()->system();
|
|
|
|
|
System* s2 = nextSegm->measure()->system();
|
2016-02-04 11:27:47 +01:00
|
|
|
|
int sysIdx1 = systems.indexOf(s1);
|
|
|
|
|
int sysIdx2 = systems.indexOf(s2);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
int i, len ,segIdx;
|
|
|
|
|
for (i = sysIdx1, segIdx = 0; i <= sysIdx2; ++i, ++segIdx) {
|
|
|
|
|
len = 0;
|
|
|
|
|
if (sysIdx1 == sysIdx2 || i == sysIdx1) {
|
|
|
|
|
// single line
|
|
|
|
|
len = nextSegm->pageX() - pageX() - 4; // stop 4 raster units before next segm
|
|
|
|
|
}
|
|
|
|
|
else if (i == sysIdx1) {
|
|
|
|
|
// initial line
|
|
|
|
|
qreal w = s1->staff(staffIdx())->right();
|
|
|
|
|
qreal x = s1->pageX() + w;
|
|
|
|
|
len = x - pageX();
|
|
|
|
|
}
|
|
|
|
|
else if (i > 0 && i != sysIdx2) {
|
|
|
|
|
// middle line
|
|
|
|
|
qDebug("FiguredBass: duration indicator middle line not implemented");
|
|
|
|
|
}
|
|
|
|
|
else if (i == sysIdx2) {
|
|
|
|
|
// end line
|
|
|
|
|
qDebug("FiguredBass: duration indicator end line not implemented");
|
|
|
|
|
}
|
|
|
|
|
// store length item, reusing array items if already present
|
|
|
|
|
if (_lineLenghts.size() <= segIdx)
|
|
|
|
|
_lineLenghts.append(len);
|
|
|
|
|
else
|
|
|
|
|
_lineLenghts[segIdx] = len;
|
|
|
|
|
}
|
|
|
|
|
// if more array items than needed, truncate array
|
|
|
|
|
if(_lineLenghts.size() > segIdx)
|
|
|
|
|
_lineLenghts.resize(segIdx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// draw
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBass::draw(QPainter* painter) const
|
|
|
|
|
{
|
2014-03-28 11:23:01 +01:00
|
|
|
|
// if not printing, draw duration line(s)
|
|
|
|
|
if( !score()->printing() ) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
foreach(qreal len, _lineLenghts)
|
|
|
|
|
if(len > 0) {
|
|
|
|
|
painter->setPen(QPen(Qt::lightGray, 1));
|
|
|
|
|
painter->drawLine(0.0, -2, len, -2); // -2: 2 rast. un. above digits
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-28 01:23:44 +01:00
|
|
|
|
// if in edit mode or with custom style, use standard text drawing
|
2014-05-30 10:13:29 +02:00
|
|
|
|
if(editMode() || textStyleType() != TextStyleType::FIGURED_BASS)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
Text::draw(painter);
|
2014-03-28 01:23:44 +01:00
|
|
|
|
// not edit mode:
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else {
|
2014-03-28 01:23:44 +01:00
|
|
|
|
if(items.size() < 1) // if not parseable into f.b. items
|
|
|
|
|
Text::draw(painter); // draw as standard text
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else
|
2014-04-21 00:46:40 +02:00
|
|
|
|
for(FiguredBassItem* item : items) { // if parseable into f.b. items
|
|
|
|
|
painter->translate(item->pos()); // draw each item in its proper position
|
|
|
|
|
item->draw(painter);
|
|
|
|
|
painter->translate(-item->pos());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* DEBUG
|
|
|
|
|
QString str = QString();
|
|
|
|
|
str.setNum(_ticks);
|
|
|
|
|
painter->drawText(0, (_onNote ? 40 : 30), str);
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
2014-03-28 01:23:44 +01:00
|
|
|
|
// startEdit / edit / endEdit
|
2012-05-26 14:26:10 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2014-03-28 01:23:44 +01:00
|
|
|
|
void FiguredBass::startEdit(MuseScoreView * msv, const QPointF & pt)
|
|
|
|
|
{
|
|
|
|
|
Text::layout(); // convert layout to standard Text conventions
|
|
|
|
|
Text::startEdit(msv, pt);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
void FiguredBass::endEdit()
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
Text::endEdit();
|
2014-03-28 01:23:44 +01:00
|
|
|
|
// as the standard text editor keeps inserting spurious HTML formatting and styles
|
|
|
|
|
// retrieve and work only on the plain text
|
|
|
|
|
QString txt = plainText();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
if(txt.isEmpty()) { // if no text, nothing to do
|
2015-04-27 12:59:30 +02:00
|
|
|
|
setXmlText(txt); // clear the stored text: the empty f.b. element will be deleted
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// split text into lines and create an item for each line
|
|
|
|
|
QStringList list = txt.split('\n', QString::SkipEmptyParts);
|
|
|
|
|
items.clear();
|
|
|
|
|
QString normalizedText = QString();
|
|
|
|
|
idx = 0;
|
|
|
|
|
foreach(QString str, list) {
|
|
|
|
|
FiguredBassItem* pItem = new FiguredBassItem(score(), idx++);
|
|
|
|
|
if(!pItem->parse(str)) { // if any item fails parsing
|
|
|
|
|
items.clear(); // clear item list
|
|
|
|
|
Text::layout(); // keeping text as entered by user
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pItem->setTrack(track());
|
|
|
|
|
pItem->setParent(this);
|
2014-04-21 00:46:40 +02:00
|
|
|
|
items.push_back(pItem);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
// add item normalized text
|
|
|
|
|
if(!normalizedText.isEmpty())
|
|
|
|
|
normalizedText.append('\n');
|
|
|
|
|
normalizedText.append(pItem->normalizedText());
|
|
|
|
|
}
|
2013-02-22 19:59:52 +01:00
|
|
|
|
// if all items parsed and text is styled, replaced entered text with normalized text
|
2014-03-14 11:30:19 +01:00
|
|
|
|
if (items.size()) {
|
2015-04-27 12:59:30 +02:00
|
|
|
|
setXmlText(normalizedText);
|
2013-02-22 19:59:52 +01:00
|
|
|
|
layout();
|
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// setSelected /setVisible
|
|
|
|
|
//
|
|
|
|
|
// forward flags to items
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void FiguredBass::setSelected(bool flag)
|
|
|
|
|
{
|
|
|
|
|
Element::setSelected(flag);
|
2014-04-21 00:46:40 +02:00
|
|
|
|
for(FiguredBassItem* item : items) {
|
|
|
|
|
item->setSelected(flag);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FiguredBass::setVisible(bool flag)
|
|
|
|
|
{
|
|
|
|
|
Element::setVisible(flag);
|
2014-04-21 00:46:40 +02:00
|
|
|
|
for(FiguredBassItem* item : items) {
|
|
|
|
|
item->setVisible(flag);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-12 16:00:05 +01:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// nextFiguredBass
|
|
|
|
|
//
|
|
|
|
|
// returns the next *contiguous* FiguredBass element if it exists,
|
|
|
|
|
// i.e. the FiguredBass element which starts where 'this' ends
|
|
|
|
|
// returns 0 if none
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
FiguredBass* FiguredBass::nextFiguredBass() const
|
|
|
|
|
{
|
|
|
|
|
if (_ticks <= 0) // if _ticks unset, no clear idea of when 'this' ends
|
|
|
|
|
return 0;
|
|
|
|
|
Segment * nextSegm; // the Segment beyond this' segment
|
|
|
|
|
int nextTick = segment()->tick() + _ticks; // the tick beyond this' duration
|
|
|
|
|
|
|
|
|
|
// locate the ChordRest segment right after this' end
|
2014-06-25 11:46:10 +02:00
|
|
|
|
nextSegm = score()->tick2segment(nextTick, true, Segment::Type::ChordRest);
|
2013-02-12 16:00:05 +01:00
|
|
|
|
if (nextSegm == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// scan segment annotations for an existing FB element in the this' staff
|
2013-05-06 14:20:31 +02:00
|
|
|
|
for (Element* e : nextSegm->annotations())
|
2014-06-24 18:36:02 +02:00
|
|
|
|
if (e->type() == Element::Type::FIGURED_BASS && e->track() == track())
|
2013-05-06 14:20:31 +02:00
|
|
|
|
return static_cast<FiguredBass*>(e);
|
2013-02-12 16:00:05 +01:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// additionalContLineX
|
|
|
|
|
//
|
|
|
|
|
// if there is a continuation line, without other text elements, at pagePosY, returns its X coord (in page coords)
|
|
|
|
|
// returns 0 if no cont.line there or if there are text elements before the cont.line
|
|
|
|
|
//
|
|
|
|
|
// In practice, returns the X coord of a cont. line which can be the continuation of a previous cont. line
|
|
|
|
|
//
|
|
|
|
|
// Note: pagePosY is the Y coord of the FiguredBassItem containing the line, not of the line itself,
|
|
|
|
|
// as line position might depend on styles.
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
qreal FiguredBass::additionalContLineX(qreal pagePosY) const
|
|
|
|
|
{
|
|
|
|
|
QPointF pgPos = pagePos();
|
2014-04-21 00:46:40 +02:00
|
|
|
|
for (FiguredBassItem* fbi : items)
|
2013-02-12 16:00:05 +01:00
|
|
|
|
// if item has cont.line but nothing before it
|
|
|
|
|
// and item Y coord near enough to pagePosY
|
2014-05-23 09:49:22 +02:00
|
|
|
|
if(fbi->contLine() != FiguredBassItem::ContLine::NONE
|
2014-04-21 00:46:40 +02:00
|
|
|
|
&& fbi->digit() == FBIDigitNone
|
2014-05-22 22:21:56 +02:00
|
|
|
|
&& fbi->prefix() == FiguredBassItem::Modifier::NONE
|
|
|
|
|
&& fbi->suffix() == FiguredBassItem::Modifier::NONE
|
2014-05-23 08:24:41 +02:00
|
|
|
|
&& fbi->parenth4() == FiguredBassItem::Parenthesis::NONE
|
2014-04-21 00:46:40 +02:00
|
|
|
|
&& qAbs(pgPos.y() + fbi->ipos().y() - pagePosY) < 0.05)
|
|
|
|
|
return pgPos.x() + fbi->ipos().x();
|
2013-02-12 16:00:05 +01:00
|
|
|
|
|
|
|
|
|
return 0.0; // no suitable line
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 01:15:22 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// PROPERTY METHODS
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
QVariant FiguredBass::getProperty(P_ID propertyId) const
|
|
|
|
|
{
|
|
|
|
|
switch(propertyId) {
|
|
|
|
|
default:
|
|
|
|
|
return Text::getProperty(propertyId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FiguredBass::setProperty(P_ID propertyId, const QVariant& v)
|
|
|
|
|
{
|
|
|
|
|
score()->addRefresh(canvasBoundingRect());
|
|
|
|
|
switch(propertyId) {
|
|
|
|
|
default:
|
|
|
|
|
return Text::setProperty(propertyId, v);
|
|
|
|
|
}
|
|
|
|
|
score()->setLayoutAll(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant FiguredBass::propertyDefault(P_ID id) const
|
|
|
|
|
{
|
|
|
|
|
switch(id) {
|
|
|
|
|
default:
|
|
|
|
|
return Text::propertyDefault(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// TEMPORARY HACK!!!
|
|
|
|
|
//---------------------------------------------------------
|
2014-07-06 01:56:30 +02:00
|
|
|
|
/*
|
2012-08-11 01:15:22 +02:00
|
|
|
|
FiguredBassItem * FiguredBass::addItem()
|
|
|
|
|
{
|
|
|
|
|
int line = items.size();
|
2014-04-21 00:46:40 +02:00
|
|
|
|
FiguredBassItem* fib = new FiguredBassItem(score(), line);
|
2014-07-06 01:56:30 +02:00
|
|
|
|
// tell QML not to garbage collect this item
|
|
|
|
|
QQmlEngine::setObjectOwnership(fib, QQmlEngine::CppOwnership);
|
2014-04-21 00:46:40 +02:00
|
|
|
|
items.push_back(fib);
|
|
|
|
|
return fib;
|
2012-08-11 01:15:22 +02:00
|
|
|
|
}
|
2014-07-06 01:56:30 +02:00
|
|
|
|
*/
|
2012-05-26 14:26:10 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// STATIC FUNCTION
|
|
|
|
|
// adding a new FiguredBass to a Segment;
|
|
|
|
|
// the main purpose of this function is to ensure that ONLY ONE F.b. element exists for each Segment/staff;
|
2015-01-03 10:58:53 +01:00
|
|
|
|
// it either re-uses an existing FiguredBass or creates a new one if none is found;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// returns the FiguredBass and sets pNew to true if it has been newly created.
|
|
|
|
|
//
|
|
|
|
|
// Sets an initial duration of the element up to the next ChordRest of the same staff.
|
|
|
|
|
//
|
|
|
|
|
// As the F.b. very concept requires the base chord to have ONLY ONE note,
|
|
|
|
|
// FiguredBass elements are created and looked for only in the first track of the staff.
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
FiguredBass * FiguredBass::addFiguredBassToSegment(Segment * seg, int track, int extTicks, bool * pNew)
|
|
|
|
|
{
|
|
|
|
|
int endTick; // where this FB is initially assumed to end
|
|
|
|
|
int staff = track / VOICES; // convert track to staff
|
|
|
|
|
track = staff * VOICES; // first track for this staff
|
|
|
|
|
|
|
|
|
|
// scan segment annotations for an existing FB element in the same staff
|
2013-05-06 14:20:31 +02:00
|
|
|
|
FiguredBass* fb = 0;
|
|
|
|
|
for (Element* e : seg->annotations()) {
|
2014-06-24 18:36:02 +02:00
|
|
|
|
if (e->type() == Element::Type::FIGURED_BASS && (e->track() / VOICES) == staff) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// an FB already exists in segment: re-use it
|
2013-05-06 14:20:31 +02:00
|
|
|
|
fb = static_cast<FiguredBass*>(e);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
*pNew = false;
|
|
|
|
|
endTick = seg->tick() + fb->ticks();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-05-06 14:20:31 +02:00
|
|
|
|
if (fb == 0) { // no FB at segment: create new
|
2012-05-26 14:26:10 +02:00
|
|
|
|
fb = new FiguredBass(seg->score());
|
|
|
|
|
fb->setTrack(track);
|
|
|
|
|
fb->setParent(seg);
|
|
|
|
|
|
|
|
|
|
// locate next SegChordRest in the same staff to estimate presumed duration of element
|
|
|
|
|
endTick = INT_MAX;
|
|
|
|
|
Segment * nextSegm;
|
|
|
|
|
for (int iVoice = 0; iVoice < VOICES; iVoice++) {
|
|
|
|
|
nextSegm = seg->nextCR(track + iVoice);
|
|
|
|
|
if(nextSegm && nextSegm->tick() < endTick)
|
|
|
|
|
endTick = nextSegm->tick();
|
|
|
|
|
}
|
|
|
|
|
if(endTick == INT_MAX) { // no next segment: set up to score end
|
|
|
|
|
Measure * meas = seg->score()->lastMeasure();
|
|
|
|
|
endTick = meas->tick() + meas->ticks();
|
|
|
|
|
}
|
|
|
|
|
fb->setTicks(endTick - seg->tick());
|
|
|
|
|
|
|
|
|
|
// set onNote status
|
|
|
|
|
fb->setOnNote(false); // assume not onNote
|
2013-05-06 14:20:31 +02:00
|
|
|
|
for (int i = track; i < track + VOICES; i++) // if segment has chord in staff, set onNote
|
2014-06-24 18:36:02 +02:00
|
|
|
|
if (seg->element(i) && seg->element(i)->type() == Element::Type::CHORD) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
fb->setOnNote(true);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
*pNew = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we are extending a previous FB
|
|
|
|
|
if(extTicks > 0) {
|
|
|
|
|
// locate previous FB for same staff
|
|
|
|
|
Segment * prevSegm;
|
|
|
|
|
FiguredBass* prevFB = 0;
|
2014-06-25 11:46:10 +02:00
|
|
|
|
for(prevSegm = seg->prev1(Segment::Type::ChordRest); prevSegm; prevSegm = prevSegm->prev1(Segment::Type::ChordRest)) {
|
2013-05-06 14:20:31 +02:00
|
|
|
|
for (Element* e : prevSegm->annotations()) {
|
2014-06-24 18:36:02 +02:00
|
|
|
|
if (e->type() == Element::Type::FIGURED_BASS && (e->track() ) == track) {
|
2013-05-06 14:20:31 +02:00
|
|
|
|
prevFB = static_cast<FiguredBass*>(e); // previous FB found
|
2012-05-26 14:26:10 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(prevFB) {
|
|
|
|
|
// if previous FB did not stop more than extTicks before this FB...
|
|
|
|
|
int delta = seg->tick() - prevFB->segment()->tick();
|
|
|
|
|
if(prevFB->ticks() + extTicks >= delta)
|
|
|
|
|
prevFB->setTicks(delta); // update prev FB ticks to last up to this FB
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return fb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// STATIC FUNCTIONS FOR FONT CONFIGURATION MANAGEMENT
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
|
bool FiguredBassFont::read(XmlReader& e)
|
|
|
|
|
{
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
const QStringRef& tag(e.name());
|
2013-02-10 07:01:31 +01:00
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
if (tag == "family")
|
2013-01-11 18:10:18 +01:00
|
|
|
|
family = e.readElementText();
|
|
|
|
|
else if (tag == "displayName")
|
|
|
|
|
displayName = e.readElementText();
|
|
|
|
|
else if (tag == "defaultPitch")
|
|
|
|
|
defPitch = e.readDouble();
|
|
|
|
|
else if (tag == "defaultLineHeight")
|
|
|
|
|
defLineHeight = e.readDouble();
|
|
|
|
|
else if (tag == "parenthesisRoundOpen")
|
|
|
|
|
displayParenthesis[1] = e.readElementText()[0];
|
|
|
|
|
else if (tag == "parenthesisRoundClosed")
|
|
|
|
|
displayParenthesis[2] = e.readElementText()[0];
|
|
|
|
|
else if (tag == "parenthesisSquareOpen")
|
|
|
|
|
displayParenthesis[3] = e.readElementText()[0];
|
|
|
|
|
else if (tag == "parenthesisSquareClosed")
|
|
|
|
|
displayParenthesis[4] = e.readElementText()[0];
|
|
|
|
|
else if (tag == "doubleflat")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::DOUBLEFLAT)]= e.readElementText()[0];
|
2013-01-11 18:10:18 +01:00
|
|
|
|
else if (tag == "flat")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::FLAT)] = e.readElementText()[0];
|
2013-01-11 18:10:18 +01:00
|
|
|
|
else if (tag == "natural")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::NATURAL)] = e.readElementText()[0];
|
2013-01-11 18:10:18 +01:00
|
|
|
|
else if (tag == "sharp")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::SHARP)] = e.readElementText()[0];
|
2013-01-11 18:10:18 +01:00
|
|
|
|
else if (tag == "doublesharp")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::DOUBLESHARP)]= e.readElementText()[0];
|
2013-02-10 07:01:31 +01:00
|
|
|
|
else if (tag == "cross")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::CROSS)] = e.readElementText()[0];
|
2013-02-10 07:01:31 +01:00
|
|
|
|
else if (tag == "backslash")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::BACKSLASH)] = e.readElementText()[0];
|
2013-02-10 07:01:31 +01:00
|
|
|
|
else if (tag == "slash")
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayAccidental[int(FiguredBassItem::Modifier::SLASH)] = e.readElementText()[0];
|
2013-01-11 18:10:18 +01:00
|
|
|
|
else if (tag == "digit") {
|
|
|
|
|
int digit = e.intAttribute("value");
|
2013-02-10 07:01:31 +01:00
|
|
|
|
if (digit < 0 || digit > 9)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return false;
|
2013-01-11 18:10:18 +01:00
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
if (tag == "simple")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::MODERN)] [digit][int(FiguredBassItem::Combination::SIMPLE)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "crossed")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::MODERN)] [digit][int(FiguredBassItem::Combination::CROSSED)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "backslashed")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::MODERN)] [digit][int(FiguredBassItem::Combination::BACKSLASHED)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "slashed")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::MODERN)] [digit][int(FiguredBassItem::Combination::SLASHED)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "simpleHistoric")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::HISTORIC)][digit][int(FiguredBassItem::Combination::SIMPLE)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "crossedHistoric")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::HISTORIC)][digit][int(FiguredBassItem::Combination::CROSSED)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "backslashedHistoric")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::HISTORIC)][digit][int(FiguredBassItem::Combination::BACKSLASHED)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else if (tag == "slashedHistoric")
|
2014-05-23 11:45:32 +02:00
|
|
|
|
displayDigit[int(FiguredBassItem::Style::HISTORIC)][digit][int(FiguredBassItem::Combination::SLASHED)] = e.readElementText()[0];
|
2012-05-26 14:26:10 +02:00
|
|
|
|
else {
|
2013-01-11 18:10:18 +01:00
|
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-01-11 18:10:18 +01:00
|
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-22 22:21:56 +02:00
|
|
|
|
displayParenthesis[0] = displayAccidental[int(FiguredBassItem::Modifier::NONE)] = ' ';
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return true;
|
2013-01-11 18:10:18 +01:00
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Read Configuration File
|
|
|
|
|
//
|
2013-02-10 07:01:31 +01:00
|
|
|
|
// reads a configuration and appends read data to g_FBFonts
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// resets everythings and reads the built-in config file if fileName is null or empty
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool FiguredBass::readConfigFile(const QString& fileName)
|
2013-01-11 18:10:18 +01:00
|
|
|
|
{
|
2012-05-26 14:26:10 +02:00
|
|
|
|
QString path;
|
|
|
|
|
|
|
|
|
|
if(fileName == 0 || fileName.isEmpty()) { // defaults to built-in xml
|
2013-05-16 16:12:22 +02:00
|
|
|
|
#ifdef Q_OS_IOS
|
2012-07-25 17:37:32 +02:00
|
|
|
|
{
|
|
|
|
|
extern QString resourcePath();
|
|
|
|
|
QString rpath = resourcePath();
|
|
|
|
|
path = rpath + QString("/fonts_figuredbass.xml");
|
|
|
|
|
}
|
|
|
|
|
#else
|
2012-05-26 14:26:10 +02:00
|
|
|
|
path = ":/fonts/fonts_figuredbass.xml";
|
2012-07-25 17:37:32 +02:00
|
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
|
g_FBFonts.clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
path = fileName;
|
|
|
|
|
|
|
|
|
|
QFile f(path);
|
2013-01-11 18:10:18 +01:00
|
|
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
2014-08-16 14:37:18 +02:00
|
|
|
|
MScore::lastError = tr("Cannot open figured bass description:\n%1\n%2").arg(f.fileName()).arg(f.errorString());
|
|
|
|
|
qDebug("FiguredBass::read failed: <%s>", qPrintable(path));
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2013-01-11 18:10:18 +01:00
|
|
|
|
XmlReader e(&f);
|
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
if (e.name() == "museScore") {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
// QString version = e.attribute(QString("version"));
|
|
|
|
|
// QStringList sl = version.split('.');
|
|
|
|
|
// int _mscVersion = sl[0].toInt() * 100 + sl[1].toInt();
|
|
|
|
|
|
2013-01-11 18:10:18 +01:00
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
if (e.name() == "font") {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
FiguredBassFont f;
|
2013-01-11 18:10:18 +01:00
|
|
|
|
if (f.read(e))
|
2012-05-26 14:26:10 +02:00
|
|
|
|
g_FBFonts.append(f);
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
2013-01-11 18:10:18 +01:00
|
|
|
|
e.unknown();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2013-01-11 18:10:18 +01:00
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Get Font Names
|
|
|
|
|
//
|
|
|
|
|
// returns a list of display names for the fonts configured to work with Figured Bass;
|
|
|
|
|
// the index of a name in the list can be used to retrieve the font data with fontData()
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
QList<QString> FiguredBass::fontNames()
|
|
|
|
|
{
|
|
|
|
|
QList<QString> names;
|
|
|
|
|
foreach(const FiguredBassFont& f, g_FBFonts)
|
|
|
|
|
names.append(f.displayName);
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Get Font Data
|
|
|
|
|
//
|
|
|
|
|
// retrieves data about a Figured Bass font.
|
|
|
|
|
// returns: true if idx is valid | false if it is not
|
|
|
|
|
// any of the pointer parameter can be null, if that datum is not needed
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool FiguredBass::fontData(int nIdx, QString * pFamily, QString * pDisplayName,
|
|
|
|
|
qreal * pSize, qreal * pLineHeight)
|
|
|
|
|
{
|
|
|
|
|
if(nIdx >= 0 && nIdx < g_FBFonts.size()) {
|
|
|
|
|
FiguredBassFont f = g_FBFonts.at(nIdx);
|
|
|
|
|
if(pFamily) *pFamily = f.family;
|
|
|
|
|
if(pDisplayName) *pDisplayName = f.displayName;
|
|
|
|
|
if(pSize) *pSize = f.defPitch;
|
|
|
|
|
if(pLineHeight) *pLineHeight = f.defLineHeight;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 01:15:22 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// MusicXML I/O
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2012-05-26 14:26:10 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Read MusicXML
|
|
|
|
|
//
|
|
|
|
|
// Set the FiguredBass state based on the MusicXML <figured-bass> node de.
|
|
|
|
|
// Note that onNote and ticks must be set by the MusicXML importer,
|
|
|
|
|
// as the required context is not present in the items DOM tree.
|
|
|
|
|
// Exception: if a <duration> element is present, tick can be set.
|
2013-01-01 14:36:49 +01:00
|
|
|
|
// Return true if valid, non-empty figure(s) are found
|
2012-05-26 14:26:10 +02:00
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2013-01-17 11:33:11 +01:00
|
|
|
|
#if 0
|
2015-01-03 10:58:53 +01:00
|
|
|
|
bool FiguredBass::readMusicXML(XmlReader& e, int divisions)
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
2013-01-11 18:10:18 +01:00
|
|
|
|
bool parentheses = e.attribute("parentheses") == "yes";
|
2012-05-26 14:26:10 +02:00
|
|
|
|
QString normalizedText;
|
|
|
|
|
int idx = 0;
|
2013-01-11 18:10:18 +01:00
|
|
|
|
while (e.readNextStartElement()) {
|
|
|
|
|
const QStringRef& tag(e.name());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
if (tag == "duration") {
|
2013-01-11 18:10:18 +01:00
|
|
|
|
QString val(e.readElementText());
|
2012-05-26 14:26:10 +02:00
|
|
|
|
bool ok = true;
|
|
|
|
|
int duration = val.toInt(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
duration *= MScore::division;
|
|
|
|
|
duration /= divisions;
|
|
|
|
|
setTicks(duration);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
qDebug("MusicXml-Import: bad duration value: <%s>",
|
|
|
|
|
qPrintable(val));
|
|
|
|
|
}
|
|
|
|
|
else if (tag == "figure") {
|
|
|
|
|
FiguredBassItem * pItem = new FiguredBassItem(score(), idx++);
|
|
|
|
|
pItem->setTrack(track());
|
|
|
|
|
pItem->setParent(this);
|
2015-01-03 10:58:53 +01:00
|
|
|
|
pItem->readMusicXML(e, parentheses);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
items.append(*pItem);
|
|
|
|
|
// add item normalized text
|
2013-01-11 18:10:18 +01:00
|
|
|
|
if (!normalizedText.isEmpty())
|
2012-05-26 14:26:10 +02:00
|
|
|
|
normalizedText.append('\n');
|
|
|
|
|
normalizedText.append(pItem->normalizedText());
|
|
|
|
|
}
|
2013-01-01 14:36:49 +01:00
|
|
|
|
else {
|
2013-01-11 18:10:18 +01:00
|
|
|
|
e.unknown();
|
2013-01-01 14:36:49 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
setText(normalizedText); // this is the text to show while editing
|
2013-01-01 14:36:49 +01:00
|
|
|
|
bool res = !normalizedText.isEmpty();
|
|
|
|
|
return res;
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
2013-01-17 11:33:11 +01:00
|
|
|
|
#endif
|
2012-05-26 14:26:10 +02:00
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// hasParentheses
|
|
|
|
|
//
|
|
|
|
|
// return true if any FiguredBassItem starts with a parenthesis
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool FiguredBass::hasParentheses() const
|
|
|
|
|
{
|
2014-04-21 00:46:40 +02:00
|
|
|
|
for(FiguredBassItem* item : items)
|
|
|
|
|
if (item->startsWithParenthesis())
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Write MusicXML
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
2015-01-03 10:58:53 +01:00
|
|
|
|
void FiguredBass::writeMusicXML(Xml& xml, bool isOriginalFigure, int crEndTick, int fbEndTick, bool writeDuration, int divisions) const
|
2012-05-26 14:26:10 +02:00
|
|
|
|
{
|
2015-01-03 10:58:53 +01:00
|
|
|
|
QString stag = "figured-bass";
|
|
|
|
|
if (hasParentheses())
|
|
|
|
|
stag += " parentheses=\"yes\"";
|
|
|
|
|
xml.stag(stag);
|
|
|
|
|
for(FiguredBassItem* item : items)
|
|
|
|
|
item->writeMusicXML(xml, isOriginalFigure, crEndTick, fbEndTick);
|
|
|
|
|
if (writeDuration)
|
|
|
|
|
xml.tag("duration", ticks() / divisions);
|
|
|
|
|
xml.etag();
|
2012-05-26 14:26:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// METHODS BELONGING TO OTHER CLASSES
|
|
|
|
|
//
|
|
|
|
|
// Work In Progress: kept here until the FiguredBass framwork is reasonably set up;
|
|
|
|
|
// To be finally moved to their respective class implementation files.
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
// Score::addFiguredBass
|
|
|
|
|
// called from Keyboard Accelerator & menus
|
|
|
|
|
//---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FiguredBass* Score::addFiguredBass()
|
|
|
|
|
{
|
|
|
|
|
Element* el = selection().element();
|
2014-06-24 18:36:02 +02:00
|
|
|
|
if (el == 0 || (el->type() != Element::Type::NOTE && el->type() != Element::Type::FIGURED_BASS)) {
|
2014-02-28 12:49:24 +01:00
|
|
|
|
if (!MScore::noGui)
|
|
|
|
|
QMessageBox::information(0,
|
2014-03-06 11:32:09 +01:00
|
|
|
|
QMessageBox::tr("MuseScore"),
|
2014-02-28 12:49:24 +01:00
|
|
|
|
QMessageBox::tr("No note or figured bass selected:\n"
|
2014-08-22 16:25:50 +02:00
|
|
|
|
"Please select a single note or figured bass and retry.\n"),
|
2014-02-28 12:49:24 +01:00
|
|
|
|
QMessageBox::Ok, QMessageBox::NoButton);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FiguredBass * fb;
|
|
|
|
|
bool bNew;
|
2014-06-24 18:36:02 +02:00
|
|
|
|
if (el->type() == Element::Type::NOTE) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
ChordRest * cr = static_cast<Note*>(el)->chord();
|
|
|
|
|
fb = FiguredBass::addFiguredBassToSegment(cr->segment(),
|
|
|
|
|
(cr->track() / VOICES) * VOICES, 0, &bNew);
|
|
|
|
|
}
|
2014-06-24 18:36:02 +02:00
|
|
|
|
else if (el->type() == Element::Type::FIGURED_BASS) {
|
2012-05-26 14:26:10 +02:00
|
|
|
|
fb = static_cast<FiguredBass*>(el);
|
|
|
|
|
bNew = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if(fb == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if(bNew)
|
|
|
|
|
undoAddElement(fb);
|
2014-05-27 10:34:08 +02:00
|
|
|
|
select(fb, SelectType::SINGLE, 0);
|
2012-05-26 14:26:10 +02:00
|
|
|
|
return fb;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 18:49:17 +02:00
|
|
|
|
}
|
|
|
|
|
|