//============================================================================= // Awl // Audio Widget Library // $Id:$ // // Copyright (C) 2002-2006 by Werner Schweer and others // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. //============================================================================= #include "al/al.h" #include "awl.h" #include "posedit.h" #include "al/sig.h" //#include "sig.h" //#include "sync.h" // Tim. namespace Awl { ///using AL::mtcType; using AL::sigmap; //--------------------------------------------------------- // PosEdit //--------------------------------------------------------- PosEdit::PosEdit(QWidget* parent) : QAbstractSpinBox(parent) { initialized = false; setReadOnly(false); setSmpte(false); } void* PosEdit::operator new(size_t n) { void* p = new char[n]; memset(p, 0, n); return p; } PosEdit::~PosEdit() { } QSize PosEdit::sizeHint() const { QFontMetrics fm(font()); int fw = style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth); int h = fm.height() + fw * 2; int w = fw * 4 + 10; // HACK: 10 = spinbox up/down arrows if (_smpte) w += 2 + fm.width('9') * 9 + fm.width(':') * 3 + fw * 4; else w += 2 + fm.width('9') * 9 + fm.width('.') * 2 + fw * 4; return QSize(w, h).expandedTo(QApplication::globalStrut()); } //--------------------------------------------------------- // event // filter Tab and Backtab key events //--------------------------------------------------------- bool PosEdit::event(QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(event); int segment = curSegment(); if (ke->key() == Qt::Key_Backtab) { if (_smpte) { if (segment == 3) { lineEdit()->setSelection(7, 2); return true; } else if (segment == 2) { lineEdit()->setSelection(4, 2); return true; } else if (segment == 1) { lineEdit()->setSelection(0, 3); return true; } } else { if (segment == 2) { lineEdit()->setSelection(5, 2); return true; } if (segment == 1) { lineEdit()->setSelection(0, 4); return true; } } } if (ke->key() == Qt::Key_Tab) { if (_smpte) { if (segment == 0) { lineEdit()->setSelection(4, 2); return true; } else if (segment == 1) { lineEdit()->setSelection(7, 2); return true; } else if (segment == 2) { lineEdit()->setSelection(10, 2); return true; } } else { if (segment == 0) { lineEdit()->setSelection(5, 2); return true; } if (segment == 1) { lineEdit()->setSelection(8, 3); return true; } } } } else if (event->type() == QEvent::FocusIn) { QFocusEvent* fe = static_cast(event); QAbstractSpinBox::focusInEvent(fe); int segment = curSegment(); switch(segment) { case 0: lineEdit()->setSelection(0,4); break; case 1: lineEdit()->setSelection(5,2); break; case 2: lineEdit()->setSelection(8,3); break; } return true; } return QAbstractSpinBox::event(event); } //--------------------------------------------------------- // setSmpte //--------------------------------------------------------- void PosEdit::setSmpte(bool f) { _smpte = f; if (_smpte) lineEdit()->setInputMask("999:99:99:99"); else lineEdit()->setInputMask("9999.99.999"); updateValue(); } //--------------------------------------------------------- // setValue //--------------------------------------------------------- void PosEdit::setValue(const Pos& time) { _pos = time; updateValue(); } void PosEdit::setValue(const QString& s) { Pos time(s); setValue(time); } void PosEdit::setValue(int t) { Pos time(t); setValue(time); } //--------------------------------------------------------- // updateValue //--------------------------------------------------------- void PosEdit::updateValue() { char buffer[64]; if (_smpte) { int minute, sec, frame, subframe; _pos.msf(&minute, &sec, &frame, &subframe); sprintf(buffer, "%03d:%02d:%02d:%02d", minute, sec, frame, subframe); } else { int bar, beat; int tick; _pos.mbt(&bar, &beat, &tick); sprintf(buffer, "%04d.%02d.%03d", bar+1, beat+1, tick); } lineEdit()->setText(buffer); } //--------------------------------------------------------- // stepEnables //--------------------------------------------------------- QAbstractSpinBox::StepEnabled PosEdit::stepEnabled() const { int segment = curSegment(); QAbstractSpinBox::StepEnabled en = QAbstractSpinBox::StepUpEnabled | QAbstractSpinBox::StepDownEnabled; if (_smpte) { int minute, sec, frame, subframe; _pos.msf(&minute, &sec, &frame, &subframe); switch(segment) { case 0: if (minute == 0) en &= ~QAbstractSpinBox::StepDownEnabled; break; case 1: if (sec == 0) en &= ~QAbstractSpinBox::StepDownEnabled; else if (sec == 59) en &= ~QAbstractSpinBox::StepUpEnabled; break; case 2: if (frame == 0) en &= ~QAbstractSpinBox::StepDownEnabled; else if (frame == 23) en &= ~QAbstractSpinBox::StepUpEnabled; break; case 3: if (subframe == 0) en &= ~QAbstractSpinBox::StepDownEnabled; else if (subframe == 99) en &= ~QAbstractSpinBox::StepUpEnabled; break; } } else { int bar, beat; unsigned tick; AL::sigmap.tickValues(_pos.tick(), &bar, &beat, &tick); //sigmap.tickValues(_pos.tick(), &bar, &beat, &tick); unsigned tb = AL::sigmap.ticksBeat(_pos.tick()); //unsigned tb = sigmap.ticksBeat(_pos.tick()); unsigned tm = AL::sigmap.ticksMeasure(_pos.tick()); //unsigned tm = sigmap.ticksMeasure(_pos.tick()); int bm = tm / tb; switch (segment) { case 0: if (bar == 0) en &= ~QAbstractSpinBox::StepDownEnabled; break; case 1: if (beat == 0) en &= ~QAbstractSpinBox::StepDownEnabled; else { if (beat >= (bm-1)) en &= ~QAbstractSpinBox::StepUpEnabled; } break; case 2: if (tick == 0) en &= ~QAbstractSpinBox::StepDownEnabled; else { if (tick >= (tb-1)) en &= ~QAbstractSpinBox::StepUpEnabled; } break; } } return en; } //--------------------------------------------------------- // fixup //--------------------------------------------------------- void PosEdit::fixup(QString& input) const { printf("fixup <%s>\n", input.toLatin1().constData()); } //--------------------------------------------------------- // validate //--------------------------------------------------------- QValidator::State PosEdit::validate(QString&,int&) const { // TODO // printf("validate\n"); return QValidator::Acceptable; } //--------------------------------------------------------- // curSegment //--------------------------------------------------------- int PosEdit::curSegment() const { QLineEdit* le = lineEdit(); int pos = le->cursorPosition(); int segment = -1; if (_smpte) { if (pos >= 0 && pos <= 3) segment = 0; else if (pos >= 4 && pos <= 6) segment = 1; else if (pos >= 7 && pos <= 9) segment = 2; else if (pos >= 10) segment = 3; } else { if (pos >= 0 && pos <= 4) segment = 0; else if (pos >= 5 && pos <= 7) segment = 1; else if (pos >= 8) segment = 2; else printf("curSegment = -1, pos %d\n", pos); } return segment; } //--------------------------------------------------------- // stepBy //--------------------------------------------------------- void PosEdit::stepBy(int steps) { int segment = curSegment(); int selPos; int selLen; bool changed = false; if (_smpte) { int minute, sec, frame, subframe; _pos.msf(&minute, &sec, &frame, &subframe); switch(segment) { case 0: minute += steps; if (minute < 0) minute = 0; selPos = 0; selLen = 3; break; case 1: sec += steps; if (sec < 0) sec = 0; if (sec > 59) sec = 59; selPos = 4; selLen = 2; break; case 2: frame += steps; if (frame < 0) frame = 0; if (frame > 24) //TD frame type? frame = 24; selPos = 7; selLen = 2; break; case 3: subframe += steps; if (subframe < 0) subframe = 0; if (subframe > 99) subframe = 99; selPos = 10; selLen = 2; break; default: return; } Pos newPos(minute, sec, frame, subframe); if (!(newPos == _pos)) { changed = true; _pos = newPos; } } else { int bar, beat, tick; _pos.mbt(&bar, &beat, &tick); int tb = AL::sigmap.ticksBeat(_pos.tick()); //int tb = sigmap.ticksBeat(_pos.tick()); unsigned tm = AL::sigmap.ticksMeasure(_pos.tick()); //unsigned tm = sigmap.ticksMeasure(_pos.tick()); int bm = tm / tb; switch(segment) { case 0: bar += steps; if (bar < 0) bar = 0; selPos = 0; selLen = 4; break; case 1: beat += steps; if (beat < 0) beat = 0; else if (beat >= bm) beat = bm - 1; selPos = 5; selLen = 2; break; case 2: tick += steps; if (tick < 0) tick = 0; else if (tick >= tb) tick = tb -1; selPos = 8; selLen = 3; break; default: return; } Pos newPos(bar, beat, tick); if (!(newPos == _pos)) { changed = true; _pos = newPos; } } if (changed) { updateValue(); emit valueChanged(_pos); } lineEdit()->setSelection(selPos, selLen); } void PosEdit::paintEvent(QPaintEvent* event) { if (!initialized) updateValue(); initialized = true; QAbstractSpinBox::paintEvent(event); } }