fix String:wrapExtend to fill out to the actual requested size
[supercollider.git] / QtCollider / widgets / QcRangeSlider.cpp
blobc23796b54721ed6536b433d3472f9c87e61d8d0f
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.f ),
38 _hi( 1.f ),
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( float val )
63 val = qMax( 0.f, qMin( 1.f, val ) );
64 if( val <= _hi ) {
65 _lo = val;
67 else {
68 _lo = _hi;
69 _hi = val;
71 update();
74 void QcRangeSlider::setHiValue( float val )
76 val = qMax( 0.f, qMin( 1.f, 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 float step = _step;
118 modifyStep( &step );
119 moveBy( step );
122 void QcRangeSlider::decrement()
124 float 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( float dif )
162 if( _lo + dif < 0.f ) {
163 _hi += 0.f - _lo;
164 _lo = 0.f;
166 else if( _hi + dif > 1.f ) {
167 _lo += 1.f - _hi;
168 _hi = 1.f;
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 float 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;
222 Q_EMIT( action() );
225 void QcRangeSlider::mousePressEvent ( QMouseEvent * e )
227 using namespace QtCollider::Style;
229 if( e->modifiers() & Qt::ShiftModifier ) {
230 double center = (_hi + _lo) * 0.5;
231 double val = valueFromPos( e->pos() );
232 if( val < center ) {
233 mouseMode = SetLo;
234 setLoValue( val );
236 else {
237 mouseMode = SetHi;
238 setHiValue( val );
240 Q_EMIT( action() );
242 else {
243 QRect thumb( thumbRect() );
245 int len, pos;
247 if( _ort == Qt::Horizontal ) {
248 len = thumb.width();
249 pos = e->pos().x() - thumb.left();
251 else {
252 len = thumb.height();
253 pos = thumb.top() + len - e->pos().y();
256 if( pos < 0 || pos > len ) return;
258 dragOrigin = e->pos();
260 if( pos < HND ) {
261 mouseMode = MoveLo;
262 dragVal = _lo;
264 else if( pos >= len - HND ) {
265 mouseMode = MoveHi;
266 dragVal = _hi;
268 else {
269 mouseMode = Move;
270 dragVal = _lo;
271 dragRange = _hi - _lo;
275 update();
278 void QcRangeSlider::mouseReleaseEvent ( QMouseEvent * e )
280 Q_UNUSED(e);
281 mouseMode = None;
284 void QcRangeSlider::keyPressEvent ( QKeyEvent *e )
286 switch( e->key() ) {
287 case Qt::Key_Up:
288 case Qt::Key_Right:
289 increment(); break;
290 case Qt::Key_Down:
291 case Qt::Key_Left:
292 decrement(); break;
293 case Qt::Key_A:
294 _lo = 0.f; _hi = 1.f; update(); break;
295 case Qt::Key_N:
296 _lo = 0.f; _hi = 0.f; update(); break;
297 case Qt::Key_X:
298 _lo = 1.f; _hi = 1.f; update(); break;
299 case Qt::Key_C:
300 _lo = 0.5; _hi = 0.5; update(); break;
301 default:
302 return QWidget::keyPressEvent( e );
304 Q_EMIT( action() );
307 inline void drawMarker( QPainter *p, const QPalette &plt, Qt::Orientation ort, bool first, const QPoint & pt, int len )
309 p->save();
310 p->setRenderHint( QPainter::Antialiasing, false );
312 QPen pen(plt.color(QPalette::ButtonText));
314 bool vert = ort == Qt::Vertical;
316 if(vert) {
317 pen.setWidth(1); p->setPen(pen);
318 p->drawPoint( QPoint( pt.x() + len * 0.5, first ? pt.y() - 5 : pt.y() + 5 ) );
320 pen.setWidth(2); p->setPen(pen);
321 QLine line( pt.x() + 1, pt.y(), pt.x() + len - 1, pt.y() );
322 p->drawLine(line);
323 } else {
324 pen.setWidth(1); p->setPen(pen);
325 p->drawPoint( QPoint( first ? pt.x() - 5 : pt.x() + 5, pt.y() + len * 0.5 ) );
327 pen.setWidth(2); p->setPen(pen);
328 QLine line( pt.x(), pt.y() + 1, pt.x(), pt.y() + len - 1 );
329 p->drawLine(line);
331 p->restore();
334 void QcRangeSlider::paintEvent ( QPaintEvent *e )
336 using namespace QtCollider::Style;
338 Q_UNUSED(e);
340 QPainter p(this);
341 p.setRenderHint( QPainter::Antialiasing, true );
343 QPalette plt = palette();
345 RoundRect frame(rect(), 2);
346 QColor baseColor( grooveColor() );
347 drawSunken( &p, plt, frame, baseColor, hasFocus() ? focusColor() : QColor() );
349 QRect contRect( sunkenContentsRect(rect()) );
351 QRect hndRect;
352 QRect valRect;
353 int HND2 = HND * 2;
354 bool horiz = _ort == Qt::Horizontal;
356 if( horiz ) {
357 double valRange = contRect.width() - HND2;
358 int lo = _lo * valRange;
359 int hi = _hi * valRange;
360 valRect = QRect( lo + HND + contRect.x(), contRect.y(), hi - lo, contRect.height() );
361 hndRect = valRect.adjusted( -HND, 0, HND, 0 );
363 else {
364 double valRange = contRect.height() - HND2;
365 int hi = _hi * valRange;
366 int lo = _lo * valRange;
367 valRect = QRect( contRect.x(), contRect.y() + contRect.height() - hi - HND, contRect.width(), hi - lo );
368 hndRect = valRect.adjusted( 0, -HND, 0, HND );
371 // handle
373 RoundRect handle(hndRect, 2);
374 drawRaised( &p, plt, handle, plt.color(QPalette::Button).lighter(105) );
376 // markers
378 if( horiz ) {
379 int mark_len = hndRect.height() - 4;
381 QPoint pt( hndRect.left() + HND, hndRect.top() + 2 );
382 drawMarker( &p, plt, _ort, true, pt, mark_len );
384 pt.setX( hndRect.right() - HND + 1 );
385 drawMarker( &p, plt, _ort, false, pt, mark_len );
386 } else {
387 int mark_len = hndRect.width() - 4;
388 QPoint pt( hndRect.left() + 2, hndRect.top() + HND );
389 drawMarker( &p, plt, _ort, true, pt, mark_len );
391 pt.setY( hndRect.bottom() - HND + 1 );
392 drawMarker( &p, plt, _ort, false, pt, mark_len );
395 // value region
397 if( horiz ? valRect.width() > 2 : valRect.height() > 2 ) {
398 p.setRenderHint( QPainter::Antialiasing, false );
400 QColor c( plt.color(QPalette::ButtonText) );
401 c.setAlpha(50);
403 p.setPen(Qt::NoPen);
404 p.setBrush(c);
405 if( horiz )
406 p.drawRect(valRect.adjusted( 1, 2, -1, -2 ));
407 else
408 p.drawRect(valRect.adjusted( 2, 1, -2, -1 ));