annotate widgets/LEDButton.cpp @ 33:651e4e868bcc

* Implement play mute, level and pan controls and a layer visibility control * Handle swapping the buffers in AudioCallbackPlaySource more gracefully, so that in many cases it can be done inaudibly. Still gets it wrong when playing in a noncontiguous selection. * Fix to SV file save for non-2d sparse models * Fixes to LED button drawing and AudioDial mouse functionality * Add progress bar for Ogg file import * Reshuffle PropertyContainer and its subclasses so it can be a QObject * Add layer dormancy (invisible layer permitted to free its cache space) * Optimisations to SpectrogramLayer, removing locks when reading/writing individual pixels in the cache (should be unnecessary there) -- there's still an issue here as we need a lock when reading from the model in case the model is replaced, and we don't currently have one * Several munlock() calls to make it harder to exhaust real memory if running in an RT mode with mlockall() active
author Chris Cannam
date Fri, 17 Feb 2006 18:04:26 +0000
parents c53b949ef142
children c43f2c4f66f2
rev   line source
Chris@32 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@32 2
Chris@32 3 /*
Chris@32 4 A waveform viewer and audio annotation editor.
Chris@32 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@32 6
Chris@32 7 This is experimental software. Not for distribution.
Chris@32 8 */
Chris@32 9
Chris@32 10 /*
Chris@32 11 This is a modified version of a source file from the KDE
Chris@32 12 libraries. Copyright (c) 1998-2004 Jörg Habenicht, Richard J
Chris@32 13 Moore, Chris Cannam and others, distributed under the GNU Lesser
Chris@32 14 General Public License.
Chris@32 15
Chris@32 16 Ported to Qt4 by Chris Cannam.
Chris@32 17 */
Chris@32 18
Chris@32 19
Chris@32 20 #include "LEDButton.h"
Chris@32 21
Chris@32 22 #include <QPainter>
Chris@32 23 #include <QImage>
Chris@32 24 #include <QColor>
Chris@33 25 #include <QMouseEvent>
Chris@32 26
Chris@32 27
Chris@32 28 class LEDButton::LEDButtonPrivate
Chris@32 29 {
Chris@32 30 friend class LEDButton;
Chris@32 31
Chris@32 32 int dark_factor;
Chris@32 33 QColor offcolor;
Chris@32 34 QPixmap *off_map;
Chris@32 35 QPixmap *on_map;
Chris@32 36 };
Chris@32 37
Chris@32 38
Chris@32 39 LEDButton::LEDButton(QWidget *parent) :
Chris@32 40 QWidget(parent),
Chris@32 41 led_state(On)
Chris@32 42 {
Chris@32 43 QColor col(Qt::green);
Chris@32 44 d = new LEDButton::LEDButtonPrivate;
Chris@32 45 d->dark_factor = 300;
Chris@32 46 d->offcolor = col.dark(300);
Chris@32 47 d->off_map = 0;
Chris@32 48 d->on_map = 0;
Chris@32 49
Chris@32 50 setColor(col);
Chris@32 51 }
Chris@32 52
Chris@32 53
Chris@32 54 LEDButton::LEDButton(const QColor& col, QWidget *parent) :
Chris@32 55 QWidget(parent),
Chris@32 56 led_state(On)
Chris@32 57 {
Chris@32 58 d = new LEDButton::LEDButtonPrivate;
Chris@32 59 d->dark_factor = 300;
Chris@32 60 d->offcolor = col.dark(300);
Chris@32 61 d->off_map = 0;
Chris@32 62 d->on_map = 0;
Chris@32 63
Chris@32 64 setColor(col);
Chris@32 65 }
Chris@32 66
Chris@32 67 LEDButton::LEDButton(const QColor& col, LEDButton::State state, QWidget *parent) :
Chris@32 68 QWidget(parent),
Chris@32 69 led_state(state)
Chris@32 70 {
Chris@32 71 d = new LEDButton::LEDButtonPrivate;
Chris@32 72 d->dark_factor = 300;
Chris@32 73 d->offcolor = col.dark(300);
Chris@32 74 d->off_map = 0;
Chris@32 75 d->on_map = 0;
Chris@32 76
Chris@32 77 setColor(col);
Chris@32 78 }
Chris@32 79
Chris@32 80 LEDButton::~LEDButton()
Chris@32 81 {
Chris@32 82 delete d->off_map;
Chris@32 83 delete d->on_map;
Chris@32 84 delete d;
Chris@32 85 }
Chris@32 86
Chris@32 87 void
Chris@33 88 LEDButton::mousePressEvent(QMouseEvent *e)
Chris@33 89 {
Chris@33 90 if (e->buttons() & Qt::LeftButton) {
Chris@33 91 toggle();
Chris@33 92 emit stateChanged(state());
Chris@33 93 }
Chris@33 94 }
Chris@33 95
Chris@33 96 void
Chris@32 97 LEDButton::paintEvent(QPaintEvent *)
Chris@32 98 {
Chris@32 99 QPainter paint;
Chris@32 100 QColor color;
Chris@32 101 QBrush brush;
Chris@32 102 QPen pen;
Chris@32 103
Chris@32 104 // First of all we want to know what area should be updated
Chris@32 105 // Initialize coordinates, width, and height of the LED
Chris@32 106 int width = this->width();
Chris@32 107
Chris@32 108 // Make sure the LED is round!
Chris@32 109 if (width > this->height())
Chris@32 110 width = this->height();
Chris@32 111 width -= 2; // leave one pixel border
Chris@32 112 if (width < 0)
Chris@32 113 width = 0;
Chris@32 114
Chris@32 115 // maybe we could stop HERE, if width <=0 ?
Chris@32 116
Chris@32 117 int scale = 1;
Chris@32 118 QPixmap *tmpMap = 0;
Chris@32 119 bool smooth = true;
Chris@32 120
Chris@32 121 if (smooth) {
Chris@32 122 if (led_state) {
Chris@32 123 if (d->on_map) {
Chris@32 124 paint.begin(this);
Chris@32 125 paint.drawPixmap(0, 0, *d->on_map);
Chris@32 126 paint.end();
Chris@32 127 return;
Chris@32 128 }
Chris@32 129 } else {
Chris@32 130 if (d->off_map) {
Chris@32 131 paint.begin(this);
Chris@32 132 paint.drawPixmap(0, 0, *d->off_map);
Chris@32 133 paint.end();
Chris@32 134 return;
Chris@32 135 }
Chris@32 136 }
Chris@32 137
Chris@33 138 scale = 1;
Chris@32 139 width *= scale;
Chris@32 140
Chris@32 141 tmpMap = new QPixmap(width, width);
Chris@32 142 tmpMap->fill(palette().background().color());
Chris@32 143 paint.begin(tmpMap);
Chris@32 144
Chris@32 145 } else {
Chris@32 146 paint.begin(this);
Chris@32 147 }
Chris@32 148
Chris@33 149 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@32 150
Chris@32 151 // Set the color of the LED according to given parameters
Chris@32 152 color = (led_state) ? led_color : d->offcolor;
Chris@32 153
Chris@32 154 // Set the brush to SolidPattern, this fills the entire area
Chris@32 155 // of the ellipse which is drawn first
Chris@32 156 brush.setStyle(Qt::SolidPattern);
Chris@32 157 brush.setColor(color);
Chris@32 158 paint.setBrush(brush);
Chris@32 159
Chris@32 160 // Draws a "flat" LED with the given color:
Chris@32 161 paint.drawEllipse( scale, scale, width - scale*2, width - scale*2 );
Chris@32 162
Chris@32 163 // Draw the bright light spot of the LED now, using modified "old"
Chris@32 164 // painter routine taken from KDEUI´s LEDButton widget:
Chris@32 165
Chris@32 166 // Setting the new width of the pen is essential to avoid "pixelized"
Chris@32 167 // shadow like it can be observed with the old LED code
Chris@32 168 pen.setWidth( 2 * scale );
Chris@32 169
Chris@32 170 // shrink the light on the LED to a size about 2/3 of the complete LED
Chris@32 171 int pos = width/5 + 1;
Chris@32 172 int light_width = width;
Chris@32 173 light_width *= 2;
Chris@32 174 light_width /= 3;
Chris@32 175
Chris@32 176 // Calculate the LED´s "light factor":
Chris@32 177 int light_quote = (130*2/(light_width?light_width:1))+100;
Chris@32 178
Chris@32 179 // Now draw the bright spot on the LED:
Chris@32 180 while (light_width) {
Chris@32 181 color = color.light( light_quote ); // make color lighter
Chris@32 182 pen.setColor( color ); // set color as pen color
Chris@32 183 paint.setPen( pen ); // select the pen for drawing
Chris@32 184 paint.drawEllipse( pos, pos, light_width, light_width ); // draw the ellipse (circle)
Chris@32 185 light_width--;
Chris@32 186 if (!light_width)
Chris@32 187 break;
Chris@32 188 paint.drawEllipse( pos, pos, light_width, light_width );
Chris@32 189 light_width--;
Chris@32 190 if (!light_width)
Chris@32 191 break;
Chris@32 192 paint.drawEllipse( pos, pos, light_width, light_width );
Chris@32 193 pos++; light_width--;
Chris@32 194 }
Chris@32 195
Chris@32 196 // Drawing of bright spot finished, now draw a thin border
Chris@32 197 // around the LED which resembles a shadow with light coming
Chris@32 198 // from the upper left.
Chris@32 199
Chris@33 200 // pen.setWidth( 2 * scale + 1 ); // ### shouldn't this value be smaller for smaller LEDs?
Chris@33 201 pen.setWidth(2 * scale);
Chris@32 202 brush.setStyle(Qt::NoBrush);
Chris@32 203 paint.setBrush(brush); // This avoids filling of the ellipse
Chris@32 204
Chris@32 205 // Set the initial color value to colorGroup().light() (bright) and start
Chris@32 206 // drawing the shadow border at 45° (45*16 = 720).
Chris@32 207
Chris@32 208 int angle = -720;
Chris@32 209 color = palette().light().color();
Chris@32 210
Chris@32 211 for (int arc = 120; arc < 2880; arc += 240) {
Chris@32 212 pen.setColor(color);
Chris@32 213 paint.setPen(pen);
Chris@32 214 int w = width - pen.width()/2 - scale + 1;
Chris@33 215 paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle + arc, 240);
Chris@33 216 paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle - arc, 240);
Chris@32 217 color = color.dark(110); //FIXME: this should somehow use the contrast value
Chris@32 218 } // end for ( angle = 720; angle < 6480; angle += 160 )
Chris@32 219
Chris@32 220 paint.end();
Chris@32 221 //
Chris@32 222 // painting done
Chris@32 223
Chris@32 224 if (smooth) {
Chris@32 225 QPixmap *&dest = led_state ? d->on_map : d->off_map;
Chris@32 226 QImage i = tmpMap->toImage();
Chris@33 227 width /= scale;
Chris@32 228 delete tmpMap;
Chris@33 229 dest = new QPixmap(QPixmap::fromImage
Chris@33 230 (i.scaled(width, width,
Chris@33 231 Qt::KeepAspectRatio,
Chris@33 232 Qt::SmoothTransformation)));
Chris@32 233 paint.begin(this);
Chris@32 234 paint.drawPixmap(0, 0, *dest);
Chris@32 235 paint.end();
Chris@32 236 }
Chris@32 237 }
Chris@32 238
Chris@32 239 LEDButton::State
Chris@32 240 LEDButton::state() const
Chris@32 241 {
Chris@32 242 return led_state;
Chris@32 243 }
Chris@32 244
Chris@32 245 QColor
Chris@32 246 LEDButton::color() const
Chris@32 247 {
Chris@32 248 return led_color;
Chris@32 249 }
Chris@32 250
Chris@32 251 void
Chris@32 252 LEDButton::setState( State state )
Chris@32 253 {
Chris@32 254 if (led_state != state)
Chris@32 255 {
Chris@32 256 led_state = state;
Chris@32 257 update();
Chris@32 258 }
Chris@32 259 }
Chris@32 260
Chris@32 261 void
Chris@32 262 LEDButton::toggleState()
Chris@32 263 {
Chris@32 264 led_state = (led_state == On) ? Off : On;
Chris@32 265 // setColor(led_color);
Chris@32 266 update();
Chris@32 267 }
Chris@32 268
Chris@32 269 void
Chris@32 270 LEDButton::setColor(const QColor& col)
Chris@32 271 {
Chris@32 272 if(led_color!=col) {
Chris@32 273 led_color = col;
Chris@32 274 d->offcolor = col.dark(d->dark_factor);
Chris@32 275 delete d->on_map;
Chris@32 276 d->on_map = 0;
Chris@32 277 delete d->off_map;
Chris@32 278 d->off_map = 0;
Chris@32 279 update();
Chris@32 280 }
Chris@32 281 }
Chris@32 282
Chris@32 283 void
Chris@32 284 LEDButton::setDarkFactor(int darkfactor)
Chris@32 285 {
Chris@32 286 if (d->dark_factor != darkfactor) {
Chris@32 287 d->dark_factor = darkfactor;
Chris@32 288 d->offcolor = led_color.dark(darkfactor);
Chris@32 289 update();
Chris@32 290 }
Chris@32 291 }
Chris@32 292
Chris@32 293 int
Chris@32 294 LEDButton::darkFactor() const
Chris@32 295 {
Chris@32 296 return d->dark_factor;
Chris@32 297 }
Chris@32 298
Chris@32 299 void
Chris@32 300 LEDButton::toggle()
Chris@32 301 {
Chris@32 302 toggleState();
Chris@32 303 }
Chris@32 304
Chris@32 305 void
Chris@32 306 LEDButton::on()
Chris@32 307 {
Chris@32 308 setState(On);
Chris@32 309 }
Chris@32 310
Chris@32 311 void
Chris@32 312 LEDButton::off()
Chris@32 313 {
Chris@32 314 setState(Off);
Chris@32 315 }
Chris@32 316
Chris@32 317 QSize
Chris@32 318 LEDButton::sizeHint() const
Chris@32 319 {
Chris@33 320 return QSize(17, 17);
Chris@32 321 }
Chris@32 322
Chris@32 323 QSize
Chris@32 324 LEDButton::minimumSizeHint() const
Chris@32 325 {
Chris@33 326 return QSize(17, 17);
Chris@32 327 }
Chris@32 328