diff options
Diffstat (limited to 'muse2/muse/widgets/posedit.cpp')
-rw-r--r-- | muse2/muse/widgets/posedit.cpp | 875 |
1 files changed, 875 insertions, 0 deletions
diff --git a/muse2/muse/widgets/posedit.cpp b/muse2/muse/widgets/posedit.cpp new file mode 100644 index 00000000..9fad1a6f --- /dev/null +++ b/muse2/muse/widgets/posedit.cpp @@ -0,0 +1,875 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: posedit.cpp,v 1.3.2.2 2008/05/21 00:28:54 terminator356 Exp $ +// (C) Copyright 2001 Werner Schweer (ws@seh.de) +//========================================================= + +#include <q3rangecontrol.h> +#include <qapplication.h> +#include <qpixmap.h> +#include <qapplication.h> +#include <q3valuelist.h> +#include <qstring.h> +#include <qstyle.h> +//Added by qt3to4: +#include <QTimerEvent> +#include <QKeyEvent> +#include <QResizeEvent> +#include <QMouseEvent> +#include <QEvent> +#include <QPaintEvent> +#include <values.h> +#include <qpainter.h> +#include <qtimer.h> + +#include "posedit.h" +#include "sig.h" + +extern int mtcType; + +//--------------------------------------------------------- +// QNumberSection +//--------------------------------------------------------- + +class QNumberSection + { + int selstart; + int selend; + + public: + QNumberSection(int selStart = 0, int selEnd = 0) + : selstart(selStart), selend(selEnd ) {} + int selectionStart() const { return selstart; } + void setSelectionStart(int s) { selstart = s; } + int selectionEnd() const { return selend; } + void setSelectionEnd( int s ) { selend = s; } + int width() const { return selend - selstart; } + }; + +//--------------------------------------------------------- +// PosEditor +//--------------------------------------------------------- + +class PosEditor : public QWidget + { + PosEdit* cw; + bool frm; + QPixmap *pm; + int focusSec; + Q3ValueList<QNumberSection> sections; + QString sep; + int offset; + + int section(const QPoint&); + + protected: + void init(); + bool event(QEvent *e); + void resizeEvent(QResizeEvent*); + void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent *e); + + void applyFocusSelection() {} + + public: + PosEditor(PosEdit* Q_PARENT, const char * Q_NAME ); + ~PosEditor(); + + void setControlWidget(PosEdit * widget); + PosEdit* controlWidget() const; + + void setSeparator(const QString& s) { sep = s; } + QString separator() const { return sep; } + int focusSection() const { return focusSec; } + + bool setFocusSection(int s); + void appendSection(const QNumberSection& sec); + void clearSections(); + void setSectionSelection(int sec, int selstart, int selend); + bool eventFilter(QObject *o, QEvent *e); + }; + +//--------------------------------------------------------- +// section +//--------------------------------------------------------- + +int PosEditor::section(const QPoint& pt) + { + if (pm->isNull()) + return -1; + QPainter p(pm); + int fw = frm ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0; + int x = 2 + fw; + int y = 0; + int w = width(); + int h = height(); + for (unsigned int i = 0; i < sections.count(); ++i) { + QString s = cw->sectionFormattedText(i); + QRect bb = p.boundingRect(x, y, w, h, Qt::AlignVCenter|Qt::AlignLeft, s); + int nx = bb.x() + bb.width(); + if (pt.x() >= x && pt.x() < nx) + return i; + x = nx; + if (i < sections.count()-1) { + QString s = sep; + p.drawText(x, y, w, h, Qt::AlignVCenter|Qt::AlignLeft, s, -1, &bb); + x = bb.x() + bb.width(); + } + } + return -1; + } + +//--------------------------------------------------------- +// PosEditor +//--------------------------------------------------------- + +PosEditor::PosEditor(PosEdit* parent, const char* name) + : QWidget(parent, name), sep(".") + { + cw = parent; + frm = true; + focusSec = 0; + pm = new QPixmap; + offset = 0; + init(); + } + +//--------------------------------------------------------- +// ~PosEditor +//--------------------------------------------------------- + +PosEditor::~PosEditor() + { + delete pm; + } + +//--------------------------------------------------------- +// init +//--------------------------------------------------------- + +void PosEditor::init() + { + setBackgroundMode(Qt::PaletteBase); + setFocusSection(-1); + setKeyCompression(true); + installEventFilter(this); + setFocusPolicy(Qt::WheelFocus); + } + +//--------------------------------------------------------- +// event +//--------------------------------------------------------- + +bool PosEditor::event(QEvent *e) + { + if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) { + repaint( rect(), false); + } + else if (e->type() == QEvent::ShortcutOverride) { + QKeyEvent* ke = (QKeyEvent*) e; + switch (ke->key()) { + case Qt::Key_Delete: + case Qt::Key_Backspace: + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_Left: + case Qt::Key_Right: + ke->accept(); + default: + break; + } + } + return QWidget::event(e); + } + +void PosEditor::resizeEvent(QResizeEvent *e) + { + pm->resize(e->size()); + QWidget::resizeEvent(e); + } + +//--------------------------------------------------------- +// paintEvent +//--------------------------------------------------------- + +void PosEditor::paintEvent(QPaintEvent *) + { + if (pm->isNull()) + return; + + const QColorGroup & cg = colorGroup(); + QPainter p(pm); + p.setPen(colorGroup().text()); + QBrush bg = cg.brush(QColorGroup::Base); + + int fw = frm ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0; + int x = 2 + fw; + int y = 0; + int w = width(); + int h = height(); + p.fillRect(0, 0, w, h, bg); + + for (unsigned int i = 0; i < sections.count(); ++i) { + QRect bb; + QString s = cw->sectionFormattedText(i); + + if (hasFocus() && (int(i) == focusSec)) { + QBrush bg = cg.brush(QColorGroup::Highlight); + QRect r = p.boundingRect(x, y, w, h, Qt::AlignVCenter|Qt::AlignLeft, s, -1); + p.setPen(colorGroup().highlightedText()); + p.fillRect(r, bg); + } + else + p.setPen(colorGroup().text()); + p.drawText(x, y, w, h, Qt::AlignVCenter|Qt::AlignLeft, s, -1, &bb); + x = bb.x() + bb.width(); + if (i < sections.count()-1) { + QString s = sep; + p.drawText(x, y, w, h, Qt::AlignVCenter|Qt::AlignLeft, s, -1, &bb); + x = bb.x() + bb.width(); + } + } + p.end(); + bitBlt(this, 0, 0, pm); + } + +//--------------------------------------------------------- +// mousePressEvent +//--------------------------------------------------------- + +void PosEditor::mousePressEvent(QMouseEvent *e) + { + QPoint p(e->pos().x(), 0); + int sec = section(p); + if (sec != -1) { + cw->setFocusSection(sec); + repaint(rect(), false); + } + } + +//--------------------------------------------------------- +// eventFilter +//--------------------------------------------------------- + +bool PosEditor::eventFilter(QObject *o, QEvent *e) + { + if (o != this) + return false; + if (e->type() != QEvent::KeyPress ) + return false; + + QKeyEvent *ke = (QKeyEvent*)e; + switch (ke->key()) { + case Qt::Key_Right: + if (unsigned(focusSec) <= sections.count()) { + if (cw->setFocusSection(focusSec+1)) + repaint(rect(), false); + } + return true; + case Qt::Key_Left: + if (focusSec > 0 ) { + if (cw->setFocusSection(focusSec-1)) + repaint(rect(), false); + } + return true; + case Qt::Key_Up: + cw->stepUp(); + return true; + case Qt::Key_Down: + cw->stepDown(); + return true; + case Qt::Key_Backspace: + case Qt::Key_Delete: + cw->removeLastNumber(focusSec); + return true; + case Qt::Key_Return: + cw->enterPressed(); + return true; + default: + QString txt = ke->text(); + if (!txt.isEmpty() && !sep.isEmpty() && txt[0] == sep[0]) { + // do the same thing as KEY_RIGHT when the user presses the separator key + if (unsigned(focusSec) < sections.count()) { + if (cw->setFocusSection(focusSec+1)) + repaint(rect(), false); + } + return true; + } + int num = txt[0].digitValue(); + if (num != -1) { + cw->addNumber(focusSec, num); + return true; + } + } + return false; + } + +void PosEditor::appendSection(const QNumberSection& sec) + { + sections.append(sec); + } +void PosEditor::clearSections() + { + sections.clear(); + } + +//--------------------------------------------------------- +// setSectionSelection +//--------------------------------------------------------- + +void PosEditor::setSectionSelection(int secNo, int selstart, int selend) + { + if (secNo < 0 || secNo > (int)sections.count()) + return; + sections[secNo].setSelectionStart(selstart); + sections[secNo].setSelectionEnd(selend); + } + +//--------------------------------------------------------- +// setFocusSection +//--------------------------------------------------------- + +bool PosEditor::setFocusSection(int idx) + { + if (idx > (int)sections.count()-1 || idx < 0) + return false; + if (idx != focusSec) { + focusSec = idx; + applyFocusSelection(); + return true; + } + return false; + } + +//--------------------------------------------------------- +// PosEdit +//--------------------------------------------------------- + +PosEdit::PosEdit(QWidget* parent, const char* name) + : QWidget(parent, name) + { + init(); + updateButtons(); + } + +PosEdit::PosEdit(const Pos& time, QWidget* parent, const char* name) + : QWidget(parent, name) + { + init(); + setValue(time); + updateButtons(); + } + +PosEdit::~PosEdit() + { + } + +//--------------------------------------------------------- +// init +//--------------------------------------------------------- + +void PosEdit::init() + { + ed = new PosEditor(this, "pos editor"); + controls = new Q3SpinWidget(this, "pos edit controls"); + controls->setEditWidget(ed); + setFocusProxy(ed); + connect(controls, SIGNAL(stepUpPressed()), SLOT(stepUp())); + connect(controls, SIGNAL(stepDownPressed()), SLOT(stepDown())); + connect(this, SIGNAL(valueChanged(const Pos&)),SLOT(updateButtons())); + + overwrite = false; + timerId = 0; + typing = false; + min = Pos(0); + max = Pos(MAX_TICK); + changed = false; + adv = false; + + + static Section s_midiSections[3] = { // measure, beat, tick + { 0, 4, 1, 0 }, + { 5, 2, 1, 0 }, + { 8, 3, 0, 0 } + }; + static Section s_smpteSections[4] = { // minute second frame subframe + { 0, 3, 0, 0 }, + { 4, 2, 0, 0 }, + { 7, 2, 0, 0 }, + { 10, 2, 0, 0 } + }; + memcpy(midiSections, s_midiSections, sizeof(s_midiSections)); + memcpy(smpteSections, s_smpteSections, sizeof(s_smpteSections)); + + _smpte = false; // show position in smpte format + sec = midiSections; + setSections(); + setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); + } + +//--------------------------------------------------------- +// setSetions +//--------------------------------------------------------- + +void PosEdit::setSections() + { + ed->clearSections(); + ed->appendSection(QNumberSection(0,0)); + ed->appendSection(QNumberSection(0,0)); + ed->appendSection(QNumberSection(0,0)); + if (_smpte) { + ed->appendSection(QNumberSection(0,0)); + ed->setSeparator(QString(":")); + } + else { + ed->setSeparator(QString(".")); + } + } + +//--------------------------------------------------------- +// smpte +//--------------------------------------------------------- + +bool PosEdit::smpte() const + { + return _smpte; + } + +//--------------------------------------------------------- +// setSmpte +//--------------------------------------------------------- + +void PosEdit::setSmpte(bool f) + { + _smpte = f; + sec = f ? smpteSections : midiSections; + setSections(); + ed->repaint(ed->rect(), false); + } + +//--------------------------------------------------------- +// minValue +//--------------------------------------------------------- + +Pos PosEdit::minValue() const + { + return min; + } + +//--------------------------------------------------------- +// maxValue +//--------------------------------------------------------- + +Pos PosEdit::maxValue() const + { + return max; + } + +//--------------------------------------------------------- +// setRange +//--------------------------------------------------------- + +void PosEdit::setRange(const Pos& _min, const Pos& _max) + { + if (min.isValid()) + min = _min; + if (max.isValid()) + max = _max; + } + +//--------------------------------------------------------- +// setValue +//--------------------------------------------------------- + +void PosEdit::setValue(const Pos& time) + { + if (time > maxValue() || time < minValue()) + return; + if (_smpte) + time.msf(&(sec[0].val), &(sec[1].val), &(sec[2].val), + &(sec[3].val)); + else + time.mbt(&(sec[0].val), &(sec[1].val), &(sec[2].val)); + changed = false; + + updateButtons(); + ed->repaint(ed->rect(), false); + } + +void PosEdit::setValue(const QString& s) + { + Pos time(s); + setValue(time); + } + +void PosEdit::setValue(int t) + { + Pos time(t); + setValue(time); + } + +Pos PosEdit::pos() const + { + if (_smpte) { + if (Pos::isValid(sec[0].val, sec[1].val, sec[2].val, sec[3].val)) + return Pos(sec[0].val, sec[1].val, sec[2].val, sec[3].val); + } + else { + if (Pos::isValid(sec[0].val, sec[1].val, sec[2].val)) + return Pos(sec[0].val, sec[1].val, sec[2].val); + } + return Pos(); + } + +void PosEdit::setSeparator(const QString& s) + { + ed->setSeparator(s); + } + +QString PosEdit::separator() const + { + return ed->separator(); + } + +bool PosEdit::event(QEvent *e) + { + if (e->type() == QEvent::FocusOut) { + typing = false; + if (changed) { + emit valueChanged(pos() ); + changed = false; + } + } + return QWidget::event(e); + } + +void PosEdit::timerEvent(QTimerEvent *) + { + overwrite = true; + } + +//--------------------------------------------------------- +// stepUp +//--------------------------------------------------------- + +void PosEdit::stepUp() + { + int secNo = ed->focusSection(); + bool accepted = false; + + if (!outOfRange(secNo, sec[secNo].val+1)) { + accepted = true; + setSec(secNo, sec[secNo].val+1); + } + if (accepted) { + changed = true; + Pos p = pos(); + emit valueChanged(p); + } + ed->repaint(ed->rect(), false); + } + +//--------------------------------------------------------- +// stepDown +//--------------------------------------------------------- + +void PosEdit::stepDown() + { + int secNo = ed->focusSection(); + bool accepted = false; + if (!outOfRange(secNo, sec[secNo].val-1)) { + accepted = true; + setSec(secNo, sec[secNo].val-1); + } + if (accepted) { + changed = true; + emit valueChanged(pos()); + } + ed->repaint(ed->rect(), false); + } + +//--------------------------------------------------------- +// sectionFormattedText +// Returns the formatted number for section sec. +//--------------------------------------------------------- + +QString PosEdit::sectionFormattedText(int secNo) + { + QString txt = sectionText(secNo); + int so = sec[secNo].offset; + int len = sec[secNo].len; + int eo = so + len; + + if (typing && secNo == ed->focusSection()) + ed->setSectionSelection(secNo, eo - txt.length(), eo); + else + ed->setSectionSelection(secNo, so, eo); + txt = txt.rightJustify(len, '0'); + return txt; + } + +//--------------------------------------------------------- +// setFocusSection +//--------------------------------------------------------- + +bool PosEdit::setFocusSection(int s) + { + if (s != ed->focusSection()) { + killTimer(timerId); + overwrite = true; + typing = false; + int so = sec[s].offset; + int eo = so + sec[s].len; + ed->setSectionSelection(s, so, eo); + if (changed) { + emit valueChanged(pos()); + changed = false; + } + } + return ed->setFocusSection(s); + } + +//--------------------------------------------------------- +// setSec +//--------------------------------------------------------- + +void PosEdit::setSec(int secNo, int val) + { + if (val < 0) + val = 0; + if (_smpte) { + switch(secNo) { + case 0: + break; + case 1: + if (val > 59) + val = 59; + break; + case 2: + switch(mtcType) { + case 0: // 24 frames sec + if (val > 23) + val = 23; + break; + case 1: + if (val > 24) + val = 24; + break; + case 2: // 30 drop frame + case 3: // 30 non drop frame + if (val > 29) + val = 29; + break; + } + break; + case 3: + if (val > 99) + val = 99; + } + } + else { + switch(secNo) { + case 0: + break; + case 1: + { + int z, n; + int tick = sigmap.bar2tick(sec[0].val, val, sec[2].val); + sigmap.timesig(tick, z, n); + if (val >= n) + val = n-1; + } + break; + case 2: + { + int tick = sigmap.bar2tick(sec[0].val, sec[1].val, val); + int tb = sigmap.ticksBeat(tick); + if (val >= tb) + val = tb-1; + } + break; + } + } + sec[secNo].val = val; + } + +//--------------------------------------------------------- +// sectionText +// Returns the text of section \a sec. +//--------------------------------------------------------- + +QString PosEdit::sectionText(int secNo) + { + return QString::number(sec[secNo].val + sec[secNo].voff); + } + +//--------------------------------------------------------- +// outOfRange +// return true if out of range +//--------------------------------------------------------- + +bool PosEdit::outOfRange(int secNo, int val) const + { + if (val < 0) + return true; + int limit = MAXINT; + if (_smpte) { + switch(secNo) { + case 0: + break; + case 1: + limit = 59; + break; + case 2: + switch(mtcType) { + case 0: // 24 frames sec + limit = 23; + break; + case 1: + limit = 24; + break; + case 2: // 30 drop frame + case 3: // 30 non drop frame + limit = 29; + break; + } + break; + case 3: + limit = 99; + break; + } + } + else { + switch(secNo) { + case 0: + break; + case 1: + { + int z; + int tick = sigmap.bar2tick(sec[0].val, val, sec[2].val); + sigmap.timesig(tick, z, limit); + limit -= 1; + } + break; + case 2: + int tick = sigmap.bar2tick(sec[0].val, sec[1].val, val); + limit = sigmap.ticksBeat(tick) - 1; + break; + } + } + return val > limit; + } + +//--------------------------------------------------------- +// addNumber +//--------------------------------------------------------- + +void PosEdit::addNumber(int secNo, int num) + { + if (secNo == -1) + return; + killTimer(timerId); + bool accepted = false; + typing = true; + int voff = sec[secNo].voff; + + QString txt = sectionText(secNo); + + if (txt.length() == sec[secNo].len) { + if (!outOfRange(secNo, num - voff)) { + accepted = true; + sec[secNo].val = num - voff; + } + } + else { + txt += QString::number(num); + int temp = txt.toInt() - voff; + if (outOfRange(secNo, temp)) + txt = sectionText(secNo); + else { + accepted = true; + sec[secNo].val = temp; + } + if (adv && (txt.length() == sec[secNo].len)) { + setFocusSection(ed->focusSection() + 1); + } + } + changed = accepted; + if (accepted) + emit valueChanged(pos()); + timerId = startTimer(qApp->doubleClickInterval()*4); + ed->repaint(ed->rect(), false); + } + +//--------------------------------------------------------- +// removeLastNumber +//--------------------------------------------------------- + +void PosEdit::removeLastNumber(int secNo) + { + if (secNo == -1) + return; + QString txt = QString::number(sec[secNo].val); + txt = txt.mid(0, txt.length() - 1); + sec[secNo].val = txt.toInt() - sec[secNo].voff; + ed->repaint(ed->rect(), false); + } + +//--------------------------------------------------------- +// resizeEvent +//--------------------------------------------------------- + +void PosEdit::resizeEvent(QResizeEvent *) + { + controls->resize(width(), height()); + } + +//--------------------------------------------------------- +// sizeHint +//--------------------------------------------------------- + +QSize PosEdit::sizeHint() const + { + QFontMetrics fm(font()); + int fw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth,0, this); // ddskrjo 0 + int h = fm.height() + fw * 2; + int w = 4 + controls->upRect().width() + fw * 4; + if (_smpte) + w += fm.width('9') * 10 + fm.width(ed->separator()) * 3; + else + w += fm.width('9') * 10 + fm.width(ed->separator()) * 2; + return QSize(w, h).expandedTo(QApplication::globalStrut()); + } + +//--------------------------------------------------------- +// updateButtons +//--------------------------------------------------------- + +void PosEdit::updateButtons() + { + bool upEnabled = isEnabled() && (pos() < maxValue()); + bool downEnabled = isEnabled() && (pos() > minValue()); + + //printf("PosEdit::updateButtons smpte:%d upEnabled:%d downEnabled:%d\n", smpte(), upEnabled, downEnabled); + + controls->setUpEnabled(upEnabled); + controls->setDownEnabled(downEnabled); + } + +//--------------------------------------------------------- +// enterPressed +//--------------------------------------------------------- +void PosEdit::enterPressed() + { + emit returnPressed(); + } + +//--------------------------------------------------------- +// setEnabled +//--------------------------------------------------------- +void PosEdit::setEnabled(bool v) +{ + QWidget::setEnabled(v); + updateButtons(); +} |