bf5e1aee70
The workspace now can save the following: - Palettes - Toolbars - Menubar - GUI preferences - GUI components Also, Basic and Advanced workspaces are no longer hard coded. See the following blog posts for more info: Project Description: https://musescore.org/en/user/1190941/blog/2018/04/26/gsoc-2018-beginner-mode-and-tutorial-creation-project-description Week 1: https://musescore.org/en/user/1190941/blog/2018/05/20/gsoc-2018-beginner-mode-and-tutorial-creation-week-1 Week 2: https://musescore.org/en/user/1190941/blog/2018/05/28/gsoc-2018-beginner-mode-and-tutorial-creation-week-2 Week 3: https://musescore.org/en/user/1190941/blog/2018/06/04/gsoc-2018-beginner-mode-and-tutorial-creation-week-3 Week 4: https://musescore.org/en/user/1190941/blog/2018/06/12/gsoc-2018-beginner-mode-and-tutorial-creation-week-4 Week 5: https://musescore.org/en/user/1190941/blog/2018/06/17/gsoc-2018-beginner-mode-and-tutorial-creation-week-5
387 lines
11 KiB
C++
387 lines
11 KiB
C++
//=============================================================================
|
|
// MuseScore
|
|
// Linux Music Score Editor
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 2009-2011 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 "musescore.h"
|
|
#include "palette.h"
|
|
#include "keyedit.h"
|
|
#include "libmscore/keysig.h"
|
|
#include "libmscore/score.h"
|
|
#include "libmscore/accidental.h"
|
|
#include "keycanvas.h"
|
|
#include "libmscore/clef.h"
|
|
#include "libmscore/mscore.h"
|
|
#include "libmscore/xml.h"
|
|
|
|
namespace Ms {
|
|
|
|
extern bool useFactorySettings;
|
|
extern Palette* newAccidentalsPalette();
|
|
extern Palette* newKeySigPalette();
|
|
|
|
//---------------------------------------------------------
|
|
// KeyCanvas
|
|
//---------------------------------------------------------
|
|
|
|
KeyCanvas::KeyCanvas(QWidget* parent)
|
|
: QFrame(parent)
|
|
{
|
|
setAcceptDrops(true);
|
|
extraMag = 2.0;
|
|
qreal mag = PALETTE_SPATIUM * extraMag / gscore->spatium();
|
|
_matrix = QTransform(mag, 0.0, 0.0, mag, 0.0, 0.0);
|
|
imatrix = _matrix.inverted();
|
|
dragElement = 0;
|
|
setFocusPolicy(Qt::StrongFocus);
|
|
QAction* a = new QAction("delete", this);
|
|
a->setShortcut(Qt::Key_Delete);
|
|
addAction(a);
|
|
clef = new Clef(gscore);
|
|
clef->setClefType(ClefType::G);
|
|
connect(a, SIGNAL(triggered()), SLOT(deleteElement()));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// delete
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::deleteElement()
|
|
{
|
|
foreach(Accidental* a, accidentals) {
|
|
if (a->selected()) {
|
|
accidentals.removeOne(a);
|
|
delete a;
|
|
update();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// clear
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::clear()
|
|
{
|
|
foreach(Accidental* a, accidentals)
|
|
delete a;
|
|
accidentals.clear();
|
|
update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// paintEvent
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::paintEvent(QPaintEvent*)
|
|
{
|
|
QPainter painter(this);
|
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
|
qreal wh = double(height());
|
|
qreal ww = double(width());
|
|
double y = wh * .5 - 2 * PALETTE_SPATIUM * extraMag;
|
|
|
|
qreal mag = PALETTE_SPATIUM * extraMag / gscore->spatium();
|
|
_matrix = QTransform(mag, 0.0, 0.0, mag, 0.0, y);
|
|
imatrix = _matrix.inverted();
|
|
|
|
qreal x = 3;
|
|
qreal w = ww - 6;
|
|
|
|
painter.setWorldTransform(_matrix);
|
|
|
|
QRectF r = imatrix.mapRect(QRectF(x, y, w, wh));
|
|
|
|
QRectF background = imatrix.mapRect(QRectF(0, 0, ww, wh));
|
|
painter.fillRect(background, Qt::white);
|
|
|
|
QPen pen(Qt::black);
|
|
pen.setWidthF(MScore::defaultStyle().value(Sid::staffLineWidth).toDouble() * gscore->spatium());
|
|
painter.setPen(pen);
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
qreal yy = r.y() + i * gscore->spatium();
|
|
painter.drawLine(QLineF(r.x(), yy, r.x() + r.width(), yy));
|
|
}
|
|
if (dragElement) {
|
|
painter.save();
|
|
painter.translate(dragElement->pagePos());
|
|
dragElement->draw(&painter);
|
|
painter.restore();
|
|
}
|
|
foreach(Accidental* a, accidentals) {
|
|
painter.save();
|
|
painter.translate(a->pagePos());
|
|
a->draw(&painter);
|
|
painter.restore();
|
|
}
|
|
clef->setPos(0.0, 0.0);
|
|
clef->layout();
|
|
painter.translate(clef->pagePos());
|
|
clef->draw(&painter);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mousePressEvent
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
startMove = imatrix.map(QPointF(event->pos() - base));
|
|
moveElement = 0;
|
|
foreach(Accidental* a, accidentals) {
|
|
QRectF r = a->abbox();
|
|
if (r.contains(startMove)) {
|
|
a->setSelected(true);
|
|
moveElement = a;
|
|
}
|
|
else
|
|
a->setSelected(false);
|
|
}
|
|
update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseMoveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::mouseMoveEvent(QMouseEvent* event)
|
|
{
|
|
if (moveElement == 0)
|
|
return;
|
|
QPointF p = imatrix.map(QPointF(event->pos()));
|
|
QPointF delta = p - startMove;
|
|
moveElement->move(delta);
|
|
startMove = p;
|
|
update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mouseReleaseEvent
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::mouseReleaseEvent(QMouseEvent*)
|
|
{
|
|
if (moveElement == 0)
|
|
return;
|
|
snap(moveElement);
|
|
update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// dragEnterEvent
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::dragEnterEvent(QDragEnterEvent* event)
|
|
{
|
|
const QMimeData* dta = event->mimeData();
|
|
if (dta->hasFormat(mimeSymbolFormat)) {
|
|
QByteArray a = dta->data(mimeSymbolFormat);
|
|
|
|
XmlReader e(a);
|
|
|
|
QPointF dragOffset;
|
|
Fraction duration;
|
|
ElementType type = Element::readType(e, &dragOffset, &duration);
|
|
if (type != ElementType::ACCIDENTAL)
|
|
return;
|
|
|
|
event->acceptProposedAction();
|
|
dragElement = static_cast<Accidental*>(Element::create(type, gscore));
|
|
dragElement->setParent(0);
|
|
dragElement->read(e);
|
|
dragElement->layout();
|
|
}
|
|
else {
|
|
if (MScore::debugMode) {
|
|
qDebug("KeyCanvas::dragEnterEvent: formats:");
|
|
foreach(const QString& s, event->mimeData()->formats())
|
|
qDebug(" %s", qPrintable(s));
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// dragMoveEvent
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::dragMoveEvent(QDragMoveEvent* event)
|
|
{
|
|
if (dragElement) {
|
|
event->acceptProposedAction();
|
|
QPointF pos(imatrix.map(QPointF(event->pos())));
|
|
dragElement->setPos(pos);
|
|
update();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// dropEvent
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::dropEvent(QDropEvent*)
|
|
{
|
|
for (Accidental* a : accidentals)
|
|
a->setSelected(false);
|
|
dragElement->setSelected(true);
|
|
accidentals.append(dragElement);
|
|
snap(dragElement);
|
|
dragElement = 0;
|
|
update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// snap
|
|
//---------------------------------------------------------
|
|
|
|
void KeyCanvas::snap(Accidental* a)
|
|
{
|
|
double y = a->ipos().y();
|
|
double spatium2 = gscore->spatium() * .5;
|
|
int line = int((y + spatium2 * .5) / spatium2);
|
|
y = line * spatium2;
|
|
a->rypos() = y;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// KeyEditor
|
|
//---------------------------------------------------------
|
|
|
|
KeyEditor::KeyEditor(QWidget* parent)
|
|
: QWidget(parent, Qt::WindowFlags(Qt::Dialog | Qt::Window))
|
|
{
|
|
setupUi(this);
|
|
setWindowTitle(tr("Key Signatures"));
|
|
|
|
// create key signature palette
|
|
|
|
QLayout* l = new QVBoxLayout();
|
|
l->setContentsMargins(0, 0, 0, 0);
|
|
frame->setLayout(l);
|
|
|
|
sp = MuseScore::newKeySigPalette();
|
|
sp->setReadOnly(false);
|
|
|
|
_keyPalette = new PaletteScrollArea(sp);
|
|
QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
_keyPalette->setSizePolicy(policy);
|
|
_keyPalette->setRestrictHeight(false);
|
|
|
|
l->addWidget(_keyPalette);
|
|
|
|
// create accidental palette
|
|
|
|
l = new QVBoxLayout();
|
|
l->setContentsMargins(0, 0, 0, 0);
|
|
frame_3->setLayout(l);
|
|
sp1 = MuseScore::newAccidentalsPalette();
|
|
PaletteScrollArea* accPalette = new PaletteScrollArea(sp1);
|
|
QSizePolicy policy1(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
accPalette->setSizePolicy(policy1);
|
|
accPalette->setRestrictHeight(false);
|
|
|
|
l->addWidget(accPalette);
|
|
|
|
connect(addButton, SIGNAL(clicked()), SLOT(addClicked()));
|
|
connect(clearButton, SIGNAL(clicked()), SLOT(clearClicked()));
|
|
connect(sp, SIGNAL(changed()), SLOT(setDirty()));
|
|
|
|
//
|
|
// set all "buildin" key signatures to read only
|
|
//
|
|
int n = sp->size();
|
|
for (int i = 0; i < n; ++i)
|
|
sp->setCellReadOnly(i, true);
|
|
|
|
if (!useFactorySettings) {
|
|
QString path = dataPath + "/keysigs";
|
|
if (!sp->read(path))
|
|
qDebug("KeyEditor: read <%s> failed", qPrintable(dataPath + "/keysigs.mpal"));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// addClicked
|
|
//---------------------------------------------------------
|
|
|
|
void KeyEditor::addClicked()
|
|
{
|
|
// double extraMag = 2.0;
|
|
const QList<Accidental*> al = canvas->getAccidentals();
|
|
// qreal mag = PALETTE_SPATIUM * extraMag / gscore->spatium();
|
|
// double spatium = 2.0 * PALETTE_SPATIUM / extraMag;
|
|
double spatium = gscore->spatium();
|
|
double xoff = 10000000.0;
|
|
|
|
for (Accidental* a : al) {
|
|
QPointF pos = a->ipos();
|
|
if (pos.x() < xoff)
|
|
xoff = pos.x();
|
|
}
|
|
|
|
KeySigEvent e;
|
|
e.setCustom(true);
|
|
for (Accidental* a : al) {
|
|
KeySym s;
|
|
s.sym = a->symbol();
|
|
QPointF pos = a->ipos();
|
|
pos.rx() -= xoff;
|
|
s.spos = pos / spatium;
|
|
e.keySymbols().append(s);
|
|
}
|
|
KeySig* ks = new KeySig(gscore);
|
|
ks->setKeySigEvent(e);
|
|
sp->append(ks, "custom");
|
|
_dirty = true;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// clearClicked
|
|
//---------------------------------------------------------
|
|
|
|
void KeyEditor::clearClicked()
|
|
{
|
|
canvas->clear();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// save
|
|
//---------------------------------------------------------
|
|
|
|
void KeyEditor::save()
|
|
{
|
|
QDir dir;
|
|
dir.mkpath(dataPath);
|
|
sp->write(dataPath + "/keysigs");
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// showKeyEditor
|
|
//---------------------------------------------------------
|
|
|
|
void MuseScore::showKeyEditor()
|
|
{
|
|
if (keyEditor == 0) {
|
|
keyEditor = new KeyEditor(0);
|
|
}
|
|
keyEditor->show();
|
|
keyEditor->raise();
|
|
}
|
|
}
|
|
|