"Post Window" -> "Post window" prevents it being seen as two separate
[supercollider.git] / QtCollider / widgets / QcNumberBox.cpp
blob6b250fb7691a97d73ceb05d98b56e45a0bd9bed3
1 /************************************************************************
3 * Copyright 2010-2012 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"
26 #include <QKeyEvent>
27 #include <QMouseEvent>
28 #include <QApplication>
30 #include <math.h>
31 #include <qmath.h>
33 QC_DECLARE_QWIDGET_FACTORY(QcNumberBox);
35 QcNumberBox::QcNumberBox()
36 : scroll( true ),
37 lastPos( 0 ),
38 editedTextColor( QColor( "red" ) ),
39 normalTextColor( palette().color(QPalette::Text) ),
40 _validator( new QDoubleValidator( this ) ),
41 step( 0.1f ),
42 scrollStep( 1.0f ),
43 dragDist( 10.f ),
44 _value( 0. ),
45 _valueType( Number ),
46 _minDec(0),
47 _maxDec(2)
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 );
55 setLocale( loc );
57 setLocked( true );
59 connect( this, SIGNAL( editingFinished() ),
60 this, SLOT( onEditingFinished() ) );
61 connect( this, SIGNAL( valueChanged() ),
62 this, SLOT( updateText() ), Qt::QueuedConnection );
63 setValue( 0 );
66 void QcNumberBox::setLocked( bool locked )
68 if( locked ) {
69 setReadOnly( true );
70 setSelection( 0, 0 );
72 else {
73 setReadOnly( false );
75 updateTextColor();
78 void QcNumberBox::setTextColor( const QColor& c ) {
79 if( c.isValid() ) {
80 normalTextColor = c;
81 updateTextColor();
85 void QcNumberBox::setEditedTextColor( const QColor& c ) {
86 if( c.isValid() ) {
87 editedTextColor = c;
88 updateTextColor();
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 );
99 _value = val;
100 _valueType = Number;
102 Q_EMIT( valueChanged() );
105 void QcNumberBox::setInfinite( bool positive )
107 _valueType = positive ? Infinite : InfiniteNegative;
108 Q_EMIT( valueChanged() );
111 void QcNumberBox::setNaN()
113 _valueType = NaN;
114 Q_EMIT( valueChanged() );
117 void QcNumberBox::setTextValue( const QString &str )
119 _valueType = Text;
120 setText( str );
123 double QcNumberBox::value () const
125 return _value;
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 )
144 if( d < 0 ) return;
145 _minDec = _maxDec = d;
146 _validator->setDecimals( d );
147 if( _valueType == Number )
148 setValue( _value ); // round current value
151 void QcNumberBox::setMinDecimals( int d )
153 if( d < 0 ) return;
154 _minDec = d;
155 if( _minDec > _maxDec ) {
156 _maxDec = d;
157 _validator->setDecimals( d );
159 if( _valueType == Number )
160 setValue( _value ); // round current value
163 void QcNumberBox::setMaxDecimals( int d )
165 if( d < 0 ) return;
166 _maxDec = 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) );
177 Q_EMIT( action() );
180 void QcNumberBox::decrement( double factor )
182 if( !isReadOnly() || _valueType != Number ) return;
183 setValue( value() - (step * factor) );
184 Q_EMIT( action() );
187 void QcNumberBox::onEditingFinished()
189 if( isReadOnly() ) return;
190 setValue( locale().toDouble( text() ) );
191 Q_EMIT( action() );
194 void QcNumberBox::updateText()
196 QString str;
198 switch( _valueType ) {
199 case Number:
200 str = stringForVal( _value );
201 break;
202 case Text:
203 return; // text was already set
204 case Infinite:
205 str = "+inf"; break;
206 case InfiniteNegative:
207 str = "-inf"; break;
208 case NaN:
209 str = "NaN"; break;
212 blockSignals(true);
213 setText( str );
214 // Set cursor to beginning so most significant digits are shown
215 // if widget size too small.
216 setCursorPosition(0);
217 setLocked( true );
218 blockSignals(false);
221 void QcNumberBox::stepBy( int steps, double 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() );
239 if( i > -1 ) {
240 QString dec = str.mid(i+1);
241 while( dec.size() > _minDec && dec.endsWith('0') ) dec.chop(1);
242 if( dec.isEmpty() )
243 str = str.left(i);
244 else
245 str = str.left(i+1) + dec;
247 return str;
250 void QcNumberBox::updateTextColor()
252 QPalette p( palette() );
253 p.setColor( QPalette::Text, isReadOnly() ? normalTextColor : editedTextColor );
254 setPalette( p );
257 void QcNumberBox::keyPressEvent ( QKeyEvent * event )
259 if( !isReadOnly() ) return QLineEdit::keyPressEvent( event );
261 int key = event->key();
263 if( key == Qt::Key_Up ){
264 stepBy( 1, step );
265 Q_EMIT( action() );
266 return;
268 else if( key == Qt::Key_Down ) {
269 stepBy( -1, step );
270 Q_EMIT( action() );
271 return;
273 else {
274 // unlock typing if valid char is entered
275 QString t = event->text();
276 int i = 0;
277 if( !t.isEmpty() &&
278 ( _validator->validate( t, i ) != QValidator::Invalid ) )
280 blockSignals(true);
281 clear();
282 blockSignals( false );
283 setLocked( false );
287 QLineEdit::keyPressEvent( event );
290 void QcNumberBox::mouseDoubleClickEvent ( QMouseEvent * event )
292 Q_UNUSED( event );
293 setCursorPosition( cursorPositionAt( event->pos() ) );
294 setLocked( false );
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;
312 if( steps != 0 ) {
313 lastPos = lastPos + (steps * dragDist);
314 stepBy( -steps, scrollStep );
315 Q_EMIT( action() );
318 else
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 );
328 Q_EMIT( action() );
332 #if 0
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 );
374 setValue( val );
377 void NumberBoxWidget::keyPressEvent ( QKeyEvent * event )
379 if( event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return )
381 interpretText();
382 Q_EMIT( editingFinished() );
384 else
385 QDoubleSpinBox::keyPressEvent( event );
387 #endif