1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //    $Id: mtscale_flo.cpp,v 1.8.2.7 2011/05/19 04:14:01 flo Exp $
5 //  (C) Copyright 1999 Werner Schweer (ws@seh.de)
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; version 2 of
10 //  the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 //=========================================================
22 
23 #include <limits.h>
24 
25 #include "mtscale_flo.h"
26 #include "song.h"
27 #include "app.h"
28 #include "icons.h"
29 #include "gconfig.h"
30 #include "scoreedit.h"
31 #include "globals.h"
32 
33 // Forwards from header:
34 #include <QWidget>
35 #include <QPainter>
36 #include <QMouseEvent>
37 
38 namespace MusEGui {
39 
40 //---------------------------------------------------------
41 //   MTScale
42 //    Midi Time Scale
43 //---------------------------------------------------------
44 
MTScaleFlo(ScoreCanvas * parent_editor,QWidget * parent_widget)45 MTScaleFlo::MTScaleFlo(ScoreCanvas* parent_editor, QWidget* parent_widget)
46     : View(parent_widget, 1, 1)
47 {
48     pos[0] = MusEGlobal::song->cpos();
49     pos[1] = MusEGlobal::song->lpos();
50     pos[2] = MusEGlobal::song->rpos();
51     xpos=0;
52     xoffset=0;
53 
54     button = Qt::NoButton;
55     setMouseTracking(true);
56     connect(MusEGlobal::song, SIGNAL(posChanged(int, unsigned, bool)), SLOT(setPos(int, unsigned, bool)));
57     connect(MusEGlobal::song, SIGNAL(songChanged(MusECore::SongChangedStruct_t)), SLOT(songChanged(MusECore::SongChangedStruct_t)));
58     connect(MusEGlobal::song, SIGNAL(markerChanged(int)), SLOT(redraw()));
59     connect(MusEGlobal::muse, SIGNAL(configChanged()), SLOT(configChanged()));
60 
61     parent=parent_editor;
62 
63     setFixedHeight(28);
64     setBg(MusEGlobal::config.rulerBg);
65 }
66 
configChanged()67 void MTScaleFlo::configChanged()
68 {
69     setBg(MusEGlobal::config.rulerBg);
70 
71 
72 }
73 //---------------------------------------------------------
74 //   songChanged
75 //---------------------------------------------------------
76 
songChanged(MusECore::SongChangedStruct_t type)77 void MTScaleFlo::songChanged(MusECore::SongChangedStruct_t type)
78 {
79     if (type & (SC_SIG|SC_TEMPO|SC_MARKERS_REBUILT|SC_MARKER_INSERTED|SC_MARKER_REMOVED|SC_MARKER_MODIFIED))
80         redraw();
81 }
82 
83 //---------------------------------------------------------
84 //   setPos
85 //---------------------------------------------------------
86 
setPos(int idx,unsigned val,bool)87 void MTScaleFlo::setPos(int idx, unsigned val, bool)
88 {
89     if ((val == INT_MAX) || (val == pos[idx]))
90         return;
91 
92     int opos = parent->tick_to_x(pos[idx] == INT_MAX ? val : pos[idx]) + xoffset - xpos;
93 
94     pos[idx] = val;
95 
96     if (isVisible()) {
97 
98         int tval   = parent->tick_to_x(val) + xoffset - xpos;
99         int x = -9;
100         int w = 18;
101 
102         if (tval < 0) { // tval<0 occurs whenever the window is scrolled left, so I switched to signed int (ml)
103             redraw();
104         }
105         else if (opos > tval) {
106             w += opos - tval;
107             x += tval;
108         }
109         else {
110             w += tval - opos;
111             x += opos;
112         }
113         redraw(QRect(x, 0, w, height()));
114     }
115 }
116 
117 //---------------------------------------------------------
118 //   mousePressEvent
119 //---------------------------------------------------------
120 
mousePressEvent(QMouseEvent * event)121 void MTScaleFlo::mousePressEvent(QMouseEvent* event)
122 {
123     button = event->button();
124     mouseMoveEvent(event);
125 }
126 
127 //---------------------------------------------------------
128 //   mouseReleaseEvent
129 //---------------------------------------------------------
130 
mouseReleaseEvent(QMouseEvent *)131 void MTScaleFlo::mouseReleaseEvent(QMouseEvent*)
132 {
133     button = Qt::NoButton;
134 }
135 
136 //---------------------------------------------------------
137 //   mouseMoveEvent
138 //---------------------------------------------------------
139 
mouseMoveEvent(QMouseEvent * event)140 void MTScaleFlo::mouseMoveEvent(QMouseEvent* event)
141 {
142     if (event->modifiers() & Qt::ShiftModifier )
143         setCursor(QCursor(Qt::PointingHandCursor));
144     else
145         setCursor(QCursor(Qt::ArrowCursor));
146 
147     int x = event->x();
148     if (x<0) x=0;
149     int tick = parent->x_to_tick(x-xoffset+xpos);
150     if (tick<0) tick=0;
151     tick = MusEGlobal::sigmap.raster(tick, parent->quant_ticks());
152 
153     MusECore::Song::POSTYPE posType;
154 
155     switch (button) {
156     case Qt::LeftButton:
157         if (event->modifiers() & Qt::ControlModifier)
158             posType = MusECore::Song::LPOS;
159         else
160             posType = MusECore::Song::CPOS;
161         break;
162     case Qt::MidButton:
163         posType = MusECore::Song::LPOS;
164         break;
165     case Qt::RightButton:
166         posType = MusECore::Song::RPOS;
167         break;
168     default:
169         return; // if no button is pressed the function returns here
170     }
171 
172     MusECore::Pos p(tick, true);
173 
174     if(posType == MusECore::Song::CPOS && (event->modifiers() & Qt::ShiftModifier )) {        // If shift +LMB we add a marker
175         const MusECore::iMarker alreadyExists = MusEGlobal::song->getMarkerAt(tick);
176         if (alreadyExists == MusEGlobal::song->marker()->end())
177             MusEGlobal::song->addMarker(QString(""), tick, false);
178     }
179     else if (posType == MusECore::Song::RPOS && (event->modifiers() & Qt::ShiftModifier )) {  // If shift +RMB we remove a marker
180         const MusECore::iMarker toRemove = MusEGlobal::song->getMarkerAt(tick);
181         if (toRemove != MusEGlobal::song->marker()->end())
182             MusEGlobal::song->removeMarker(toRemove->second);
183         else
184             fprintf(stderr, "No marker to remove\n");
185     }
186     else
187         MusEGlobal::song->setPos(posType, p);                             // all other cases: relocating one of the locators
188 }
189 
190 
191 
192 //---------------------------------------------------------
193 //   draw
194 //---------------------------------------------------------
195 
draw(QPainter & p,const QRect & r,const QRegion &)196 void MTScaleFlo::draw(QPainter& p, const QRect& r, const QRegion&)
197 {
198     int x = r.x();
199     int w = r.width();
200 
201     x -= 20;
202     w += 40;    // wg. Text
203 
204     //---------------------------------------------------
205     //    draw Marker
206     //---------------------------------------------------
207 
208     int y = 12;
209     p.setRenderHint(QPainter::Antialiasing);
210     p.setPen(MusEGlobal::config.rulerFg);
211     p.setFont(MusEGlobal::config.fonts[5]);
212     p.drawLine(r.x(), y+1, r.x() + r.width(), y+1);
213     QRect tr(r);
214     tr.setHeight(12);
215     MusECore::MarkerList* marker = MusEGlobal::song->marker();
216     for (MusECore::iMarker m = marker->begin(); m != marker->end(); ++m) {
217 
218         int xp = parent->tick_to_x(m->second.tick()) + xoffset - xpos;
219         if (xp > x+w)
220             break;
221         int xe = r.x() + r.width();
222         MusECore::iMarker mm = m;
223         ++mm;
224         if (mm != marker->end())
225             xe = parent->tick_to_x(mm->first) + xoffset - xpos;
226 
227         QRect tr(xp, 0, xe-xp, 13);
228 
229         QRect wr = r.intersected(tr);
230         if(!wr.isEmpty())
231         {
232             if (m->second.current())
233                 p.fillRect(wr, MusEGlobal::config.rulerCurrent);
234 
235             int x2;
236             if (mm != marker->end())
237                 x2 = parent->tick_to_x(mm->first) + xoffset - xpos;
238             else
239                 x2 = xp+200;
240 
241             if(xp >= -32) {
242                 p.setBrush(MusEGlobal::config.markerColor);
243                 p.setPen(MusEGlobal::config.markerColor);
244                 p.drawPolygon( QVector<QPointF>{ {static_cast<qreal>(xp), 1.},
245                                                  {static_cast<qreal>(xp) + 7., 6.},
246                                                  {static_cast<qreal>(xp), 11.} } );
247             }
248 
249             if(xp >= -1023)
250             {
251                 QRect r = QRect(xp+10, 0, x2-xp, 12);
252                 p.setPen(MusEGlobal::config.rulerFg);
253                 p.drawText(r, Qt::AlignLeft|Qt::AlignVCenter, m->second.name());
254             }
255 
256             if(xp >= 0)
257             {
258                 p.setPen(MusEGlobal::config.markerColor);
259                 p.drawLine(xp, y, xp, height());
260             }
261         }
262     }
263 
264     //---------------------------------------------------
265     //    draw location marker
266     //---------------------------------------------------
267 
268     int h = height()-12;
269 
270 //    for (int i = 0; i < 3; ++i) {
271 //        int xp = parent->tick_to_x(pos[i]) + xoffset - xpos;
272 //        if (xp >= x && xp < x+w) {
273 //            QPixmap* pm = markIcon[i];
274 //            p.drawPixmap(xp - pm->width()/2, y-1, *pm);
275 //        }
276 //    }
277 
278 
279     const qreal mtop = 18.;
280     const qreal mbottom = 26.;
281     const int radius = 8;
282 
283     // draw left range marker
284     {
285         const int xp = parent->tick_to_x(static_cast<int>(pos[1])) + xoffset - xpos;
286 
287         if (xp >= x && xp < x+w) {
288 //            QPixmap* pm = markIcon[i];
289 //            p.drawPixmap(xp - pm->width()/2, y-1, *pm);
290 
291             const int pmx = xp - radius;
292 
293             p.setBrush(MusEGlobal::config.rangeMarkerColor);
294             p.setPen(MusEGlobal::config.rangeMarkerColor);
295             p.drawPolygon( QVector<QPointF>{ {static_cast<qreal>(mapx(xp)), mtop},
296                                              {static_cast<qreal>(mapx(pmx)), mtop},
297                                              {static_cast<qreal>(mapx(xp)), mbottom} } );
298         }
299     }
300 
301     // draw right range marker
302     {
303         const int xp = parent->tick_to_x(static_cast<int>(pos[2])) + xoffset - xpos;
304 
305         if (xp >= x && xp < x+w) {
306 
307             const int pmx2 = xp + radius;
308 
309             p.setBrush(MusEGlobal::config.rangeMarkerColor);
310             p.setPen(MusEGlobal::config.rangeMarkerColor);
311             p.drawPolygon( QVector<QPointF>{ {static_cast<qreal>(mapx(xp)), mtop},
312                                              {static_cast<qreal>(mapx(pmx2)), mtop},
313                                              {static_cast<qreal>(mapx(xp)), mbottom} } );
314         }
315     }
316 
317     // draw position marker
318     {
319         const int xp = parent->tick_to_x(static_cast<int>(pos[0])) + xoffset - xpos;
320 
321         if (xp >= x && xp < x+w) {
322 
323             const int pmx = xp - radius;
324             const int pmx2 = xp + radius;
325 
326             p.setBrush(MusEGlobal::config.positionMarkerColor);
327             p.setPen(MusEGlobal::config.positionMarkerColor);
328             p.drawPolygon( QVector<QPointF>{ {static_cast<qreal>(mapx(pmx)), mtop},
329                                              {static_cast<qreal>(mapx(pmx2)), mtop},
330                                              {static_cast<qreal>(mapx(xp)), mbottom} } );
331         }
332     }
333 
334 
335     //---------------------------------------------------
336     //    draw beats
337     //---------------------------------------------------
338 
339 
340     p.setPen(MusEGlobal::config.rulerFg);
341 
342     unsigned ctick;
343     int bar1, bar2, beat;
344     unsigned tick;
345 
346     ctick = parent->x_to_tick(x - xoffset + xpos);
347     MusEGlobal::sigmap.tickValues(ctick, &bar1, &beat, &tick);
348     MusEGlobal::sigmap.tickValues(parent->x_to_tick(x+w - xoffset + xpos), &bar2, &beat, &tick);
349 
350 
351     int stick = MusEGlobal::sigmap.bar2tick(bar1, 0, 0);
352     int ntick;
353     for (int bar = bar1; bar <= bar2; bar++, stick = ntick) {
354         ntick     = MusEGlobal::sigmap.bar2tick(bar+1, 0, 0);
355         int tpix = parent->delta_tick_to_delta_x(ntick - stick);
356         if (tpix < 64) {
357             // don�t show beats if measure is this small
358             int n = 1;
359             if (tpix < 32)
360                 n = 2;
361             if (tpix <= 16)
362                 n = 4;
363             if (tpix < 8)
364                 n = 8;
365             if (tpix <= 4)
366                 n = 16;
367             if (tpix <= 2)
368                 n = 32;
369             if (bar % n)
370                 continue;
371             p.setFont(MusEGlobal::config.fonts[3]);
372             int x = parent->tick_to_x(stick) + xoffset - xpos;
373             QString s;
374             s.setNum(bar + 1);
375             p.drawLine(x, y+1, x, y+1+h);
376             QRect r = QRect(x+2, y, 1000, h);
377             p.drawText(r, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextDontClip, s);
378         }
379         else {
380             int z, n;
381             MusEGlobal::sigmap.timesig(stick, z, n);
382             for (int beat = 0; beat < z; beat++) {
383                 int xp = parent->tick_to_x(MusEGlobal::sigmap.bar2tick(bar, beat, 0)) + xoffset - xpos;
384                 QString s;
385                 QRect r(xp+2, y, 1000, h);
386                 int y1;
387                 int num;
388                 if (beat == 0) {
389                     num = bar + 1;
390                     y1  = y + 1;
391                     p.setFont(MusEGlobal::config.fonts[3]);
392                 }
393                 else {
394                     num = beat + 1;
395                     y1  = y + 7;
396                     p.setFont(MusEGlobal::config.fonts[4]);
397                     r.setY(y+3);
398                 }
399                 s.setNum(num);
400                 p.drawLine(xp, y1, xp, y+1+h);
401                 p.drawText(r, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextDontClip, s);
402             }
403         }
404     }
405 }
406 
set_xpos(int pos)407 void MTScaleFlo::set_xpos(int pos)
408 {
409     xpos=pos;
410     redraw();
411 }
412 
set_xoffset(int o)413 void MTScaleFlo::set_xoffset(int o)
414 {
415     xoffset=o;
416     redraw();
417 }
418 
pos_add_changed()419 void MTScaleFlo::pos_add_changed()
420 {
421     redraw();
422 }
423 
424 } // namespace MusEGui
425