1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2013-15 Werner Schweer & 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 LICENCE.GPL
11 //=============================================================================
12 
13 #include "textcursor.h"
14 
15 #include "libmscore/input.h"
16 #include "libmscore/measure.h"
17 #include "libmscore/page.h"
18 #include "libmscore/score.h"
19 #include "libmscore/segment.h"
20 #include "libmscore/staff.h"
21 #include "libmscore/stafftype.h"
22 #include "libmscore/sym.h"
23 #include "libmscore/system.h"
24 
25 #include "scoreview.h"
26 
27 namespace Ms {
28 
29 //---------------------------------------------------------
30 //   PositionCursor
31 //---------------------------------------------------------
32 
setType(CursorType t)33 void PositionCursor::setType(CursorType t)
34       {
35       _type = t;
36       if (_type == CursorType::LOOP_IN) {
37             // QColor cIn(Qt::green);
38             QColor cIn(0x2456aa);
39             // cIn.setAlpha(90);
40             setColor(cIn);
41             }
42       else if (_type == CursorType::LOOP_OUT) {
43             // QColor cOut(Qt::red);
44             QColor cOut(0x2456aa);
45             // cOut.setAlpha(90);
46             setColor(cOut);
47             }
48       }
49 
50 //---------------------------------------------------------
51 //   paint
52 //---------------------------------------------------------
53 
paint(QPainter * p)54 void PositionCursor::paint(QPainter* p)
55       {
56       if (!visible())
57             return;
58       QPointF points[3];
59       qreal h = _sv->score()->spatium() * 2;
60 
61       qreal x = _rect.left();
62       qreal y = _rect.top();
63 
64       switch(_type) {
65             case CursorType::LOOP_IN:           // draw a right-pointing triangle
66                   {
67                   qreal tx = x - 1.0;
68                   p->setPen(QPen(_color, 2.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
69                   p->drawLine(x, y, x, _rect.bottom());
70                   points[0] = QPointF(tx, y);
71                   points[1] = QPointF(tx, y + h);
72                   points[2] = QPointF(tx + h, y + h * .5);
73                   p->setBrush(_color);
74                   p->drawConvexPolygon(points, 3);
75                   }
76                   break;
77             case CursorType::LOOP_OUT:          // draw a left-pointing triangle
78                   p->setPen(QPen(_color, 2.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
79                   p->drawLine(x, y, x, _rect.bottom());
80                   points[0] = QPointF(x, y);
81                   points[1] = QPointF(x, y + h);
82                   points[2] = QPointF(x - h, y + h * .5);
83                   p->setBrush(_color);
84                   p->drawConvexPolygon(points, 3);
85                   break;
86             default:                            // fill the rectangle and add TAB string marks, if required
87                   p->fillRect(_rect, color());
88                   if (_sv->score()->noteEntryMode()) {
89                         int         track       = _sv->score()->inputTrack();
90                         if (track >= 0) {
91                               Staff*      staff       = _sv->score()->staff(track2staff(track));
92                               const StaffType*  staffType   = staff->staffType(Fraction(0,1));
93                               if (staffType && staffType->group() == StaffGroup::TAB)
94                                     staffType->drawInputStringMarks(p, _sv->score()->inputState().string(),
95                                        track2voice(track), _rect);
96                                     }
97                         }
98                   break;
99             }
100       }
101 
102 //---------------------------------------------------------
103 //   bbox
104 //---------------------------------------------------------
105 
bbox() const106 QRectF PositionCursor::bbox() const
107       {
108       QRectF r;
109       qreal h = _sv->score()->spatium() * 2;
110 
111       switch(_type) {
112             case CursorType::LOOP_IN:
113                   r.setRect(_rect.x(), _rect.y(), h, _rect.height());
114                   break;
115             case CursorType::LOOP_OUT:
116                   r.setRect(_rect.x() - h, _rect.y(), h, _rect.height());
117                   break;
118             default:
119                   r = _rect;
120                   break;
121             }
122       return r.adjusted(-2, -2, 2, 2);
123       }
124 
125 
126 //---------------------------------------------------------
127 //   move
128 //---------------------------------------------------------
129 
move(const Fraction & t)130 void PositionCursor::move(const Fraction& t)
131       {
132       Fraction tick(t);
133       QRectF r(bbox());
134       //
135       // set mark height for whole system
136       //
137       if (_type == CursorType::LOOP_OUT && tick > Fraction(0,1))
138             tick -= Fraction::fromTicks(1);           // tick--
139       Score* score = _sv->score();
140       Measure* measure = score->tick2measureMM(tick);
141       if (measure == 0)
142             return;
143       qreal x = 0.0;
144       const Fraction offset = {0,1};    //??
145 
146       Segment* s;
147       for (s = measure->first(SegmentType::ChordRest); s;) {
148             Fraction t1 = s->tick();
149             int x1 = s->canvasPos().x();
150             qreal x2;
151             Fraction t2;
152             Segment* ns = s->next(SegmentType::ChordRest);
153             if (ns) {
154                   t2 = ns->tick();
155                   x2 = ns->canvasPos().x();
156                   }
157             else {
158                   t2 = measure->endTick();
159                   x2 = measure->canvasPos().x() + measure->width();
160                   }
161             t1 += offset;
162             t2 += offset;
163             if (tick >= t1 && tick < t2) {
164                   Fraction dt = t2 - t1;
165                   qreal dx = x2 - x1;
166                   x = x1 + dx * (tick-t1).ticks() / dt.ticks();
167                   break;
168                   }
169             s = ns;
170             }
171       if (s == 0)
172             return;
173 
174       System* system = measure->system();
175       if (system == 0 || system->page() == 0)
176             return;
177       double y        = system->staffYpage(0) + system->page()->pos().y();
178       double _spatium = score->spatium();
179 
180       qreal mag = _spatium / SPATIUM20;
181       double w  = (_spatium * 2.0 + score->scoreFont()->width(SymId::noteheadBlack, mag))/3;
182       double h  = 6 * _spatium;
183       //
184       // set cursor height for whole system
185       //
186       double y2 = 0.0;
187 
188       for (int i = 0; i < score->nstaves(); ++i) {
189             SysStaff* ss = system->staff(i);
190             if (!ss->show() || !score->staff(i)->show())
191                   continue;
192             y2 = ss->y() + ss->bbox().height();
193             }
194       h += y2;
195       y -= 3 * _spatium;
196 
197       if (_type == CursorType::LOOP_IN) {
198             x = x - _spatium + w/1.5;
199             }
200       else {
201             x = x - _spatium * .5;
202             }
203       _tick = tick;
204       _rect = QRectF(x, y, w, h);
205       _sv->update(_sv->matrix().mapRect(r | bbox()).toRect().adjusted(-1,-1,1,1));
206       }
207 }
208 
209