class library: Volume - remove debug message
[supercollider.git] / QtCollider / widgets / QcMultiSlider.cpp
blobbce1348800bb0c6aa053f9477d3da8210e486d3a
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>
28 #include <QPainter>
30 #include <cmath>
32 QC_DECLARE_QWIDGET_FACTORY(QcMultiSlider);
34 QcMultiSlider::QcMultiSlider() :
35 QtCollider::Style::Client(this),
36 _currentIndex(0),
37 _selectionSize(1),
38 roundStep( 0.f ),
39 editable( true ),
40 ort( Qt::Vertical),
41 elastic( false ),
42 thumbSize( QSizeF( 12.f, 12.f ) ),
43 gap( 1 ),
44 drawRects( true ),
45 drawLines( false ),
46 isFilled( false ),
47 highlight( false ),
48 startIndex( 0 )
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() )
61 _values.removeLast();
62 update();
65 QVector<double> QcMultiSlider::values() const
67 return QVector<double>::fromList(_values);
70 void QcMultiSlider::setValues( const QVector<double> & vec )
72 _values.clear();
74 Q_FOREACH( double value, vec )
75 _values << qBound(0.0, rounded(value), 1.0);
77 update();
81 double QcMultiSlider::value() const
83 if( _currentIndex >= 0 && _currentIndex < _values.count() )
84 return _values[_currentIndex];
85 else
86 return 0.0;
89 void QcMultiSlider::setValue( double val )
91 if( _currentIndex >= 0 && _currentIndex < _values.count() )
92 setValue( _currentIndex, val );
94 update();
97 QVector<double> QcMultiSlider::reference() const
99 return QVector<double>::fromList(_ref);
102 void QcMultiSlider::setReference( const QVector<double> & vec )
104 _ref.clear();
106 Q_FOREACH( double value, vec )
107 _ref << qBound( 0.0, value, 1.0 );
109 update();
112 void QcMultiSlider::setStep( double step ) {
113 if( roundStep == step ) return;
114 roundStep = step;
115 if( step == 0.0 ) return;
116 int c = _values.count();
117 int i;
118 for( i=0; i<c; ++i ) setValue( i, _values[i] );
119 update();
122 void QcMultiSlider::setIndex( int i ) {
123 if( i >= 0 && i < _values.count() ) {
124 _currentIndex = i;
125 _selectionSize = 1;
126 update();
130 void QcMultiSlider::setSelectionSize( int i ) {
131 _selectionSize = qMin(i, _values.count() - _currentIndex);
132 update();
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 :
144 value;
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;
160 if( !isFilled ) {
161 int hnd = thumbSize.height();
162 if( horiz ) {
163 r.setWidth( r.width() - hnd );
164 r.moveLeft( r.left() + hnd * 0.5 );
166 else {
167 r.setHeight( r.height() - hnd );
168 r.moveTop( r.top() + hnd * 0.5 );
172 return r;
175 void QcMultiSlider::mousePressEvent( QMouseEvent *e )
177 using namespace QtCollider::Style;
179 moveOrigin = e->pos();
180 int c = _values.count();
182 if( !c ) return;
184 bool horiz = ort == Qt::Horizontal;
185 double spacing;
187 QRect r( valueRect( c - startIndex, spacing ) );
189 int i;
190 float val;
192 if( horiz ) {
193 i = spacing > 0.f ? floor((float)(moveOrigin.y() - r.y()) / spacing) : 0;
194 val = xValue((qreal)moveOrigin.x(), r);
196 else {
197 i = spacing > 0.f ? floor((float)(moveOrigin.x() - r.x()) / spacing) : 0;
198 val = yValue((qreal)moveOrigin.y(), r);
201 i += startIndex;
203 if( i >= startIndex && i < c ) {
204 _currentIndex = i;
205 _selectionSize = 1;
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();
224 if( !c ) {
225 moveOrigin = pos;
226 return;
229 qreal xStep;
231 QRect r( valueRect( c - startIndex, xStep ) );
233 float xOrig, yOrig, xDest, yDest;
234 int xOffset, xRange;
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);
241 xDest = pos.x();
242 yDest = yValue(pos.y(), r);
244 else {
245 xOffset = r.top(); xRange = r.height();
246 xOrig = moveOrigin.y();
247 yOrig = xValue(moveOrigin.x(), r);
248 xDest = pos.y();
249 yDest = xValue(pos.x(), r);
252 if( xStep > 0.0 ) {
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);
257 else
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 ) {
268 ++i;
269 if( iOrig >= startIndex && iOrig < iMax ) {
270 float y = (i * xStep) * k + n;
271 setValue( iOrig, y );
273 ++iOrig;
275 while( iOrig > iDest ) {
276 if( iOrig >= startIndex && iOrig < iMax ) {
277 float y = (i * xStep) * k + n;
278 setValue( iOrig, y );
280 --iOrig; --i;
284 if( iDest >= startIndex && iDest < iMax ) {
285 if( editable ) setValue( iDest, yDest );
287 _currentIndex = iDest;
288 _selectionSize = 1;
291 moveOrigin = pos;
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;
303 Q_UNUSED(e);
304 QPainter p(this);
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 );
320 if( horiz ) {
321 p.translate( bounds.topLeft() );
322 p.rotate(90);
323 p.scale(1.0, -1.0);
324 bounds.setSize( QSize( bounds.height(), bounds.width() ) );
326 else {
327 p.translate( bounds.left(), bounds.top() + bounds.height() );
328 p.scale(1.0, -1.0);
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();
341 // selection
343 if( highlight ) {
344 int i = _currentIndex - startIndex;
345 int c = qMin( count - i, _selectionSize );
346 if(c) {
347 QRect r;
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() );
360 // lines
362 if( drawLines ) {
363 bool fill = isFilled & !drawRects;
365 p.save();
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 );
372 QPainterPath path;
374 // value line
376 path.moveTo( 0, _values[startIndex] );
377 for( int i = 1; i < count; ++i )
378 path.lineTo( (qreal) i * spacing, _values[i + startIndex] );
380 // reference line
382 int refcount = _ref.count() - startIndex;
383 if( refcount > 0 || fill ) {
384 qreal x, y;
385 int i = count - 1;
387 x = i * spacing;
388 y = i < refcount ? _ref[i + startIndex] : 0.f;
389 if( fill ) path.lineTo(x, y);
390 else path.moveTo(x, y);
392 while( --i >= 0 ) {
393 x = i * spacing;
394 y = i < refcount ? _ref[i + startIndex] : 0.f;
395 path.lineTo(x, y);
398 if( fill ) path.closeSubpath();
401 p.drawPath( path );
403 p.restore();
406 // rects
408 if( drawRects ) {
409 p.setRenderHint( QPainter::Antialiasing, false );
410 p.translate( (spacing - width) * 0.5, 0 );
411 p.setBrush( fillClr );
413 QRectF r;
414 r.setWidth( width );
416 if( isFilled ) {
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 );
422 r.moveTop( ref );
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));
428 else {
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 =
443 #ifdef Q_OS_MAC
444 Qt::MetaModifier;
445 #else
446 Qt::ControlModifier;
447 #endif
449 if( QApplication::keyboardModifiers() & ctrlMod )
450 Q_EMIT( metaAction() );
451 else
452 Q_EMIT( action() );