You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
603 lines
14 KiB
603 lines
14 KiB
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** |
|
* Qwt Widget Library |
|
* Copyright (C) 1997 Josef Wilgen |
|
* Copyright (C) 2002 Uwe Rathmann |
|
* |
|
* This library is free software; you can redistribute it and/or |
|
* modify it under the terms of the Qwt License, Version 1.0 |
|
*****************************************************************************/ |
|
|
|
// vim: expandtab |
|
|
|
#include <qlayout.h> |
|
#include <qlineedit.h> |
|
#include <qvalidator.h> |
|
#include <qevent.h> |
|
#include <qstyle.h> |
|
#include "qwt_math.h" |
|
#include "qwt_counter.h" |
|
#include "qwt_arrow_button.h" |
|
|
|
class QwtCounter::PrivateData |
|
{ |
|
public: |
|
PrivateData(): |
|
editable(true) { |
|
increment[Button1] = 1; |
|
increment[Button2] = 10; |
|
increment[Button3] = 100; |
|
} |
|
|
|
QwtArrowButton *buttonDown[ButtonCnt]; |
|
QwtArrowButton *buttonUp[ButtonCnt]; |
|
QLineEdit *valueEdit; |
|
|
|
int increment[ButtonCnt]; |
|
int nButtons; |
|
|
|
bool editable; |
|
}; |
|
|
|
/*! |
|
The default number of buttons is set to 2. The default increments are: |
|
\li Button 1: 1 step |
|
\li Button 2: 10 steps |
|
\li Button 3: 100 steps |
|
|
|
\param parent |
|
*/ |
|
QwtCounter::QwtCounter(QWidget *parent): |
|
QWidget(parent) |
|
{ |
|
initCounter(); |
|
} |
|
|
|
#if QT_VERSION < 0x040000 |
|
/*! |
|
The default number of buttons is set to 2. The default increments are: |
|
\li Button 1: 1 step |
|
\li Button 2: 10 steps |
|
\li Button 3: 100 steps |
|
|
|
\param parent |
|
*/ |
|
QwtCounter::QwtCounter(QWidget *parent, const char *name): |
|
QWidget(parent, name) |
|
{ |
|
initCounter(); |
|
} |
|
#endif |
|
|
|
void QwtCounter::initCounter() |
|
{ |
|
d_data = new PrivateData; |
|
|
|
#if QT_VERSION >= 0x040000 |
|
using namespace Qt; |
|
#endif |
|
|
|
QHBoxLayout *layout = new QHBoxLayout(this); |
|
layout->setSpacing(0); |
|
layout->setMargin(0); |
|
|
|
int i; |
|
for(i = ButtonCnt - 1; i >= 0; i--) { |
|
QwtArrowButton *btn = |
|
new QwtArrowButton(i+1, Qt::DownArrow,this); |
|
btn->setFocusPolicy(NoFocus); |
|
btn->installEventFilter(this); |
|
layout->addWidget(btn); |
|
|
|
connect(btn, SIGNAL(released()), SLOT(btnReleased())); |
|
connect(btn, SIGNAL(clicked()), SLOT(btnClicked())); |
|
|
|
d_data->buttonDown[i] = btn; |
|
} |
|
|
|
d_data->valueEdit = new QLineEdit(this); |
|
d_data->valueEdit->setReadOnly(false); |
|
d_data->valueEdit->setValidator(new QDoubleValidator(d_data->valueEdit)); |
|
layout->addWidget(d_data->valueEdit); |
|
|
|
#if QT_VERSION >= 0x040000 |
|
connect( d_data->valueEdit, SIGNAL(editingFinished()), |
|
SLOT(textChanged()) ); |
|
#else |
|
connect( d_data->valueEdit, SIGNAL(returnPressed()), SLOT(textChanged()) ); |
|
connect( d_data->valueEdit, SIGNAL(lostFocus()), SLOT(textChanged()) ); |
|
#endif |
|
|
|
layout->setStretchFactor(d_data->valueEdit, 10); |
|
|
|
for(i = 0; i < ButtonCnt; i++) { |
|
#if QT_VERSION >= 0x040000 |
|
using namespace Qt; |
|
#endif |
|
QwtArrowButton *btn = |
|
new QwtArrowButton(i+1, Qt::UpArrow, this); |
|
btn->setFocusPolicy(NoFocus); |
|
btn->installEventFilter(this); |
|
layout->addWidget(btn); |
|
|
|
connect(btn, SIGNAL(released()), SLOT(btnReleased())); |
|
connect(btn, SIGNAL(clicked()), SLOT(btnClicked())); |
|
|
|
d_data->buttonUp[i] = btn; |
|
} |
|
|
|
setNumButtons(2); |
|
setRange(0.0,1.0,0.001); |
|
setValue(0.0); |
|
|
|
setSizePolicy( |
|
QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); |
|
|
|
setFocusProxy(d_data->valueEdit); |
|
setFocusPolicy(StrongFocus); |
|
} |
|
|
|
//! Destructor |
|
QwtCounter::~QwtCounter() |
|
{ |
|
delete d_data; |
|
} |
|
|
|
/*! |
|
Sets the minimum width for the buttons |
|
*/ |
|
void QwtCounter::polish() |
|
{ |
|
const int w = d_data->valueEdit->fontMetrics().width("W") + 8; |
|
|
|
for ( int i = 0; i < ButtonCnt; i++ ) { |
|
d_data->buttonDown[i]->setMinimumWidth(w); |
|
d_data->buttonUp[i]->setMinimumWidth(w); |
|
} |
|
|
|
#if QT_VERSION < 0x040000 |
|
QWidget::polish(); |
|
#endif |
|
} |
|
|
|
//! Set from lineedit |
|
void QwtCounter::textChanged() |
|
{ |
|
if ( !d_data->editable ) |
|
return; |
|
|
|
bool converted = false; |
|
|
|
const double value = d_data->valueEdit->text().toDouble(&converted); |
|
if ( converted ) |
|
setValue( value ); |
|
} |
|
|
|
/** |
|
\brief Allow/disallow the user to manually edit the value |
|
|
|
\param editable true enables editing |
|
\sa editable() |
|
*/ |
|
void QwtCounter::setEditable(bool editable) |
|
{ |
|
#if QT_VERSION >= 0x040000 |
|
using namespace Qt; |
|
#endif |
|
if ( editable == d_data->editable ) |
|
return; |
|
|
|
d_data->editable = editable; |
|
d_data->valueEdit->setReadOnly(!editable); |
|
} |
|
|
|
//! returns whether the line edit is edatble. (default is yes) |
|
bool QwtCounter::editable() const |
|
{ |
|
return d_data->editable; |
|
} |
|
|
|
/*! |
|
Handle PolishRequest events |
|
*/ |
|
bool QwtCounter::event ( QEvent * e ) |
|
{ |
|
#if QT_VERSION >= 0x040000 |
|
if ( e->type() == QEvent::PolishRequest ) |
|
polish(); |
|
#endif |
|
return QWidget::event(e); |
|
} |
|
|
|
/*! |
|
Handles key events |
|
|
|
- Ctrl + Qt::Key_Home |
|
Step to minValue() |
|
- Ctrl + Qt::Key_End |
|
Step to maxValue() |
|
- Qt::Key_Up |
|
Increment by incSteps(QwtCounter::Button1) |
|
- Qt::Key_Down |
|
Decrement by incSteps(QwtCounter::Button1) |
|
- Qt::Key_PageUp |
|
Increment by incSteps(QwtCounter::Button2) |
|
- Qt::Key_PageDown |
|
Decrement by incSteps(QwtCounter::Button2) |
|
- Shift + Qt::Key_PageUp |
|
Increment by incSteps(QwtCounter::Button3) |
|
- Shift + Qt::Key_PageDown |
|
Decrement by incSteps(QwtCounter::Button3) |
|
*/ |
|
|
|
void QwtCounter::keyPressEvent (QKeyEvent *e) |
|
{ |
|
bool accepted = true; |
|
|
|
switch ( e->key() ) { |
|
case Qt::Key_Home: |
|
#if QT_VERSION >= 0x040000 |
|
if ( e->modifiers() & Qt::ControlModifier ) |
|
#else |
|
if ( e->state() & Qt::ControlButton ) |
|
#endif |
|
setValue(minValue()); |
|
else |
|
accepted = false; |
|
break; |
|
case Qt::Key_End: |
|
#if QT_VERSION >= 0x040000 |
|
if ( e->modifiers() & Qt::ControlModifier ) |
|
#else |
|
if ( e->state() & Qt::ControlButton ) |
|
#endif |
|
setValue(maxValue()); |
|
else |
|
accepted = false; |
|
break; |
|
case Qt::Key_Up: |
|
incValue(d_data->increment[0]); |
|
break; |
|
case Qt::Key_Down: |
|
incValue(-d_data->increment[0]); |
|
break; |
|
case Qt::Key_PageUp: |
|
case Qt::Key_PageDown: { |
|
int increment = d_data->increment[0]; |
|
if ( d_data->nButtons >= 2 ) |
|
increment = d_data->increment[1]; |
|
if ( d_data->nButtons >= 3 ) { |
|
#if QT_VERSION >= 0x040000 |
|
if ( e->modifiers() & Qt::ShiftModifier ) |
|
#else |
|
if ( e->state() & Qt::ShiftButton ) |
|
#endif |
|
increment = d_data->increment[2]; |
|
} |
|
if ( e->key() == Qt::Key_PageDown ) |
|
increment = -increment; |
|
incValue(increment); |
|
break; |
|
} |
|
default: |
|
accepted = false; |
|
} |
|
|
|
if ( accepted ) { |
|
e->accept(); |
|
return; |
|
} |
|
|
|
QWidget::keyPressEvent (e); |
|
} |
|
|
|
void QwtCounter::wheelEvent(QWheelEvent *e) |
|
{ |
|
e->accept(); |
|
|
|
if ( d_data->nButtons <= 0 ) |
|
return; |
|
|
|
int increment = d_data->increment[0]; |
|
if ( d_data->nButtons >= 2 ) { |
|
#if QT_VERSION >= 0x040000 |
|
if ( e->modifiers() & Qt::ControlModifier ) |
|
#else |
|
if ( e->state() & Qt::ControlButton ) |
|
#endif |
|
increment = d_data->increment[1]; |
|
} |
|
if ( d_data->nButtons >= 3 ) { |
|
#if QT_VERSION >= 0x040000 |
|
if ( e->modifiers() & Qt::ShiftModifier ) |
|
#else |
|
if ( e->state() & Qt::ShiftButton ) |
|
#endif |
|
increment = d_data->increment[2]; |
|
} |
|
|
|
for ( int i = 0; i < d_data->nButtons; i++ ) { |
|
if ( d_data->buttonDown[i]->geometry().contains(e->pos()) || |
|
d_data->buttonUp[i]->geometry().contains(e->pos()) ) { |
|
increment = d_data->increment[i]; |
|
} |
|
} |
|
|
|
const int wheel_delta = 120; |
|
|
|
int delta = e->delta(); |
|
if ( delta >= 2 * wheel_delta ) |
|
delta /= 2; // Never saw an abs(delta) < 240 |
|
|
|
incValue(delta / wheel_delta * increment); |
|
} |
|
|
|
/*! |
|
Specify the number of steps by which the value |
|
is incremented or decremented when a specified button |
|
is pushed. |
|
|
|
\param btn One of \c QwtCounter::Button1, \c QwtCounter::Button2, |
|
\c QwtCounter::Button3 |
|
\param nSteps Number of steps |
|
*/ |
|
void QwtCounter::setIncSteps(QwtCounter::Button btn, int nSteps) |
|
{ |
|
if (( btn >= 0) && (btn < ButtonCnt)) |
|
d_data->increment[btn] = nSteps; |
|
} |
|
|
|
/*! |
|
\return the number of steps by which a specified button increments the value |
|
or 0 if the button is invalid. |
|
\param btn One of \c QwtCounter::Button1, \c QwtCounter::Button2, |
|
\c QwtCounter::Button3 |
|
*/ |
|
int QwtCounter::incSteps(QwtCounter::Button btn) const |
|
{ |
|
if (( btn >= 0) && (btn < ButtonCnt)) |
|
return d_data->increment[btn]; |
|
|
|
return 0; |
|
} |
|
|
|
/*! |
|
\brief Set a new value |
|
\param v new value |
|
Calls QwtDoubleRange::setValue and does all visual updates. |
|
\sa QwtDoubleRange::setValue |
|
*/ |
|
|
|
void QwtCounter::setValue(double v) |
|
{ |
|
QwtDoubleRange::setValue(v); |
|
|
|
showNum(value()); |
|
updateButtons(); |
|
} |
|
|
|
/*! |
|
\brief Notify a change of value |
|
*/ |
|
void QwtCounter::valueChange() |
|
{ |
|
if ( isValid() ) |
|
showNum(value()); |
|
else |
|
d_data->valueEdit->setText(QString::null); |
|
|
|
updateButtons(); |
|
|
|
if ( isValid() ) |
|
emit valueChanged(value()); |
|
} |
|
|
|
/*! |
|
\brief Update buttons according to the current value |
|
|
|
When the QwtCounter under- or over-flows, the focus is set to the smallest |
|
up- or down-button and counting is disabled. |
|
|
|
Counting is re-enabled on a button release event (mouse or space bar). |
|
*/ |
|
void QwtCounter::updateButtons() |
|
{ |
|
if ( isValid() ) { |
|
// 1. save enabled state of the smallest down- and up-button |
|
// 2. change enabled state on under- or over-flow |
|
|
|
for ( int i = 0; i < ButtonCnt; i++ ) { |
|
d_data->buttonDown[i]->setEnabled(value() > minValue()); |
|
d_data->buttonUp[i]->setEnabled(value() < maxValue()); |
|
} |
|
} else { |
|
for ( int i = 0; i < ButtonCnt; i++ ) { |
|
d_data->buttonDown[i]->setEnabled(false); |
|
d_data->buttonUp[i]->setEnabled(false); |
|
} |
|
} |
|
} |
|
|
|
/*! |
|
\brief Specify the number of buttons on each side of the label |
|
\param n Number of buttons |
|
*/ |
|
void QwtCounter::setNumButtons(int n) |
|
{ |
|
if ( n<0 || n>ButtonCnt ) |
|
return; |
|
|
|
for ( int i = 0; i < ButtonCnt; i++ ) { |
|
if ( i < n ) { |
|
d_data->buttonDown[i]->show(); |
|
d_data->buttonUp[i]->show(); |
|
} else { |
|
d_data->buttonDown[i]->hide(); |
|
d_data->buttonUp[i]->hide(); |
|
} |
|
} |
|
|
|
d_data->nButtons = n; |
|
} |
|
|
|
/*! |
|
\return The number of buttons on each side of the widget. |
|
*/ |
|
int QwtCounter::numButtons() const |
|
{ |
|
return d_data->nButtons; |
|
} |
|
|
|
//! Display number string |
|
void QwtCounter::showNum(double d) |
|
{ |
|
QString v; |
|
v.setNum(d); |
|
|
|
const int cursorPos = d_data->valueEdit->cursorPosition(); |
|
d_data->valueEdit->setText(v); |
|
d_data->valueEdit->setCursorPosition(cursorPos); |
|
} |
|
|
|
//! Button clicked |
|
void QwtCounter::btnClicked() |
|
{ |
|
for ( int i = 0; i < ButtonCnt; i++ ) { |
|
if ( d_data->buttonUp[i] == sender() ) |
|
incValue(d_data->increment[i]); |
|
|
|
if ( d_data->buttonDown[i] == sender() ) |
|
incValue(-d_data->increment[i]); |
|
} |
|
} |
|
|
|
//! Button released |
|
void QwtCounter::btnReleased() |
|
{ |
|
emit buttonReleased(value()); |
|
} |
|
|
|
/*! |
|
\brief Notify change of range |
|
|
|
This function updates the enabled property of |
|
all buttons contained in QwtCounter. |
|
*/ |
|
void QwtCounter::rangeChange() |
|
{ |
|
updateButtons(); |
|
} |
|
|
|
//! A size hint |
|
QSize QwtCounter::sizeHint() const |
|
{ |
|
QString tmp; |
|
|
|
int w = tmp.setNum(minValue()).length(); |
|
int w1 = tmp.setNum(maxValue()).length(); |
|
if ( w1 > w ) |
|
w = w1; |
|
w1 = tmp.setNum(minValue() + step()).length(); |
|
if ( w1 > w ) |
|
w = w1; |
|
w1 = tmp.setNum(maxValue() - step()).length(); |
|
if ( w1 > w ) |
|
w = w1; |
|
|
|
tmp.fill('9', w); |
|
|
|
QFontMetrics fm(d_data->valueEdit->font()); |
|
w = fm.width(tmp) + 2; |
|
#if QT_VERSION >= 0x040000 |
|
if ( d_data->valueEdit->hasFrame() ) |
|
w += 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth); |
|
#else |
|
w += 2 * d_data->valueEdit->frameWidth(); |
|
#endif |
|
|
|
// Now we replace default sizeHint contribution of d_data->valueEdit by |
|
// what we really need. |
|
|
|
w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width(); |
|
|
|
const int h = qwtMin(QWidget::sizeHint().height(), |
|
d_data->valueEdit->minimumSizeHint().height()); |
|
return QSize(w, h); |
|
} |
|
|
|
//! returns the step size |
|
double QwtCounter::step() const |
|
{ |
|
return QwtDoubleRange::step(); |
|
} |
|
|
|
//! sets the step size |
|
void QwtCounter::setStep(double s) |
|
{ |
|
QwtDoubleRange::setStep(s); |
|
} |
|
|
|
//! returns the minimum value of the range |
|
double QwtCounter::minVal() const |
|
{ |
|
return minValue(); |
|
} |
|
|
|
//! sets the minimum value of the range |
|
void QwtCounter::setMinValue(double m) |
|
{ |
|
setRange(m, maxValue(), step()); |
|
} |
|
|
|
//! returns the maximum value of the range |
|
double QwtCounter::maxVal() const |
|
{ |
|
return QwtDoubleRange::maxValue(); |
|
} |
|
|
|
//! sets the maximum value of the range |
|
void QwtCounter::setMaxValue(double m) |
|
{ |
|
setRange(minValue(), m, step()); |
|
} |
|
|
|
//! set the number of increment steps for button 1 |
|
void QwtCounter::setStepButton1(int nSteps) |
|
{ |
|
setIncSteps(Button1, nSteps); |
|
} |
|
|
|
//! returns the number of increment steps for button 1 |
|
int QwtCounter::stepButton1() const |
|
{ |
|
return incSteps(Button1); |
|
} |
|
|
|
//! set the number of increment steps for button 2 |
|
void QwtCounter::setStepButton2(int nSteps) |
|
{ |
|
setIncSteps(Button2, nSteps); |
|
} |
|
|
|
//! returns the number of increment steps for button 2 |
|
int QwtCounter::stepButton2() const |
|
{ |
|
return incSteps(Button2); |
|
} |
|
|
|
//! set the number of increment steps for button 3 |
|
void QwtCounter::setStepButton3(int nSteps) |
|
{ |
|
setIncSteps(Button3, nSteps); |
|
} |
|
|
|
//! returns the number of increment steps for button 3 |
|
int QwtCounter::stepButton3() const |
|
{ |
|
return incSteps(Button3); |
|
} |
|
|
|
double QwtCounter::value() const |
|
{ |
|
return QwtDoubleRange::value(); |
|
} |
|
|
|
|