1 /************************************************************************
3 * Copyright 2010 Jakob Leben (jakob.leben@gmail.com)
5 * This file is part of SuperCollider Qt GUI.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ************************************************************************/
22 #include "QcNumberBox.h"
23 #include "../Common.h"
24 #include "../QcWidgetFactory.h"
27 #include <QMouseEvent>
28 #include <QApplication>
33 static QcWidgetFactory
<QcNumberBox
> factory
;
35 QcNumberBox::QcNumberBox()
38 editedTextColor( QColor( "red" ) ),
39 normalTextColor( palette().color(QPalette::Text
) ),
40 _validator( new QDoubleValidator( this ) ),
49 _validator
->setDecimals( _maxDec
);
50 setValidator( _validator
);
52 // Do not display thousands separator. It only eats up precious space.
53 QLocale
loc( locale() );
54 loc
.setNumberOptions( QLocale::OmitGroupSeparator
);
59 connect( this, SIGNAL( editingFinished() ),
60 this, SLOT( onEditingFinished() ) );
61 connect( this, SIGNAL( valueChanged() ),
62 this, SLOT( updateText() ), Qt::QueuedConnection
);
66 void QcNumberBox::setLocked( bool locked
)
78 void QcNumberBox::setTextColor( const QColor
& c
) {
85 void QcNumberBox::setEditedTextColor( const QColor
& c
) {
92 void QcNumberBox::setValue( double val
)
94 if( val
> _validator
->top() ) val
= _validator
->top();
95 if ( val
< _validator
->bottom() ) val
= _validator
->bottom();
97 val
= roundedVal( val
);
102 Q_EMIT( valueChanged() );
105 void QcNumberBox::setInfinite( bool positive
)
107 _valueType
= positive
? Infinite
: InfiniteNegative
;
108 Q_EMIT( valueChanged() );
111 void QcNumberBox::setNaN()
114 Q_EMIT( valueChanged() );
117 void QcNumberBox::setTextValue( const QString
&str
)
123 double QcNumberBox::value () const
128 void QcNumberBox::setMinimum( double min
)
130 _validator
->setBottom(min
);
131 if( _valueType
== Number
)
132 setValue( _value
); // clip current value
135 void QcNumberBox::setMaximum( double max
)
137 _validator
->setTop(max
);
138 if( _valueType
== Number
)
139 setValue( _value
); // clip current value
142 void QcNumberBox::setDecimals( int d
)
145 _minDec
= _maxDec
= d
;
146 _validator
->setDecimals( d
);
147 if( _valueType
== Number
)
148 setValue( _value
); // round current value
151 void QcNumberBox::setMinDecimals( int d
)
155 if( _minDec
> _maxDec
) {
157 _validator
->setDecimals( d
);
159 if( _valueType
== Number
)
160 setValue( _value
); // round current value
163 void QcNumberBox::setMaxDecimals( int d
)
167 if( _maxDec
< _minDec
) _minDec
= d
;
168 _validator
->setDecimals( d
);
169 if( _valueType
== Number
)
170 setValue( _value
); // round current value
173 void QcNumberBox::increment( double factor
)
175 if( !isReadOnly() || _valueType
!= Number
) return;
176 setValue( value() + (step
* factor
) );
180 void QcNumberBox::decrement( double factor
)
182 if( !isReadOnly() || _valueType
!= Number
) return;
183 setValue( value() - (step
* factor
) );
187 void QcNumberBox::onEditingFinished()
189 if( isReadOnly() ) return;
190 setValue( locale().toDouble( text() ) );
194 void QcNumberBox::updateText()
198 switch( _valueType
) {
200 str
= stringForVal( _value
);
203 return; // text was already set
206 case InfiniteNegative
:
214 // Set cursor to beginning so most significant digits are shown
215 // if widget size too small.
216 setCursorPosition(0);
221 void QcNumberBox::stepBy( int steps
, float stepSize
)
223 if( _valueType
!= Number
) return;
224 modifyStep( &stepSize
);
225 setValue( value() + (steps
* stepSize
) );
228 double QcNumberBox::roundedVal( double val
)
230 double k
= pow( 10, _maxDec
);
231 return round( val
* k
) / k
;
234 QString
QcNumberBox::stringForVal( double val
)
236 QLocale loc
= locale();
237 QString str
= loc
.toString( val
, 'f', _maxDec
);
238 int i
= str
.indexOf( loc
.decimalPoint() );
240 QString dec
= str
.mid(i
+1);
241 while( dec
.size() > _minDec
&& dec
.endsWith('0') ) dec
.chop(1);
245 str
= str
.left(i
+1) + dec
;
250 void QcNumberBox::updateTextColor()
252 QPalette
p( palette() );
253 p
.setColor( QPalette::Text
, isReadOnly() ? normalTextColor
: editedTextColor
);
257 void QcNumberBox::keyPressEvent ( QKeyEvent
* event
)
259 if( !isReadOnly() ) return QLineEdit::keyPressEvent( event
);
261 int key
= event
->key();
263 if( key
== Qt::Key_Up
){
268 else if( key
== Qt::Key_Down
) {
274 // unlock typing if valid char is entered
275 QString t
= event
->text();
278 ( _validator
->validate( t
, i
) != QValidator::Invalid
) )
282 blockSignals( false );
287 QLineEdit::keyPressEvent( event
);
290 void QcNumberBox::mouseDoubleClickEvent ( QMouseEvent
* event
)
293 setCursorPosition( cursorPositionAt( event
->pos() ) );
297 void QcNumberBox::mousePressEvent ( QMouseEvent
* event
)
299 lastPos
= event
->globalY();
300 // If locked, prevent cursor position change. Cursor has to stay at 0
301 // so most significant digits are shown if widget size too small.
302 if( isReadOnly() ) return;
303 QLineEdit::mousePressEvent( event
);
306 void QcNumberBox::mouseMoveEvent ( QMouseEvent
* event
)
308 if( scroll
&& isReadOnly() && _valueType
== Number
309 && ( event
->buttons() & Qt::LeftButton
) )
311 int steps
= (event
->globalY() - lastPos
) / dragDist
;
313 lastPos
= lastPos
+ (steps
* dragDist
);
314 stepBy( -steps
, scrollStep
);
319 QLineEdit::mouseMoveEvent( event
);
322 void QcNumberBox::wheelEvent ( QWheelEvent
* event
)
324 if( scroll
&& isReadOnly() && _valueType
== Number
325 && event
->orientation() == Qt::Vertical
)
327 stepBy( event
->delta() > 0 ? 1 : -1, scrollStep
);
333 NumberBoxWidget::NumberBoxWidget()
334 : modifier( 0 ), scrollStep( 1 )
336 ScrollLineEdit
*scrollLineEdit
= new ScrollLineEdit();
337 scrollLineEdit
->setScroll( true );
338 setLineEdit( scrollLineEdit
);
340 connect( scrollLineEdit
, SIGNAL( scrolled(int) ),
341 this, SLOT( scrollBy(int) ) );
342 connect( this, SIGNAL( editingFinished() ),
343 this, SLOT( onEditingFinished() ) );
346 void NumberBoxWidget::setScroll( bool b
)
348 ScrollLineEdit
*edit
= qobject_cast
<ScrollLineEdit
*>( lineEdit() );
349 edit
->setScroll( b
);
352 void NumberBoxWidget::stepBy( int steps
)
354 stepBy( steps
, singleStep() );
357 void NumberBoxWidget::scrollBy( int steps
)
359 stepBy( steps
, scrollStep
);
362 void NumberBoxWidget::onEditingFinished()
364 ScrollLineEdit
*edit
= qobject_cast
<ScrollLineEdit
*>( lineEdit() );
365 edit
->setLocked( true );
368 void NumberBoxWidget::stepBy( int steps
, float stepSize
)
370 modifier
->modifyStep( &stepSize
);
372 double val
= qMin( maximum(), value() + (steps
* stepSize
) );
373 val
= qMax( minimum(), val
);
377 void NumberBoxWidget::keyPressEvent ( QKeyEvent
* event
)
379 if( event
->key() == Qt::Key_Enter
|| event
->key() == Qt::Key_Return
)
382 Q_EMIT( editingFinished() );
385 QDoubleSpinBox::keyPressEvent( event
);