You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/gui/kdeext/RGLed.cpp

728 lines
19 KiB

/* This file is a modified version of kled.cpp, which is part of the
KDE libraries. The modifications (for "brute-force" antialiasing)
were carried out by Chris Cannam, April 2004.
Copyright (C) 1998 J<>rg Habenicht (j.habenicht@europemail.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/*************************************************************************
* $Id: rgled.cpp 6694 2005-07-17 11:42:36Z cannam $
*
* $Log$
* Revision 1.2 2005/07/17 11:42:36 cannam
* * fixes from stg branch:
* - fix failure to recolour led when switching track from audio to midi or vice versa
* - fix colour number / menu index confusion in spb colour menu
*
* Revision 1.1.10.1 2005/07/17 00:00:30 cannam
*
* * merge across from HEAD to 17/07/2005
* * appearance fixes
*
* Revision 1.1 2004/04/05 09:54:05 cannam
*
* * antialiased LEDs
*
* Revision 1.24 2002/12/16 15:10:03 mkretz
* don't use a gray background but rather take the color from the current
* colorscheme
*
* Revision 1.23 2002/03/04 00:51:49 lunakl
* Keep BC changes (the patch is almost 100KiB of boring stuff
* ... anybody willing to review? ;) ).
*
* Revision 1.22 2002/02/27 23:15:45 pfeiffer
* kapp--
*
* Revision 1.21 2002/01/22 10:23:55 hausmann
* - minor API fix (don't return a const TQColor object)
*
* Revision 1.20 2001/10/10 17:40:39 mueller
* CVS_SILENT: fixincludes
*
* Revision 1.19 2001/08/08 14:35:12 hausmann
* - removed empty TDEActionCollection::childEvent
* - added sizeHint() and minimumSizeHint() methods to KLed, as advised by
* Rik in the comment in kled.h
* - removed unused mousePressEvent, mouseMoveEvent and mouseReleaseEvent
* handlers from KPassDlg
* - merged TDEToolBar::insertSeparator() and TDEToolBar::insertLineSeparator()
* with their overloaded variants
*
* Revision 1.18 2001/04/16 22:08:43 pfeiffer
* don't assume that the first item of an enum is 0
*
* Revision 1.17 2000/09/12 19:15:53 pfeiffer
* Stefan Hellwig in cooperation with Joerg Habenicht:
* Draw nicer LEDs, especially sunken ones.
*
* Revision 1.16 2000/08/24 12:44:48 porten
* "friend class" patches from Thomas Kunert <kunert@physik.tu-dresden.de>
*
* Revision 1.15 2000/08/17 16:44:44 reggie
* Don't crash
*
* Revision 1.14 2000/06/03 01:04:42 gehrmab
* * Made drawing routines available for overriding
* * Added a parent/name constructor
* * Propertyfication
*
* Revision 1.13 2000/05/08 19:38:49 sschiman
* Calling setColor before setting up the private data is a bad idea ;-)
*
* Revision 1.12 2000/05/07 09:49:57 habenich
* provided method to set the factor to dark the LED
* precalculated the dark color, is just retrieved at paint events
*
* Revision 1.11 2000/04/09 16:08:33 habenich
* fixed nasty bug #70 disappearing led
* reenabled flat and raised led painting
*
* Revision 1.10 1999/12/25 17:12:18 mirko
* Modified Look "round" to "raised", as the others are flat and
* sunken. All enums start with uppercase letters now to fit the overall
* KDE style.
* Implemented raised rectangluar look.
* --Mirko.
*
* Revision 1.9 1999/11/12 21:17:09 antlarr
* Fixed some bugs.
* Added the possibility to draw a sunk rectangle as the "old" KLedLamp did.
*
* Revision 1.9 1999/11/11 16:08:15 antlarr
* Fixed some bugs.
* Added the possibility to draw a sunk rectangle as the "old" KLedLamp did.
*
* Revision 1.8 1999/11/01 22:03:15 dmuell
* fixing all kinds of compile warnings
* (unused var, unused argument etc)
*
* Revision 1.7 1999/10/10 13:34:14 mirko
* First merge with KLedLamp that shows a rectangular LED.
* It does not yet work reliably.
*
* Revision 1.6 1999/03/01 23:34:49 kulow
* CVS_SILENT ported to TQt 2.0
*
* Revision 1.5 1999/02/19 08:52:42 habenich
* ID und LOG tags included
*
*
*************************************************************************/
#define PAINT_BENCH
#undef PAINT_BENCH
#ifdef PAINT_BENCH
#include <tqdatetime.h>
#include <stdio.h>
#endif
#include <tqpainter.h>
#include <tqimage.h>
#include <tqcolor.h>
#include <tdeapplication.h>
#include <kpixmapeffect.h>
#include "kled.h"
class KLed::KLedPrivate
{
friend class KLed;
int dark_factor;
TQColor offcolor;
TQPixmap *off_map;
TQPixmap *on_map;
};
KLed::KLed(TQWidget *parent, const char *name)
: TQWidget( parent, name),
led_state(On),
led_look(Raised),
led_shape(Circular)
{
TQColor col(green);
d = new KLed::KLedPrivate;
d->dark_factor = 300;
d->offcolor = col.dark(300);
d->off_map = 0;
d->on_map = 0;
setColor(col);
}
KLed::KLed(const TQColor& col, TQWidget *parent, const char *name)
: TQWidget( parent, name),
led_state(On),
led_look(Raised),
led_shape(Circular)
{
d = new KLed::KLedPrivate;
d->dark_factor = 300;
d->offcolor = col.dark(300);
d->off_map = 0;
d->on_map = 0;
setColor(col);
//setShape(Circular);
}
KLed::KLed(const TQColor& col, KLed::State state,
KLed::Look look, KLed::Shape shape, TQWidget *parent, const char *name )
: TQWidget(parent, name),
led_state(state),
led_look(look),
led_shape(shape)
{
d = new KLed::KLedPrivate;
d->dark_factor = 300;
d->offcolor = col.dark(300);
d->off_map = 0;
d->on_map = 0;
//setShape(shape);
setColor(col);
}
KLed::~KLed()
{
delete d->off_map;
delete d->on_map;
delete d;
}
void
KLed::paintEvent(TQPaintEvent *)
{
#ifdef PAINT_BENCH
const int rounds = 1000;
TQTime t;
t.start();
for (int i = 0; i < rounds; i++) {
#endif
switch (led_shape) {
case Rectangular:
switch (led_look) {
case Sunken :
paintRectFrame(false);
break;
case Raised :
paintRectFrame(true);
break;
case Flat :
paintRect();
break;
default :
tqWarning("%s: in class KLed: no KLed::Look set", tqApp->argv()[0]);
}
break;
case Circular:
switch (led_look) {
case Flat :
paintFlat();
break;
case Raised :
paintRound();
break;
case Sunken :
paintSunken();
break;
default:
tqWarning("%s: in class KLed: no KLed::Look set", tqApp->argv()[0]);
}
break;
default:
tqWarning("%s: in class KLed: no KLed::Shape set", tqApp->argv()[0]);
break;
}
#ifdef PAINT_BENCH
}
int ready = t.elapsed();
tqWarning("elapsed: %d msec. for %d rounds", ready, rounds);
#endif
}
void
KLed::paintFlat() // paint a ROUND FLAT led lamp
{
TQPainter paint;
TQColor color;
TQBrush brush;
TQPen pen;
// Initialize coordinates, width, and height of the LED
//
int width = this->width();
// Make sure the LED is round!
if (width > this->height())
width = this->height();
width -= 2; // leave one pixel border
if (width < 0)
width = 0;
// start painting widget
//
paint.begin( this );
// Set the color of the LED according to given parameters
color = ( led_state ) ? led_color : d->offcolor;
// Set the brush to SolidPattern, this fills the entire area
// of the ellipse which is drawn with a thin grey "border" (pen)
brush.setStyle( TQt::SolidPattern );
brush.setColor( color );
pen.setWidth( 1 );
color = colorGroup().dark();
pen.setColor( color ); // Set the pen accordingly
paint.setPen( pen ); // Select pen for drawing
paint.setBrush( brush ); // Assign the brush to the painter
// Draws a "flat" LED with the given color:
paint.drawEllipse( 1, 1, width, width );
paint.end();
//
// painting done
}
void
KLed::paintRound() // paint a ROUND RAISED led lamp
{
TQPainter paint;
TQColor color;
TQBrush brush;
TQPen pen;
// Initialize coordinates, width, and height of the LED
int width = this->width();
// Make sure the LED is round!
if (width > this->height())
width = this->height();
width -= 2; // leave one pixel border
if (width < 0)
width = 0;
// start painting widget
//
paint.begin( this );
// Set the color of the LED according to given parameters
color = ( led_state ) ? led_color : d->offcolor;
// Set the brush to SolidPattern, this fills the entire area
// of the ellipse which is drawn first
brush.setStyle( TQt::SolidPattern );
brush.setColor( color );
paint.setBrush( brush ); // Assign the brush to the painter
// Draws a "flat" LED with the given color:
paint.drawEllipse( 1, 1, width, width );
// Draw the bright light spot of the LED now, using modified "old"
// painter routine taken from TDEUI<55>s KLed widget:
// Setting the new width of the pen is essential to avoid "pixelized"
// shadow like it can be observed with the old LED code
pen.setWidth( 2 );
// shrink the light on the LED to a size about 2/3 of the complete LED
int pos = width / 5 + 1;
int light_width = width;
light_width *= 2;
light_width /= 3;
// Calculate the LED<45>s "light factor":
int light_quote = (130 * 2 / (light_width ? light_width : 1)) + 100;
// Now draw the bright spot on the LED:
while (light_width)
{
color = color.light( light_quote ); // make color lighter
pen.setColor( color ); // set color as pen color
paint.setPen( pen ); // select the pen for drawing
paint.drawEllipse( pos, pos, light_width, light_width ); // draw the ellipse (circle)
light_width--;
if (!light_width)
break;
paint.drawEllipse( pos, pos, light_width, light_width );
light_width--;
if (!light_width)
break;
paint.drawEllipse( pos, pos, light_width, light_width );
pos++;
light_width--;
}
// Drawing of bright spot finished, now draw a thin grey border
// around the LED; it looks nicer that way. We do this here to
// avoid that the border can be erased by the bright spot of the LED
pen.setWidth( 1 );
color = colorGroup().dark();
pen.setColor( color ); // Set the pen accordingly
paint.setPen( pen ); // Select pen for drawing
brush.setStyle( TQt::NoBrush ); // Switch off the brush
paint.setBrush( brush ); // This avoids filling of the ellipse
paint.drawEllipse( 1, 1, width, width );
paint.end();
//
// painting done
}
void
KLed::paintSunken() // paint a ROUND SUNKEN led lamp
{
TQPainter paint;
TQColor color;
TQBrush brush;
TQPen pen;
// First of all we want to know what area should be updated
// Initialize coordinates, width, and height of the LED
int width = this->width();
// Make sure the LED is round!
if (width > this->height())
width = this->height();
width -= 2; // leave one pixel border
if (width < 0)
width = 0;
// maybe we could stop HERE, if width <=0 ?
int scale = 1;
TQPixmap *tmpMap = 0;
bool smooth = true;
if (smooth)
{
if (led_state) {
if (d->on_map) {
paint.begin(this);
paint.drawPixmap(0, 0, *d->on_map);
paint.end();
return ;
}
} else {
if (d->off_map) {
paint.begin(this);
paint.drawPixmap(0, 0, *d->off_map);
paint.end();
return ;
}
}
scale = 3;
width *= scale;
tmpMap = new TQPixmap(width, width);
tmpMap->fill(paletteBackgroundColor());
paint.begin(tmpMap);
} else
{
paint.begin(this);
}
// Set the color of the LED according to given parameters
color = ( led_state ) ? led_color : d->offcolor;
// Set the brush to SolidPattern, this fills the entire area
// of the ellipse which is drawn first
brush.setStyle( TQt::SolidPattern );
brush.setColor( color );
paint.setBrush( brush ); // Assign the brush to the painter
// Draws a "flat" LED with the given color:
paint.drawEllipse( scale, scale, width - scale*2, width - scale*2 );
// Draw the bright light spot of the LED now, using modified "old"
// painter routine taken from TDEUI<55>s KLed widget:
// Setting the new width of the pen is essential to avoid "pixelized"
// shadow like it can be observed with the old LED code
pen.setWidth( 2 * scale );
// shrink the light on the LED to a size about 2/3 of the complete LED
int pos = width / 5 + 1;
int light_width = width;
light_width *= 2;
light_width /= 3;
// Calculate the LED<45>s "light factor":
int light_quote = (130 * 2 / (light_width ? light_width : 1)) + 100;
// Now draw the bright spot on the LED:
while (light_width)
{
color = color.light( light_quote ); // make color lighter
pen.setColor( color ); // set color as pen color
paint.setPen( pen ); // select the pen for drawing
paint.drawEllipse( pos, pos, light_width, light_width ); // draw the ellipse (circle)
light_width--;
if (!light_width)
break;
paint.drawEllipse( pos, pos, light_width, light_width );
light_width--;
if (!light_width)
break;
paint.drawEllipse( pos, pos, light_width, light_width );
pos++;
light_width--;
}
// Drawing of bright spot finished, now draw a thin border
// around the LED which resembles a shadow with light coming
// from the upper left.
pen.setWidth( 2 * scale + 1 ); // ### shouldn't this value be smaller for smaller LEDs?
brush.setStyle( TQt::NoBrush ); // Switch off the brush
paint.setBrush( brush ); // This avoids filling of the ellipse
// Set the initial color value to colorGroup().light() (bright) and start
// drawing the shadow border at 45<34> (45*16 = 720).
int angle = -720;
color = colorGroup().light();
for ( int arc = 120; arc < 2880; arc += 240 )
{
pen.setColor( color );
paint.setPen( pen );
int w = width - pen.width() / 2 - scale + 1;
paint.drawArc( pen.width() / 2, pen.width() / 2, w, w, angle + arc, 240 );
paint.drawArc( pen.width() / 2, pen.width() / 2, w, w, angle - arc, 240 );
color = color.dark( 110 ); //FIXME: this should somehow use the contrast value
} // end for ( angle = 720; angle < 6480; angle += 160 )
paint.end();
//
// painting done
if (smooth)
{
TQPixmap *&dest = led_state ? d->on_map : d->off_map;
TQImage i = tmpMap->convertToImage();
width /= 3;
i = i.smoothScale(width, width);
delete tmpMap;
dest = new TQPixmap(i);
paint.begin(this);
paint.drawPixmap(0, 0, *dest);
paint.end();
}
}
void
KLed::paintRect()
{
TQPainter painter(this);
TQBrush lightBrush(led_color);
TQBrush darkBrush(d->offcolor);
TQPen pen(led_color.dark(300));
int w = width();
int h = height();
// -----
switch (led_state) {
case On:
painter.setBrush(lightBrush);
painter.drawRect(0, 0, w, h);
break;
case Off:
painter.setBrush(darkBrush);
painter.drawRect(0, 0, w, h);
painter.setPen(pen);
painter.drawLine(0, 0, w, 0);
painter.drawLine(0, h - 1, w, h - 1);
// Draw verticals
int i;
for (i = 0; i < w; i += 4 /* dx */)
painter.drawLine(i, 1, i, h - 1);
break;
default:
break;
}
}
void
KLed::paintRectFrame(bool raised)
{
TQPainter painter(this);
TQBrush lightBrush(led_color);
TQBrush darkBrush(d->offcolor);
int w = width();
int h = height();
TQColor black = TQt::black;
TQColor white = TQt::white;
// -----
if (raised) {
painter.setPen(white);
painter.drawLine(0, 0, 0, h - 1);
painter.drawLine(1, 0, w - 1, 0);
painter.setPen(black);
painter.drawLine(1, h - 1, w - 1, h - 1);
painter.drawLine(w - 1, 1, w - 1, h - 1);
painter.fillRect(1, 1, w - 2, h - 2,
(led_state == On) ? lightBrush : darkBrush);
} else {
painter.setPen(black);
painter.drawRect(0, 0, w, h);
painter.drawRect(0, 0, w - 1, h - 1);
painter.setPen(white);
painter.drawRect(1, 1, w - 1, h - 1);
painter.fillRect(2, 2, w - 4, h - 4,
(led_state == On) ? lightBrush : darkBrush);
}
}
KLed::State
KLed::state() const
{
return led_state;
}
KLed::Shape
KLed::shape() const
{
return led_shape;
}
TQColor
KLed::color() const
{
return led_color;
}
KLed::Look
KLed::look() const
{
return led_look;
}
void
KLed::setState( State state )
{
if (led_state != state) {
led_state = state;
update();
}
}
void
KLed::toggleState()
{
led_state = (led_state == On) ? Off : On;
// setColor(led_color);
update();
}
void
KLed::setShape(KLed::Shape s)
{
if (led_shape != s) {
led_shape = s;
update();
}
}
void
KLed::setColor(const TQColor& col)
{
if (led_color != col) {
led_color = col;
d->offcolor = col.dark(d->dark_factor);
delete d->on_map;
d->on_map = 0;
delete d->off_map;
d->off_map = 0;
update();
}
}
void
KLed::setDarkFactor(int darkfactor)
{
if (d->dark_factor != darkfactor) {
d->dark_factor = darkfactor;
d->offcolor = led_color.dark(darkfactor);
update();
}
}
int
KLed::darkFactor() const
{
return d->dark_factor;
}
void
KLed::setLook( Look look )
{
if (led_look != look) {
led_look = look;
update();
}
}
void
KLed::toggle()
{
toggleState();
}
void
KLed::on()
{
setState(On);
}
void
KLed::off()
{
setState(Off);
}
TQSize
KLed::sizeHint() const
{
return TQSize(16, 16);
}
TQSize
KLed::minimumSizeHint() const
{
return TQSize(16, 16 );
}
void KLed::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/
}