MuseScore/mscore/fretproperties.cpp
Joachim Schmitz e18b6b2bd3 improve texts of fretboard diagram inspector
and fix a compiler warning
2019-05-05 16:37:06 +02:00

428 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//=============================================================================
// MusE Score
// Linux Music Score Editor
//
// Copyright (C) 2010-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 "libmscore/fret.h"
#include "fretproperties.h"
#include "libmscore/measure.h"
#include "libmscore/system.h"
#include "libmscore/score.h"
//#include "libmscore/stringdata.h"
#include "fretcanvas.h"
#include "preferences.h"
#include "libmscore/chord.h"
#include "libmscore/note.h"
#include "libmscore/segment.h"
#include "libmscore/undo.h"
#include "musescore.h"
namespace Ms {
//---------------------------------------------------------
// FretDiagramProperties
//---------------------------------------------------------
FretDiagramProperties::FretDiagramProperties(FretDiagram* _fd, QWidget* parent)
: QDialog(parent)
{
setObjectName("FretDiagramProperties");
setupUi(this);
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
fd = _fd;
frets->setValue(fd->frets());
strings->setValue(fd->strings());
diagram->setFretDiagram(fd);
diagramScrollBar->setRange(0, fd->maxFrets());
diagramScrollBar->setValue(fd->fretOffset());
connect(strings, SIGNAL(valueChanged(int)), SLOT(stringsChanged(int)));
connect(frets, SIGNAL(valueChanged(int)), SLOT(fretsChanged(int)));
connect(diagramScrollBar, SIGNAL(valueChanged(int)), SLOT(fretOffsetChanged(int)));
MuseScore::restoreGeometry(this);
}
//---------------------------------------------------------
// fretsChanged
//---------------------------------------------------------
void FretDiagramProperties::fretsChanged(int val)
{
fd->setFrets(val);
diagram->update();
}
//---------------------------------------------------------
// stringsChanged
//---------------------------------------------------------
void FretDiagramProperties::stringsChanged(int val)
{
fd->setStrings(val);
diagram->update();
}
//---------------------------------------------------------
// hideEvent
//---------------------------------------------------------
void FretDiagramProperties::hideEvent(QHideEvent* event)
{
MuseScore::saveGeometry(this);
QDialog::hideEvent(event);
}
//---------------------------------------------------------
// fretOffsetChanged
//---------------------------------------------------------
void FretDiagramProperties::fretOffsetChanged(int val)
{
fd->setFretOffset(val);
diagram->update();
}
//---------------------------------------------------------
// paintEvent
//---------------------------------------------------------
void FretCanvas::paintEvent(QPaintEvent* ev)
{
double mag = 1.5;
double _spatium = 20.0 * mag;
double lw1 = _spatium * 0.08;
int fretOffset = diagram->fretOffset();
double lw2 = (fretOffset || !diagram->showNut()) ? lw1 : _spatium * 0.2;
double stringDist = _spatium * .7;
double fretDist = _spatium * .8;
int _strings = diagram->strings();
int _frets = diagram->frets();
double dotd = stringDist * .6 + lw1;
double w = (_strings - 1) * stringDist;
double xo = (width() - w) * .5;
double h = (_frets * fretDist) + fretDist * .5;
double yo = (height() - h) * .5;
QFont font("FreeSans");
int size = lrint(18.0 * mag);
font.setPixelSize(size);
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing, preferences.getBool(PREF_UI_CANVAS_MISC_ANTIALIASEDDRAWING));
p.setRenderHint(QPainter::TextAntialiasing, true);
p.translate(xo, yo);
QPen pen(p.pen());
pen.setWidthF(lw2);
pen.setCapStyle(Qt::FlatCap);
p.setPen(pen);
p.setBrush(pen.color());
double x2 = (_strings-1) * stringDist;
p.drawLine(QLineF(-lw1 * .5, 0.0, x2 + lw1 * .5, 0.0));
pen.setWidthF(lw1);
p.setPen(pen);
double y2 = (_frets+1) * fretDist - fretDist*.5;
QPen symPen(pen);
symPen.setCapStyle(Qt::RoundCap);
symPen.setWidthF(lw1 * 1.2);
// Draw strings and frets
for (int i = 0; i < _strings; ++i) {
double x = stringDist * i;
p.drawLine(QLineF(x, fretOffset ? -_spatium*.2 : 0.0, x, y2));
}
for (int i = 1; i <= _frets; ++i) {
double y = fretDist * i;
p.drawLine(QLineF(0.0, y, x2, y));
}
// Draw dots and markers
for (int i = 0; i < _strings; ++i) {
for (auto const& d : diagram->dot(i)) {
if (d.exists()) {
p.setPen(symPen);
int fret = d.fret;
double x = stringDist * i - dotd * .5;
double y = fretDist * (fret - 1) + fretDist * .5 - dotd * .5;
paintDotSymbol(p, symPen, x, y, dotd, d.dtype);
}
}
p.setPen(pen);
FretItem::Marker mark = diagram->marker(i);
if (mark.exists()) {
p.setFont(font);
double x = stringDist * i;
double y = -fretDist * .1;
p.drawText(QRectF(x, y, 0.0, 0.0),
Qt::AlignHCenter | Qt::AlignBottom | Qt::TextDontClip, FretItem::markerToChar(mark.mtype));
}
}
// Draw barres
p.setPen(pen);
for (auto const& i : diagram->barres()) {
int fret = i.first;
int startString = i.second.startString;
int endString = i.second.endString;
qreal x1 = stringDist * startString;
qreal newX2 = endString == -1 ? x2 : stringDist * endString;
qreal y = fretDist * (fret - 1) + fretDist * .5;
pen.setWidthF(dotd * diagram->score()->styleD(Sid::barreLineWidth)); // dont use style barreLineWidth - why not?
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
p.drawLine(QLineF(x1, y, newX2, y));
}
// Draw 'hover' dot
if ((cfret > 0) && (cfret <= _frets) && (cstring >= 0) && (cstring < _strings)) {
FretItem::Dot cd = diagram->dot(cstring, cfret)[0];
std::vector<FretItem::Dot> otherDots = diagram->dot(cstring);
FretDotType dtype;
symPen.setColor(Qt::lightGray);
if (cd.exists()) {
dtype = cd.dtype;
symPen.setColor(Qt::red);
}
else {
dtype = _automaticDotType ? FretDotType::NORMAL : _currentDtype;
}
p.setPen(symPen);
double x = stringDist * cstring - dotd * .5;
double y = fretDist * (cfret-1) + fretDist * .5 - dotd * .5;
p.setBrush(Qt::lightGray);
paintDotSymbol(p, symPen, x, y, dotd, dtype);
}
if (fretOffset > 0) {
qreal fretNumMag = 2.0; // TODO: get the value from Sid::fretNumMag
QFont scaledFont(font);
scaledFont.setPixelSize(font.pixelSize() * fretNumMag);
p.setFont(scaledFont);
p.setPen(pen);
// Todo: make dependent from Sid::fretNumPos
p.drawText(QRectF(-stringDist * .4, 0.0, 0.0, fretDist),
Qt::AlignVCenter|Qt::AlignRight|Qt::TextDontClip,
QString("%1").arg(fretOffset+1));
p.setFont(font);
}
QFrame::paintEvent(ev);
}
//---------------------------------------------------------
// paintDotSymbol
//---------------------------------------------------------
void FretCanvas::paintDotSymbol(QPainter& p, QPen& pen, qreal x, qreal y, qreal dotd, FretDotType dtype)
{
switch (dtype) {
case FretDotType::CROSS:
p.drawLine(QLineF(x, y, x + dotd, y + dotd));
p.drawLine(QLineF(x + dotd, y, x, y + dotd));
break;
case FretDotType::SQUARE:
p.setBrush(Qt::NoBrush);
p.drawRect(QRectF(x, y, dotd, dotd));
break;
case FretDotType::TRIANGLE:
p.drawLine(QLineF(x, y + dotd, x + .5 * dotd, y));
p.drawLine(QLineF(x + .5 * dotd, y, x + dotd, y + dotd));
p.drawLine(QLineF(x + dotd, y + dotd, x, y + dotd));
break;
case FretDotType::NORMAL:
default:
p.setBrush(pen.color());
p.setPen(Qt::NoPen);
p.drawEllipse(QRectF(x, y, dotd, dotd));
break;
}
}
//---------------------------------------------------------
// getPosition
//---------------------------------------------------------
void FretCanvas::getPosition(const QPointF& p, int* string, int* fret)
{
double mag = 1.5;
double _spatium = 20.0 * mag;
int _strings = diagram->strings();
int _frets = diagram->frets();
double stringDist = _spatium * .7;
double fretDist = _spatium * .8;
double w = (_strings - 1) * stringDist;
double xo = (width() - w) * .5;
double h = (_frets * fretDist) + fretDist * .5;
double yo = (height() - h) * .5;
*fret = (p.y() - yo + fretDist) / fretDist;
*string = (p.x() - xo + stringDist * .5) / stringDist;
}
//---------------------------------------------------------
// mousePressEvent
//---------------------------------------------------------
void FretCanvas::mousePressEvent(QMouseEvent* ev)
{
int string;
int fret;
getPosition(ev->pos(), &string, &fret);
int _strings = diagram->strings();
int _frets = diagram->frets();
if (fret < 0 || fret > _frets || string < 0 || string >= _strings)
return;
diagram->score()->startCmd();
// Click above the fret diagram, so change the open/closed string marker
if (fret == 0) {
switch (diagram->marker(string).mtype) {
case FretMarkerType::CIRCLE:
diagram->undoSetFretMarker(string, FretMarkerType::CROSS);
break;
case FretMarkerType::CROSS:
diagram->undoSetFretMarker(string, FretMarkerType::NONE);
break;
case FretMarkerType::NONE:
default:
diagram->undoSetFretDot(string, 0);
diagram->undoSetFretMarker(string, FretMarkerType::CIRCLE);
break;
}
}
// Otherwise, the click is on the fretboard itself
else {
FretItem::Dot thisDot = diagram->dot(string, fret)[0];
bool haveShift = (ev->modifiers() & Qt::ShiftModifier) || _barreMode;
bool haveCtrl = (ev->modifiers() & Qt::ControlModifier) || _multidotMode;
// Click on an existing dot
if (thisDot.exists() && !haveShift)
diagram->undoSetFretDot(string, haveCtrl ? fret : 0, haveCtrl);
else {
// Shift adds a barre
if (haveShift)
diagram->undoSetFretBarre(string, fret, haveCtrl);
else {
FretDotType dtype = FretDotType::NORMAL;
if (_automaticDotType && haveCtrl && diagram->dot(string)[0].exists()) {
dtype = FretDotType::TRIANGLE;
std::vector<FretDotType> dtypes {
FretDotType::NORMAL,
FretDotType::CROSS,
FretDotType::SQUARE,
FretDotType::TRIANGLE
};
// Find the lowest dot type that doesn't already exist on the string
for (int i = 0; i < int(dtypes.size()); i++) {
FretDotType t = dtypes[i];
bool hasThisType = false;
for (auto const& dot : diagram->dot(string)) {
if (dot.dtype == t) {
hasThisType = true;
break;
}
}
if (hasThisType)
continue;
dtype = t;
break;
}
}
else if (!_automaticDotType)
dtype = _currentDtype;
// Ctrl adds a dot without removing other dots on a string
diagram->undoSetFretDot(string, fret, haveCtrl, dtype);
}
}
}
diagram->triggerLayout();
diagram->score()->endCmd();
update();
}
//---------------------------------------------------------
// mouseMoveEvent
//---------------------------------------------------------
void FretCanvas::mouseMoveEvent(QMouseEvent* ev)
{
int string;
int fret;
getPosition(ev->pos(), &string, &fret);
if (string != cstring || cfret != fret) {
cfret = fret;
cstring = string;
update();
}
}
//---------------------------------------------------------
// FretCanvas
//---------------------------------------------------------
FretCanvas::FretCanvas(QWidget* parent)
: QFrame(parent)
{
setAcceptDrops(true);
// setFrameStyle(QFrame::Raised | QFrame::Panel);
cstring = -2;
cfret = -2;
}
//---------------------------------------------------------
// setFretDiagram
//---------------------------------------------------------
void FretCanvas::setFretDiagram(FretDiagram* fd)
{
diagram = fd;
update();
}
//---------------------------------------------------------
// clear
//---------------------------------------------------------
void FretCanvas::clear()
{
diagram->score()->startCmd();
diagram->undoFretClear();
diagram->score()->endCmd();
update();
}
}