564 lines
20 KiB
C++
564 lines
20 KiB
C++
//=============================================================================
|
|
// MuseScore
|
|
// Linux Music Score Editor
|
|
// $Id: editstaff.cpp 5149 2011-12-29 08:38:43Z wschweer $
|
|
//
|
|
// Copyright (C) 2002-2010 Werner Schweer and others
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//=============================================================================
|
|
|
|
#include "editstaff.h"
|
|
|
|
#include "editdrumset.h"
|
|
#include "editpitch.h"
|
|
#include "editstafftype.h"
|
|
#include "editstringdata.h"
|
|
#include "icons.h"
|
|
#include "libmscore/instrtemplate.h"
|
|
#include "libmscore/measure.h"
|
|
#include "libmscore/part.h"
|
|
#include "libmscore/score.h"
|
|
#include "libmscore/staff.h"
|
|
#include "libmscore/stringdata.h"
|
|
#include "libmscore/text.h"
|
|
#include "libmscore/undo.h"
|
|
#include "libmscore/utils.h"
|
|
#include "musescore.h"
|
|
#include "seq.h"
|
|
#include "selinstrument.h"
|
|
|
|
namespace Ms {
|
|
|
|
//---------------------------------------------------------
|
|
// EditStaff
|
|
//---------------------------------------------------------
|
|
|
|
EditStaff::EditStaff(Staff* s, int /*tick*/, QWidget* parent)
|
|
: QDialog(parent)
|
|
{
|
|
setObjectName("EditStaff");
|
|
setupUi(this);
|
|
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
setModal(true);
|
|
|
|
staff = nullptr;
|
|
setStaff(s);
|
|
|
|
MuseScore::restoreGeometry(this);
|
|
|
|
connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), SLOT(bboxClicked(QAbstractButton*)));
|
|
connect(changeInstrument, SIGNAL(clicked()), SLOT(showInstrumentDialog()));
|
|
connect(changeStaffType, SIGNAL(clicked()), SLOT(showStaffTypeDialog()));
|
|
connect(minPitchASelect, SIGNAL(clicked()), SLOT(minPitchAClicked()));
|
|
connect(maxPitchASelect, SIGNAL(clicked()), SLOT(maxPitchAClicked()));
|
|
connect(minPitchPSelect, SIGNAL(clicked()), SLOT(minPitchPClicked()));
|
|
connect(maxPitchPSelect, SIGNAL(clicked()), SLOT(maxPitchPClicked()));
|
|
connect(editStringData, SIGNAL(clicked()), SLOT(editStringDataClicked()));
|
|
connect(lines, SIGNAL(valueChanged(int)), SLOT(numOfLinesChanged()));
|
|
connect(lineDistance, SIGNAL(valueChanged(double)), SLOT(lineDistanceChanged()));
|
|
connect(showClef, SIGNAL(clicked()), SLOT(showClefChanged()));
|
|
connect(showTimesig, SIGNAL(clicked()), SLOT(showTimeSigChanged()));
|
|
connect(showBarlines, SIGNAL(clicked()), SLOT(showBarlinesChanged()));
|
|
|
|
connect(nextButton, SIGNAL(clicked()), SLOT(gotoNextStaff()));
|
|
connect(previousButton, SIGNAL(clicked()), SLOT(gotoPreviousStaff()));
|
|
|
|
addAction(getAction("help")); // why is this needed?
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setStaff
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::setStaff(Staff* s)
|
|
{
|
|
if (staff != nullptr)
|
|
delete staff;
|
|
|
|
orgStaff = s;
|
|
Part* part = orgStaff->part();
|
|
instrument = *part->instrument(/*tick*/);
|
|
Score* score = part->score();
|
|
staff = new Staff(score);
|
|
staff->setSmall(0, orgStaff->small(0));
|
|
staff->setInvisible(orgStaff->invisible());
|
|
staff->setUserDist(orgStaff->userDist());
|
|
staff->setColor(orgStaff->color());
|
|
staff->setStaffType(0, orgStaff->staffType(0));
|
|
staff->setPart(part);
|
|
staff->setCutaway(orgStaff->cutaway());
|
|
staff->setHideWhenEmpty(orgStaff->hideWhenEmpty());
|
|
staff->setShowIfEmpty(orgStaff->showIfEmpty());
|
|
staff->setUserMag(0, orgStaff->userMag(0));
|
|
staff->setHideSystemBarLine(orgStaff->hideSystemBarLine());
|
|
|
|
// get tick range for instrument
|
|
auto i = part->instruments()->upper_bound(0); // tick
|
|
if (i == part->instruments()->end())
|
|
_tickEnd = -1;
|
|
else
|
|
_tickEnd = i->first;
|
|
#if 1
|
|
_tickStart = -1;
|
|
#else
|
|
--i;
|
|
if (i == part->instruments()->begin())
|
|
_tickStart = 0;
|
|
else
|
|
_tickStart = i->first;
|
|
#endif
|
|
|
|
// set dlg controls
|
|
spinExtraDistance->setValue(s->userDist() / score->spatium());
|
|
invisible->setChecked(staff->invisible());
|
|
small->setChecked(staff->small(0));
|
|
color->setColor(s->color());
|
|
partName->setText(part->partName());
|
|
cutaway->setChecked(staff->cutaway());
|
|
hideMode->setCurrentIndex(int(staff->hideWhenEmpty()));
|
|
showIfEmpty->setChecked(staff->showIfEmpty());
|
|
hideSystemBarLine->setChecked(staff->hideSystemBarLine());
|
|
mag->setValue(staff->userMag(0) * 100.0);
|
|
updateStaffType();
|
|
updateInstrument();
|
|
updateNextPreviousButtons();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// hideEvent
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::hideEvent(QHideEvent* ev)
|
|
{
|
|
MuseScore::saveGeometry(this);
|
|
QWidget::hideEvent(ev);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateStaffType
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::updateStaffType()
|
|
{
|
|
StaffType* staffType = staff->staffType(0);
|
|
lines->setValue(staffType->lines());
|
|
lineDistance->setValue(staffType->lineDistance().val());
|
|
showClef->setChecked(staffType->genClef());
|
|
showTimesig->setChecked(staffType->genTimesig());
|
|
showBarlines->setChecked(staffType->showBarlines());
|
|
staffGroupName->setText(qApp->translate("Staff type group name", staffType->groupName()));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateInstrument
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::updateInstrument()
|
|
{
|
|
updateInterval(instrument.transpose());
|
|
|
|
QList<StaffName>& snl = instrument.shortNames();
|
|
QString df = snl.isEmpty() ? "" : snl[0].name();
|
|
shortName->setPlainText(df);
|
|
|
|
QList<StaffName>& lnl = instrument.longNames();
|
|
df = lnl.isEmpty() ? "" : lnl[0].name();
|
|
|
|
longName->setPlainText(df);
|
|
|
|
if (partName->text() == instrumentName->text()) // Updates part name if no custom name has been set before
|
|
partName->setText(instrument.trackName());
|
|
|
|
instrumentName->setText(instrument.trackName());
|
|
|
|
_minPitchA = instrument.minPitchA();
|
|
_maxPitchA = instrument.maxPitchA();
|
|
_minPitchP = instrument.minPitchP();
|
|
_maxPitchP = instrument.maxPitchP();
|
|
minPitchA->setText(midiCodeToStr(_minPitchA));
|
|
maxPitchA->setText(midiCodeToStr(_maxPitchA));
|
|
minPitchP->setText(midiCodeToStr(_minPitchP));
|
|
maxPitchP->setText(midiCodeToStr(_maxPitchP));
|
|
|
|
// only show string data controls if instrument has strings
|
|
int numStr = instrument.stringData() ? instrument.stringData()->strings() : 0;
|
|
stringDataFrame->setVisible(numStr > 0);
|
|
numOfStrings->setText(QString::number(numStr));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateInterval
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::updateInterval(const Interval& iv)
|
|
{
|
|
int diatonic = iv.diatonic;
|
|
int chromatic = iv.chromatic;
|
|
|
|
int oct = chromatic / 12;
|
|
if (oct < 0)
|
|
oct = -oct;
|
|
|
|
bool upFlag = true;
|
|
if (chromatic < 0 || diatonic < 0) {
|
|
upFlag = false;
|
|
chromatic = -chromatic;
|
|
diatonic = -diatonic;
|
|
}
|
|
chromatic %= 12;
|
|
diatonic %= 7;
|
|
|
|
int interval = searchInterval(diatonic, chromatic);
|
|
if (interval == -1) {
|
|
qDebug("EditStaff: unknown interval %d %d", diatonic, chromatic);
|
|
interval = 0;
|
|
}
|
|
iList->setCurrentIndex(interval);
|
|
up->setChecked(upFlag);
|
|
down->setChecked(!upFlag);
|
|
octave->setValue(oct);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateNextPreviousButtons
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::updateNextPreviousButtons()
|
|
{
|
|
int staffIdx = orgStaff->idx();
|
|
|
|
nextButton->setEnabled(staffIdx < (orgStaff->score()->nstaves() - 1));
|
|
previousButton->setEnabled(staffIdx != 0);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// gotoNextStaff
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::gotoNextStaff()
|
|
{
|
|
Staff* nextStaff = orgStaff->score()->staff(orgStaff->idx() + 1);
|
|
if (nextStaff)
|
|
{
|
|
setStaff(nextStaff);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// gotoPreviousStaff
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::gotoPreviousStaff()
|
|
{
|
|
Staff* prevStaff = orgStaff->score()->staff(orgStaff->idx() - 1);
|
|
if (prevStaff)
|
|
{
|
|
setStaff(prevStaff);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// bboxClicked
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::bboxClicked(QAbstractButton* button)
|
|
{
|
|
QDialogButtonBox::ButtonRole br = buttonBox->buttonRole(button);
|
|
switch(br) {
|
|
case QDialogButtonBox::ApplyRole:
|
|
apply();
|
|
break;
|
|
|
|
case QDialogButtonBox::AcceptRole:
|
|
apply();
|
|
// fall through
|
|
|
|
case QDialogButtonBox::RejectRole:
|
|
close();
|
|
if (staff != nullptr)
|
|
delete staff;
|
|
break;
|
|
|
|
default:
|
|
qDebug("EditStaff: unknown button %d", int(br));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// apply
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::apply()
|
|
{
|
|
Score* score = orgStaff->score();
|
|
Part* part = orgStaff->part();
|
|
|
|
QString sn = shortName->toPlainText();
|
|
QString ln = longName->toPlainText();
|
|
if (!Text::validateText(sn) || !Text::validateText(ln)) {
|
|
QMessageBox msgBox;
|
|
msgBox.setText(tr("The instrument name is invalid."));
|
|
msgBox.exec();
|
|
return;
|
|
}
|
|
shortName->setPlainText(sn); // show the fixed text
|
|
longName->setPlainText(ln);
|
|
|
|
int intervalIdx = iList->currentIndex();
|
|
bool upFlag = up->isChecked();
|
|
|
|
Interval interval = intervalList[intervalIdx];
|
|
interval.diatonic += octave->value() * 7;
|
|
interval.chromatic += octave->value() * 12;
|
|
|
|
if (!upFlag)
|
|
interval.flip();
|
|
instrument.setTranspose(interval);
|
|
|
|
instrument.setMinPitchA(_minPitchA);
|
|
instrument.setMaxPitchA(_maxPitchA);
|
|
instrument.setMinPitchP(_minPitchP);
|
|
instrument.setMaxPitchP(_maxPitchP);
|
|
|
|
instrument.setShortName(sn);
|
|
instrument.setLongName(ln);
|
|
|
|
bool inv = invisible->isChecked();
|
|
ClefTypeList clefType = instrument.clefType(orgStaff->rstaff());
|
|
qreal userDist = spinExtraDistance->value();
|
|
bool ifEmpty = showIfEmpty->isChecked();
|
|
bool hideSystemBL = hideSystemBarLine->isChecked();
|
|
bool cutAway = cutaway->isChecked();
|
|
Staff::HideMode hideEmpty = Staff::HideMode(hideMode->currentIndex());
|
|
|
|
QString newPartName = partName->text().simplified();
|
|
if (!(instrument == *part->instrument()) || part->partName() != newPartName) {
|
|
// instrument has changed
|
|
Interval v1 = instrument.transpose();
|
|
Interval v2 = part->instrument()->transpose();
|
|
|
|
score->undo(new ChangePart(part, new Instrument(instrument), newPartName));
|
|
emit instrumentChanged();
|
|
|
|
if (v1 != v2)
|
|
score->transpositionChanged(part, v2, _tickStart, _tickEnd);
|
|
}
|
|
orgStaff->undoChangeProperty(Pid::MAG, mag->value() / 100.0);
|
|
orgStaff->undoChangeProperty(Pid::COLOR, color->color());
|
|
orgStaff->undoChangeProperty(Pid::SMALL, small->isChecked());
|
|
|
|
if (inv != orgStaff->invisible()
|
|
|| clefType != orgStaff->defaultClefType()
|
|
|| userDist != orgStaff->userDist()
|
|
|| cutAway != orgStaff->cutaway()
|
|
|| hideEmpty != orgStaff->hideWhenEmpty()
|
|
|| ifEmpty != orgStaff->showIfEmpty()
|
|
|| hideSystemBL != orgStaff->hideSystemBarLine()
|
|
) {
|
|
score->undo(new ChangeStaff(orgStaff, inv, clefType, userDist * score->spatium(), hideEmpty, ifEmpty, cutAway, hideSystemBL));
|
|
}
|
|
|
|
if ( !(*orgStaff->staffType(0) == *staff->staffType(0)) ) {
|
|
// updateNeeded |= (orgStaff->staffGroup() == StaffGroup::TAB || staff->staffGroup() == StaffGroup::TAB);
|
|
score->undo(new ChangeStaffType(orgStaff, *staff->staffType(0)));
|
|
}
|
|
|
|
score->update();
|
|
score->masterScore()->updateChannel();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// <Pitch>Clicked
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::minPitchAClicked()
|
|
{
|
|
int newCode;
|
|
EditPitch ep(this, instrument.minPitchA());
|
|
ep.setWindowModality(Qt::WindowModal);
|
|
if ( (newCode = ep.exec()) != -1) {
|
|
minPitchA->setText(midiCodeToStr(newCode));
|
|
_minPitchA = newCode;
|
|
}
|
|
}
|
|
|
|
void EditStaff::maxPitchAClicked()
|
|
{
|
|
int newCode;
|
|
EditPitch ep(this, instrument.maxPitchA());
|
|
ep.setWindowModality(Qt::WindowModal);
|
|
if ( (newCode = ep.exec()) != -1) {
|
|
maxPitchA->setText(midiCodeToStr(newCode));
|
|
_maxPitchA = newCode;
|
|
}
|
|
}
|
|
|
|
void EditStaff::minPitchPClicked()
|
|
{
|
|
int newCode;
|
|
EditPitch ep(this, instrument.minPitchP());
|
|
ep.setWindowModality(Qt::WindowModal);
|
|
if ( (newCode = ep.exec()) != -1) {
|
|
minPitchP->setText(midiCodeToStr(newCode));
|
|
_minPitchP = newCode;
|
|
}
|
|
}
|
|
|
|
void EditStaff::maxPitchPClicked()
|
|
{
|
|
int newCode;
|
|
EditPitch ep(this, instrument.maxPitchP());
|
|
ep.setWindowModality(Qt::WindowModal);
|
|
if ( (newCode = ep.exec()) != -1) {
|
|
maxPitchP->setText(midiCodeToStr(newCode));
|
|
_maxPitchP = newCode;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// StaffType props slots
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::lineDistanceChanged()
|
|
{
|
|
staff->staffType(0)->setLineDistance(Spatium(lineDistance->value()));
|
|
}
|
|
|
|
void EditStaff::numOfLinesChanged()
|
|
{
|
|
staff->staffType(0)->setLines(lines->value());
|
|
}
|
|
|
|
void EditStaff::showClefChanged()
|
|
{
|
|
staff->staffType(0)->setGenClef(showClef->checkState() == Qt::Checked);
|
|
}
|
|
|
|
void EditStaff::showTimeSigChanged()
|
|
{
|
|
staff->staffType(0)->setGenTimesig(showTimesig->checkState() == Qt::Checked);
|
|
}
|
|
|
|
void EditStaff::showBarlinesChanged()
|
|
{
|
|
staff->staffType(0)->setShowBarlines(showBarlines->checkState() == Qt::Checked);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// showInstrumentDialog
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::showInstrumentDialog()
|
|
{
|
|
SelectInstrument si(&instrument, this);
|
|
si.setWindowModality(Qt::WindowModal);
|
|
if (si.exec()) {
|
|
instrument = Instrument::fromTemplate(si.instrTemplate());
|
|
updateInstrument();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// editStringDataClicked
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::editStringDataClicked()
|
|
{
|
|
int frets = instrument.stringData()->frets();
|
|
QList<instrString> stringList = instrument.stringData()->stringList();
|
|
|
|
EditStringData* esd = new EditStringData(this, &stringList, &frets);
|
|
esd->setWindowModality(Qt::WindowModal);
|
|
if (esd->exec()) {
|
|
StringData stringData(frets, stringList);
|
|
|
|
// update instrument pitch ranges as necessary
|
|
if (stringList.size() > 0) {
|
|
// get new string range bottom and top
|
|
// as we have to choose an int size, INT16 are surely beyond midi pitch limits
|
|
int oldHighestStringPitch = INT16_MIN;
|
|
int highestStringPitch = INT16_MIN;
|
|
int lowestStringPitch = INT16_MAX;
|
|
for (const instrString& str : stringList) {
|
|
if (str.pitch > highestStringPitch) highestStringPitch = str.pitch;
|
|
if (str.pitch < lowestStringPitch) lowestStringPitch = str.pitch;
|
|
}
|
|
// get old string range bottom
|
|
for (const instrString& str : instrument.stringData()->stringList())
|
|
if (str.pitch > oldHighestStringPitch) oldHighestStringPitch = str.pitch;
|
|
// if there were no string, arbitrarely set old top to maxPitchA
|
|
if (oldHighestStringPitch == INT16_MIN)
|
|
oldHighestStringPitch = instrument.maxPitchA();
|
|
|
|
// range bottom is surely the pitch of the lowest string
|
|
instrument.setMinPitchA(lowestStringPitch);
|
|
instrument.setMinPitchP(lowestStringPitch);
|
|
// range top should keep the same interval with the highest string it has now
|
|
instrument.setMaxPitchA(instrument.maxPitchA() + highestStringPitch - oldHighestStringPitch);
|
|
instrument.setMaxPitchP(instrument.maxPitchP() + highestStringPitch - oldHighestStringPitch);
|
|
// update dlg controls
|
|
minPitchA->setText(midiCodeToStr(instrument.minPitchA()));
|
|
maxPitchA->setText(midiCodeToStr(instrument.maxPitchA()));
|
|
minPitchP->setText(midiCodeToStr(instrument.minPitchP()));
|
|
maxPitchP->setText(midiCodeToStr(instrument.maxPitchP()));
|
|
// if no longer there is any string, leave everything as it is now
|
|
}
|
|
|
|
// update instrument data and dlg controls
|
|
instrument.setStringData(stringData);
|
|
numOfStrings->setText(QString::number(stringData.strings()));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// midiCodeToStr
|
|
// Converts a MIDI numeric pitch code to human-readable note name
|
|
//---------------------------------------------------------
|
|
|
|
static const char* g_cNoteName[] = {
|
|
QT_TRANSLATE_NOOP("editstaff", "C"),
|
|
QT_TRANSLATE_NOOP("editstaff", "C#"),
|
|
QT_TRANSLATE_NOOP("editstaff", "D"),
|
|
QT_TRANSLATE_NOOP("editstaff", "Eb"),
|
|
QT_TRANSLATE_NOOP("editstaff", "E"),
|
|
QT_TRANSLATE_NOOP("editstaff", "F"),
|
|
QT_TRANSLATE_NOOP("editstaff", "F#"),
|
|
QT_TRANSLATE_NOOP("editstaff", "G"),
|
|
QT_TRANSLATE_NOOP("editstaff", "Ab"),
|
|
QT_TRANSLATE_NOOP("editstaff", "A"),
|
|
QT_TRANSLATE_NOOP("editstaff", "Bb"),
|
|
QT_TRANSLATE_NOOP("editstaff", "B")
|
|
};
|
|
|
|
QString EditStaff::midiCodeToStr(int midiCode)
|
|
{
|
|
return QString("%1 %2").arg(qApp->translate("editstaff", g_cNoteName[midiCode % 12])).arg(midiCode / 12 - 1);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// showStaffTypeDialog
|
|
//---------------------------------------------------------
|
|
|
|
void EditStaff::showStaffTypeDialog()
|
|
{
|
|
EditStaffType editor(this, staff);
|
|
editor.setWindowModality(Qt::WindowModal);
|
|
if (editor.exec()) {
|
|
staff->setStaffType(0, editor.getStaffType());
|
|
updateStaffType();
|
|
}
|
|
}
|
|
}
|
|
|