summaryrefslogtreecommitdiffstats
path: root/arts/gui/kde/kpoti.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'arts/gui/kde/kpoti.cpp')
-rw-r--r--arts/gui/kde/kpoti.cpp780
1 files changed, 780 insertions, 0 deletions
diff --git a/arts/gui/kde/kpoti.cpp b/arts/gui/kde/kpoti.cpp
new file mode 100644
index 00000000..e12c1bf5
--- /dev/null
+++ b/arts/gui/kde/kpoti.cpp
@@ -0,0 +1,780 @@
+/***************************************************************************
+ kpoti.cpp - potentiometer widget
+ -------------------
+ begin : Wed Apr 28 23:05:05 MEST 1999
+
+ copyright : (C) 1999 by Martin Lorenz
+ email : lorenz@ch.tum.de
+ (C) 2002-2003 Matthias Kretz <kretz@kde.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kpoti.h"
+#include "kpoti.moc"
+
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qcolor.h>
+#include <qdrawutil.h>
+#include <qtimer.h>
+#include <qkeycode.h>
+#include <qpen.h>
+#include <qstring.h>
+#include <qstyle.h>
+
+#include <math.h>
+
+#include <kpixmap.h>
+#include <kpixmapeffect.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#define PI 3.1415926
+static const int thresholdTime = 500;
+static const int repeatTime = 100;
+static const float maxAngle = PI*135/180; // 140 degrees to both sides
+static const float tickLength = 3;
+
+struct KPoti::KPotiPrivate
+{
+ KPotiPrivate()
+ : bgDirty( false )
+ , potiDirty( false )
+ {}
+
+ bool bgDirty;
+ KPixmap bgdb;
+ KPixmap bgPixmap( const QColorGroup & colorGroup )
+ {
+ if( bgDirty || bgdb.isNull() )
+ {
+ bgdb.resize( buttonRect.size() );
+ QPainter dbp( &bgdb );
+ dbp.setPen( Qt::NoPen );
+ QRect drawRect = bgdb.rect();
+
+ // create mask
+ QBitmap mask( bgdb.size(), true );
+ QPainter maskpainter( &mask );
+ maskpainter.setPen( Qt::NoPen );
+ maskpainter.setBrush( Qt::color1 );
+ maskpainter.drawEllipse( drawRect );
+ maskpainter.end();
+ bgdb.setMask( mask );
+
+ // inset shadow
+ KPixmap gradient( bgdb.size() );
+ KPixmapEffect::gradient( gradient, colorGroup.light(), colorGroup.dark(), KPixmapEffect::DiagonalGradient );
+ dbp.setBrush( QBrush( colorGroup.button(), gradient ) );
+ dbp.drawEllipse( drawRect );
+
+ potiRect.setSize( drawRect.size() * 0.9 );
+ if( potiRect.width() + 6 > drawRect.width() )
+ {
+ potiRect.setWidth( drawRect.width() - 6 );
+ potiRect.setHeight( drawRect.height() - 6 );
+ }
+ potiRect.moveCenter( center );
+
+ bgDirty = false;
+ }
+ return bgdb;
+ }
+
+ QColor potiColor;
+ bool potiDirty;
+ KPixmap potidb;
+ KPixmap potiPixmap()
+ {
+ if( ( potiDirty || potidb.isNull() ) && ! potiRect.size().isEmpty() )
+ {
+ potidb.resize( potiRect.size() );
+ QPainter dbp( &potidb );
+ dbp.setPen( Qt::NoPen );
+ QRect drawRect( potidb.rect() );
+
+ // create mask
+ QBitmap mask( potidb.size(), true );
+ QPainter maskpainter( &mask );
+ maskpainter.setPen( Qt::NoPen );
+ maskpainter.setBrush( Qt::color1 );
+ maskpainter.drawEllipse( drawRect );
+ maskpainter.end();
+ potidb.setMask( mask );
+
+ KPixmap gradient( potidb.size() );
+ KPixmapEffect::gradient( gradient, potiColor.dark( 130 ), potiColor.light( 130 ), KPixmapEffect::DiagonalGradient );
+ dbp.setBrush( QBrush( potiColor, gradient ) );
+ dbp.drawEllipse( drawRect );
+
+ potiDirty = false;
+ }
+ return potidb;
+ }
+
+ QRect buttonRect;
+ QRect potiRect;
+ QRect labelRect;
+ QString label;
+ QPoint center;
+};
+
+QSizePolicy KPoti::sizePolicy() const
+{
+ return QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
+}
+
+QSize KPoti::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+QSize KPoti::minimumSizeHint() const
+{
+ int width = 40;
+ int height = 40;
+ if( m_bLabel )
+ {
+ QFontMetrics metrics( font() );
+ d->labelRect = metrics.boundingRect( d->label );
+ d->labelRect.setHeight( metrics.lineSpacing() );
+ width = KMAX( width, d->labelRect.width() + frameRect().width() - contentsRect().width() );
+ height += metrics.lineSpacing();
+ }
+ //kdDebug() << k_funcinfo << "return " << width << "x" << height << endl;
+ return QSize( width, height );
+}
+
+QString KPoti::text() const
+{
+ return d->label;
+}
+
+void KPoti::setText( const QString & text )
+{
+ d->label = text;
+ setMinimumSize( minimumSizeHint() );
+ updateGeometry();
+}
+
+/**
+ Constructs a poti.
+
+ The \e parent and \e name arguments are sent to the QWidget constructor.
+*/
+KPoti::KPoti( QWidget *parent, const char *name )
+ : QFrame( parent, name, WResizeNoErase | WRepaintNoErase )
+ , d( 0 )
+{
+ init();
+}
+
+
+
+/**
+ Constructs a poti.
+
+ \arg \e minValue is the minimum slider value.
+ \arg \e maxValue is the maximum slider value.
+ \arg \e step is the page step value.
+ \arg \e value is the initial value.
+
+ The \e parent and \e name arguments are sent to the QWidget constructor.
+*/
+
+KPoti::KPoti( int minValue, int maxValue, int step,
+ int value, QWidget *parent, const char *name )
+ : QFrame( parent, name, WResizeNoErase | WRepaintNoErase )
+ , QRangeControl( minValue, maxValue, 1, step, value )
+ , d( 0 )
+{
+ init(value);
+}
+
+KPoti::~KPoti()
+{
+ delete d;
+ d = 0;
+}
+
+void KPoti::init(int value)
+{
+ d = new KPotiPrivate;
+ font().setPointSize( 8 );
+ d->potiColor.setNamedColor( "red" );
+
+ timer = 0;
+ potiVal = value;
+ potiPos = positionFromValue(value);
+ clickOffset = 0;
+ state = Idle;
+ track = TRUE;
+ ticks = TRUE;
+ m_bLabel = true;
+ tickInt = 0;
+
+ setFocusPolicy( TabFocus );
+ initTicks();
+}
+
+
+/**
+ Does what's needed when someone changes the tickmark status
+*/
+
+void KPoti::initTicks()
+{
+ QRect available = contentsRect();
+ if( m_bLabel )
+ available.rTop() += d->labelRect.height();
+ d->center = available.center();
+ // make the width and height equal
+ if( available.width() > available.height() )
+ available.setWidth( available.height() );
+ else if( available.height() > available.width() )
+ available.setHeight( available.width() );
+ available.moveCenter( d->center );
+ d->buttonRect = available;
+
+ buttonRadius = available.width() / 2.0;
+ if( ticks )
+ {
+ buttonRadius -= tickLength;
+ int tickSpace = static_cast<int>( tickLength );
+ d->buttonRect.rTop() += tickSpace;
+ d->buttonRect.rLeft() += tickSpace;
+ d->buttonRect.rRight() -= tickSpace;
+ d->buttonRect.rBottom() -= tickSpace;
+ }
+
+ d->potiDirty = true;
+ d->bgDirty = true;
+}
+
+
+/**
+ Enables slider tracking if \e enable is TRUE, or disables tracking
+ if \e enable is FALSE.
+
+ If tracking is enabled (default), the slider emits the
+ valueChanged() signal whenever the slider is being dragged. If
+ tracking is disabled, the slider emits the valueChanged() signal
+ when the user releases the mouse button (unless the value happens to
+ be the same as before).
+
+ \sa tracking()
+*/
+
+void KPoti::setTracking( bool enable )
+{
+ track = enable;
+}
+
+
+/**
+ \fn bool KPoti::tracking() const
+ Returns TRUE if tracking is enabled, or FALSE if tracking is disabled.
+
+ Tracking is initially enabled.
+
+ \sa setTracking()
+*/
+
+
+/**
+ \fn void KPoti::valueChanged( int value )
+ This signal is emitted when the slider value is changed, with the
+ new slider value as an argument.
+*/
+
+/**
+ \fn void KPoti::sliderPressed()
+ This signal is emitted when the user presses the slider with the mouse.
+*/
+
+/**
+ \fn void KPoti::sliderMoved( int value )
+ This signal is emitted when the slider is dragged, with the
+ new slider value as an argument.
+*/
+
+/**
+ \fn void KPoti::sliderReleased()
+ This signal is emitted when the user releases the slider with the mouse.
+*/
+
+/**
+ Calculates slider position corresponding to value \a v. Does not perform
+ rounding.
+*/
+
+float KPoti::positionFromValue( int v ) const
+{
+
+ int range = maxValue() - minValue();
+ return ( (v - minValue() ) *2* maxAngle) / range - maxAngle;
+}
+
+
+/**
+ Calculates value corresponding to poti position \a p. Performs rounding.
+*/
+
+int KPoti::valueFromPosition( float p ) const
+{
+ int range = maxValue() - minValue();
+ return (int) (minValue() + ((p+maxAngle)*range)/(2*maxAngle));
+}
+
+/*!
+ Implements the virtual QRangeControl function.
+*/
+
+void KPoti::rangeChange()
+{
+ float newPos = positionFromValue( value() );
+ if ( newPos != potiPos ) {
+ reallyMovePoti( newPos );
+ }
+}
+
+void KPoti::paletteChange( const QPalette & )
+{
+ d->bgDirty = true;
+ d->potiDirty = true;
+}
+
+/*!
+ Changes the value (slot)
+*/
+
+void KPoti::valueChange()
+{
+ if ( potiVal != value() ) {
+ float newPos = positionFromValue( value() );
+ potiVal = value();
+ reallyMovePoti( newPos );
+ }
+ emit valueChanged(value());
+}
+
+
+/*!
+ Handles resize events for the poti.
+*/
+
+void KPoti::resizeEvent( QResizeEvent * )
+{
+ rangeChange();
+ initTicks();
+}
+
+void KPoti::setLabel(bool s)
+{
+ m_bLabel = s;
+ initTicks();
+}
+
+/**
+ Sets the color of the button
+ */
+void KPoti::setColor( const QColor &c )
+{
+ d->potiColor = c;
+ d->potiDirty = true;
+ repaint();
+}
+
+
+void KPoti::paintPoti( QPainter * p )
+{
+ if( isVisible() )
+ {
+ KPixmap db = d->potiPixmap();
+ if( db.isNull() )
+ return;
+
+ QPainter p2( &db );
+ p2.translate( db.rect().center().x(), db.rect().center().y() );
+ p2.rotate( potiPos * 180.0 / PI );
+ QRect pointer( db.width() / -20, db.width() / -2, db.width() / 10, db.width() / 2 );
+ QBrush buttonbrush( colorGroup().button() );
+ qDrawShadePanel( &p2, pointer, colorGroup(), true, 1, &buttonbrush );
+ p2.end();
+
+ p->drawPixmap( d->potiRect, db );
+ }
+}
+
+/*!
+ Performs the actual moving of the slider.
+*/
+
+void KPoti::reallyMovePoti( float newPos )
+{
+ QPainter p;
+ p.begin( this );
+ p.setPen(NoPen);
+ potiPos = newPos;
+ paintPoti(&p);
+ p.end();
+}
+
+
+
+
+/**
+ Handles paint events for the slider.
+*/
+
+void KPoti::drawContents( QPainter * p )
+{
+ QPixmap doublebuffer( contentsRect().size() );
+ doublebuffer.fill( colorGroup().background() );
+ QPainter dbp( &doublebuffer );
+ if( m_bLabel )
+ {
+ dbp.setFont( font() );
+ QFontMetrics metrics = dbp.fontMetrics();
+ dbp.drawText( contentsRect().x() - metrics.leftBearing( d->label[ 0 ] ) + ( contentsRect().width() - d->labelRect.width() ) / 2, metrics.height(), d->label );
+ }
+
+ int interval = tickInt;
+ if( interval <= 0 )
+ interval = 12;
+ if( ticks )
+ drawTicks( &dbp, buttonRadius, tickLength, interval );
+
+ dbp.drawPixmap( d->buttonRect, d->bgPixmap( colorGroup() ) );
+
+ if( hasFocus() )
+ style().drawPrimitive( QStyle::PE_FocusRect, &dbp, d->buttonRect, colorGroup() );
+
+ paintPoti( &dbp );
+ dbp.end();
+ p->drawPixmap( contentsRect(), doublebuffer );
+}
+
+
+/*!
+ Handles mouse press events for the slider.
+*/
+
+void KPoti::mousePressEvent( QMouseEvent *e )
+{
+ resetState();
+
+ if ( e->button() == MidButton ) {
+ double pos = atan2( double(e->pos().x()-d->center.x()),
+ double(- e->pos().y() + d->center.y()) );
+ movePoti( pos );
+ return;
+ }
+ if ( e->button() != LeftButton )
+ return;
+
+
+ int dx=e->pos().x()-d->center.x(), dy=e->pos().y()-d->center.y();
+
+ if ( dx*dx+dy*dy < buttonRadius*buttonRadius ) {
+ state = Dragging;
+ clickOffset = potiVal + (e->pos().y() ) ;
+ emit potiPressed();
+ } else if ( e->pos().x() < width()/2 ) {
+ state = TimingDown;
+ subtractPage();
+ if ( !timer )
+ timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
+ timer->start( thresholdTime, TRUE );
+ } else {
+ state = TimingUp;
+ addPage();
+ if ( !timer )
+ timer = new QTimer( this );
+ connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
+ timer->start( thresholdTime, TRUE );
+ }
+}
+
+/*!
+ Handles mouse move events for the slider.
+*/
+void KPoti::mouseMoveEvent( QMouseEvent *e )
+{
+
+ if ( (e->state() & MidButton) ) { // middle button wins
+ double pos = atan2( double(e->pos().x()-d->center.x()),
+ double(- e->pos().y()+d->center.y()) );
+ movePoti( pos );
+ return;
+ }
+ if ( !(e->state() & LeftButton) )
+ return; // left mouse button is up
+ if ( state != Dragging )
+ return;
+
+
+ movePoti( positionFromValue(- e->pos().y() + clickOffset ));
+}
+
+
+/*!
+ Handles mouse release events for the slider.
+*/
+
+void KPoti::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( !(e->button() & LeftButton) )
+ return;
+ resetState();
+}
+
+void KPoti::focusInEvent( QFocusEvent * e )
+{
+ //setFrameStyle( Raised | Box );
+ //setLineWidth( 1 );
+ QFrame::focusInEvent( e );
+}
+
+void KPoti::focusOutEvent( QFocusEvent * e )
+{
+ //setFrameStyle( NoFrame );
+ //setLineWidth( 0 );
+ QFrame::focusOutEvent( e );
+}
+
+
+void KPoti::enterEvent( QEvent * )
+{
+ emit mouseEntered( potiVal );
+}
+
+
+/*!
+ Moves the left (or top) edge of the slider to position
+ \a pos. Performs snapping.
+*/
+
+void KPoti::movePoti( float pos )
+{
+ float newPos = QMIN( maxAngle, QMAX( -maxAngle, pos ) );
+ int newVal = valueFromPosition( newPos );
+ if ( potiVal != newVal ) {
+ potiVal = newVal;
+ emit potiMoved( potiVal );
+ }
+ if ( tracking() && potiVal != value() ) {
+ directSetValue( potiVal );
+ emit valueChanged( potiVal );
+ }
+
+
+ if ( potiPos != newPos )
+ reallyMovePoti( newPos );
+}
+
+
+/*!
+ Resets all state information and stops my timer.
+*/
+
+void KPoti::resetState()
+{
+ if ( timer ) {
+ timer->stop();
+ timer->disconnect();
+ }
+ switch ( state ) {
+ case TimingUp:
+ case TimingDown:
+ break;
+ case Dragging: {
+ setValue( valueFromPosition( potiPos ) );
+ emit potiReleased();
+ break;
+ }
+ case Idle:
+ break;
+ default:
+ kdWarning() << "KPoti: in wrong state" << endl;
+ }
+ state = Idle;
+}
+
+
+/*!
+ Handles key press events for the slider.
+*/
+
+void KPoti::keyPressEvent( QKeyEvent *e )
+{
+
+ switch ( e->key() ) {
+ case Key_Left:
+ subtractLine();
+ break;
+ case Key_Right:
+ addLine();
+ break;
+ case Key_Up:
+ addLine();
+ break;
+ case Key_Down:
+ subtractLine();
+ break;
+ case Key_Prior:
+ subtractPage();
+ break;
+ case Key_Next:
+ addPage();
+ break;
+ case Key_Home:
+ setValue( minValue() );
+ break;
+ case Key_End:
+ setValue( maxValue() );
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ e->accept();
+}
+
+
+
+
+
+/*!
+ Makes QRangeControl::setValue() available as a slot.
+*/
+
+void KPoti::setValue( int value )
+{
+ QRangeControl::setValue( value );
+}
+
+
+/*!
+ Moves the slider one pageStep() upwards.
+*/
+
+void KPoti::addStep()
+{
+ addPage();
+}
+
+
+/*!
+ Moves the slider one pageStep() downwards.
+*/
+
+void KPoti::subtractStep()
+{
+ subtractPage();
+}
+
+
+/*!
+ Waits for autorepeat.
+*/
+
+void KPoti::repeatTimeout()
+{
+ Q_ASSERT( timer );
+ timer->disconnect();
+ if ( state == TimingDown )
+ connect( timer, SIGNAL(timeout()), SLOT(subtractStep()) );
+ else if ( state == TimingUp )
+ connect( timer, SIGNAL(timeout()), SLOT(addStep()) );
+ timer->start( repeatTime, FALSE );
+}
+
+
+
+
+/*!
+ Using \a p, draws tickmarks at a distance of \a dist from the edge
+ of the widget, using \a w pixels and \a i intervals.
+ */
+
+void KPoti::drawTicks( QPainter *p, double dist, double w, int i ) const
+{
+ p->setPen( colorGroup().foreground() );
+ double angle,s,c;
+ double x, y;
+ for (int v=0; v<=i; v++)
+ {
+ angle = -maxAngle+2*maxAngle*v/i;
+ s = sin( angle );
+ c = cos( angle );
+ x = d->center.x() - s * dist;
+ y = d->center.y() - c * dist;
+
+ p->drawLine( (int)x, (int)y, (int)(x - s * w), (int)(y - c * w) );
+ }
+}
+
+void KPoti::wheelEvent(QWheelEvent *e)
+{
+ setValue(value()+e->delta()/120*8);
+}
+
+
+/*!
+ Sets the way tickmarks are displayed by the slider. \a s can take
+ the following values:
+ <ul>
+ <li> \c NoMarks
+ <li> \c Above
+ <li> \c Left
+ <li> \c Below
+ <li> \c Right
+ <li> \c Both
+ </ul>
+ The initial value is \c NoMarks.
+ \sa tickmarks(), setTickInterval()
+*/
+
+void KPoti::setTickmarks( bool s )
+{
+ ticks = s;
+ initTicks();
+ update();
+}
+
+
+
+/*!
+ Sets the interval between tickmarks to \a i. This is a value interval,
+ not a pixel interval. If \a i is 0, the slider
+ will choose between lineStep() and pageStep(). The initial value of
+ tickInterval() is 0.
+ \sa tickInterval(), QRangeControl::lineStep(), QRangeControl::pageStep()
+*/
+
+void KPoti::setTickInterval( int i )
+{
+ tickInt = QMAX( 0, i );
+ update();
+}
+
+
+/*!
+ \fn int KPoti::tickInterval() const
+ Returns the interval between tickmarks. Returns 0 if the slider
+ chooses between pageStep() and lineStep().
+ \sa setTickInterval()
+*/
+
+// vim: sw=4 ts=4