1 //=============================================================================
2 //  MuseScore
3 //  Linux Music Score Editor
4 //
5 //  Copyright (C) 2009-2011 Werner Schweer and others
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //=============================================================================
19 
20 #include "musescore.h"
21 #include "palette.h"
22 #include "keyedit.h"
23 #include "libmscore/keysig.h"
24 #include "libmscore/score.h"
25 #include "libmscore/accidental.h"
26 #include "keycanvas.h"
27 #include "libmscore/clef.h"
28 #include "libmscore/mscore.h"
29 #include "libmscore/xml.h"
30 
31 namespace Ms {
32 
33 extern bool useFactorySettings;
34 extern Palette* newAccidentalsPalette();
35 extern Palette* newKeySigPalette();
36 
37 static const qreal editScale = 1.0;
38 
39 //---------------------------------------------------------
40 //   KeyCanvas
41 //---------------------------------------------------------
42 
KeyCanvas(QWidget * parent)43 KeyCanvas::KeyCanvas(QWidget* parent)
44    : QFrame(parent)
45       {
46       setAcceptDrops(true);
47       extraMag   = editScale * guiScaling;
48       qreal mag  = PALETTE_SPATIUM * extraMag / gscore->spatium();
49       _matrix    = QTransform(mag, 0.0, 0.0, mag, 0.0, 0.0);
50       imatrix    = _matrix.inverted();
51       dragElement = 0;
52       setFocusPolicy(Qt::StrongFocus);
53       QAction* a = new QAction("delete", this);
54       a->setShortcut(Qt::Key_Delete);
55       addAction(a);
56       clef = new Clef(gscore);
57       clef->setClefType(ClefType::G);
58       connect(a, SIGNAL(triggered()), SLOT(deleteElement()));
59       }
60 
61 //---------------------------------------------------------
62 //   delete
63 //---------------------------------------------------------
64 
deleteElement()65 void KeyCanvas::deleteElement()
66       {
67       foreach(Accidental* a, accidentals) {
68             if (a->selected()) {
69                   accidentals.removeOne(a);
70                   delete a;
71                   update();
72                   break;
73                   }
74             }
75       }
76 
77 //---------------------------------------------------------
78 //   clear
79 //---------------------------------------------------------
80 
clear()81 void KeyCanvas::clear()
82       {
83       foreach(Accidental* a, accidentals)
84             delete a;
85       accidentals.clear();
86       update();
87       }
88 
89 //---------------------------------------------------------
90 //   paintEvent
91 //---------------------------------------------------------
92 
paintEvent(QPaintEvent *)93 void KeyCanvas::paintEvent(QPaintEvent*)
94       {
95       QPainter painter(this);
96       painter.setRenderHint(QPainter::Antialiasing, true);
97       qreal wh = double(height());
98       qreal ww = double(width());
99       double y = wh * .5 - 2 * PALETTE_SPATIUM * extraMag;
100 
101       qreal mag  = PALETTE_SPATIUM * extraMag / gscore->spatium();
102       _matrix    = QTransform(mag, 0.0, 0.0, mag, 0.0, y);
103       imatrix    = _matrix.inverted();
104 
105       qreal x = 3;
106       qreal w = ww - 6;
107 
108       painter.setWorldTransform(_matrix);
109 
110       QRectF r = imatrix.mapRect(QRectF(x, y, w, wh));
111 
112       QRectF background = imatrix.mapRect(QRectF(0, 0, ww, wh));
113       painter.fillRect(background, Qt::white);
114 
115       QPen pen(Qt::black);
116       pen.setWidthF(MScore::defaultStyle().value(Sid::staffLineWidth).toDouble() * gscore->spatium());
117       painter.setPen(pen);
118 
119       for (int i = 0; i < 5; ++i) {
120             qreal yy = r.y() + i * gscore->spatium();
121             painter.drawLine(QLineF(r.x(), yy, r.x() + r.width(), yy));
122             }
123       if (dragElement) {
124             painter.save();
125             painter.translate(dragElement->pagePos());
126             dragElement->draw(&painter);
127             painter.restore();
128             }
129       foreach(Accidental* a, accidentals) {
130             painter.save();
131             painter.translate(a->pagePos());
132             a->draw(&painter);
133             painter.restore();
134             }
135       clef->setPos(0.0, 0.0);
136       clef->layout();
137       painter.translate(clef->pagePos());
138       clef->draw(&painter);
139       }
140 
141 //---------------------------------------------------------
142 //   mousePressEvent
143 //---------------------------------------------------------
144 
mousePressEvent(QMouseEvent * event)145 void KeyCanvas::mousePressEvent(QMouseEvent* event)
146       {
147       startMove = imatrix.map(QPointF(event->pos() - base));
148       moveElement = 0;
149       foreach(Accidental* a, accidentals) {
150             QRectF r = a->abbox();
151             if (r.contains(startMove)) {
152                   a->setSelected(true);
153                   moveElement = a;
154                   }
155             else
156                   a->setSelected(false);
157             }
158       update();
159       }
160 
161 //---------------------------------------------------------
162 //   mouseMoveEvent
163 //---------------------------------------------------------
164 
mouseMoveEvent(QMouseEvent * event)165 void KeyCanvas::mouseMoveEvent(QMouseEvent* event)
166       {
167       if (moveElement == 0)
168             return;
169       QPointF p = imatrix.map(QPointF(event->pos()));
170       QPointF delta = p - startMove;
171       moveElement->move(delta);
172       startMove = p;
173       update();
174       }
175 
176 //---------------------------------------------------------
177 //   mouseReleaseEvent
178 //---------------------------------------------------------
179 
mouseReleaseEvent(QMouseEvent *)180 void KeyCanvas::mouseReleaseEvent(QMouseEvent*)
181       {
182       if (moveElement == 0)
183             return;
184       snap(moveElement);
185       update();
186       }
187 
188 //---------------------------------------------------------
189 //   dragEnterEvent
190 //---------------------------------------------------------
191 
dragEnterEvent(QDragEnterEvent * event)192 void KeyCanvas::dragEnterEvent(QDragEnterEvent* event)
193       {
194       const QMimeData* dta = event->mimeData();
195       if (dta->hasFormat(mimeSymbolFormat)) {
196             QByteArray a = dta->data(mimeSymbolFormat);
197 
198             XmlReader e(a);
199 
200             QPointF dragOffset;
201             Fraction duration;
202             ElementType type = Element::readType(e, &dragOffset, &duration);
203             if (type != ElementType::ACCIDENTAL)
204                   return;
205 
206             event->acceptProposedAction();
207             dragElement = static_cast<Accidental*>(Element::create(type, gscore));
208             dragElement->setParent(0);
209             dragElement->read(e);
210             dragElement->layout();
211             }
212       else {
213             if (MScore::debugMode) {
214                   qDebug("KeyCanvas::dragEnterEvent: formats:");
215                   foreach(const QString& s, event->mimeData()->formats())
216                         qDebug("   %s", qPrintable(s));
217                   }
218             }
219       }
220 
221 //---------------------------------------------------------
222 //   dragMoveEvent
223 //---------------------------------------------------------
224 
dragMoveEvent(QDragMoveEvent * event)225 void KeyCanvas::dragMoveEvent(QDragMoveEvent* event)
226       {
227       if (dragElement) {
228             event->acceptProposedAction();
229             QPointF pos(imatrix.map(QPointF(event->pos())));
230             dragElement->setPos(pos);
231             update();
232             }
233       }
234 
235 //---------------------------------------------------------
236 //   dropEvent
237 //---------------------------------------------------------
238 
dropEvent(QDropEvent *)239 void KeyCanvas::dropEvent(QDropEvent*)
240       {
241       for (Accidental* a : accidentals)
242             a->setSelected(false);
243       dragElement->setSelected(true);
244       accidentals.append(dragElement);
245       snap(dragElement);
246       dragElement = 0;
247       update();
248       }
249 
250 //---------------------------------------------------------
251 //   snap
252 //---------------------------------------------------------
253 
snap(Accidental * a)254 void KeyCanvas::snap(Accidental* a)
255       {
256       double y        = a->ipos().y();
257       double spatium2 = gscore->spatium() * .5;
258       int line        = int((y + spatium2 * .5) / spatium2);
259       y               = line * spatium2;
260       a->rypos()      = y;
261       }
262 
263 //---------------------------------------------------------
264 //   KeyEditor
265 //---------------------------------------------------------
266 
KeyEditor(QWidget * parent)267 KeyEditor::KeyEditor(QWidget* parent)
268    : QWidget(parent, Qt::WindowFlags(Qt::Dialog | Qt::Window))
269       {
270       setupUi(this);
271       setWindowTitle(tr("Key Signatures"));
272 
273       // create key signature palette
274 
275       QLayout* l = new QVBoxLayout();
276       l->setContentsMargins(0, 0, 0, 0);
277       frame->setLayout(l);
278 
279       sp = MuseScore::newKeySigPalette();
280       sp->setReadOnly(false);
281 
282       _keyPalette = new PaletteScrollArea(sp);
283       QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding);
284       _keyPalette->setSizePolicy(policy);
285       _keyPalette->setRestrictHeight(false);
286 
287       l->addWidget(_keyPalette);
288 
289       // create accidental palette
290 
291       l = new QVBoxLayout();
292       l->setContentsMargins(0, 0, 0, 0);
293       frame_3->setLayout(l);
294       sp1 = MuseScore::newAccidentalsPalette();
295       qreal adj = sp1->mag();
296       sp1->setGrid(sp1->gridWidth() * editScale / adj, sp1->gridHeight() * editScale / adj);
297       sp1->setMag(editScale);
298       PaletteScrollArea* accPalette = new PaletteScrollArea(sp1);
299       QSizePolicy policy1(QSizePolicy::Expanding, QSizePolicy::Expanding);
300       accPalette->setSizePolicy(policy1);
301       accPalette->setRestrictHeight(false);
302 
303       l->addWidget(accPalette);
304 
305       connect(addButton,   SIGNAL(clicked()), SLOT(addClicked()));
306       connect(clearButton, SIGNAL(clicked()), SLOT(clearClicked()));
307       connect(sp,          SIGNAL(changed()), SLOT(setDirty()));
308 
309       //
310       // set all "buildin" key signatures to read only
311       //
312       int n = sp->size();
313       for (int i = 0; i < n; ++i)
314             sp->setCellReadOnly(i, true);
315 
316       if (!useFactorySettings) {
317             QString path = dataPath + "/keysigs";
318             if (!sp->read(path))
319                   qDebug("KeyEditor: read <%s> failed", qPrintable(dataPath + "/keysigs.mpal"));
320             }
321       }
322 
323 //---------------------------------------------------------
324 //   addClicked
325 //---------------------------------------------------------
326 
addClicked()327 void KeyEditor::addClicked()
328       {
329       // double extraMag = 2.0;
330       const QList<Accidental*> al = canvas->getAccidentals();
331       // qreal mag  = PALETTE_SPATIUM * extraMag / gscore->spatium();
332       // double spatium = 2.0 * PALETTE_SPATIUM / extraMag;
333       double spatium = gscore->spatium();
334       double xoff = 10000000.0;
335 
336       for (Accidental* a : al) {
337             QPointF pos = a->ipos();
338             if (pos.x() < xoff)
339                   xoff = pos.x();
340             }
341 
342       KeySigEvent e;
343       e.setCustom(true);
344       for (Accidental* a : al) {
345             KeySym s;
346             s.sym       = a->symbol();
347             QPointF pos = a->ipos();
348             pos.rx()   -= xoff;
349             s.spos      = pos / spatium;
350             e.keySymbols().append(s);
351             }
352       KeySig* ks = new KeySig(gscore);
353       ks->setKeySigEvent(e);
354       sp->append(ks, "custom");
355       _dirty = true;
356       emit keySigAdded(ks);
357       }
358 
359 //---------------------------------------------------------
360 //   clearClicked
361 //---------------------------------------------------------
362 
clearClicked()363 void KeyEditor::clearClicked()
364       {
365       canvas->clear();
366       }
367 
368 //---------------------------------------------------------
369 //   showKeyPalette
370 //---------------------------------------------------------
371 
showKeyPalette(bool val)372 void KeyEditor::showKeyPalette(bool val)
373       {
374       _keyPalette->setVisible(val);
375       }
376 
377 //---------------------------------------------------------
378 //   save
379 //---------------------------------------------------------
380 
save()381 void KeyEditor::save()
382       {
383       QDir dir;
384       dir.mkpath(dataPath);
385       sp->write(dataPath + "/keysigs");
386       }
387 
388 //---------------------------------------------------------
389 //   showKeyEditor
390 //---------------------------------------------------------
391 
showKeyEditor()392 void MuseScore::showKeyEditor()
393       {
394       if (keyEditor == 0) {
395             keyEditor = new KeyEditor(0);
396             }
397       keyEditor->show();
398       keyEditor->raise();
399       }
400 }
401 
402