summaryrefslogtreecommitdiff
path: root/muse2/muse/widgets/posedit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/muse/widgets/posedit.cpp')
-rw-r--r--muse2/muse/widgets/posedit.cpp875
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();
+}