//========================================================= // MusE // Linux Music Editor // $Id: sigedit.cpp,v 1.1.1.1.2.1 2004/12/28 23:23:51 lunar_shuttle Exp $ // (C) Copyright 2001 Werner Schweer (ws@seh.de) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; version 2 of // the License, or (at your option) any later version. // // 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //========================================================= #include #include #include #include #include #include #include #include #include #include #include #include #include ///#include "sig.h" #include "al/sig.h" #include "sigedit.h" #include "spinbox.h" extern int MusEGlobal::mtcType; namespace MusEGui { bool Sig::isValid() const { if((z < 1) || (z > 63)) return false; switch(n) { case 1: case 2: case 3: case 4: case 8: case 16: case 32: case 64: case 128: return true; default: return false; } } //--------------------------------------------------------- // NumberSection //--------------------------------------------------------- class NumberSection { int selstart; int selend; public: NumberSection(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; } }; //--------------------------------------------------------- // SigEditor //--------------------------------------------------------- class SigEditor : public QLineEdit { SigEdit* cw; bool frm; QPixmap *pm; int focusSec; QList sections; int offset; int section(const QPoint&); protected: void init(); virtual bool event(QEvent *e); virtual void resizeEvent(QResizeEvent*); virtual void paintEvent(QPaintEvent*); virtual void mousePressEvent(QMouseEvent *e); virtual void keyPressEvent(QKeyEvent * event ); void applyFocusSelection() {} public: SigEditor(SigEdit* parent, const char* name); ~SigEditor(); void setControlWidget(SigEdit * widget); SigEdit* controlWidget() const; int focusSection() const { return focusSec; } bool setFocusSection(int s); void appendSection(const NumberSection& sec); void clearSections(); void setSectionSelection(int sec, int selstart, int selend); }; //--------------------------------------------------------- // section //--------------------------------------------------------- int SigEditor::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 (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("/"); p.drawText(x, y, w, h, Qt::AlignVCenter|Qt::AlignLeft, s, -1, &bb); x = bb.x() + bb.width(); } } return -1; } //--------------------------------------------------------- // SigEditor //--------------------------------------------------------- SigEditor::SigEditor(SigEdit* parent, const char* name) : QLineEdit(parent) { setObjectName(name); cw = parent; frm = true; focusSec = 0; pm = new QPixmap; offset = 0; init(); } //--------------------------------------------------------- // ~SigEditor //--------------------------------------------------------- SigEditor::~SigEditor() { delete pm; } //--------------------------------------------------------- // init //--------------------------------------------------------- void SigEditor::init() { setBackgroundMode(Qt::PaletteBase); setFocusSection(-1); setKeyCompression(true); setFocusPolicy(Qt::WheelFocus); } //--------------------------------------------------------- // event //--------------------------------------------------------- bool SigEditor::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 QLineEdit::event(e); } void SigEditor::resizeEvent(QResizeEvent *e) { pm->resize(e->size()); QLineEdit::resizeEvent(e); } //--------------------------------------------------------- // paintEvent //--------------------------------------------------------- void SigEditor::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 (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("/"); 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 SigEditor::mousePressEvent(QMouseEvent *e) { QPoint p(e->pos().x(), 0); int sec = section(p); if (sec != -1) { cw->setFocusSection(sec); repaint(rect(), false); } } //--------------------------------------------------------- // keyPressEvent //--------------------------------------------------------- void SigEditor::keyPressEvent(QKeyEvent * e ) { switch (e->key()) { case Qt::Key_Right: if (unsigned(focusSec) <= sections.count()) { if (cw->setFocusSection(focusSec+1)) repaint(rect(), false); } case Qt::Key_Left: if (focusSec > 0 ) { if (cw->setFocusSection(focusSec-1)) repaint(rect(), false); } case Qt::Key_Up: cw->stepUp(); case Qt::Key_Down: cw->stepDown(); case Qt::Key_Backspace: case Qt::Key_Delete: cw->removeLastNumber(focusSec); case Qt::Key_Enter: case Qt::Key_Return: cw->enterPressed(); default: QString txt = e->text(); if (!txt.isEmpty() && txt[0] == '/') { // do the same thing as KEY_RIGHT when the user presses the separator key if (focusSec < (signed)(sections.count())) { if (cw->setFocusSection(focusSec+1)) repaint(rect(), false); } } int num = txt[0].digitValue(); //printf("SigEditor::keyPressEvent num:%d\n", num); if (num != -1) { cw->addNumber(focusSec, num); } } } void SigEditor::appendSection(const NumberSection& sec) { sections.append(sec); } void SigEditor::clearSections() { sections.clear(); } //--------------------------------------------------------- // setSectionSelection //--------------------------------------------------------- void SigEditor::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 SigEditor::setFocusSection(int idx) { if (idx > (int)sections.count()-1 || idx < 0) return false; if (idx != focusSec) { focusSec = idx; applyFocusSelection(); return true; } return false; } //--------------------------------------------------------- // SigEdit //--------------------------------------------------------- SigEdit::SigEdit(QWidget* parent, const char* name) : QWidget(parent) { setObjectName(name); init(); updateButtons(); } SigEdit::~SigEdit() { } //--------------------------------------------------------- // init //--------------------------------------------------------- void SigEdit::init() { ed = new SigEditor(this, "pos editor"); controls = new SpinBox(this); controls->setEditor(ed); setFocusProxy(ed); connect(controls, SIGNAL(stepUpPressed()), SLOT(stepUp())); connect(controls, SIGNAL(stepDownPressed()), SLOT(stepDown())); connect(this, SIGNAL(valueChanged(int,int)),SLOT(updateButtons())); overwrite = false; timerId = 0; typing = false; changed = false; adv = false; sec[0].offset = 0; sec[0].len = 2; sec[0].val = 4; sec[0].voff = 0; sec[1].offset = 3; sec[1].len = 3; sec[1].val = 4; sec[1].voff = 0; ed->clearSections(); ed->appendSection(NumberSection(0,0)); ed->appendSection(NumberSection(0,0)); setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); } //--------------------------------------------------------- // setValue //--------------------------------------------------------- void SigEdit::setValue(const Sig& sig) { sec[0].val = sig.z; sec[1].val = sig.n; changed = false; ed->repaint(ed->rect(), false); } void SigEdit::setValue(const QString& s) { int z, n; sscanf(s.toLatin1(), "%d/%d", &z, &n); Sig sig(z, n); setValue(sig); } Sig SigEdit::sig() const { Sig sig(sec[0].val, sec[1].val); return sig; } bool SigEdit::event(QEvent *e) { if (e->type() == QEvent::FocusOut) { typing = false; if (changed) { emit valueChanged(sig().z, sig().n); changed = false; } } return QWidget::event(e); } void SigEdit::timerEvent(QTimerEvent *) { overwrite = true; } //--------------------------------------------------------- // stepUp //--------------------------------------------------------- void SigEdit::stepUp() { bool accepted = false; int secNo = ed->focusSection(); int val = sec[secNo].val; if (secNo == 0) { if (val < 63) { ++val; accepted = true; } } else { accepted = true; switch(val) { case 1: val = 2; break; case 2: val = 3; break; case 3: val = 4; break; case 4: val = 8; break; case 8: val = 16; break; case 16: val = 32; break; case 32: val = 64; break; case 64: val = 128; break; case 128: accepted = false; break; } } if (accepted) { setSec(secNo, val); changed = true; emit valueChanged(sec[0].val, sec[1].val); } ed->repaint(ed->rect(), false); } //--------------------------------------------------------- // stepDown //--------------------------------------------------------- void SigEdit::stepDown() { bool accepted = false; int secNo = ed->focusSection(); int val = sec[secNo].val; if (secNo == 0) { if (val > 1) { --val; accepted = true; } } else { accepted = true; switch(val) { case 1: accepted = false; break; case 2: val = 1; break; case 3: val = 2; break; case 4: val = 3; break; case 8: val = 4; break; case 16: val = 8; break; case 32: val = 16; break; case 64: val = 32; break; case 128: val = 64; break; } } if (accepted) { setSec(secNo, val); changed = true; emit valueChanged(sec[0].val, sec[1].val); } ed->repaint(ed->rect(), false); } //--------------------------------------------------------- // sectionFormattedText // Returns the formatted number for section sec. //--------------------------------------------------------- QString SigEdit::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); if (secNo == 0) txt = txt.rightJustify(len, ' '); // else // txt = txt.leftJustify(len, ' '); return txt; } //--------------------------------------------------------- // setFocusSection //--------------------------------------------------------- bool SigEdit::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(sig().z, sig().n); changed = false; } } return ed->setFocusSection(s); } //--------------------------------------------------------- // setSec //--------------------------------------------------------- void SigEdit::setSec(int secNo, int val) { sec[secNo].val = val; } //--------------------------------------------------------- // sectionText // Returns the text of section \a sec. //--------------------------------------------------------- QString SigEdit::sectionText(int secNo) { return QString::number(sec[secNo].val + sec[secNo].voff); } //--------------------------------------------------------- // outOfRange // return true if out of range //--------------------------------------------------------- bool SigEdit::outOfRange(int secNo, int val) const { if (secNo == 0) return ((val < 1) || (val > 63)); switch (val) { case 1: case 2: case 3: case 4: case 8: case 16: case 32: case 64: case 128: // Changed p3.3.43 //return true; return false; default: // Changed p3.3.43 //return false; return true; } } //--------------------------------------------------------- // addNumber //--------------------------------------------------------- void SigEdit::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); //printf("SigEdit::addNumber secNo:%d num:%d voff:%d txt:%s\n", secNo, num, voff, txt.toLatin1()); if ((unsigned) txt.length() == sec[secNo].len) { //printf("SigEdit::addNumber txt.length() == sec[secNo].len (%d)\n", sec[secNo].len); if (!outOfRange(secNo, num - voff)) { //printf("SigEdit::addNumber accepted\n"); accepted = true; sec[secNo].val = num - voff; } } else { //printf("SigEdit::addNumber txt.length() != sec[secNo].len (%d)\n", sec[secNo].len); txt += QString::number(num); int temp = txt.toInt() - voff; if (outOfRange(secNo, temp)) { //printf("SigEdit::addNumber not accepted secNo:%d txt:%s temp:%d\n", secNo, txt.toLatin1(), temp); txt = sectionText(secNo); } else { //printf("SigEdit::addNumber accepted\n"); accepted = true; sec[secNo].val = temp; } if (adv && ((unsigned) txt.length() == sec[secNo].len)) { setFocusSection(ed->focusSection() + 1); } } changed = accepted; if (accepted) emit valueChanged(sig().z, sig().n); timerId = startTimer(qApp->doubleClickInterval()*4); ed->repaint(ed->rect(), false); } //--------------------------------------------------------- // removeLastNumber //--------------------------------------------------------- void SigEdit::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 SigEdit::resizeEvent(QResizeEvent* ev) { QWidget::resizeEvent(ev); controls->resize(width(), height()); } //--------------------------------------------------------- // sizeHint //--------------------------------------------------------- QSize SigEdit::sizeHint() const { QFontMetrics fm(font()); int fw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this); // ddskrjo int h = fm.height() + fw * 2; int w = 2 + controls->arrowWidth() + fw * 4; w += fm.width('9') * 5 + fm.width('/'); return QSize(w, h).expandedTo(QApplication::globalStrut()); } //--------------------------------------------------------- // updateButtons //--------------------------------------------------------- void SigEdit::updateButtons() { int secNo = ed->focusSection(); int val = sec[secNo].val; bool upEnabled; bool downEnabled; if (secNo == 0) { upEnabled = val < 63; downEnabled = val > 1; } else { upEnabled = true; downEnabled = true; switch (val) { case 1: downEnabled = false; break; case 128: upEnabled = false; break; } } controls->setStepEnabled(isEnabled() & upEnabled, isEnabled() & downEnabled); } //--------------------------------------------------------- // enterPressed //! emit returnPressed //--------------------------------------------------------- void SigEdit::enterPressed() { emit returnPressed(); } } // namespace MusEGui