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 QPalette pal
= palette();
309 RoundRect
frame(rect(), 2);
310 drawSunken( &p
, pal
, frame
, pal
.color(QPalette::Base
), hasFocus() ? focusColor() : QColor() );
312 if( !_values
.count() ) return;
314 p
.setRenderHint( QPainter::Antialiasing
, false );
316 bool horiz
= ort
== Qt::Horizontal
;
319 _fillColor
.isValid() ? _fillColor
: pal
.color( QPalette::Text
);
321 _strokeColor
.isValid() ? _strokeColor
: pal
.color( QPalette::Text
);
323 QRect
bounds( contentsRect() );
325 p
.setClipRect( bounds
);
328 p
.translate( bounds
.topLeft() );
331 bounds
.setSize( QSize( bounds
.height(), bounds
.width() ) );
334 p
.translate( bounds
.left(), bounds
.top() + bounds
.height() );
338 int count
= _values
.count() - startIndex
;
339 double spacing
, width
, yscale
;
341 spacing
= elastic
? (double) bounds
.width() / count
: thumbSize
.width() + gap
;
342 width
= elastic
? qMin( spacing
, (double) thumbSize
.width() ) : thumbSize
.width();
343 yscale
= bounds
.height();
344 if( !isFilled
) yscale
-= thumbSize
.height();
349 int i
= _currentIndex
- startIndex
;
350 int c
= qMin( count
- i
, _selectionSize
);
353 r
.setHeight( bounds
.height() );
354 r
.setWidth( c
* spacing
);
355 r
.moveLeft( i
* spacing
);
357 QColor hlColor
= fillColor
;
358 hlColor
.setAlpha( 70 );
359 p
.fillRect( r
, hlColor
);
363 p
.setPen( strokeColor
);
368 bool fill
= isFilled
& !drawRects
;
372 p
.setRenderHint( QPainter::Antialiasing
, true );
373 p
.translate( spacing
* 0.5, isFilled
? 0.0 : thumbSize
.height() * 0.5 );
374 p
.scale( 1.0, (qreal
) yscale
);
375 if( fill
) p
.setBrush( fillColor
);
381 path
.moveTo( 0, _values
[startIndex
] );
382 for( int i
= 1; i
< count
; ++i
)
383 path
.lineTo( (qreal
) i
* spacing
, _values
[i
+ startIndex
] );
387 int refcount
= _ref
.count() - startIndex
;
388 if( refcount
> 0 || fill
) {
393 y
= i
< refcount
? _ref
[i
+ startIndex
] : 0.f
;
394 if( fill
) path
.lineTo(x
, y
);
395 else path
.moveTo(x
, y
);
399 y
= i
< refcount
? _ref
[i
+ startIndex
] : 0.f
;
403 if( fill
) path
.closeSubpath();
414 p
.setRenderHint( QPainter::Antialiasing
, false );
415 p
.translate( (spacing
- width
) * 0.5, 0 );
416 p
.setBrush( fillColor
);
422 int refcount
= _ref
.count() - startIndex
;
423 for( int i
= 0; i
< count
; ++i
) {
424 int ref
= (i
< refcount
? _ref
[i
+ startIndex
] : 0.f
) * yscale
;
425 int val
= _values
[i
+ startIndex
] * yscale
;
426 r
.moveLeft( i
* spacing
);
428 r
.setHeight( val
- ref
);
429 if(horiz
) p
.drawRect(r
.normalized().adjusted(0,0,-1,-1));
430 else p
.drawRect(r
.normalized().adjusted(0,1,-1,0));
434 r
.setHeight( thumbSize
.height() );
435 for( int i
= 0; i
< count
; ++i
) {
436 r
.moveLeft( i
* spacing
);
437 r
.moveTop( _values
[i
+ startIndex
] * yscale
);
438 if(horiz
) p
.drawRect(r
.adjusted(0,0,-1,-1));
439 else p
.drawRect(r
.adjusted(0,1,-1,0));
445 void QcMultiSlider::doAction()
447 Qt::KeyboardModifier ctrlMod
=
454 if( QApplication::keyboardModifiers() & ctrlMod
)
455 Q_EMIT( metaAction() );