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