annotate widgets/LEDButton.cpp @ 966:e297b7d752f2

Prevent selection being dragged beyond start/end of content
author Chris Cannam
date Thu, 21 May 2015 14:06:20 +0100
parents 1a0dfcbffaf1
children 04337eb34f23
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@32 2
Chris@32 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@32 7
Chris@59 8 This program is free software; you can redistribute it and/or
Chris@59 9 modify it under the terms of the GNU General Public License as
Chris@59 10 published by the Free Software Foundation; either version 2 of the
Chris@59 11 License, or (at your option) any later version. See the file
Chris@59 12 COPYING included with this distribution for more information.
Chris@32 13 */
Chris@32 14
Chris@32 15 /*
Chris@32 16 This is a modified version of a source file from the KDE
Chris@32 17 libraries. Copyright (c) 1998-2004 Jörg Habenicht, Richard J
Chris@32 18 Moore, Chris Cannam and others, distributed under the GNU Lesser
Chris@32 19 General Public License.
Chris@32 20
Chris@32 21 Ported to Qt4 by Chris Cannam.
Chris@32 22 */
Chris@32 23
Chris@32 24
Chris@32 25 #include "LEDButton.h"
Chris@32 26
Chris@32 27 #include <QPainter>
Chris@32 28 #include <QImage>
Chris@32 29 #include <QColor>
Chris@33 30 #include <QMouseEvent>
Chris@32 31
Chris@34 32 #include <iostream>
Chris@34 33
Chris@32 34
Chris@32 35 class LEDButton::LEDButtonPrivate
Chris@32 36 {
Chris@32 37 friend class LEDButton;
Chris@32 38
Chris@32 39 int dark_factor;
Chris@32 40 QColor offcolor;
Chris@32 41 QPixmap *off_map;
Chris@32 42 QPixmap *on_map;
Chris@32 43 };
Chris@32 44
Chris@32 45
Chris@32 46 LEDButton::LEDButton(QWidget *parent) :
Chris@32 47 QWidget(parent),
Chris@34 48 led_state(true)
Chris@32 49 {
Chris@32 50 QColor col(Qt::green);
Chris@32 51 d = new LEDButton::LEDButtonPrivate;
Chris@32 52 d->dark_factor = 300;
Chris@32 53 d->offcolor = col.dark(300);
Chris@32 54 d->off_map = 0;
Chris@32 55 d->on_map = 0;
Chris@32 56
Chris@32 57 setColor(col);
Chris@32 58 }
Chris@32 59
Chris@32 60
Chris@32 61 LEDButton::LEDButton(const QColor& col, QWidget *parent) :
Chris@32 62 QWidget(parent),
Chris@34 63 led_state(true)
Chris@32 64 {
Chris@32 65 d = new LEDButton::LEDButtonPrivate;
Chris@32 66 d->dark_factor = 300;
Chris@32 67 d->offcolor = col.dark(300);
Chris@32 68 d->off_map = 0;
Chris@32 69 d->on_map = 0;
Chris@32 70
Chris@32 71 setColor(col);
Chris@32 72 }
Chris@32 73
Chris@34 74 LEDButton::LEDButton(const QColor& col, bool state, QWidget *parent) :
Chris@32 75 QWidget(parent),
Chris@32 76 led_state(state)
Chris@32 77 {
Chris@32 78 d = new LEDButton::LEDButtonPrivate;
Chris@32 79 d->dark_factor = 300;
Chris@32 80 d->offcolor = col.dark(300);
Chris@32 81 d->off_map = 0;
Chris@32 82 d->on_map = 0;
Chris@32 83
Chris@32 84 setColor(col);
Chris@32 85 }
Chris@32 86
Chris@32 87 LEDButton::~LEDButton()
Chris@32 88 {
Chris@32 89 delete d->off_map;
Chris@32 90 delete d->on_map;
Chris@32 91 delete d;
Chris@32 92 }
Chris@32 93
Chris@32 94 void
Chris@33 95 LEDButton::mousePressEvent(QMouseEvent *e)
Chris@33 96 {
Chris@682 97 cerr << "LEDButton(" << this << ")::mousePressEvent" << endl;
Chris@34 98
Chris@33 99 if (e->buttons() & Qt::LeftButton) {
Chris@33 100 toggle();
Chris@34 101 bool newState = state();
Chris@587 102 SVDEBUG << "emitting new state " << newState << endl;
Chris@34 103 emit stateChanged(newState);
Chris@33 104 }
Chris@33 105 }
Chris@33 106
Chris@33 107 void
Chris@189 108 LEDButton::enterEvent(QEvent *)
Chris@189 109 {
Chris@189 110 emit mouseEntered();
Chris@189 111 }
Chris@189 112
Chris@189 113 void
Chris@189 114 LEDButton::leaveEvent(QEvent *)
Chris@189 115 {
Chris@189 116 emit mouseLeft();
Chris@189 117 }
Chris@189 118
Chris@189 119 void
Chris@32 120 LEDButton::paintEvent(QPaintEvent *)
Chris@32 121 {
Chris@32 122 QPainter paint;
Chris@32 123 QColor color;
Chris@32 124 QBrush brush;
Chris@32 125 QPen pen;
Chris@32 126
Chris@32 127 // First of all we want to know what area should be updated
Chris@32 128 // Initialize coordinates, width, and height of the LED
Chris@32 129 int width = this->width();
Chris@32 130
Chris@32 131 // Make sure the LED is round!
Chris@32 132 if (width > this->height())
Chris@32 133 width = this->height();
Chris@32 134 width -= 2; // leave one pixel border
Chris@32 135 if (width < 0)
Chris@32 136 width = 0;
Chris@32 137
Chris@34 138 QPixmap *tmpMap = 0;
Chris@34 139
Chris@34 140 if (led_state) {
Chris@34 141 if (d->on_map) {
Chris@496 142 if (d->on_map->size() == size()) {
Chris@496 143 paint.begin(this);
Chris@496 144 paint.drawPixmap(0, 0, *d->on_map);
Chris@496 145 paint.end();
Chris@496 146 return;
Chris@496 147 } else {
Chris@496 148 delete d->on_map;
Chris@496 149 d->on_map = 0;
Chris@496 150 }
Chris@34 151 }
Chris@34 152 } else {
Chris@34 153 if (d->off_map) {
Chris@496 154 if (d->off_map->size() == size()) {
Chris@496 155 paint.begin(this);
Chris@496 156 paint.drawPixmap(0, 0, *d->off_map);
Chris@496 157 paint.end();
Chris@496 158 return;
Chris@496 159 } else {
Chris@496 160 delete d->off_map;
Chris@496 161 d->off_map = 0;
Chris@496 162 }
Chris@34 163 }
Chris@34 164 }
Chris@32 165
Chris@32 166 int scale = 1;
Chris@34 167 width *= scale;
Chris@32 168
Chris@34 169 tmpMap = new QPixmap(width, width);
Chris@34 170 tmpMap->fill(palette().background().color());
Chris@34 171 paint.begin(tmpMap);
Chris@32 172
Chris@33 173 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@32 174
Chris@32 175 // Set the color of the LED according to given parameters
Chris@32 176 color = (led_state) ? led_color : d->offcolor;
Chris@32 177
Chris@32 178 // Set the brush to SolidPattern, this fills the entire area
Chris@32 179 // of the ellipse which is drawn first
Chris@32 180 brush.setStyle(Qt::SolidPattern);
Chris@32 181 brush.setColor(color);
Chris@32 182 paint.setBrush(brush);
Chris@32 183
Chris@32 184 // Draws a "flat" LED with the given color:
Chris@32 185 paint.drawEllipse( scale, scale, width - scale*2, width - scale*2 );
Chris@32 186
Chris@32 187 // Draw the bright light spot of the LED now, using modified "old"
Chris@32 188 // painter routine taken from KDEUI´s LEDButton widget:
Chris@32 189
Chris@32 190 // Setting the new width of the pen is essential to avoid "pixelized"
Chris@32 191 // shadow like it can be observed with the old LED code
Chris@32 192 pen.setWidth( 2 * scale );
Chris@32 193
Chris@32 194 // shrink the light on the LED to a size about 2/3 of the complete LED
Chris@32 195 int pos = width/5 + 1;
Chris@32 196 int light_width = width;
Chris@32 197 light_width *= 2;
Chris@32 198 light_width /= 3;
Chris@32 199
Chris@32 200 // Calculate the LED´s "light factor":
Chris@32 201 int light_quote = (130*2/(light_width?light_width:1))+100;
Chris@32 202
Chris@32 203 // Now draw the bright spot on the LED:
Chris@32 204 while (light_width) {
Chris@32 205 color = color.light( light_quote ); // make color lighter
Chris@32 206 pen.setColor( color ); // set color as pen color
Chris@32 207 paint.setPen( pen ); // select the pen for drawing
Chris@32 208 paint.drawEllipse( pos, pos, light_width, light_width ); // draw the ellipse (circle)
Chris@32 209 light_width--;
Chris@32 210 if (!light_width)
Chris@32 211 break;
Chris@32 212 paint.drawEllipse( pos, pos, light_width, light_width );
Chris@32 213 light_width--;
Chris@32 214 if (!light_width)
Chris@32 215 break;
Chris@32 216 paint.drawEllipse( pos, pos, light_width, light_width );
Chris@32 217 pos++; light_width--;
Chris@32 218 }
Chris@32 219
Chris@32 220 // Drawing of bright spot finished, now draw a thin border
Chris@32 221 // around the LED which resembles a shadow with light coming
Chris@32 222 // from the upper left.
Chris@32 223
Chris@33 224 // pen.setWidth( 2 * scale + 1 ); // ### shouldn't this value be smaller for smaller LEDs?
Chris@33 225 pen.setWidth(2 * scale);
Chris@32 226 brush.setStyle(Qt::NoBrush);
Chris@32 227 paint.setBrush(brush); // This avoids filling of the ellipse
Chris@32 228
Chris@32 229 // Set the initial color value to colorGroup().light() (bright) and start
Chris@32 230 // drawing the shadow border at 45° (45*16 = 720).
Chris@32 231
Chris@32 232 int angle = -720;
Chris@32 233 color = palette().light().color();
Chris@32 234
Chris@32 235 for (int arc = 120; arc < 2880; arc += 240) {
Chris@32 236 pen.setColor(color);
Chris@32 237 paint.setPen(pen);
Chris@32 238 int w = width - pen.width()/2 - scale + 1;
Chris@33 239 paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle + arc, 240);
Chris@33 240 paint.drawArc(pen.width()/2 + 1, pen.width()/2 + 1, w - 2, w - 2, angle - arc, 240);
Chris@32 241 color = color.dark(110); //FIXME: this should somehow use the contrast value
Chris@32 242 } // end for ( angle = 720; angle < 6480; angle += 160 )
Chris@32 243
Chris@32 244 paint.end();
Chris@32 245 //
Chris@32 246 // painting done
Chris@32 247
Chris@34 248 QPixmap *&dest = led_state ? d->on_map : d->off_map;
Chris@34 249
Chris@34 250 if (scale > 1) {
Chris@34 251
Chris@32 252 QImage i = tmpMap->toImage();
Chris@33 253 width /= scale;
Chris@32 254 delete tmpMap;
Chris@33 255 dest = new QPixmap(QPixmap::fromImage
Chris@33 256 (i.scaled(width, width,
Chris@33 257 Qt::KeepAspectRatio,
Chris@33 258 Qt::SmoothTransformation)));
Chris@34 259
Chris@34 260 } else {
Chris@34 261
Chris@34 262 dest = tmpMap;
Chris@32 263 }
Chris@34 264
Chris@34 265 paint.begin(this);
Chris@34 266 paint.drawPixmap(0, 0, *dest);
Chris@34 267 paint.end();
Chris@32 268 }
Chris@32 269
Chris@34 270 bool
Chris@32 271 LEDButton::state() const
Chris@32 272 {
Chris@32 273 return led_state;
Chris@32 274 }
Chris@32 275
Chris@32 276 QColor
Chris@32 277 LEDButton::color() const
Chris@32 278 {
Chris@32 279 return led_color;
Chris@32 280 }
Chris@32 281
Chris@32 282 void
Chris@34 283 LEDButton::setState( bool state )
Chris@32 284 {
Chris@32 285 if (led_state != state)
Chris@32 286 {
Chris@32 287 led_state = state;
Chris@32 288 update();
Chris@32 289 }
Chris@32 290 }
Chris@32 291
Chris@32 292 void
Chris@32 293 LEDButton::toggleState()
Chris@32 294 {
Chris@34 295 led_state = (led_state == true) ? false : true;
Chris@32 296 // setColor(led_color);
Chris@32 297 update();
Chris@32 298 }
Chris@32 299
Chris@32 300 void
Chris@32 301 LEDButton::setColor(const QColor& col)
Chris@32 302 {
Chris@32 303 if(led_color!=col) {
Chris@32 304 led_color = col;
Chris@32 305 d->offcolor = col.dark(d->dark_factor);
Chris@32 306 delete d->on_map;
Chris@32 307 d->on_map = 0;
Chris@32 308 delete d->off_map;
Chris@32 309 d->off_map = 0;
Chris@32 310 update();
Chris@32 311 }
Chris@32 312 }
Chris@32 313
Chris@32 314 void
Chris@32 315 LEDButton::setDarkFactor(int darkfactor)
Chris@32 316 {
Chris@32 317 if (d->dark_factor != darkfactor) {
Chris@32 318 d->dark_factor = darkfactor;
Chris@32 319 d->offcolor = led_color.dark(darkfactor);
Chris@32 320 update();
Chris@32 321 }
Chris@32 322 }
Chris@32 323
Chris@32 324 int
Chris@32 325 LEDButton::darkFactor() const
Chris@32 326 {
Chris@32 327 return d->dark_factor;
Chris@32 328 }
Chris@32 329
Chris@32 330 void
Chris@32 331 LEDButton::toggle()
Chris@32 332 {
Chris@32 333 toggleState();
Chris@32 334 }
Chris@32 335
Chris@32 336 void
Chris@32 337 LEDButton::on()
Chris@32 338 {
Chris@34 339 setState(true);
Chris@32 340 }
Chris@32 341
Chris@32 342 void
Chris@32 343 LEDButton::off()
Chris@32 344 {
Chris@34 345 setState(false);
Chris@32 346 }
Chris@32 347
Chris@32 348 QSize
Chris@32 349 LEDButton::sizeHint() const
Chris@32 350 {
Chris@33 351 return QSize(17, 17);
Chris@32 352 }
Chris@32 353
Chris@32 354 QSize
Chris@32 355 LEDButton::minimumSizeHint() const
Chris@32 356 {
Chris@33 357 return QSize(17, 17);
Chris@32 358 }
Chris@32 359