1
//=========================================================
4
// $Id: posedit.cpp,v 1.1 2002/01/30 14:54:03 muse Exp $
5
// (C) Copyright 2001 Werner Schweer (ws@seh.de)
6
//=========================================================
10
#include <qrangecontrol.h>
11
#include <qapplication.h>
13
#include <qapplication.h>
14
#include <qvaluelist.h>
24
//---------------------------------------------------------
26
//---------------------------------------------------------
34
QNumberSection(int selStart = 0, int selEnd = 0)
35
: selstart(selStart), selend(selEnd ) {}
36
int selectionStart() const { return selstart; }
37
void setSelectionStart(int s) { selstart = s; }
38
int selectionEnd() const { return selend; }
39
void setSelectionEnd( int s ) { selend = s; }
40
int width() const { return selend - selstart; }
43
//---------------------------------------------------------
45
//---------------------------------------------------------
47
class PosEditor : public QWidget
53
QValueList<QNumberSection> sections;
57
int section(const QPoint&);
61
bool event(QEvent *e);
62
void resizeEvent(QResizeEvent*);
63
void paintEvent(QPaintEvent*);
64
void mousePressEvent(QMouseEvent *e);
66
void applyFocusSelection() {}
69
PosEditor(PosEdit* Q_PARENT, const char * Q_NAME );
72
void setControlWidget(PosEdit * widget);
73
PosEdit* controlWidget() const;
75
void setSeparator(const QString& s) { sep = s; }
76
QString separator() const { return sep; }
77
int focusSection() const { return focusSec; }
79
bool setFocusSection(int s);
80
void appendSection(const QNumberSection& sec);
82
void setSectionSelection(int sec, int selstart, int selend);
83
bool eventFilter(QObject *o, QEvent *e);
86
//---------------------------------------------------------
88
//---------------------------------------------------------
90
int PosEditor::section(const QPoint& pt)
95
int fw = frm ? style().pixelMetric(QStyle::PM_DefaultFrameWidth) : 0;
100
for (unsigned int i = 0; i < sections.count(); ++i) {
101
QString s = cw->sectionFormattedText(i);
102
QRect bb = p.boundingRect(x, y, w, h, AlignVCenter|AlignLeft, s);
103
int nx = bb.x() + bb.width();
104
if (pt.x() >= x && pt.x() < nx)
107
if (i < sections.count()-1) {
109
p.drawText(x, y, w, h, AlignVCenter|AlignLeft, s, -1, &bb);
110
x = bb.x() + bb.width();
116
//---------------------------------------------------------
118
//---------------------------------------------------------
120
PosEditor::PosEditor(PosEdit* parent, const char* name)
121
: QWidget(parent, name), sep(".")
131
//---------------------------------------------------------
133
//---------------------------------------------------------
135
PosEditor::~PosEditor()
140
//---------------------------------------------------------
142
//---------------------------------------------------------
144
void PosEditor::init()
146
setBackgroundMode(PaletteBase);
148
setKeyCompression(true);
149
installEventFilter(this);
150
setFocusPolicy(WheelFocus);
153
//---------------------------------------------------------
155
//---------------------------------------------------------
157
bool PosEditor::event(QEvent *e)
159
if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) {
160
repaint( rect(), false);
162
else if (e->type() == QEvent::AccelOverride) {
163
QKeyEvent* ke = (QKeyEvent*) e;
176
return QWidget::event(e);
179
void PosEditor::resizeEvent(QResizeEvent *e)
181
pm->resize(e->size());
182
QWidget::resizeEvent(e);
185
//---------------------------------------------------------
187
//---------------------------------------------------------
189
void PosEditor::paintEvent(QPaintEvent *)
194
const QColorGroup & cg = colorGroup();
196
p.setPen(colorGroup().text());
197
QBrush bg = cg.brush(QColorGroup::Base);
199
int fw = frm ? style().pixelMetric(QStyle::PM_DefaultFrameWidth) : 0;
204
p.fillRect(0, 0, w, h, bg);
206
for (unsigned int i = 0; i < sections.count(); ++i) {
208
QString s = cw->sectionFormattedText(i);
210
if (hasFocus() && (int(i) == focusSec)) {
211
QBrush bg = cg.brush(QColorGroup::Highlight);
212
QRect r = p.boundingRect(x, y, w, h, AlignVCenter|AlignLeft, s, -1);
213
p.setPen(colorGroup().highlightedText());
217
p.setPen(colorGroup().text());
218
p.drawText(x, y, w, h, AlignVCenter|AlignLeft, s, -1, &bb);
219
x = bb.x() + bb.width();
220
if (i < sections.count()-1) {
222
p.drawText(x, y, w, h, AlignVCenter|AlignLeft, s, -1, &bb);
223
x = bb.x() + bb.width();
227
bitBlt(this, 0, 0, pm);
230
//---------------------------------------------------------
232
//---------------------------------------------------------
234
void PosEditor::mousePressEvent(QMouseEvent *e)
236
QPoint p(e->pos().x(), 0);
237
int sec = section(p);
239
cw->setFocusSection(sec);
240
repaint(rect(), false);
244
//---------------------------------------------------------
246
//---------------------------------------------------------
248
bool PosEditor::eventFilter(QObject *o, QEvent *e)
252
if (e->type() != QEvent::KeyPress )
255
QKeyEvent *ke = (QKeyEvent*)e;
258
if (unsigned(focusSec) <= sections.count()) {
259
if (cw->setFocusSection(focusSec+1))
260
repaint(rect(), false);
265
if (cw->setFocusSection(focusSec-1))
266
repaint(rect(), false);
277
cw->removeLastNumber(focusSec);
280
QString txt = ke->text();
281
if (!txt.isEmpty() && !sep.isEmpty() && txt[0] == sep[0]) {
282
// do the same thing as KEY_RIGHT when the user presses the separator key
283
if (focusSec < sections.count()) {
284
if (cw->setFocusSection(focusSec+1))
285
repaint(rect(), false);
289
int num = txt[0].digitValue();
291
cw->addNumber(focusSec, num);
298
void PosEditor::appendSection(const QNumberSection& sec)
300
sections.append(sec);
302
void PosEditor::clearSections()
307
//---------------------------------------------------------
308
// setSectionSelection
309
//---------------------------------------------------------
311
void PosEditor::setSectionSelection(int secNo, int selstart, int selend)
313
if (secNo < 0 || secNo > (int)sections.count())
315
sections[secNo].setSelectionStart(selstart);
316
sections[secNo].setSelectionEnd(selend);
319
//---------------------------------------------------------
321
//---------------------------------------------------------
323
bool PosEditor::setFocusSection(int idx)
325
if (idx > (int)sections.count()-1 || idx < 0)
327
if (idx != focusSec) {
329
applyFocusSelection();
335
//---------------------------------------------------------
337
//---------------------------------------------------------
339
PosEdit::PosEdit(QWidget* parent, const char* name = 0)
340
: QWidget(parent, name)
346
PosEdit::PosEdit(const Pos& time, QWidget* parent, const char* name = 0)
347
: QWidget(parent, name)
358
//---------------------------------------------------------
360
//---------------------------------------------------------
364
ed = new PosEditor(this, "pos editor");
365
controls = new QSpinWidget(this, "pos edit controls");
366
controls->setEditWidget(ed);
368
connect(controls, SIGNAL(stepUpPressed()), SLOT(stepUp()));
369
connect(controls, SIGNAL(stepDownPressed()), SLOT(stepDown()));
370
connect(this, SIGNAL(valueChanged(const Pos&)),SLOT(updateButtons()));
381
static Section s_midiSections[3] = { // measure, beat, tick
386
static Section s_smpteSections[4] = { // minute second frame subframe
392
memcpy(midiSections, s_midiSections, sizeof(s_midiSections));
393
memcpy(smpteSections, s_smpteSections, sizeof(s_smpteSections));
395
_smpte = false; // show position in smpte format
398
setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
401
//---------------------------------------------------------
403
//---------------------------------------------------------
405
void PosEdit::setSections()
408
ed->appendSection(QNumberSection(0,0));
409
ed->appendSection(QNumberSection(0,0));
410
ed->appendSection(QNumberSection(0,0));
412
ed->appendSection(QNumberSection(0,0));
413
ed->setSeparator(":");
416
ed->setSeparator(".");
420
//---------------------------------------------------------
422
//---------------------------------------------------------
424
bool PosEdit::smpte() const
429
//---------------------------------------------------------
431
//---------------------------------------------------------
433
void PosEdit::setSmpte(bool f)
436
sec = f ? smpteSections : midiSections;
438
ed->repaint(ed->rect(), false);
441
//---------------------------------------------------------
443
//---------------------------------------------------------
445
Pos PosEdit::minValue() const
450
//---------------------------------------------------------
452
//---------------------------------------------------------
454
Pos PosEdit::maxValue() const
459
//---------------------------------------------------------
461
//---------------------------------------------------------
463
void PosEdit::setRange(const Pos& _min, const Pos& _max)
471
//---------------------------------------------------------
473
//---------------------------------------------------------
475
void PosEdit::setValue(const Pos& time)
477
/* if (!time.isValid()) {
484
if (time > maxValue() || time < minValue())
487
time.msf(&(sec[0].val), &(sec[1].val), &(sec[2].val),
490
time.mbt(&(sec[0].val), &(sec[1].val), &(sec[2].val));
491
// emit valueChanged(time);
493
ed->repaint(ed->rect(), false);
496
void PosEdit::setValue(const QString& s)
502
void PosEdit::setValue(int t)
508
Pos PosEdit::pos() const
511
if (Pos::isValid(sec[0].val, sec[1].val, sec[2].val, sec[3].val))
512
return Pos(sec[0].val, sec[1].val, sec[2].val, sec[3].val);
515
if (Pos::isValid(sec[0].val, sec[1].val, sec[2].val))
516
return Pos(sec[0].val, sec[1].val, sec[2].val);
521
void PosEdit::setSeparator(const QString& s)
526
QString PosEdit::separator() const
528
return ed->separator();
531
bool PosEdit::event(QEvent *e)
533
if (e->type() == QEvent::FocusOut) {
536
emit valueChanged(pos() );
540
return QWidget::event(e);
543
void PosEdit::timerEvent(QTimerEvent *)
548
//---------------------------------------------------------
550
//---------------------------------------------------------
552
void PosEdit::stepUp()
554
int secNo = ed->focusSection();
555
bool accepted = false;
557
if (!outOfRange(secNo, sec[secNo].val+1)) {
559
setSec(secNo, sec[secNo].val+1);
563
emit valueChanged(pos());
565
ed->repaint(ed->rect(), false);
569
//---------------------------------------------------------
571
//---------------------------------------------------------
573
void PosEdit::stepDown()
575
int secNo = ed->focusSection();
576
bool accepted = false;
577
if (!outOfRange(secNo, sec[secNo].val-1)) {
579
setSec(secNo, sec[secNo].val-1);
583
emit valueChanged(pos());
585
ed->repaint(ed->rect(), false);
588
//---------------------------------------------------------
589
// sectionFormattedText
590
// Returns the formatted number for section sec.
591
//---------------------------------------------------------
593
QString PosEdit::sectionFormattedText(int secNo)
595
QString txt = sectionText(secNo);
596
int so = sec[secNo].offset;
597
int len = sec[secNo].len;
600
if (typing && secNo == ed->focusSection())
601
ed->setSectionSelection(secNo, eo - txt.length(), eo);
603
ed->setSectionSelection(secNo, so, eo);
604
txt = txt.rightJustify(len, '0');
608
//---------------------------------------------------------
610
//---------------------------------------------------------
612
bool PosEdit::setFocusSection(int s)
614
if (s != ed->focusSection()) {
618
int so = sec[s].offset;
619
int eo = so + sec[s].len;
620
ed->setSectionSelection(s, so, eo);
622
emit valueChanged(pos());
626
return ed->setFocusSection(s);
629
//---------------------------------------------------------
631
//---------------------------------------------------------
633
void PosEdit::setSec(int secNo, int val)
647
case 0: // 24 frames sec
655
case 2: // 30 drop frame
656
case 3: // 30 non drop frame
674
int tick = sigmap.bar2tick(sec[0].val, val, sec[2].val);
675
sigmap.timesig(tick, z, n);
682
int tick = sigmap.bar2tick(sec[0].val, sec[1].val, val);
683
int tb = sigmap.ticksBeat(tick);
690
sec[secNo].val = val;
693
//---------------------------------------------------------
695
// Returns the text of section \a sec.
696
//---------------------------------------------------------
698
QString PosEdit::sectionText(int secNo)
700
return QString::number(sec[secNo].val + sec[secNo].voff);
703
//---------------------------------------------------------
705
// return true if out of range
706
//---------------------------------------------------------
708
bool PosEdit::outOfRange(int secNo, int val) const
722
case 0: // 24 frames sec
728
case 2: // 30 drop frame
729
case 3: // 30 non drop frame
746
int tick = sigmap.bar2tick(sec[0].val, val, sec[2].val);
747
sigmap.timesig(tick, z, limit);
752
int tick = sigmap.bar2tick(sec[0].val, sec[1].val, val);
753
limit = sigmap.ticksBeat(tick) - 1;
760
//---------------------------------------------------------
762
//---------------------------------------------------------
764
void PosEdit::addNumber(int secNo, int num)
769
bool accepted = false;
771
int voff = sec[secNo].voff;
773
QString txt = sectionText(secNo);
775
if (txt.length() == sec[secNo].len) {
776
if (!outOfRange(secNo, num - voff)) {
778
sec[secNo].val = num - voff;
782
txt += QString::number(num);
783
int temp = txt.toInt() - voff;
784
if (outOfRange(secNo, temp))
785
txt = sectionText(secNo);
788
sec[secNo].val = temp;
790
if (adv && (txt.length() == sec[secNo].len)) {
791
setFocusSection(ed->focusSection() + 1);
796
emit valueChanged(pos());
797
timerId = startTimer(qApp->doubleClickInterval()*4);
798
ed->repaint(ed->rect(), false);
801
//---------------------------------------------------------
803
//---------------------------------------------------------
805
void PosEdit::removeLastNumber(int secNo)
809
QString txt = QString::number(sec[secNo].val);
810
txt = txt.mid(0, txt.length() - 1);
811
sec[secNo].val = txt.toInt() - sec[secNo].voff;
812
ed->repaint(ed->rect(), false);
815
//---------------------------------------------------------
817
//---------------------------------------------------------
819
void PosEdit::resizeEvent(QResizeEvent *)
821
controls->resize(width(), height());
824
//---------------------------------------------------------
826
//---------------------------------------------------------
828
QSize PosEdit::sizeHint() const
830
QFontMetrics fm(font());
831
int fw = style().pixelMetric(QStyle::PM_DefaultFrameWidth, this);
832
int h = fm.height() + fw * 2;
833
int w = 2 + controls->upRect().width() + fw * 4;
835
w += fm.width('9') * 9 + fm.width(ed->separator()) * 3;
837
w += fm.width('9') * 9 + fm.width(ed->separator()) * 2;
838
return QSize(w, h).expandedTo(QApplication::globalStrut());
841
//---------------------------------------------------------
843
//---------------------------------------------------------
845
void PosEdit::updateButtons()
847
bool upEnabled = isEnabled() && pos() < maxValue();
848
bool downEnabled = isEnabled() && pos() > minValue();
850
controls->setUpEnabled(upEnabled);
851
controls->setDownEnabled(downEnabled);