QRect WPiano::rect2qrect(const Rect &rect) const { int l = time2x(rect.time_beg); int r = time2x(rect.time_end); int t = rect.level_end > levels(track()) ? 0 : level2y(rect.level_end); int b = rect.level_end > levels(track()) ? height() : level2y(rect.level_beg); return QRect(l, t, r-l, b-t); }
void WPiano::look_at_cursor(LookMode mode) { QWidget *viewport_widget = qobject_cast<QWidget *>(parent()); if (viewport_widget == NULL) return; QScrollArea *scroll = qobject_cast<QScrollArea *>(viewport_widget->parent()); if (scroll == NULL) return; QScrollBar *hs = scroll->horizontalScrollBar(); QScrollBar *vs = scroll->verticalScrollBar(); bool pl = playing(); QRect v = viewport(); int x1, x2, y1, y2; x1 = time2x(cursorTime()); x2 = pl ? x1 + 1 : time2x(cursorEndTime()); y1 = level2y(cursor_level_ + 1); y2 = level2y(cursor_level_ - 1); switch (mode) { case PAGE: if (x1 < v.left()) hs->setValue(scroll_snap(this, x2 - v.width(), true)); if (x2 > v.right()) hs->setValue(scroll_snap(this, x1 - 1)); if (pl && y1 < v.top()) vs->setValue(y2 - v.height() + level_height); if (pl && y2 > v.bottom()) vs->setValue(y1 - level_height); break; case MINSCROLL: scroll->ensureVisible(x1, y1, level_height, level_height); scroll->ensureVisible(x2, y2, level_height, level_height); break; case CENTER: hs->setValue((x1 + x2 - v.width()) / 2); vs->setValue((y1 + y2 - v.height()) / 2); break; } }
void QScope::addSpike(Spikeinfo const &si) { // int x = time2x(si.time+qss.sf->first()); int x = time2x(si.time); QPainter qpai(this); qpai.setPen(aux_pen); qpai.setBrush(aux_pen.color()); qpai.drawEllipse(x-2, coffset+(si.height>0?-1:1)*halfhei*7/8-2,4,4); if (nspikes>=spikes.size()) spikes.push_back(si); else spikes[nspikes] = si; nspikes++; forall(&QScope::addSpike,si); }
QRect WPiano::cursor_qrect() const { if (playing()) return QRect(time2x(cursor_time_), 0, 1, height()); else { Rect rect( cursorTime(), cursorEndTime(), cursor_level_ - 1, cursor_level_ + 1 ); return rect2qrect(rect).adjusted(-3, -3, 3, 3); } }
WPiano::WPiano(File *_file, vmd_track_t *_track, vmd_time_t time, Player *_player) :file_(_file), track_(_track), grid_size_(file()->division), mouse_captured_(false), cursor_time_(grid_snap_left(this, time)), cursor_size_(file()->division), cursor_level_(0), pivot_enabled_(false), selection_(NULL), player_(_player) { int w = time2x(vmd_file_length(file())); int h = margin * 2 + level_height * levels(track()); setMinimumSize(w, h); setPalette(PianoPalette()); setFocusPolicy(Qt::StrongFocus); connect(file_, SIGNAL(acted()), this, SLOT(update())); connect(player_, SIGNAL(started()), this, SLOT(playStarted())); connect(player_, SIGNAL(finished()), this, SLOT(playStopped())); if (playing()) playStarted(); }
void QScope::drawContents_box(QPainter *qp) { QGraph::drawContents(qp); if (guide_spacing) { // Let's draw zero line and guide lines qp->setPen(zero_pen); int yy = value2y(center); qp->drawLine(xoffset, yy, xoffset+wid-1, yy); qp->setPen(guide_pen); int gs = guide_spacing; for (raw_t y=gs; y<extent; y+=gs) { int yy = value2y(center + y); qp->drawLine(xoffset, yy, xoffset+wid-1, yy); yy = value2y(center-y); qp->drawLine(xoffset, yy, xoffset+wid-1, yy); } } if (!qss.sf) return; if (qss.endtime>0) { // let's draw trace. // I *assume* that there are more data points than pixels, but even if // this is not so, I think this should be OK. qp->setPen(trace_pen); qp->setBrush(trace_pen.color()); timeref_t starttime = (qss.endtime>qss.length)?(qss.endtime-qss.length):0; int tlength = qss.endtime-starttime; int twidth = wid * tlength/qss.length; int lastend; timeref_t time; if (controller || speedy!=AvgOnly) { // I am a satellite or not speedy // -- collect max line -- lastend = 0; time = starttime; int x_end = 2*twidth-1; raw_t maxv=(*qss.sf)[time][qss.channel]; for (int x=0; x<twidth; x++) { raw_t max=(*qss.sf)[time][qss.channel]; int nextend = (x+1)*tlength/twidth; // int n=nextend-lastend; for (; lastend<nextend; lastend++) maxIs(max, (*qss.sf)[time++][qss.channel]); qpa->setPoint(x_end-x, x+xoffset, value2y(max)); //if(qss.channel<126) qpa->setPoint(x_end-x, x+xoffset, value2y(max)); //else qpa->setPoint(x_end-x, x+xoffset, yoffset+(4095-max)*hei/4096); maxIs(maxv,max); } // -- collect min line -- lastend=0; time = starttime; raw_t minv=(*qss.sf)[time][qss.channel]; for (int x=0; x<twidth; x++) { raw_t min=(*qss.sf)[time][qss.channel]; int nextend = (x+1)*tlength/twidth; // int n=nextend-lastend; for (; lastend<nextend; lastend++) minIs(min, (*qss.sf)[time++][qss.channel]); qpa->setPoint(x, x+xoffset, value2y(min)); //if(qss.channel<126) qpa->setPoint(x, x+xoffset, value2y(min)); //else qpa->setPoint(x, x+xoffset, yoffset+(4095-min)*hei/4096); minIs(minv,min); } // -- draw it -- // db need to send qp for allgraphs also, use graphptrs offsets and apply to draw functions /*if (maxv-minv>4000) // do not plot rail-to-rail noisy channels qp->drawLine(xoffset, value2y(center), xoffset+wid, value2y(center)); else*/ if (speedy==MinMax) qp->drawPolyline(*qpa,0,x_end*2); else qp->drawPolygon(*qpa,true,0,x_end*2); } else { // I am a speedy small QMultiGraph member // -- draw average line -- lastend=0; time=starttime; for (int x=0; x<twidth; x++) { float sum=0; int nextend = (x+1)*tlength/twidth; int n=nextend-lastend; for (; lastend<nextend; lastend++) sum += (*qss.sf)[time++][qss.channel]; qpa->setPoint(x, x+xoffset, value2y(raw_t(sum/n))); //if(qss.channel<126) qpa->setPoint(x, x+xoffset, value2y(raw_t(sum/n))); //else qpa->setPoint(x, x+xoffset, yoffset+(4095-raw_t(sum/n))*hei/4096); } qp->drawPolyline(*qpa,0,twidth); } if (controller) { // draw more guide lines QFont f(qp->font()); f.setPointSize(14); qp->setFont(f); qp->setPen(guide_pen); int timelines[4] = { 2, 10, 50, 250 }; bool drawtl[4]; int tlmax=0; for (int n=0; n<4; n++) { drawtl[n] = twidth * timelines[n]*FREQKHZ / tlength > 10; if (timelines[n]*FREQKHZ < tlength) tlmax=n; } bool subtext = tlmax>0 && (twidth * timelines[tlmax-1]*FREQKHZ / tlength)>60; bool hundreds = tlmax>2; bool tens = tlmax>1; int uvlines[2] = { 10, 50 }; bool drawuv[2]; int uvmax=0; float uvpdig = uvpd(); for (int n=0; n<2; n++) { drawuv[n] = halfhei * (uvlines[n]/uvpdig) / extent > 10; if (uvlines[n]/uvpdig < extent) uvmax=n; } timeref_t t0 = qss.sf?qss.sf->first():0; timeref_t t = starttime - t0; t = timeref_t(t/(FREQKHZ*timelines[0])+.99999) * FREQKHZ*timelines[0]; timeref_t t1 = starttime-t0+tlength; while (t<t1) { // sdbx("Time: %.5f / starttime=%.5f t0=%.5f x=%i",t/25000.0,starttime/25000.0,t0/25000.0,time2x(t+t0)); for (int n=0; n<4; n++) { if (t % (FREQKHZ*timelines[n]) == 0) { if (drawtl[n]) { int x = time2x(t+t0); qp->drawLine(x,0,x,10*(n+1)); qp->drawLine(x,hei,x,hei-10*(n+1)); if (n==tlmax) { qp->setPen(black_pen); char buf[100]; sprintf(buf,"%.3f",t/(1000.0*FREQKHZ)); qp->drawText(x-40,hei-70,80,35, Qt::AlignHCenter|Qt::AlignBottom,buf); qp->setPen(guide_pen); } else if (subtext && n==tlmax-1 && t % (FREQKHZ*timelines[n+1]) != 0) { char buf[100]; if (hundreds) sprintf(buf,"%03i",int(t/FREQKHZ)%1000); else if (tens) sprintf(buf,"%02i",int(t/FREQKHZ)%100); else sprintf(buf,"%01i",int(t/FREQKHZ)%10); qp->drawText(x-40,hei-70,80,35, Qt::AlignHCenter|Qt::AlignBottom,buf); } } } else { break; } } t+=FREQKHZ*timelines[0]; } for (int uv=0; uv<uvpdig*extent; uv+=uvlines[0]) { for (int n=0; n<2; n++) { if (uv%uvlines[n] == 0 && drawuv[n]) { int y=coffset - int(uv/uvpdig * halfhei/extent); qp->drawLine(0,y,10*(n+1),y); qp->drawLine(wid,y,wid-10*(n+1),y); if (n==uvmax) { char buf[100]; sprintf(buf,"%i",uv); qp->setPen(black_pen); qp->drawText(wid-110,y-50,80,100, Qt::AlignVCenter|Qt::AlignRight,buf); qp->setPen(guide_pen); } if (uv) { y=coffset + int(uv/uvpdig * halfhei/extent); qp->drawLine(0,y,10*(n+1),y); qp->drawLine(wid,y,wid-10*(n+1),y); if (n==uvmax) { char buf[100]; sprintf(buf,"%i",-uv); qp->setPen(black_pen); qp->drawText(wid-110,y-50,80,100, Qt::AlignVCenter|Qt::AlignRight,buf); qp->setPen(guide_pen); } } } } } } } qp->setPen(aux_pen); qp->setBrush(aux_pen.color()); timeref_t t0 = qss.sf->first(); for (unsigned int i=0; i<nspikes; i++) { Spikeinfo const &si = spikes[i]; int x = time2x(si.time+t0); qp->drawEllipse(x-2, coffset+(si.height>0?-1:1)*halfhei*7/8-2,4,4); } }
void WPiano::paintEvent(QPaintEvent *ev) { QPainter painter(this); QPen pen; vmd_time_t beg = x2time(ev->rect().left()); vmd_time_t end = x2time(ev->rect().right()); /* background */ painter.setPen(Qt::NoPen); painter.setBrush(palette().base()); painter.drawRect(0, 0, width(), level2y(levels(track()))); painter.drawRect(0, level2y(0), width(), height() - level2y(0)); for (int i = 0; i < (levels(track()) + 1) / 2; i++) { painter.setBrush(i % 2 == 0 ? palette().alternateBase() : palette().base()); painter.drawRect(0, level2y(i*2+2), width(), level2y(i*2) - level2y(i*2+2)); } /* selection */ if (pivot_enabled_) { painter.setBrush(palette().highlight()); painter.setPen(Qt::NoPen); Rect sel = selectionRect(); sel.level_beg -= 1; painter.drawRect(rect2qrect(sel)); } /* vertical grid */ painter.setPen(QPen()); vmd_file_measures(file(), beg, end + 1, draw_measure, &painter); /* horizontal grid */ for (int i = 0; i < levels(track()); i++) { int style = level_style(track(), i); int y = level2y(i); if (style != LEVEL_NORMAL) { pen.setWidth(style == LEVEL_OCTAVE_LINE ? 2 : 0); painter.setPen(pen); painter.drawLine(0, y, width(), y); } } /* notes */ vmd_track_for_range(track(), beg, end, draw_note, &painter); /* cursor */ if (playing()) { painter.setPen(QPen()); int x = time2x(cursor_time_); painter.drawLine(x, 0, x, height()); } else { Qt::GlobalColor colors[2] = { Qt::black, cursorPitch() >= 0 ? Qt::red : Qt::lightGray }; QRect r = cursor_qrect(); for (int i = 0; i < 2; i++) { r.adjust(1, 1, -1, -1); painter.setPen(QColor(colors[i])); painter.setBrush(Qt::NoBrush); painter.drawRect(r); } } }
void WPiano::keyPressEvent(QKeyEvent *ev) { int key = ev->key(); int mod = ev->modifiers() & (Qt::CTRL | Qt::SHIFT); #define SHIFT_SELECTS \ do { \ if (mod & Qt::SHIFT) { \ capture_mouse(false); \ set_pivot(); \ } else \ drop_pivot(); \ } while(0) switch (key) { case Qt::Key_Escape: drop_pivot(); capture_mouse(false); break; case Qt::Key_Home: SHIFT_SELECTS; setCursorTime(0); break; case Qt::Key_End: SHIFT_SELECTS; setCursorTime(grid_snap_right(this, vmd_track_length(track_))); break; case Qt::Key_Left: SHIFT_SELECTS; setCursorTime(grid_snap_left(this, cursor_time_ - 1)); break; case Qt::Key_Right: SHIFT_SELECTS; setCursorTime(grid_snap_right(this, cursor_time_ + 1)); break; case Qt::Key_Up: SHIFT_SELECTS; if (cursor_level_ < levels(track())) setCursorLevel(cursor_level_ + 1); break; case Qt::Key_Down: SHIFT_SELECTS; if (cursor_level_ > 0) setCursorLevel(cursor_level_ - 1); break; case Qt::Key_Space: drop_pivot(); if (playing()) player_->stop(); else player_->play(file(), cursor_time_); break; case Qt::Key_QuoteLeft: { QString s = QInputDialog::getText( this, "vomid", mod & Qt::CTRL ? QString("Enter grid size:") : QString("Enter cursor size:") ); QStringList sl = s.split("/"); if (sl.size() != 2) break; int n = sl[0].toInt(); int m = sl[1].toInt(); if (n <= 0 && m <= 0) break; vmd_time_t size = file()->division * 4 * n / m; if (mod & Qt::CTRL) grid_size_ = size; else cursor_size_ = size; } break; case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: case Qt::Key_7: { vmd_time_t size = file()->division * 4; for (int i = 0; i < key - Qt::Key_1; i++) size /= 2; if (mod & Qt::CTRL) grid_size_ = size; else cursor_size_ = size; } break; case Qt::Key_Enter: case Qt::Key_Return: drop_pivot(); toggle_note(); break; case Qt::Key_I: if (mod == Qt::CTRL) { vmd_note_t *note = noteAtCursor(); if (note == NULL) break; QPoint pos(time2x(cursor_time_), level2y(cursor_level_)); QString text = "Note: "; text += "channel = "; text += QString::number(note->channel->number); QToolTip::hideText(); QToolTip::showText(mapToGlobal(pos), text); } break; case Qt::Key_C: if (mod == Qt::CTRL) { if (clipboard == NULL) clipboard = vmd_track_create(&clipboard_file, VMD_CHANMASK_ALL); Rect s = selectionRect(); vmd_time_t base_time = s.time_beg; int base_pitch = level2pitch(track(), s.level_beg, true); clipboard_time_relative = s.time_end != VMD_MAX_TIME; clipboard_pitch_relative = s.level_end <= levels(track()); vmd_track_clear(clipboard); for (vmd_note_t *i = selection(); i != NULL; i = i->next) vmd_copy_note(i, clipboard, -base_time, -base_pitch); } break; case Qt::Key_V: if (mod == Qt::CTRL) { vmd_time_t t = clipboard_time_relative ? cursorTime() : 0; vmd_pitch_t p = clipboard_pitch_relative ? cursorPitch() : 0; if (clipboard == NULL || p < 0) break; VMD_BST_FOREACH(vmd_bst_node_t *i, &clipboard->notes) vmd_copy_note(vmd_track_note(i), track(), t, p); file()->commit("Paste Notes"); drop_pivot(); } break; case Qt::Key_Delete: for (vmd_note_t *i = selection(); i != NULL; i = i->next) vmd_erase_note(i); file()->commit("Erase Notes"); drop_pivot(); case Qt::Key_T: if (mod == Qt::CTRL) { int dPitch = QInputDialog::getInt( this, "vomid", QString("Transpose (in semi-tones):") ); if (dPitch == 0) break; for (vmd_note_t *i = selection(), *next; i != NULL; i = next) { next = i->next; vmd_copy_note(i, track(), 0, dPitch); vmd_erase_note(i); } file()->commit("Transpose"); } default: return QWidget::keyPressEvent(ev); } look_at_cursor(); update(); }