1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2013 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 // as published by the Free Software Foundation and appearing in
10 // the file LICENSE.GPL
11 //=============================================================================
12
13 #include "exampleview.h"
14 #include "preferences.h"
15 #include "libmscore/score.h"
16 #include "libmscore/element.h"
17 #include "libmscore/page.h"
18 #include "libmscore/system.h"
19 #include "libmscore/icon.h"
20 #include "libmscore/chord.h"
21 #include "libmscore/xml.h"
22
23 namespace Ms {
24
25 //---------------------------------------------------------
26 // ExampleView
27 //---------------------------------------------------------
28
ExampleView(QWidget * parent)29 ExampleView::ExampleView(QWidget* parent)
30 : QFrame(parent)
31 {
32 _score = 0;
33 setAcceptDrops(true);
34 setFocusPolicy(Qt::StrongFocus);
35 resetMatrix();
36 _fgPixmap = nullptr;
37 _fgColor = Qt::white;
38 if (preferences.getBool(PREF_UI_CANVAS_FG_USECOLOR))
39 _fgColor = preferences.getColor(PREF_UI_CANVAS_FG_COLOR);
40 else {
41 _fgPixmap = new QPixmap(preferences.getString(PREF_UI_CANVAS_FG_WALLPAPER));
42 if (_fgPixmap == 0 || _fgPixmap->isNull())
43 qDebug("no valid pixmap %s", qPrintable(preferences.getString(PREF_UI_CANVAS_FG_WALLPAPER)));
44 }
45 // setup drag canvas state
46 sm = new QStateMachine(this);
47 QState* stateActive = new QState;
48
49 QState* s1 = new QState(stateActive);
50 s1->setObjectName("example-normal");
51 s1->assignProperty(this, "cursor", QCursor(Qt::ArrowCursor));
52
53 QState* s = new QState(stateActive);
54 s->setObjectName("example-drag");
55 s->assignProperty(this, "cursor", QCursor(Qt::SizeAllCursor));
56 QEventTransition* cl = new QEventTransition(this, QEvent::MouseButtonRelease);
57 cl->setTargetState(s1);
58 s->addTransition(cl);
59 s1->addTransition(new DragTransitionExampleView(this));
60
61
62 sm->addState(stateActive);
63 stateActive->setInitialState(s1);
64 sm->setInitialState(stateActive);
65
66 sm->start();
67 }
68
69 //---------------------------------------------------------
70 // ~ExampleView
71 //---------------------------------------------------------
72
~ExampleView()73 ExampleView::~ExampleView()
74 {
75 if (_fgPixmap)
76 delete _fgPixmap;
77 }
78
79 //---------------------------------------------------------
80 // resetMatrix
81 // used to reset scrolling in case time signature num or denom changed
82 //---------------------------------------------------------
83
resetMatrix()84 void ExampleView::resetMatrix()
85 {
86 double mag = 0.9 * guiScaling * (DPI_DISPLAY / DPI); // 90% of nominal
87 qreal _spatium = SPATIUM20 * mag;
88 // example would normally be 10sp from top of page; this leaves 3sp margin above
89 _matrix = QTransform(mag, 0.0, 0.0, mag, _spatium, -_spatium * 7.0);
90 imatrix = _matrix.inverted();
91 }
92
layoutChanged()93 void ExampleView::layoutChanged()
94 {
95 }
96
dataChanged(const QRectF &)97 void ExampleView::dataChanged(const QRectF&)
98 {
99 }
100
updateAll()101 void ExampleView::updateAll()
102 {
103 update();
104 }
105
adjustCanvasPosition(const Element *,bool)106 void ExampleView::adjustCanvasPosition(const Element* /*el*/, bool /*playBack*/)
107 {
108 }
109
110 //---------------------------------------------------------
111 // setScore
112 //---------------------------------------------------------
113
setScore(Score * s)114 void ExampleView::setScore(Score* s)
115 {
116 delete _score;
117 _score = s;
118 _score->addViewer(this);
119 _score->setLayoutMode(LayoutMode::LINE);
120
121 ScoreLoad sl;
122 _score->doLayout();
123 update();
124 }
125
removeScore()126 void ExampleView::removeScore()
127 {
128 }
129
changeEditElement(Element *)130 void ExampleView::changeEditElement(Element*)
131 {
132 }
133
cursor() const134 QCursor ExampleView::cursor() const
135 {
136 return QCursor();
137 }
138
setCursor(const QCursor &)139 void ExampleView::setCursor(const QCursor&)
140 {
141 }
142
setDropRectangle(const QRectF &)143 void ExampleView::setDropRectangle(const QRectF&)
144 {
145 }
146
cmdAddSlur(Note *,Note *)147 void ExampleView::cmdAddSlur(Note* /*firstNote*/, Note* /*lastNote*/)
148 {
149 }
150
elementNear(QPointF)151 Element* ExampleView::elementNear(QPointF)
152 {
153 return 0;
154 }
155
drawBackground(QPainter * p,const QRectF & r) const156 void ExampleView::drawBackground(QPainter* p, const QRectF& r) const
157 {
158 if (_fgPixmap == 0 || _fgPixmap->isNull())
159 p->fillRect(r, _fgColor);
160 else {
161 p->drawTiledPixmap(r, *_fgPixmap, r.topLeft()
162 - QPoint(lrint(_matrix.dx()), lrint(_matrix.dy())));
163 }
164 }
165
166 //---------------------------------------------------------
167 // drawElements
168 //---------------------------------------------------------
169
drawElements(QPainter & painter,const QList<Element * > & el)170 void ExampleView::drawElements(QPainter& painter, const QList<Element*>& el)
171 {
172 for (Element* e : el) {
173 e->itemDiscovered = 0;
174 QPointF pos(e->pagePos());
175 painter.translate(pos);
176 e->draw(&painter);
177 painter.translate(-pos);
178 }
179 }
180
181 //---------------------------------------------------------
182 // paintEvent
183 //---------------------------------------------------------
184
paintEvent(QPaintEvent * ev)185 void ExampleView::paintEvent(QPaintEvent* ev)
186 {
187 if (_score) {
188 QPainter p(this);
189 p.setRenderHint(QPainter::Antialiasing, preferences.getBool(PREF_UI_CANVAS_MISC_ANTIALIASEDDRAWING));
190 p.setRenderHint(QPainter::TextAntialiasing, true);
191 const QRect r(ev->rect());
192
193 drawBackground(&p, r);
194
195 p.setTransform(_matrix);
196 QRectF fr = imatrix.mapRect(QRectF(r));
197
198 Page* page = _score->pages().front();
199 QList<Element*> ell = page->items(fr);
200 std::stable_sort(ell.begin(), ell.end(), elementLessThan);
201 drawElements(p, ell);
202 }
203 QFrame::paintEvent(ev);
204 }
205
206 //---------------------------------------------------------
207 // dragEnterEvent
208 //---------------------------------------------------------
209
dragEnterEvent(QDragEnterEvent * event)210 void ExampleView::dragEnterEvent(QDragEnterEvent* event)
211 {
212 const QMimeData* d = event->mimeData();
213 if (d->hasFormat(mimeSymbolFormat)) {
214 event->acceptProposedAction();
215
216 QByteArray a = d->data(mimeSymbolFormat);
217
218 // qDebug("ExampleView::dragEnterEvent Symbol: <%s>", a.data());
219
220 XmlReader e(a);
221 QPointF dragOffset;
222 Fraction duration; // dummy
223 ElementType type = Element::readType(e, &dragOffset, &duration);
224
225 dragElement = Element::create(type, _score);
226 if (dragElement) {
227 dragElement->setParent(0);
228 dragElement->read(e);
229 dragElement->layout();
230 }
231 return;
232 }
233 }
234
235 //---------------------------------------------------------
236 // dragLeaveEvent
237 //---------------------------------------------------------
238
dragLeaveEvent(QDragLeaveEvent *)239 void ExampleView::dragLeaveEvent(QDragLeaveEvent*)
240 {
241 if (dragElement) {
242 delete dragElement;
243 dragElement = 0;
244 }
245 setDropTarget(0);
246 }
247
248 //---------------------------------------------------------
249 // moveElement
250 //---------------------------------------------------------
251
moveElement(void * data,Element * e)252 static void moveElement(void* data, Element* e)
253 {
254 QPointF* pos = (QPointF*)data;
255 e->score()->addRefresh(e->canvasBoundingRect());
256 e->setPos(*pos);
257 e->score()->addRefresh(e->canvasBoundingRect());
258 }
259
260 //---------------------------------------------------------
261 // dragMoveEvent
262 //---------------------------------------------------------
263
dragMoveEvent(QDragMoveEvent * event)264 void ExampleView::dragMoveEvent(QDragMoveEvent* event)
265 {
266 event->acceptProposedAction();
267
268 if (!dragElement || dragElement->type() != ElementType::ICON)
269 return;
270
271 QPointF pos(imatrix.map(QPointF(event->pos())));
272 QList<Element*> el = elementsAt(pos);
273 bool found = false;
274 foreach(const Element* e, el) {
275 if (e->type() == ElementType::NOTE) {
276 setDropTarget(const_cast<Element*>(e));
277 found = true;
278 break;
279 }
280 }
281 if (!found)
282 setDropTarget(0);
283 dragElement->scanElements(&pos, moveElement, false);
284 _score->update();
285 return;
286 }
287
288 //---------------------------------------------------------
289 // setDropTarget
290 //---------------------------------------------------------
291
setDropTarget(const Element * el)292 void ExampleView::setDropTarget(const Element* el)
293 {
294 if (dropTarget != el) {
295 if (dropTarget) {
296 dropTarget->setDropTarget(false);
297 dropTarget = 0;
298 }
299 dropTarget = el;
300 if (dropTarget) {
301 dropTarget->setDropTarget(true);
302 }
303 }
304 if (!dropAnchor.isNull()) {
305 QRectF r;
306 r.setTopLeft(dropAnchor.p1());
307 r.setBottomRight(dropAnchor.p2());
308 dropAnchor = QLineF();
309 }
310 if (dropRectangle.isValid()) {
311 dropRectangle = QRectF();
312 }
313 update();
314 }
315
316 //---------------------------------------------------------
317 // dropEvent
318 //---------------------------------------------------------
319
dropEvent(QDropEvent * event)320 void ExampleView::dropEvent(QDropEvent* event)
321 {
322 QPointF pos(imatrix.map(QPointF(event->pos())));
323
324 if (!dragElement)
325 return;
326 if (dragElement->type() != ElementType::ICON) {
327 delete dragElement;
328 dragElement = 0;
329 return;
330 }
331 foreach (Element* e, elementsAt(pos)) {
332 if (e->type() == ElementType::NOTE) {
333 Icon* icon = static_cast<Icon*>(dragElement);
334 Chord* chord = static_cast<Note*>(e)->chord();
335 emit beamPropertyDropped(chord, icon);
336 switch (icon->iconType()) {
337 case IconType::SBEAM:
338 chord->setBeamMode(Beam::Mode::BEGIN);
339 break;
340 case IconType::MBEAM:
341 chord->setBeamMode(Beam::Mode::AUTO);
342 break;
343 case IconType::BEAM32:
344 chord->setBeamMode(Beam::Mode::BEGIN32);
345 break;
346 case IconType::BEAM64:
347 chord->setBeamMode(Beam::Mode::BEGIN64);
348 break;
349 default:
350 break;
351 }
352 score()->doLayout();
353 break;
354 }
355 }
356 event->acceptProposedAction();
357 delete dragElement;
358 dragElement = 0;
359 setDropTarget(0);
360 }
361
362 //---------------------------------------------------------
363 // mousePressEvent
364 //---------------------------------------------------------
365
mousePressEvent(QMouseEvent * event)366 void ExampleView::mousePressEvent(QMouseEvent* event)
367 {
368 startMove = imatrix.map(QPointF(event->pos()));
369 QPointF pos(imatrix.map(QPointF(event->pos())));
370
371 foreach (Element* e, elementsAt(pos)) {
372 if (e->type() == ElementType::NOTE) {
373 emit noteClicked(static_cast<Note*>(e));
374 break;
375 }
376 }
377 }
378
379 //---------------------------------------------------------
380 // sizeHint
381 //---------------------------------------------------------
382
sizeHint() const383 QSize ExampleView::sizeHint() const
384 {
385 qreal mag = 0.9 * guiScaling * (DPI_DISPLAY / DPI);
386 qreal _spatium = SPATIUM20 * mag;
387 // staff is 4sp tall with 3sp margin above; this leaves 3sp margin below
388 qreal height = 10.0 * _spatium;
389 if (score() && score()->pages().size() > 0)
390 height = score()->pages()[0]->tbbox().height() * mag + (6 * _spatium);
391 return QSize(1000 * mag, height);
392 }
393
394 //---------------------------------------------------------
395 // dragExampleView
396 // constrained scrolling ensuring that this ExampleView won't be moved past the borders of its QFrame
397 //---------------------------------------------------------
398
dragExampleView(QMouseEvent * ev)399 void ExampleView::dragExampleView(QMouseEvent* ev)
400 {
401 QPoint d = ev->pos() - _matrix.map(startMove).toPoint();
402 int dx = d.x();
403 if (dx == 0)
404 return;
405
406 constraintCanvas(&dx);
407
408 // Perform the actual scrolling
409 _matrix.setMatrix(_matrix.m11(), _matrix.m12(), _matrix.m13(), _matrix.m21(),
410 _matrix.m22(), _matrix.m23(), _matrix.dx()+dx, _matrix.dy(), _matrix.m33());
411 imatrix = _matrix.inverted();
412 scroll(dx, 0);
413 }
414
onTransition(QEvent * e)415 void DragTransitionExampleView::onTransition(QEvent* e)
416 {
417 QStateMachine::WrappedEvent* we = static_cast<QStateMachine::WrappedEvent*>(e);
418 QMouseEvent* me = static_cast<QMouseEvent*>(we->event());
419 canvas->dragExampleView(me);
420 }
421
422 //---------------------------------------------------------
423 // wheelEvent
424 //---------------------------------------------------------
425
wheelEvent(QWheelEvent * event)426 void ExampleView::wheelEvent(QWheelEvent* event)
427 {
428 QPoint pixelsScrolled = event->pixelDelta();
429 QPoint stepsScrolled = event->angleDelta();
430 int dx = 0, dy = 0;
431 if (!pixelsScrolled.isNull()) {
432 dx = pixelsScrolled.x();
433 dy = pixelsScrolled.y();
434 }
435 else if (!stepsScrolled.isNull()) {
436 dx = static_cast<qreal>(stepsScrolled.x()) * qMax(2, width() / 10) / 120;
437 dy = static_cast<qreal>(stepsScrolled.y()) * qMax(2, height() / 10) / 120;
438 }
439
440 if (dx == 0) {
441 if (dy == 0)
442 return;
443 else
444 dx = dy;
445 }
446
447 constraintCanvas(&dx);
448
449 _matrix.setMatrix(_matrix.m11(), _matrix.m12(), _matrix.m13(), _matrix.m21(),
450 _matrix.m22(), _matrix.m23(), _matrix.dx()+dx, _matrix.dy(), _matrix.m33());
451 imatrix = _matrix.inverted();
452 scroll(dx, 0);
453 }
454
455 //-----------------------------------------------------------------------------
456 // constraintCanvas
457 //-----------------------------------------------------------------------------
458
constraintCanvas(int * dxx)459 void ExampleView::constraintCanvas (int* dxx)
460 {
461 int dx = *dxx;
462
463 Q_ASSERT(_score->pages().front()->system(0)); // should exist if doLayout ran
464
465 // form rectangle bounding the system with a spatium margin and translate relative to view space
466 qreal xstart = _score->pages().front()->system(0)->bbox().left() - SPATIUM20;
467 qreal xend = _score->pages().front()->system(0)->bbox().right() + 2.0 * SPATIUM20;
468 QRectF systemScaledViewRect(xstart * _matrix.m11(), 0, xend * _matrix.m11(), 0);
469 systemScaledViewRect.translate(_matrix.dx(), 0);
470
471 qreal frameWidth = static_cast<QFrame*>(this)->frameRect().width();
472
473 // constrain the dx of scrolling so that this ExampleView won't be moved past the borders of its QFrame
474 if (dx > 0) {
475 // when moving right, ensure the left edge of systemScaledViewRect won't be right of frame's left edge
476 if (systemScaledViewRect.left() + dx > 0)
477 dx = -systemScaledViewRect.left();
478 }
479 else {
480 // never move left if entire system already fits entirely within the frame
481 if (systemScaledViewRect.width() < frameWidth)
482 dx = 0;
483 // when moving left, ensure the right edge of systemScaledViewRect won't be left of frame's right edge
484 else if (systemScaledViewRect.right() + dx < frameWidth)
485 dx = frameWidth - systemScaledViewRect.right();
486 }
487
488 *dxx = dx;
489 }
490 }
491
492