1 //=============================================================================
2 //  MusE Score
3 //  Linux Music Score Editor
4 //
5 //  Copyright (C) 2009 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 "ruler.h"
21 #include "libmscore/score.h"
22 
23 namespace Ms {
24 
25 #if 0 // yet(?) unused
26 static const int MAP_OFFSET = 480;
27 #endif
28 
29 QPixmap* Ruler::markIcon[3];
30 
31 static const char* rmark_xpm[]={
32       "18 18 2 1",
33       "# c #0000ff",
34       ". c None",
35       "..................",
36       "..................",
37       "..................",
38       "..................",
39       "..................",
40       "..................",
41       "..................",
42       "........##########",
43       "........#########.",
44       "........########..",
45       "........#######...",
46       "........######....",
47       "........#####.....",
48       "........####......",
49       "........###.......",
50       "........##........",
51       "........##........",
52       "........##........"};
53 static const char* lmark_xpm[]={
54       "18 18 2 1",
55       "# c #0000ff",
56       ". c None",
57       "..................",
58       "..................",
59       "..................",
60       "..................",
61       "..................",
62       "..................",
63       "..................",
64       "##########........",
65       ".#########........",
66       "..########........",
67       "...#######........",
68       "....######........",
69       ".....#####........",
70       "......####........",
71       ".......###........",
72       "........##........",
73       "........##........",
74       "........##........"};
75 static const char* cmark_xpm[]={
76       "18 18 2 1",
77       "# c #ff0000",
78       ". c None",
79       "..................",
80       "..................",
81       "..................",
82       "..................",
83       "..................",
84       "..................",
85       "..................",
86       "##################",
87       ".################.",
88       "..##############..",
89       "...############...",
90       "....##########....",
91       ".....########.....",
92       "......######......",
93       ".......####.......",
94       "........##........",
95       "........##........",
96       "........##........"};
97 
98 
99 //---------------------------------------------------------
100 //   Ruler
101 //---------------------------------------------------------
102 
Ruler(QWidget * parent)103 Ruler::Ruler(QWidget* parent)
104    : QWidget(parent)
105       {
106       if (markIcon[0] == 0) {
107             markIcon[0] = new QPixmap(cmark_xpm);
108             markIcon[1] = new QPixmap(lmark_xpm);
109             markIcon[2] = new QPixmap(rmark_xpm);
110             }
111       setMouseTracking(true);
112       _score      = nullptr;
113       _locator    = nullptr;
114       magStep     = 0;
115       _xpos       = 0;
116       _xmag       = 0.1;
117       _timeType   = TType::TICKS;
118       _font2.setPixelSize(14);
119       _font2.setBold(true);
120       _font1.setPixelSize(10);
121       }
122 
123 //---------------------------------------------------------
124 //   setScore
125 //---------------------------------------------------------
126 
setScore(Score * s,Pos * lc)127 void Ruler::setScore(Score* s, Pos* lc)
128       {
129       _score = s;
130       _locator = lc;
131       if (_score)
132             _cursor.setContext(_score->tempomap(), _score->sigmap());
133       setEnabled(_score != 0);
134       }
135 
136 //---------------------------------------------------------
137 //   setXmag
138 //---------------------------------------------------------
139 
setMag(double x,double)140 void Ruler::setMag(double x, double /*y*/)
141       {
142       if (_xmag != x) {
143             _xmag = x;
144 
145             int tpix  = (480 * 4) * _xmag;
146             magStep = 0;
147             if (tpix < 64)
148                   magStep = 1;
149             if (tpix < 32)
150                   magStep = 2;
151             if (tpix <= 16)
152                   magStep = 3;
153             if (tpix < 8)
154                   magStep = 4;
155             if (tpix <= 4)
156                   magStep = 5;
157             if (tpix <= 2)
158                   magStep = 6;
159             update();
160             }
161       }
162 
163 //---------------------------------------------------------
164 //   setXpos
165 //---------------------------------------------------------
166 
setXpos(int val)167 void Ruler::setXpos(int val)
168       {
169       _xpos = val;
170       update();
171       }
172 
173 //---------------------------------------------------------
174 //   pix2pos
175 //---------------------------------------------------------
176 
pix2pos(int x) const177 Pos Ruler::pix2pos(int x) const
178       {
179       int val = lrint((x + 5 + _xpos)/_xmag - 480);
180       if (val < 0)
181             val = 0;
182       return Pos(_score->tempomap(), _score->sigmap(), val, _timeType);
183       }
184 
185 //---------------------------------------------------------
186 //   pos2pix
187 //---------------------------------------------------------
188 
pos2pix(const Pos & p) const189 int Ruler::pos2pix(const Pos& p) const
190       {
191 //      return lrint((p.time(_timeType) + 480) * _xmag) - _xpos - 5;
192       return lrint((p.time(_timeType) + 480) * _xmag) - _xpos - 1;
193       }
194 
195 //---------------------------------------------------------
196 //   paintEvent
197 //---------------------------------------------------------
198 
paintEvent(QPaintEvent * e)199 void Ruler::paintEvent(QPaintEvent* e)
200       {
201       QPainter p(this);
202       const QRect& r = e->rect();
203 
204       static const int mag[7] = {
205             1, 1, 2, 5, 10, 20, 50
206             };
207 
208       int x  = r.x();
209       int w  = r.width();
210       int y  = rulerHeight - 16;
211       int h  = 16; // 14;
212       int y1 = r.y();
213       int rh = r.height();
214       if (y1 < rulerHeight) {
215             rh -= rulerHeight - y1;
216             y1 = rulerHeight;
217             }
218       int y2 = y1 + rh;
219 
220       if (x < (-_xpos))
221             x = -_xpos;
222 
223       if (!_score)
224             return;
225 
226       Pos pos1 = pix2pos(x);
227       Pos pos2 = pix2pos(x+w);
228 
229       //---------------------------------------------------
230       //    draw raster
231       //---------------------------------------------------
232 
233       int bar1, bar2, beat1, tick;
234 
235       pos1.mbt(&bar1, &beat1, &tick);
236       pos2.mbt(&bar2, &beat1, &tick);
237 
238       int n = mag[magStep];
239 
240       bar1 = (bar1 / n) * n;        // round down
241       if (bar1 && n >= 2)
242             bar1 -= 1;
243       bar2 = ((bar2 + n - 1) / n) * n; // round up
244 
245       for (int bar = bar1; bar <= bar2;) {
246             Pos stick(_score->tempomap(), _score->sigmap(), bar, 0, 0);
247             if (magStep) {
248                   p.setFont(_font2);
249                   int x1 = pos2pix(stick);
250                   QString s;
251                   s.setNum(bar + 1);
252 
253                   p.setPen(Qt::black);
254                   p.drawLine(x1, y, x1, y + h);
255                   QRect r1 = QRect(x1+2, y, 1000, h);
256                   p.drawText(r1, Qt::AlignLeft | Qt::AlignVCenter, s);
257                   p.setPen(Qt::lightGray);
258                   if (x1 > 0)
259                         p.drawLine(x1, y1, x1, y2);
260                   }
261             else {
262                   SigEvent sig = stick.timesig();
263                   int z = sig.timesig().numerator();
264                   for (int beat = 0; beat < z; beat++) {
265                         Pos xx(_score->tempomap(), _score->sigmap(), bar, beat, 0);
266                         int xp = pos2pix(xx);
267                         if (xp < 0)
268                               continue;
269                         QString s;
270                         QRect r1(xp+2, y + 1, 1000, h);
271                         int y3;
272                         int num;
273                         if (beat == 0) {
274                               num = bar + 1;
275                               y3  = y + 2;
276                               p.setFont(_font2);
277                               }
278                         else {
279                               num = beat + 1;
280                               y3  = y + 8;
281                               p.setFont(_font1);
282                               r1.moveTop(r1.top() + 1);
283                               }
284                         s.setNum(num);
285                         p.setPen(Qt::black);
286                         p.drawLine(xp, y3, xp, y+h);
287                         p.drawText(r1, Qt::AlignLeft | Qt::AlignVCenter, s);
288                         p.setPen(beat == 0 ? Qt::lightGray : Qt::gray);
289                         if (xp > 0)
290                               p.drawLine(xp, y1, xp, y2);
291                         }
292                   }
293             if (bar == 0 && n >= 2)
294                   bar += (n-1);
295             else
296                   bar += n;
297             }
298       //
299       //  draw mouse cursor marker
300       //
301       p.setPen(Qt::black);
302       if (_cursor.valid()) {
303             int xp = pos2pix(_cursor);
304             if (xp >= x && xp < x+w)
305                   p.drawLine(xp, 0, xp, rulerHeight);
306             }
307       static const QColor lcColors[3] = { Qt::red, Qt::blue, Qt::blue };
308       for (int i = 0; i < 3; ++i) {
309             if (!_locator[i].valid())
310                   continue;
311             p.setPen(lcColors[i]);
312             int xp      = pos2pix(_locator[i]);
313             QPixmap* pm = markIcon[i];
314             // int pw = (pm->width() + 1) / 2;
315             int pw = pm->width() / 2;
316             int x1 = x - pw;
317             int x2 = x + w + pw;
318             if (xp >= x1 && xp < x2)
319                   p.drawPixmap(xp - pw, y-2, *pm);
320             }
321       }
322 
323 //---------------------------------------------------------
324 //   mousePressEvent
325 //---------------------------------------------------------
326 
mousePressEvent(QMouseEvent * e)327 void Ruler::mousePressEvent(QMouseEvent* e)
328       {
329       moveLocator(e);
330       }
331 
332 //---------------------------------------------------------
333 //   mouseMoveEvent
334 //---------------------------------------------------------
335 
mouseMoveEvent(QMouseEvent * e)336 void Ruler::mouseMoveEvent(QMouseEvent* e)
337       {
338       moveLocator(e);
339       }
340 
341 //---------------------------------------------------------
342 //   moveLocator
343 //---------------------------------------------------------
344 
moveLocator(QMouseEvent * e)345 void Ruler::moveLocator(QMouseEvent* e)
346       {
347       Pos pos(pix2pos(e->pos().x()));
348       if (e->buttons() & Qt::LeftButton)
349             emit locatorMoved(0, pos);
350       else if (e->buttons() & Qt::MidButton)
351             emit locatorMoved(1, pos);
352       else if (e->buttons() & Qt::RightButton)
353             emit locatorMoved(2, pos);
354       }
355 
356 //---------------------------------------------------------
357 //   leaveEvent
358 //---------------------------------------------------------
359 
leaveEvent(QEvent *)360 void Ruler::leaveEvent(QEvent*)
361       {
362       _cursor.setInvalid();
363       emit posChanged(_cursor);
364       update();
365       }
366 
367 //---------------------------------------------------------
368 //   setPos
369 //---------------------------------------------------------
370 
setPos(const Pos & pos)371 void Ruler::setPos(const Pos& pos)
372       {
373       if (_cursor != pos) {
374             int x1 = pos2pix(_cursor);
375             int x2 = pos2pix(pos);
376             if (x1 > x2) {
377                   int tmp = x2;
378                   x2 = x1;
379                   x1 = tmp;
380                   }
381             update(QRect(x1-1, 0, x2-x1+2, height()));
382             _cursor = pos;
383             }
384       }
385 }
386 
387