scide: implement selectionLength for openDocument
[supercollider.git] / QtCollider / widgets / QcRangeSlider.cpp
bloba51c7aa41a3f812ce75c78b035935358b6ab0bed
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 "QcRangeSlider.h"
23 #include "../QcWidgetFactory.h"
24 #include "../style/routines.hpp"
26 #include <QKeyEvent>
27 #include <QMouseEvent>
28 #include <QApplication>
29 #include <QPainter>
31 #define HND 10
33 QC_DECLARE_QWIDGET_FACTORY(QcRangeSlider);
35 QcRangeSlider::QcRangeSlider() :
36 QtCollider::Style::Client(this),
37 _lo( 0.0 ),
38 _hi( 1.0 ),
39 _step( 0.01f ),
40 mouseMode( None )
42 setFocusPolicy( Qt::StrongFocus );
43 setOrientation( Qt::Vertical );
46 void QcRangeSlider::setOrientation( Qt::Orientation o )
48 _ort = o;
50 if( _ort == Qt::Horizontal ) {
51 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
53 else {
54 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
57 updateGeometry();
58 update();
61 void QcRangeSlider::setLoValue( double val )
63 val = qMax( 0.0, qMin( 1.0, val ) );
64 if( val <= _hi ) {
65 _lo = val;
67 else {
68 _lo = _hi;
69 _hi = val;
71 update();
74 void QcRangeSlider::setHiValue( double val )
76 val = qMax( 0.0, qMin( 1.0, val ) );
77 if( val >= _lo ) {
78 _hi = val;
80 else {
81 _hi = _lo;
82 _lo = val;
84 update();
87 void QcRangeSlider::setRange( double val, double range )
89 range = qBound( 0.0, range, 1.0 );
90 _lo = qBound( 0.0, val, 1.0 - range);
91 _hi = _lo + range;
92 update();
95 QSize QcRangeSlider::sizeHint() const
97 return ( _ort == Qt::Horizontal ? QSize( 150, 20 ) : QSize( 20, 150 ) );
100 QSize QcRangeSlider::minimumSizeHint() const
102 return ( _ort == Qt::Horizontal ? QSize( 30, 20 ) : QSize( 20, 30 ) );
105 void QcRangeSlider::increment( double factor )
107 moveBy( factor * _step );
110 void QcRangeSlider::decrement( double factor )
112 moveBy( -factor * _step );
115 void QcRangeSlider::increment()
117 double step = _step;
118 modifyStep( &step );
119 moveBy( step );
122 void QcRangeSlider::decrement()
124 double step = _step;
125 modifyStep( &step );
126 moveBy( -step );
129 QRect QcRangeSlider::thumbRect()
131 using namespace QtCollider::Style;
132 QRect contRect( sunkenContentsRect(rect()) );
133 int hnd2 = HND * 2;
134 if( _ort == Qt::Horizontal ) {
135 double valRange = contRect.width() - hnd2;
136 double left = _lo * valRange;
137 double right = _hi * valRange; right += hnd2;
138 return QRect( left + contRect.x(), contRect.y(), right - left, contRect.height() );
140 else {
141 double valRange = contRect.height() - hnd2;
142 int up = (1.0 - _hi) * valRange;
143 int down = (1.0 - _lo) * valRange; down += hnd2;
144 return QRect( contRect.x(), contRect.y() + up, contRect.width(), down - up );
148 double QcRangeSlider::valueFromPos( const QPoint& pos )
150 using namespace QtCollider::Style;
152 bool horiz = _ort == Qt::Horizontal;
154 QSize margins = horiz ? QSize(HND*2, 0) : QSize(0, HND*2);
155 QRect valBounds = marginsRect( sunkenContentsRect(rect()), margins );
157 return horiz ? xValue( pos.x(), valBounds ) : yValue( pos.y(), valBounds );
160 void QcRangeSlider::moveBy( double dif )
162 if( _lo + dif < 0.0 ) {
163 _hi += 0.0 - _lo;
164 _lo = 0.0;
166 else if( _hi + dif > 1.0 ) {
167 _lo += 1.0 - _hi;
168 _hi = 1.0;
170 else {
171 _lo += dif;
172 _hi += dif;
174 update();
177 void QcRangeSlider::mouseMoveEvent ( QMouseEvent * e )
179 using namespace QtCollider::Style;
181 if( !e->buttons() ) return;
183 if( mouseMode == SetHi || mouseMode == SetLo )
185 double val = valueFromPos( e->pos() );
186 if( mouseMode == SetLo ) {
187 if( val > _hi ) mouseMode = SetHi;
188 setLoValue( val );
190 else if( mouseMode == SetHi ) {
191 if( val < _lo ) mouseMode = SetLo;
192 setHiValue( val );
195 else if( mouseMode != None )
197 QPoint pt = e->pos() - dragOrigin;
198 QRect contRect( sunkenContentsRect(rect()) );
200 double dif;
201 if( _ort == Qt::Horizontal ) {
202 double range = contRect.width() - HND*2;
203 dif = range > 0 ? pt.x() / range : 0.0;
205 else {
206 double range = contRect.height() - HND*2;
207 dif = range > 0 ? - pt.y() / range : 0.0;
210 if( dif != 0.0 ) {
211 switch( mouseMode ) {
212 case Move:
213 setRange( dragVal + dif, dragRange ); break;
214 case MoveHi:
215 setHiValue( qMax(dragVal + dif, (double)_lo) ); break;
216 case MoveLo:
217 setLoValue( qMin(dragVal + dif, (double)_hi) ); break;
219 default:;
224 Q_EMIT( action() );
227 void QcRangeSlider::mousePressEvent ( QMouseEvent * e )
229 using namespace QtCollider::Style;
231 if( e->modifiers() & Qt::ShiftModifier ) {
232 double center = (_hi + _lo) * 0.5;
233 double val = valueFromPos( e->pos() );
234 if( val < center ) {
235 mouseMode = SetLo;
236 setLoValue( val );
238 else {
239 mouseMode = SetHi;
240 setHiValue( val );
242 Q_EMIT( action() );
244 else {
245 QRect thumb( thumbRect() );
247 int len, pos;
249 if( _ort == Qt::Horizontal ) {
250 len = thumb.width();
251 pos = e->pos().x() - thumb.left();
253 else {
254 len = thumb.height();
255 pos = thumb.top() + len - e->pos().y();
258 if( pos < 0 || pos > len ) return;
260 dragOrigin = e->pos();
262 if( pos < HND ) {
263 mouseMode = MoveLo;
264 dragVal = _lo;
266 else if( pos >= len - HND ) {
267 mouseMode = MoveHi;
268 dragVal = _hi;
270 else {
271 mouseMode = Move;
272 dragVal = _lo;
273 dragRange = _hi - _lo;
277 update();
280 void QcRangeSlider::mouseReleaseEvent ( QMouseEvent * e )
282 Q_UNUSED(e);
283 mouseMode = None;
286 void QcRangeSlider::keyPressEvent ( QKeyEvent *e )
288 switch( e->key() ) {
289 case Qt::Key_Up:
290 case Qt::Key_Right:
291 increment(); break;
292 case Qt::Key_Down:
293 case Qt::Key_Left:
294 decrement(); break;
295 case Qt::Key_A:
296 _lo = 0.0; _hi = 1.0; update(); break;
297 case Qt::Key_N:
298 _lo = 0.0; _hi = 0.0; update(); break;
299 case Qt::Key_X:
300 _lo = 1.0; _hi = 1.0; update(); break;
301 case Qt::Key_C:
302 _lo = 0.5; _hi = 0.5; update(); break;
303 default:
304 return QWidget::keyPressEvent( e );
306 Q_EMIT( action() );
309 inline void drawMarker( QPainter *p, const QColor &color,
310 Qt::Orientation ort, bool first, const QPoint & pt, int len )
312 p->save();
313 p->setRenderHint( QPainter::Antialiasing, false );
315 QPen pen(color);
317 bool vert = ort == Qt::Vertical;
319 if(vert) {
320 pen.setWidth(1); p->setPen(pen);
321 p->drawPoint( QPoint( pt.x() + len * 0.5, first ? pt.y() - 5 : pt.y() + 5 ) );
323 pen.setWidth(2); p->setPen(pen);
324 QLine line( pt.x() + 1, pt.y(), pt.x() + len - 1, pt.y() );
325 p->drawLine(line);
326 } else {
327 pen.setWidth(1); p->setPen(pen);
328 p->drawPoint( QPoint( first ? pt.x() - 5 : pt.x() + 5, pt.y() + len * 0.5 ) );
330 pen.setWidth(2); p->setPen(pen);
331 QLine line( pt.x(), pt.y() + 1, pt.x(), pt.y() + len - 1 );
332 p->drawLine(line);
334 p->restore();
337 void QcRangeSlider::paintEvent ( QPaintEvent *e )
339 using namespace QtCollider::Style;
340 using QtCollider::Style::RoundRect;
342 Q_UNUSED(e);
344 QPainter p(this);
345 p.setRenderHint( QPainter::Antialiasing, true );
347 const QPalette & plt = palette();
348 const QColor & knobClr = knobColor();
350 RoundRect frame(rect(), 2);
351 drawSunken( &p, plt, frame, grooveColor(), hasFocus() ? focusColor() : QColor() );
353 QRect contRect( sunkenContentsRect(rect()) );
355 QRect hndRect;
356 QRect valRect;
357 int HND2 = HND * 2;
358 bool horiz = _ort == Qt::Horizontal;
360 if( horiz ) {
361 double valRange = contRect.width() - HND2;
362 int lo = _lo * valRange;
363 int hi = _hi * valRange;
364 valRect = QRect( lo + HND + contRect.x(), contRect.y(), hi - lo, contRect.height() );
365 hndRect = valRect.adjusted( -HND, 0, HND, 0 );
367 else {
368 double valRange = contRect.height() - HND2;
369 int hi = _hi * valRange;
370 int lo = _lo * valRange;
371 valRect = QRect( contRect.x(), contRect.y() + contRect.height() - hi - HND, contRect.width(), hi - lo );
372 hndRect = valRect.adjusted( 0, -HND, 0, HND );
375 // handle
377 RoundRect handle(hndRect, 2);
378 drawRaised( &p, plt, handle, plt.color(QPalette::Button).lighter(105) );
380 // markers
382 if( horiz ) {
383 int mark_len = hndRect.height() - 4;
385 QPoint pt( hndRect.left() + HND, hndRect.top() + 2 );
386 drawMarker( &p, knobClr, _ort, true, pt, mark_len );
388 pt.setX( hndRect.right() - HND + 1 );
389 drawMarker( &p, knobClr, _ort, false, pt, mark_len );
390 } else {
391 int mark_len = hndRect.width() - 4;
392 QPoint pt( hndRect.left() + 2, hndRect.top() + HND );
393 drawMarker( &p, knobClr, _ort, true, pt, mark_len );
395 pt.setY( hndRect.bottom() - HND + 1 );
396 drawMarker( &p, knobClr, _ort, false, pt, mark_len );
399 // value region
401 if( horiz ? valRect.width() > 2 : valRect.height() > 2 ) {
402 p.setRenderHint( QPainter::Antialiasing, false );
404 QColor c( knobClr );
405 c.setAlpha(50);
407 p.setPen(Qt::NoPen);
408 p.setBrush(c);
409 if( horiz )
410 p.drawRect(valRect.adjusted( 1, 2, -1, -2 ));
411 else
412 p.drawRect(valRect.adjusted( 2, 1, -2, -1 ));