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 "QcMultiSlider.h"
23 #include "../QcWidgetFactory.h"
24 #include "../style/routines.hpp"
26 #include <QApplication>
27 #include <QMouseEvent>
32 QC_DECLARE_QWIDGET_FACTORY(QcMultiSlider
);
34 QcMultiSlider::QcMultiSlider() :
35 QtCollider::Style::Client(this),
42 thumbSize( QSizeF( 12.f
, 12.f
) ),
50 setFocusPolicy( Qt::StrongFocus
);
51 setSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Expanding
);
52 connect( this, SIGNAL(modified()), this, SLOT(update()) );
53 connect( this, SIGNAL(interacted()), this, SLOT(doAction()) );
56 void QcMultiSlider::setSliderCount( int newSize
)
58 while( newSize
> _values
.size() )
59 _values
.append( 0.f
);
60 while( newSize
< _values
.size() )
66 VariantList
QcMultiSlider::values() const
69 Q_FOREACH( float val
, _values
)
70 list
.data
<< QVariant( val
);
74 void QcMultiSlider::setValues( const VariantList
& newValues
)
77 Q_FOREACH( QVariant var
, newValues
.data
) {
78 // FIXME Seems there is a crash in case _values are out of range and
80 float value
= var
.value
<float>();
82 value
= round( value
/ roundStep
) * roundStep
;
83 _values
.append( qMax( 0.f
, qMin( 1.f
, value
) ) );
88 void QcMultiSlider::setReference( const VariantList
&reference
)
91 Q_FOREACH( QVariant var
, reference
.data
) {
92 _ref
.append( qMax( 0.f
, qMin( 1.f
, var
.value
<float>() ) ) );
97 float QcMultiSlider::value() const
99 if( _currentIndex
>= 0 && _currentIndex
< _values
.count() )
100 return _values
[_currentIndex
];
105 void QcMultiSlider::setValue( float f
)
107 if( _currentIndex
>= 0 && _currentIndex
< _values
.count() )
108 setValue( _currentIndex
, f
);
113 void QcMultiSlider::setStepSize( float f
) {
114 if( roundStep
== f
) return;
116 if( f
== 0.f
) return;
117 int c
= _values
.count();
119 for( i
=0; i
<c
; ++i
) setValue( i
, _values
[i
] );
123 void QcMultiSlider::setIndex( int i
) {
124 if( i
>= 0 && i
< _values
.count() ) {
131 void QcMultiSlider::setSelectionSize( int i
) {
132 _selectionSize
= qMin(i
, _values
.count() - _currentIndex
);
136 inline void QcMultiSlider::setValue( int index
, float value
)
138 if( roundStep
> 0.f
)
139 value
= round( value
/ roundStep
) * roundStep
;
140 _values
.replace( index
, qMax( 0.f
, qMin( 1.f
, value
) ) );
143 QRect
QcMultiSlider::contentsRect()
145 return QtCollider::Style::sunkenContentsRect(rect()).adjusted(2, 2,-2,-2);
148 QRect
QcMultiSlider::valueRect( int count
, qreal
& spacing
)
150 QRect
r( contentsRect() );
152 bool horiz
= ort
== Qt::Horizontal
;
154 spacing
= elastic
? (qreal
) (horiz
? r
.height() : r
.width()) / count
: thumbSize
.width() + gap
;
157 int hnd
= thumbSize
.height();
159 r
.setWidth( r
.width() - hnd
);
160 r
.moveLeft( r
.left() + hnd
* 0.5 );
163 r
.setHeight( r
.height() - hnd
);
164 r
.moveTop( r
.top() + hnd
* 0.5 );
171 void QcMultiSlider::mousePressEvent( QMouseEvent
*e
)
173 using namespace QtCollider::Style
;
175 moveOrigin
= e
->pos();
176 int c
= _values
.count();
180 bool horiz
= ort
== Qt::Horizontal
;
183 QRect
r( valueRect( c
- startIndex
, spacing
) );
189 i
= spacing
> 0.f
? floor((float)(moveOrigin
.y() - r
.y()) / spacing
) : 0;
190 val
= xValue((qreal
)moveOrigin
.x(), r
);
193 i
= spacing
> 0.f
? floor((float)(moveOrigin
.x() - r
.x()) / spacing
) : 0;
194 val
= yValue((qreal
)moveOrigin
.y(), r
);
199 if( i
>= startIndex
&& i
< c
) {
203 if( editable
) setValue( i
, val
);
204 if( editable
|| highlight
) Q_EMIT( modified() );
206 Q_EMIT( interacted() );
210 void QcMultiSlider::mouseMoveEvent( QMouseEvent
*e
)
212 using namespace QtCollider::Style
;
214 if( !e
->buttons() ) return;
216 int c
= _values
.count();
218 QPoint pos
= e
->pos();
227 QRect
r( valueRect( c
- startIndex
, xStep
) );
229 float xOrig
, yOrig
, xDest
, yDest
;
231 int iOrig
, iDest
, iMax
;
233 if( ort
== Qt::Vertical
) {
234 xOffset
= r
.left(); xRange
= r
.width();
235 xOrig
= moveOrigin
.x();
236 yOrig
= yValue(moveOrigin
.y(), r
);
238 yDest
= yValue(pos
.y(), r
);
241 xOffset
= r
.top(); xRange
= r
.height();
242 xOrig
= moveOrigin
.y();
243 yOrig
= xValue(moveOrigin
.x(), r
);
245 yDest
= xValue(pos
.x(), r
);
249 iOrig
= floor((xOrig
- xOffset
) / xStep
); iOrig
+= startIndex
;
250 iDest
= floor((xDest
- xOffset
) / xStep
); iDest
+= startIndex
;
251 iMax
= elastic
? c
: qMin( c
, int( (float)xRange
/ xStep
) + startIndex
+ 1);
255 iOrig
= iDest
= iMax
= startIndex
;
258 if( editable
&& (iOrig
!= iDest
) ) {
259 float k
= (yDest
- yOrig
) / (xDest
- xOrig
);
260 float n
= yOrig
- (xOrig
- xOffset
) * k
;
261 int i
= iOrig
- startIndex
;
263 while( iOrig
< iDest
) {
265 if( iOrig
>= startIndex
&& iOrig
< iMax
) {
266 float y
= (i
* xStep
) * k
+ n
;
267 setValue( iOrig
, y
);
271 while( iOrig
> iDest
) {
272 if( iOrig
>= startIndex
&& iOrig
< iMax
) {
273 float y
= (i
* xStep
) * k
+ n
;
274 setValue( iOrig
, y
);
280 if( iDest
>= startIndex
&& iDest
< iMax
) {
281 if( editable
) setValue( iDest
, yDest
);
283 _currentIndex
= iDest
;
289 Q_EMIT( modified() );
290 Q_EMIT( interacted() );
293 void QcMultiSlider::paintEvent( QPaintEvent
*e
)
295 using namespace QtCollider::Style
;
299 p
.setRenderHint( QPainter::Antialiasing
, true );
301 QPalette pal
= palette();
303 RoundRect
frame(rect(), 2);
304 drawSunken( &p
, pal
, frame
, pal
.color(QPalette::Base
), hasFocus() ? focusColor() : QColor() );
306 if( !_values
.count() ) return;
308 p
.setRenderHint( QPainter::Antialiasing
, false );
310 bool horiz
= ort
== Qt::Horizontal
;
313 _fillColor
.isValid() ? _fillColor
: pal
.color( QPalette::Text
);
315 _strokeColor
.isValid() ? _strokeColor
: pal
.color( QPalette::Text
);
317 QRect
bounds( contentsRect() );
319 p
.setClipRect( bounds
);
322 p
.translate( bounds
.topLeft() );
325 bounds
.setSize( QSize( bounds
.height(), bounds
.width() ) );
328 p
.translate( bounds
.left(), bounds
.top() + bounds
.height() );
332 int count
= _values
.count() - startIndex
;
333 double spacing
, width
, yscale
;
335 spacing
= elastic
? (double) bounds
.width() / count
: thumbSize
.width() + gap
;
336 width
= elastic
? qMin( spacing
, (double) thumbSize
.width() ) : thumbSize
.width();
337 yscale
= bounds
.height();
338 if( !isFilled
) yscale
-= thumbSize
.height();
343 int i
= _currentIndex
- startIndex
;
344 int c
= qMin( count
- i
, _selectionSize
);
347 r
.setHeight( bounds
.height() );
348 r
.setWidth( c
* spacing
);
349 r
.moveLeft( i
* spacing
);
351 QColor hlColor
= fillColor
;
352 hlColor
.setAlpha( 70 );
353 p
.fillRect( r
, hlColor
);
357 p
.setPen( strokeColor
);
362 bool fill
= isFilled
& !drawRects
;
366 p
.setRenderHint( QPainter::Antialiasing
, true );
367 p
.translate( spacing
* 0.5, isFilled
? 0.0 : thumbSize
.height() * 0.5 );
368 p
.scale( 1.0, (qreal
) yscale
);
369 if( fill
) p
.setBrush( fillColor
);
375 path
.moveTo( 0, _values
[startIndex
] );
376 for( int i
= 1; i
< count
; ++i
)
377 path
.lineTo( (qreal
) i
* spacing
, _values
[i
+ startIndex
] );
381 int refcount
= _ref
.count() - startIndex
;
382 if( refcount
> 0 || fill
) {
387 y
= i
< refcount
? _ref
[i
+ startIndex
] : 0.f
;
388 if( fill
) path
.lineTo(x
, y
);
389 else path
.moveTo(x
, y
);
393 y
= i
< refcount
? _ref
[i
+ startIndex
] : 0.f
;
397 if( fill
) path
.closeSubpath();
408 p
.setRenderHint( QPainter::Antialiasing
, false );
409 p
.translate( (spacing
- width
) * 0.5, 0 );
410 p
.setBrush( fillColor
);
416 int refcount
= _ref
.count() - startIndex
;
417 for( int i
= 0; i
< count
; ++i
) {
418 int ref
= (i
< refcount
? _ref
[i
+ startIndex
] : 0.f
) * yscale
;
419 int val
= _values
[i
+ startIndex
] * yscale
;
420 r
.moveLeft( i
* spacing
);
422 r
.setHeight( val
- ref
);
423 if(horiz
) p
.drawRect(r
.normalized().adjusted(0,0,-1,-1));
424 else p
.drawRect(r
.normalized().adjusted(0,1,-1,0));
428 r
.setHeight( thumbSize
.height() );
429 for( int i
= 0; i
< count
; ++i
) {
430 r
.moveLeft( i
* spacing
);
431 r
.moveTop( _values
[i
+ startIndex
] * yscale
);
432 if(horiz
) p
.drawRect(r
.adjusted(0,0,-1,-1));
433 else p
.drawRect(r
.adjusted(0,1,-1,0));
439 void QcMultiSlider::doAction()
441 Qt::KeyboardModifier ctrlMod
=
448 if( QApplication::keyboardModifiers() & ctrlMod
)
449 Q_EMIT( metaAction() );