svgui  1.9
LEDButton.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     
00008     This program is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU General Public License as
00010     published by the Free Software Foundation; either version 2 of the
00011     License, or (at your option) any later version.  See the file
00012     COPYING included with this distribution for more information.
00013 */
00014 
00015 /*
00016     This is a modified version of a source file from the KDE
00017     libraries.  Copyright (c) 1998-2004 Jörg Habenicht, Richard J
00018     Moore, Chris Cannam and others, distributed under the GNU Lesser
00019     General Public License.
00020 
00021     Ported to Qt4 by Chris Cannam.
00022 */
00023 
00024 
00025 #include "LEDButton.h"
00026 
00027 #include <QPainter>
00028 #include <QImage>
00029 #include <QColor>
00030 #include <QMouseEvent>
00031 
00032 #include <iostream>
00033 
00034 
00035 class LEDButton::LEDButtonPrivate
00036 {
00037     friend class LEDButton;
00038 
00039     int dark_factor;
00040     QColor offcolor;
00041     QPixmap *off_map;
00042     QPixmap *on_map;
00043 };
00044 
00045 
00046 LEDButton::LEDButton(QWidget *parent) :
00047     QWidget(parent),
00048     led_state(true)
00049 {
00050     QColor col(Qt::green);
00051     d = new LEDButton::LEDButtonPrivate;
00052     d->dark_factor = 300;
00053     d->offcolor = col.dark(300);
00054     d->off_map = 0;
00055     d->on_map = 0;
00056     
00057     setColor(col);
00058 }
00059 
00060 
00061 LEDButton::LEDButton(const QColor& col, QWidget *parent) :
00062     QWidget(parent),
00063     led_state(true)
00064 {
00065     d = new LEDButton::LEDButtonPrivate;
00066     d->dark_factor = 300;
00067     d->offcolor = col.dark(300);
00068     d->off_map = 0;
00069     d->on_map = 0;
00070 
00071     setColor(col);
00072 }
00073 
00074 LEDButton::LEDButton(const QColor& col, bool state, QWidget *parent) :
00075     QWidget(parent),
00076     led_state(state)
00077 {
00078     d = new LEDButton::LEDButtonPrivate;
00079     d->dark_factor = 300;
00080     d->offcolor = col.dark(300);
00081     d->off_map = 0;
00082     d->on_map = 0;
00083 
00084     setColor(col);
00085 }
00086 
00087 LEDButton::~LEDButton()
00088 {
00089     delete d->off_map;
00090     delete d->on_map;
00091     delete d;
00092 }
00093 
00094 void
00095 LEDButton::mousePressEvent(QMouseEvent *e)
00096 {
00097     cerr << "LEDButton(" << this << ")::mousePressEvent" << endl;
00098 
00099     if (e->buttons() & Qt::LeftButton) {
00100         toggle();
00101         bool newState = state();
00102         SVDEBUG << "emitting new state " << newState << endl;
00103         emit stateChanged(newState);
00104     }
00105 }
00106 
00107 void
00108 LEDButton::enterEvent(QEvent *)
00109 {
00110     emit mouseEntered();
00111 }
00112 
00113 void
00114 LEDButton::leaveEvent(QEvent *)
00115 {
00116     emit mouseLeft();
00117 }
00118 
00119 void
00120 LEDButton::paintEvent(QPaintEvent *)
00121 {
00122     QPainter paint;
00123     QColor color;
00124     QBrush brush;
00125     QPen pen;
00126                 
00127     // First of all we want to know what area should be updated
00128     // Initialize coordinates, width, and height of the LED
00129     int width = this->width();
00130 
00131     // Make sure the LED is round!
00132     if (width > this->height())
00133         width = this->height();
00134     width -= 2; // leave one pixel border
00135     if (width < 0) 
00136         width = 0;
00137 
00138     QPixmap *tmpMap = 0;
00139 
00140     if (led_state) {
00141         if (d->on_map) {
00142             if (d->on_map->size() == size()) {
00143                 paint.begin(this);
00144                 paint.drawPixmap(0, 0, *d->on_map);
00145                 paint.end();
00146                 return;
00147             } else {
00148                 delete d->on_map;
00149                 d->on_map = 0;
00150             }
00151         }
00152     } else {
00153         if (d->off_map) {
00154             if (d->off_map->size() == size()) {
00155                 paint.begin(this);
00156                 paint.drawPixmap(0, 0, *d->off_map);
00157                 paint.end();
00158                 return;
00159             } else {
00160                 delete d->off_map;
00161                 d->off_map = 0;
00162             }
00163         }
00164     }
00165 
00166     int scale = 1;
00167     width *= scale;
00168 
00169     tmpMap = new QPixmap(width, width);
00170     tmpMap->fill(palette().background().color());
00171     paint.begin(tmpMap);
00172 
00173     paint.setRenderHint(QPainter::Antialiasing, true);
00174 
00175     // Set the color of the LED according to given parameters
00176     color = (led_state) ? led_color : d->offcolor;
00177 
00178     // Set the brush to SolidPattern, this fills the entire area
00179     // of the ellipse which is drawn first
00180     brush.setStyle(Qt::SolidPattern);
00181     brush.setColor(color);
00182     paint.setBrush(brush);
00183 
00184     // Draws a "flat" LED with the given color:
00185     paint.drawEllipse( scale, scale, width - scale*2, width - scale*2 );
00186 
00187     // Draw the bright light spot of the LED now, using modified "old"
00188     // painter routine taken from KDEUI´s LEDButton widget:
00189 
00190     // Setting the new width of the pen is essential to avoid "pixelized"
00191     // shadow like it can be observed with the old LED code
00192     pen.setWidth( 2 * scale );
00193 
00194     // shrink the light on the LED to a size about 2/3 of the complete LED
00195     int pos = width/5 + 1;
00196     int light_width = width;
00197     light_width *= 2;
00198     light_width /= 3;
00199         
00200     // Calculate the LED´s "light factor":
00201     int light_quote = (130*2/(light_width?light_width:1))+100;
00202 
00203     // Now draw the bright spot on the LED:
00204     while (light_width) {
00205         color = color.light( light_quote );                      // make color lighter
00206         pen.setColor( color );                                   // set color as pen color
00207         paint.setPen( pen );                                     // select the pen for drawing
00208         paint.drawEllipse( pos, pos, light_width, light_width ); // draw the ellipse (circle)
00209         light_width--;
00210         if (!light_width)
00211             break;
00212         paint.drawEllipse( pos, pos, light_width, light_width );
00213         light_width--;
00214         if (!light_width)
00215             break;
00216         paint.drawEllipse( pos, pos, light_width, light_width );
00217         pos++; light_width--;
00218     }
00219 
00220     // Drawing of bright spot finished, now draw a thin border
00221     // around the LED which resembles a shadow with light coming
00222     // from the upper left.
00223 
00224 //    pen.setWidth( 2 * scale + 1 ); // ### shouldn't this value be smaller for smaller LEDs?
00225     pen.setWidth(2 * scale);
00226     brush.setStyle(Qt::NoBrush);
00227     paint.setBrush(brush); // This avoids filling of the ellipse
00228 
00229     // Set the initial color value to colorGroup().light() (bright) and start
00230     // drawing the shadow border at 45° (45*16 = 720).
00231 
00232     int angle = -720;
00233     color = palette().light().color();
00234     
00235     for (int arc = 120; arc < 2880; arc += 240) {
00236         pen.setColor(color);
00237         paint.setPen(pen);
00238         int w = width - pen.width()/2 - scale + 1;
00239         paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle + arc, 240);
00240         paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle - arc, 240);
00241         color = color.dark(110); //FIXME: this should somehow use the contrast value
00242     }   // end for ( angle = 720; angle < 6480; angle += 160 )
00243 
00244     paint.end();
00245     //
00246     // painting done
00247 
00248     QPixmap *&dest = led_state ? d->on_map : d->off_map;
00249 
00250     if (scale > 1) {
00251 
00252         QImage i = tmpMap->toImage();
00253         width /= scale;
00254         delete tmpMap;
00255         dest = new QPixmap(QPixmap::fromImage
00256                            (i.scaled(width, width, 
00257                                      Qt::KeepAspectRatio,
00258                                      Qt::SmoothTransformation)));
00259 
00260     } else {
00261 
00262         dest = tmpMap;
00263     }
00264 
00265     paint.begin(this);
00266     paint.drawPixmap(0, 0, *dest);
00267     paint.end();
00268 }
00269 
00270 bool
00271 LEDButton::state() const
00272 {
00273     return led_state;
00274 }
00275 
00276 QColor
00277 LEDButton::color() const
00278 {
00279     return led_color;
00280 }
00281 
00282 void
00283 LEDButton::setState( bool state )
00284 {
00285     if (led_state != state)
00286     {
00287         led_state = state;
00288         update();
00289     }
00290 }
00291 
00292 void
00293 LEDButton::toggleState()
00294 {
00295     led_state = (led_state == true) ? false : true;
00296     // setColor(led_color);
00297     update();
00298 }
00299 
00300 void
00301 LEDButton::setColor(const QColor& col)
00302 {
00303     if(led_color!=col) {
00304         led_color = col;
00305         d->offcolor = col.dark(d->dark_factor);
00306         delete d->on_map;
00307         d->on_map = 0;
00308         delete d->off_map;
00309         d->off_map = 0;
00310         update();
00311     }
00312 }
00313 
00314 void
00315 LEDButton::setDarkFactor(int darkfactor)
00316 {
00317     if (d->dark_factor != darkfactor) {
00318         d->dark_factor = darkfactor;
00319         d->offcolor = led_color.dark(darkfactor);
00320         update();
00321     }
00322 }
00323 
00324 int
00325 LEDButton::darkFactor() const
00326 {
00327     return d->dark_factor;
00328 }
00329 
00330 void
00331 LEDButton::toggle()
00332 {
00333     toggleState();
00334 }
00335 
00336 void
00337 LEDButton::on()
00338 {
00339     setState(true);
00340 }
00341 
00342 void
00343 LEDButton::off()
00344 {
00345     setState(false);
00346 }
00347 
00348 QSize
00349 LEDButton::sizeHint() const
00350 {
00351     return QSize(17, 17);
00352 }
00353 
00354 QSize
00355 LEDButton::minimumSizeHint() const
00356 {
00357     return QSize(17, 17);
00358 }
00359