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