Chris@58: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@32: 
Chris@32: /*
Chris@59:     Sonic Visualiser
Chris@59:     An audio file viewer and annotation editor.
Chris@59:     Centre for Digital Music, Queen Mary, University of London.
Chris@32:     
Chris@59:     This program is free software; you can redistribute it and/or
Chris@59:     modify it under the terms of the GNU General Public License as
Chris@59:     published by the Free Software Foundation; either version 2 of the
Chris@59:     License, or (at your option) any later version.  See the file
Chris@59:     COPYING included with this distribution for more information.
Chris@32: */
Chris@32: 
Chris@32: /*
Chris@32:     This is a modified version of a source file from the KDE
Chris@32:     libraries.  Copyright (c) 1998-2004 J�rg Habenicht, Richard J
Chris@32:     Moore, Chris Cannam and others, distributed under the GNU Lesser
Chris@32:     General Public License.
Chris@32: 
Chris@32:     Ported to Qt4 by Chris Cannam.
Chris@32: */
Chris@32: 
Chris@32: 
Chris@32: #include "LEDButton.h"
Chris@32: 
Chris@32: #include <QPainter>
Chris@32: #include <QImage>
Chris@32: #include <QColor>
Chris@33: #include <QMouseEvent>
Chris@32: 
Chris@34: #include <iostream>
Chris@34: 
Chris@32: 
Chris@32: class LEDButton::LEDButtonPrivate
Chris@32: {
Chris@32:     friend class LEDButton;
Chris@32: 
Chris@32:     int dark_factor;
Chris@32:     QColor offcolor;
Chris@32:     QPixmap *off_map;
Chris@32:     QPixmap *on_map;
Chris@32: };
Chris@32: 
Chris@32: 
Chris@32: LEDButton::LEDButton(QWidget *parent) :
Chris@32:     QWidget(parent),
Chris@34:     led_state(true)
Chris@32: {
Chris@32:     QColor col(Qt::green);
Chris@32:     d = new LEDButton::LEDButtonPrivate;
Chris@32:     d->dark_factor = 300;
Chris@32:     d->offcolor = col.dark(300);
Chris@32:     d->off_map = 0;
Chris@32:     d->on_map = 0;
Chris@32:     
Chris@32:     setColor(col);
Chris@32: }
Chris@32: 
Chris@32: 
Chris@32: LEDButton::LEDButton(const QColor& col, QWidget *parent) :
Chris@32:     QWidget(parent),
Chris@34:     led_state(true)
Chris@32: {
Chris@32:     d = new LEDButton::LEDButtonPrivate;
Chris@32:     d->dark_factor = 300;
Chris@32:     d->offcolor = col.dark(300);
Chris@32:     d->off_map = 0;
Chris@32:     d->on_map = 0;
Chris@32: 
Chris@32:     setColor(col);
Chris@32: }
Chris@32: 
Chris@34: LEDButton::LEDButton(const QColor& col, bool state, QWidget *parent) :
Chris@32:     QWidget(parent),
Chris@32:     led_state(state)
Chris@32: {
Chris@32:     d = new LEDButton::LEDButtonPrivate;
Chris@32:     d->dark_factor = 300;
Chris@32:     d->offcolor = col.dark(300);
Chris@32:     d->off_map = 0;
Chris@32:     d->on_map = 0;
Chris@32: 
Chris@32:     setColor(col);
Chris@32: }
Chris@32: 
Chris@32: LEDButton::~LEDButton()
Chris@32: {
Chris@32:     delete d->off_map;
Chris@32:     delete d->on_map;
Chris@32:     delete d;
Chris@32: }
Chris@32: 
Chris@32: void
Chris@33: LEDButton::mousePressEvent(QMouseEvent *e)
Chris@33: {
Chris@34:     std::cerr << "LEDButton(" << this << ")::mousePressEvent" << std::endl;
Chris@34: 
Chris@33:     if (e->buttons() & Qt::LeftButton) {
Chris@33: 	toggle();
Chris@34: 	bool newState = state();
Chris@587: 	SVDEBUG << "emitting new state " << newState << endl;
Chris@34: 	emit stateChanged(newState);
Chris@33:     }
Chris@33: }
Chris@33: 
Chris@33: void
Chris@189: LEDButton::enterEvent(QEvent *)
Chris@189: {
Chris@189:     emit mouseEntered();
Chris@189: }
Chris@189: 
Chris@189: void
Chris@189: LEDButton::leaveEvent(QEvent *)
Chris@189: {
Chris@189:     emit mouseLeft();
Chris@189: }
Chris@189: 
Chris@189: void
Chris@32: LEDButton::paintEvent(QPaintEvent *)
Chris@32: {
Chris@32:     QPainter paint;
Chris@32:     QColor color;
Chris@32:     QBrush brush;
Chris@32:     QPen pen;
Chris@32: 		
Chris@32:     // First of all we want to know what area should be updated
Chris@32:     // Initialize coordinates, width, and height of the LED
Chris@32:     int	width = this->width();
Chris@32: 
Chris@32:     // Make sure the LED is round!
Chris@32:     if (width > this->height())
Chris@32: 	width = this->height();
Chris@32:     width -= 2; // leave one pixel border
Chris@32:     if (width < 0) 
Chris@32: 	width = 0;
Chris@32: 
Chris@34:     QPixmap *tmpMap = 0;
Chris@34: 
Chris@34:     if (led_state) {
Chris@34: 	if (d->on_map) {
Chris@496:             if (d->on_map->size() == size()) {
Chris@496:                 paint.begin(this);
Chris@496:                 paint.drawPixmap(0, 0, *d->on_map);
Chris@496:                 paint.end();
Chris@496:                 return;
Chris@496:             } else {
Chris@496:                 delete d->on_map;
Chris@496:                 d->on_map = 0;
Chris@496:             }
Chris@34: 	}
Chris@34:     } else {
Chris@34: 	if (d->off_map) {
Chris@496:             if (d->off_map->size() == size()) {
Chris@496:                 paint.begin(this);
Chris@496:                 paint.drawPixmap(0, 0, *d->off_map);
Chris@496:                 paint.end();
Chris@496:                 return;
Chris@496:             } else {
Chris@496:                 delete d->off_map;
Chris@496:                 d->off_map = 0;
Chris@496:             }
Chris@34: 	}
Chris@34:     }
Chris@32: 
Chris@32:     int scale = 1;
Chris@34:     width *= scale;
Chris@32: 
Chris@34:     tmpMap = new QPixmap(width, width);
Chris@34:     tmpMap->fill(palette().background().color());
Chris@34:     paint.begin(tmpMap);
Chris@32: 
Chris@33:     paint.setRenderHint(QPainter::Antialiasing, true);
Chris@32: 
Chris@32:     // Set the color of the LED according to given parameters
Chris@32:     color = (led_state) ? led_color : d->offcolor;
Chris@32: 
Chris@32:     // Set the brush to SolidPattern, this fills the entire area
Chris@32:     // of the ellipse which is drawn first
Chris@32:     brush.setStyle(Qt::SolidPattern);
Chris@32:     brush.setColor(color);
Chris@32:     paint.setBrush(brush);
Chris@32: 
Chris@32:     // Draws a "flat" LED with the given color:
Chris@32:     paint.drawEllipse( scale, scale, width - scale*2, width - scale*2 );
Chris@32: 
Chris@32:     // Draw the bright light spot of the LED now, using modified "old"
Chris@32:     // painter routine taken from KDEUI�s LEDButton widget:
Chris@32: 
Chris@32:     // Setting the new width of the pen is essential to avoid "pixelized"
Chris@32:     // shadow like it can be observed with the old LED code
Chris@32:     pen.setWidth( 2 * scale );
Chris@32: 
Chris@32:     // shrink the light on the LED to a size about 2/3 of the complete LED
Chris@32:     int pos = width/5 + 1;
Chris@32:     int light_width = width;
Chris@32:     light_width *= 2;
Chris@32:     light_width /= 3;
Chris@32: 	
Chris@32:     // Calculate the LED�s "light factor":
Chris@32:     int light_quote = (130*2/(light_width?light_width:1))+100;
Chris@32: 
Chris@32:     // Now draw the bright spot on the LED:
Chris@32:     while (light_width) {
Chris@32: 	color = color.light( light_quote );                      // make color lighter
Chris@32: 	pen.setColor( color );                                   // set color as pen color
Chris@32: 	paint.setPen( pen );                                     // select the pen for drawing
Chris@32: 	paint.drawEllipse( pos, pos, light_width, light_width ); // draw the ellipse (circle)
Chris@32: 	light_width--;
Chris@32: 	if (!light_width)
Chris@32: 	    break;
Chris@32: 	paint.drawEllipse( pos, pos, light_width, light_width );
Chris@32: 	light_width--;
Chris@32: 	if (!light_width)
Chris@32: 	    break;
Chris@32: 	paint.drawEllipse( pos, pos, light_width, light_width );
Chris@32: 	pos++; light_width--;
Chris@32:     }
Chris@32: 
Chris@32:     // Drawing of bright spot finished, now draw a thin border
Chris@32:     // around the LED which resembles a shadow with light coming
Chris@32:     // from the upper left.
Chris@32: 
Chris@33: //    pen.setWidth( 2 * scale + 1 ); // ### shouldn't this value be smaller for smaller LEDs?
Chris@33:     pen.setWidth(2 * scale);
Chris@32:     brush.setStyle(Qt::NoBrush);
Chris@32:     paint.setBrush(brush); // This avoids filling of the ellipse
Chris@32: 
Chris@32:     // Set the initial color value to colorGroup().light() (bright) and start
Chris@32:     // drawing the shadow border at 45� (45*16 = 720).
Chris@32: 
Chris@32:     int angle = -720;
Chris@32:     color = palette().light().color();
Chris@32:     
Chris@32:     for (int arc = 120; arc < 2880; arc += 240) {
Chris@32: 	pen.setColor(color);
Chris@32: 	paint.setPen(pen);
Chris@32: 	int w = width - pen.width()/2 - scale + 1;
Chris@33: 	paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle + arc, 240);
Chris@33: 	paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle - arc, 240);
Chris@32: 	color = color.dark(110); //FIXME: this should somehow use the contrast value
Chris@32:     }	// end for ( angle = 720; angle < 6480; angle += 160 )
Chris@32: 
Chris@32:     paint.end();
Chris@32:     //
Chris@32:     // painting done
Chris@32: 
Chris@34:     QPixmap *&dest = led_state ? d->on_map : d->off_map;
Chris@34: 
Chris@34:     if (scale > 1) {
Chris@34: 
Chris@32: 	QImage i = tmpMap->toImage();
Chris@33: 	width /= scale;
Chris@32: 	delete tmpMap;
Chris@33: 	dest = new QPixmap(QPixmap::fromImage
Chris@33: 			   (i.scaled(width, width, 
Chris@33: 				     Qt::KeepAspectRatio,
Chris@33: 				     Qt::SmoothTransformation)));
Chris@34: 
Chris@34:     } else {
Chris@34: 
Chris@34: 	dest = tmpMap;
Chris@32:     }
Chris@34: 
Chris@34:     paint.begin(this);
Chris@34:     paint.drawPixmap(0, 0, *dest);
Chris@34:     paint.end();
Chris@32: }
Chris@32: 
Chris@34: bool
Chris@32: LEDButton::state() const
Chris@32: {
Chris@32:     return led_state;
Chris@32: }
Chris@32: 
Chris@32: QColor
Chris@32: LEDButton::color() const
Chris@32: {
Chris@32:     return led_color;
Chris@32: }
Chris@32: 
Chris@32: void
Chris@34: LEDButton::setState( bool state )
Chris@32: {
Chris@32:     if (led_state != state)
Chris@32:     {
Chris@32: 	led_state = state;
Chris@32: 	update();
Chris@32:     }
Chris@32: }
Chris@32: 
Chris@32: void
Chris@32: LEDButton::toggleState()
Chris@32: {
Chris@34:     led_state = (led_state == true) ? false : true;
Chris@32:     // setColor(led_color);
Chris@32:     update();
Chris@32: }
Chris@32: 
Chris@32: void
Chris@32: LEDButton::setColor(const QColor& col)
Chris@32: {
Chris@32:     if(led_color!=col) {
Chris@32: 	led_color = col;
Chris@32: 	d->offcolor = col.dark(d->dark_factor);
Chris@32: 	delete d->on_map;
Chris@32: 	d->on_map = 0;
Chris@32: 	delete d->off_map;
Chris@32: 	d->off_map = 0;
Chris@32: 	update();
Chris@32:     }
Chris@32: }
Chris@32: 
Chris@32: void
Chris@32: LEDButton::setDarkFactor(int darkfactor)
Chris@32: {
Chris@32:     if (d->dark_factor != darkfactor) {
Chris@32: 	d->dark_factor = darkfactor;
Chris@32: 	d->offcolor = led_color.dark(darkfactor);
Chris@32: 	update();
Chris@32:     }
Chris@32: }
Chris@32: 
Chris@32: int
Chris@32: LEDButton::darkFactor() const
Chris@32: {
Chris@32:     return d->dark_factor;
Chris@32: }
Chris@32: 
Chris@32: void
Chris@32: LEDButton::toggle()
Chris@32: {
Chris@32:     toggleState();
Chris@32: }
Chris@32: 
Chris@32: void
Chris@32: LEDButton::on()
Chris@32: {
Chris@34:     setState(true);
Chris@32: }
Chris@32: 
Chris@32: void
Chris@32: LEDButton::off()
Chris@32: {
Chris@34:     setState(false);
Chris@32: }
Chris@32: 
Chris@32: QSize
Chris@32: LEDButton::sizeHint() const
Chris@32: {
Chris@33:     return QSize(17, 17);
Chris@32: }
Chris@32: 
Chris@32: QSize
Chris@32: LEDButton::minimumSizeHint() const
Chris@32: {
Chris@33:     return QSize(17, 17);
Chris@32: }
Chris@32: