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() )
65 QVector
<double> QcMultiSlider::values() const
67 return QVector
<double>::fromList(_values
);
70 void QcMultiSlider::setValues( const QVector
<double> & vec
)
74 Q_FOREACH( double value
, vec
)
75 _values
<< qBound(0.0, rounded(value
), 1.0);
81 double QcMultiSlider::value() const
83 if( _currentIndex
>= 0 && _currentIndex
< _values
.count() )
84 return _values
[_currentIndex
];
89 void QcMultiSlider::setValue( double val
)
91 if( _currentIndex
>= 0 && _currentIndex
< _values
.count() )
92 setValue( _currentIndex
, val
);
97 QVector
<double> QcMultiSlider::reference() const
99 return QVector
<double>::fromList(_ref
);
102 void QcMultiSlider::setReference( const QVector
<double> & vec
)
106 Q_FOREACH( double value
, vec
)
107 _ref
<< qBound( 0.0, value
, 1.0 );
112 void QcMultiSlider::setStep( double step
) {
113 if( roundStep
== step
) return;
115 if( step
== 0.0 ) return;
116 int c
= _values
.count();
118 for( i
=0; i
<c
; ++i
) setValue( i
, _values
[i
] );
122 void QcMultiSlider::setIndex( int i
) {
123 if( i
>= 0 && i
< _values
.count() ) {
130 void QcMultiSlider::setSelectionSize( int i
) {
131 _selectionSize
= qMin(i
, _values
.count() - _currentIndex
);
135 inline void QcMultiSlider::setValue( int index
, double value
)
137 _values
[index
] = qBound( 0.0, rounded(value
), 1.0 );
140 inline double QcMultiSlider::rounded ( double value
)
142 return roundStep
> 0.0 ?
143 qRound( value
/ roundStep
) * roundStep
:
147 QRect
QcMultiSlider::contentsRect()
149 return QtCollider::Style::sunkenContentsRect(rect()).adjusted(2, 2,-2,-2);
152 QRect
QcMultiSlider::valueRect( int count
, qreal
& spacing
)
154 QRect
r( contentsRect() );
156 bool horiz
= ort
== Qt::Horizontal
;
158 spacing
= elastic
? (qreal
) (horiz
? r
.height() : r
.width()) / count
: thumbSize
.width() + gap
;
161 int hnd
= thumbSize
.height();
163 r
.setWidth( r
.width() - hnd
);
164 r
.moveLeft( r
.left() + hnd
* 0.5 );
167 r
.setHeight( r
.height() - hnd
);
168 r
.moveTop( r
.top() + hnd
* 0.5 );
175 void QcMultiSlider::mousePressEvent( QMouseEvent
*e
)
177 using namespace QtCollider::Style
;
179 moveOrigin
= e
->pos();
180 int c
= _values
.count();
184 bool horiz
= ort
== Qt::Horizontal
;
187 QRect
r( valueRect( c
- startIndex
, spacing
) );
193 i
= spacing
> 0.f
? floor((float)(moveOrigin
.y() - r
.y()) / spacing
) : 0;
194 val
= xValue((qreal
)moveOrigin
.x(), r
);
197 i
= spacing
> 0.f
? floor((float)(moveOrigin
.x() - r
.x()) / spacing
) : 0;
198 val
= yValue((qreal
)moveOrigin
.y(), r
);
203 if( i
>= startIndex
&& i
< c
) {
207 if( editable
) setValue( i
, val
);
208 if( editable
|| highlight
) Q_EMIT( modified() );
210 Q_EMIT( interacted() );
214 void QcMultiSlider::mouseMoveEvent( QMouseEvent
*e
)
216 using namespace QtCollider::Style
;
218 if( !e
->buttons() ) return;
220 int c
= _values
.count();
222 QPoint pos
= e
->pos();
231 QRect
r( valueRect( c
- startIndex
, xStep
) );
233 float xOrig
, yOrig
, xDest
, yDest
;
235 int iOrig
, iDest
, iMax
;
237 if( ort
== Qt::Vertical
) {
238 xOffset
= r
.left(); xRange
= r
.width();
239 xOrig
= moveOrigin
.x();
240 yOrig
= yValue(moveOrigin
.y(), r
);
242 yDest
= yValue(pos
.y(), r
);
245 xOffset
= r
.top(); xRange
= r
.height();
246 xOrig
= moveOrigin
.y();
247 yOrig
= xValue(moveOrigin
.x(), r
);
249 yDest
= xValue(pos
.x(), r
);
253 iOrig
= floor((xOrig
- xOffset
) / xStep
); iOrig
+= startIndex
;
254 iDest
= floor((xDest
- xOffset
) / xStep
); iDest
+= startIndex
;
255 iMax
= elastic
? c
: qMin( c
, int( (float)xRange
/ xStep
) + startIndex
+ 1);
259 iOrig
= iDest
= iMax
= startIndex
;
262 if( editable
&& (iOrig
!= iDest
) ) {
263 float k
= (yDest
- yOrig
) / (xDest
- xOrig
);
264 float n
= yOrig
- (xOrig
- xOffset
) * k
;
265 int i
= iOrig
- startIndex
;
267 while( iOrig
< iDest
) {
269 if( iOrig
>= startIndex
&& iOrig
< iMax
) {
270 float y
= (i
* xStep
) * k
+ n
;
271 setValue( iOrig
, y
);
275 while( iOrig
> iDest
) {
276 if( iOrig
>= startIndex
&& iOrig
< iMax
) {
277 float y
= (i
* xStep
) * k
+ n
;
278 setValue( iOrig
, y
);
284 if( iDest
>= startIndex
&& iDest
< iMax
) {
285 if( editable
) setValue( iDest
, yDest
);
287 _currentIndex
= iDest
;
293 Q_EMIT( modified() );
294 Q_EMIT( interacted() );
297 void QcMultiSlider::paintEvent( QPaintEvent
*e
)
299 using namespace QtCollider::Style
;
300 using QtCollider::Style::Ellipse
;
301 using QtCollider::Style::RoundRect
;
305 p
.setRenderHint( QPainter::Antialiasing
, true );
307 RoundRect
frame(rect(), 2);
308 drawSunken( &p
, palette(), frame
, background(), hasFocus() ? focusColor() : QColor() );
310 if( !_values
.count() ) return;
312 p
.setRenderHint( QPainter::Antialiasing
, false );
314 bool horiz
= ort
== Qt::Horizontal
;
316 QRect
bounds( contentsRect() );
318 p
.setClipRect( bounds
);
321 p
.translate( bounds
.topLeft() );
324 bounds
.setSize( QSize( bounds
.height(), bounds
.width() ) );
327 p
.translate( bounds
.left(), bounds
.top() + bounds
.height() );
331 int count
= _values
.count() - startIndex
;
332 qreal spacing
, width
, yscale
;
334 spacing
= elastic
? (qreal
) bounds
.width() / count
: thumbSize
.width() + gap
;
335 width
= elastic
? qMin( spacing
, (qreal
) thumbSize
.width() ) : thumbSize
.width();
336 yscale
= bounds
.height();
337 if( !isFilled
) yscale
-= thumbSize
.height();
339 const QColor
& fillClr
= fillColor();
344 int i
= _currentIndex
- startIndex
;
345 int c
= qMin( count
- i
, _selectionSize
);
348 r
.setHeight( bounds
.height() );
349 r
.setWidth( c
* spacing
);
350 r
.moveLeft( i
* spacing
);
352 QColor hlColor
= fillClr
;
353 hlColor
.setAlpha( 70 );
354 p
.fillRect( r
, hlColor
);
358 p
.setPen( strokeColor() );
363 bool fill
= isFilled
& !drawRects
;
367 p
.setRenderHint( QPainter::Antialiasing
, true );
368 p
.translate( spacing
* 0.5, isFilled
? 0.0 : thumbSize
.height() * 0.5 );
369 p
.scale( 1.0, (qreal
) yscale
);
370 if( fill
) p
.setBrush( fillClr
);
376 path
.moveTo( 0, _values
[startIndex
] );
377 for( int i
= 1; i
< count
; ++i
)
378 path
.lineTo( (qreal
) i
* spacing
, _values
[i
+ startIndex
] );
382 int refcount
= _ref
.count() - startIndex
;
383 if( refcount
> 0 || fill
) {
388 y
= i
< refcount
? _ref
[i
+ startIndex
] : 0.f
;
389 if( fill
) path
.lineTo(x
, y
);
390 else path
.moveTo(x
, y
);
394 y
= i
< refcount
? _ref
[i
+ startIndex
] : 0.f
;
398 if( fill
) path
.closeSubpath();
409 p
.setRenderHint( QPainter::Antialiasing
, false );
410 p
.translate( (spacing
- width
) * 0.5, 0 );
411 p
.setBrush( fillClr
);
417 int refcount
= _ref
.count() - startIndex
;
418 for( int i
= 0; i
< count
; ++i
) {
419 int ref
= (i
< refcount
? _ref
[i
+ startIndex
] : 0.f
) * yscale
;
420 int val
= _values
[i
+ startIndex
] * yscale
;
421 r
.moveLeft( i
* spacing
);
423 r
.setHeight( val
- ref
);
424 if(horiz
) p
.drawRect(r
.normalized().adjusted(0,0,-1,-1));
425 else p
.drawRect(r
.normalized().adjusted(0,1,-1,0));
429 r
.setHeight( thumbSize
.height() );
430 for( int i
= 0; i
< count
; ++i
) {
431 r
.moveLeft( i
* spacing
);
432 r
.moveTop( _values
[i
+ startIndex
] * yscale
);
433 if(horiz
) p
.drawRect(r
.adjusted(0,0,-1,-1));
434 else p
.drawRect(r
.adjusted(0,1,-1,0));
440 void QcMultiSlider::doAction()
442 Qt::KeyboardModifier ctrlMod
=
449 if( QApplication::keyboardModifiers() & ctrlMod
)
450 Q_EMIT( metaAction() );