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