kselect.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1997 Martin Jones (mjones@kde.org) 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include <qimage.h> 00021 #include <qpainter.h> 00022 #include <qdrawutil.h> 00023 #include <qstyle.h> 00024 #include <kimageeffect.h> 00025 #include "kselect.h" 00026 00027 #define STORE_W 8 00028 #define STORE_W2 STORE_W * 2 00029 00030 //----------------------------------------------------------------------------- 00031 /* 00032 * 2D value selector. 00033 * The contents of the selector are drawn by derived class. 00034 */ 00035 00036 KXYSelector::KXYSelector( QWidget *parent, const char *name ) 00037 : QWidget( parent, name ) 00038 { 00039 xPos = 0; 00040 yPos = 0; 00041 minX = 0; 00042 minY = 0; 00043 maxX = 100; 00044 maxY = 100; 00045 store.setOptimization( QPixmap::BestOptim ); 00046 store.resize( STORE_W2, STORE_W2 ); 00047 } 00048 00049 00050 KXYSelector::~KXYSelector() 00051 {} 00052 00053 00054 void KXYSelector::setRange( int _minX, int _minY, int _maxX, int _maxY ) 00055 { 00056 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00057 px = w; 00058 py = w; 00059 minX = _minX; 00060 minY = _minY; 00061 maxX = _maxX; 00062 maxY = _maxY; 00063 } 00064 00065 void KXYSelector::setXValue( int _xPos ) 00066 { 00067 setValues(_xPos, yPos); 00068 } 00069 00070 void KXYSelector::setYValue( int _yPos ) 00071 { 00072 setValues(xPos, _yPos); 00073 } 00074 00075 void KXYSelector::setValues( int _xPos, int _yPos ) 00076 { 00077 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00078 if (w < 5) w = 5; 00079 00080 xPos = _xPos; 00081 yPos = _yPos; 00082 00083 if ( xPos > maxX ) 00084 xPos = maxX; 00085 else if ( xPos < minX ) 00086 xPos = minX; 00087 00088 if ( yPos > maxY ) 00089 yPos = maxY; 00090 else if ( yPos < minY ) 00091 yPos = minY; 00092 00093 int xp = w + (width() - 2 * w) * xPos / (maxX - minX); 00094 int yp = height() - w - (height() - 2 * w) * yPos / (maxY - minY); 00095 00096 setPosition( xp, yp ); 00097 } 00098 00099 QRect KXYSelector::contentsRect() const 00100 { 00101 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00102 if (w < 5) { 00103 w = 5; 00104 } 00105 QRect contents(rect()); 00106 contents.addCoords(w, w, -w, -w); 00107 return contents; 00108 } 00109 00110 void KXYSelector::paintEvent( QPaintEvent *ev ) 00111 { 00112 QRect cursorRect( px - STORE_W, py - STORE_W, STORE_W2, STORE_W2); 00113 QRect paintRect = ev->rect(); 00114 QRect borderRect = rect(); 00115 00116 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00117 if (w < 5) { 00118 w = 5 - w; 00119 } 00120 borderRect.addCoords(w, w, -w, -w); 00121 00122 QPainter painter; 00123 painter.begin( this ); 00124 00125 style().drawPrimitive(QStyle::PE_Panel, &painter, 00126 borderRect, colorGroup(), 00127 QStyle::Style_Sunken); 00128 00129 drawContents( &painter ); 00130 if (paintRect.contains(cursorRect)) 00131 { 00132 bitBlt( &store, 0, 0, this, px - STORE_W, py - STORE_W, 00133 STORE_W2, STORE_W2, CopyROP ); 00134 drawCursor( &painter, px, py ); 00135 } 00136 else if (paintRect.intersects(cursorRect)) 00137 { 00138 repaint( cursorRect, false); 00139 } 00140 00141 painter.end(); 00142 } 00143 00144 void KXYSelector::mousePressEvent( QMouseEvent *e ) 00145 { 00146 mouseMoveEvent(e); 00147 } 00148 00149 void KXYSelector::mouseMoveEvent( QMouseEvent *e ) 00150 { 00151 int xVal, yVal; 00152 00153 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00154 valuesFromPosition( e->pos().x() - w, e->pos().y() - w, xVal, yVal ); 00155 00156 setValues( xVal, yVal ); 00157 00158 emit valueChanged( xPos, yPos ); 00159 } 00160 00161 void KXYSelector::wheelEvent( QWheelEvent *e ) 00162 { 00163 if ( e->orientation() == Qt::Horizontal ) 00164 setValues( xValue() + e->delta()/120, yValue() ); 00165 else 00166 setValues( xValue(), yValue() + e->delta()/120 ); 00167 00168 emit valueChanged( xPos, yPos ); 00169 } 00170 00171 void KXYSelector::valuesFromPosition( int x, int y, int &xVal, int &yVal ) const 00172 { 00173 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00174 if (w < 5) w = 5; 00175 xVal = ( (maxX-minX) * (x-w) ) / ( width()-2*w ); 00176 yVal = maxY - ( ( (maxY-minY) * (y-w) ) / ( height()-2*w ) ); 00177 00178 if ( xVal > maxX ) 00179 xVal = maxX; 00180 else if ( xVal < minX ) 00181 xVal = minX; 00182 00183 if ( yVal > maxY ) 00184 yVal = maxY; 00185 else if ( yVal < minY ) 00186 yVal = minY; 00187 } 00188 00189 void KXYSelector::setPosition( int xp, int yp ) 00190 { 00191 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00192 if (w < 5) w = 5; 00193 if ( xp < w ) 00194 xp = w; 00195 else if ( xp > width() - w ) 00196 xp = width() - w; 00197 00198 if ( yp < w ) 00199 yp = w; 00200 else if ( yp > height() - w ) 00201 yp = height() - w; 00202 00203 QPainter painter; 00204 painter.begin( this ); 00205 00206 bitBlt( this, px - STORE_W, py - STORE_W, &store, 0, 0, 00207 STORE_W2, STORE_W2, CopyROP ); 00208 bitBlt( &store, 0, 0, this, xp - STORE_W, yp - STORE_W, 00209 STORE_W2, STORE_W2, CopyROP ); 00210 drawCursor( &painter, xp, yp ); 00211 px = xp; 00212 py = yp; 00213 00214 painter.end(); 00215 } 00216 00217 void KXYSelector::drawContents( QPainter * ) 00218 {} 00219 00220 00221 void KXYSelector::drawCursor( QPainter *p, int xp, int yp ) 00222 { 00223 p->setPen( QPen( white ) ); 00224 00225 p->drawLine( xp - 6, yp - 6, xp - 2, yp - 2 ); 00226 p->drawLine( xp - 6, yp + 6, xp - 2, yp + 2 ); 00227 p->drawLine( xp + 6, yp - 6, xp + 2, yp - 2 ); 00228 p->drawLine( xp + 6, yp + 6, xp + 2, yp + 2 ); 00229 } 00230 00231 //----------------------------------------------------------------------------- 00232 /* 00233 * 1D value selector with contents drawn by derived class. 00234 * See KColorDialog for example. 00235 */ 00236 00237 00238 KSelector::KSelector( QWidget *parent, const char *name ) 00239 : QWidget( parent, name ), QRangeControl() 00240 { 00241 _orientation = Horizontal; 00242 _indent = true; 00243 } 00244 00245 KSelector::KSelector( Orientation o, QWidget *parent, const char *name ) 00246 : QWidget( parent, name ), QRangeControl() 00247 { 00248 _orientation = o; 00249 _indent = true; 00250 } 00251 00252 00253 KSelector::~KSelector() 00254 {} 00255 00256 00257 QRect KSelector::contentsRect() const 00258 { 00259 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00260 int iw = (w < 5) ? 5 : w; 00261 if ( orientation() == Vertical ) 00262 return QRect( w, iw, width() - w * 2 - 5, height() - 2 * iw ); 00263 else 00264 return QRect( iw, w, width() - 2 * iw, height() - w * 2 - 5 ); 00265 } 00266 00267 void KSelector::paintEvent( QPaintEvent * ) 00268 { 00269 QPainter painter; 00270 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00271 int iw = (w < 5) ? 5 : w; 00272 00273 painter.begin( this ); 00274 00275 drawContents( &painter ); 00276 00277 if ( indent() ) 00278 { 00279 QRect r = rect(); 00280 if ( orientation() == Vertical ) 00281 r.addCoords(0, iw - w, -iw, w - iw); 00282 else 00283 r.addCoords(iw - w, 0, w - iw, -iw); 00284 style().drawPrimitive(QStyle::PE_Panel, &painter, 00285 r, colorGroup(), 00286 QStyle::Style_Sunken); 00287 } 00288 00289 QPoint pos = calcArrowPos( value() ); 00290 drawArrow( &painter, true, pos ); 00291 00292 painter.end(); 00293 } 00294 00295 void KSelector::mousePressEvent( QMouseEvent *e ) 00296 { 00297 moveArrow( e->pos() ); 00298 } 00299 00300 void KSelector::mouseMoveEvent( QMouseEvent *e ) 00301 { 00302 moveArrow( e->pos() ); 00303 } 00304 00305 void KSelector::wheelEvent( QWheelEvent *e ) 00306 { 00307 int val = value() + e->delta()/120; 00308 setValue( val ); 00309 } 00310 00311 void KSelector::valueChange() 00312 { 00313 QPainter painter; 00314 QPoint pos; 00315 00316 painter.begin( this ); 00317 00318 pos = calcArrowPos( prevValue() ); 00319 drawArrow( &painter, false, pos ); 00320 00321 pos = calcArrowPos( value() ); 00322 drawArrow( &painter, true, pos ); 00323 00324 painter.end(); 00325 00326 emit valueChanged( value() ); 00327 } 00328 00329 void KSelector::moveArrow( const QPoint &pos ) 00330 { 00331 int val; 00332 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00333 int iw = (w < 5) ? 5 : w; 00334 00335 if ( orientation() == Vertical ) 00336 val = ( maxValue() - minValue() ) * (height()-pos.y()-5+w) 00337 / (height()-iw*2) + minValue(); 00338 else 00339 val = ( maxValue() - minValue() ) * (width()-pos.x()-5+w) 00340 / (width()-iw*2) + minValue(); 00341 00342 setValue( val ); 00343 } 00344 00345 QPoint KSelector::calcArrowPos( int val ) 00346 { 00347 QPoint p; 00348 00349 int w = style().pixelMetric(QStyle::PM_DefaultFrameWidth); 00350 int iw = (w < 5) ? 5 : w; 00351 if ( orientation() == Vertical ) 00352 { 00353 p.setY( height() - ( (height()-2*iw) * val 00354 / ( maxValue() - minValue() ) + 5 ) ); 00355 p.setX( width() - 5 ); 00356 } 00357 else 00358 { 00359 p.setX( width() - ( (width()-2*iw) * val 00360 / ( maxValue() - minValue() ) + 5 ) ); 00361 p.setY( height() - 5 ); 00362 } 00363 00364 return p; 00365 } 00366 00367 void KSelector::drawContents( QPainter * ) 00368 {} 00369 00370 void KSelector::drawArrow( QPainter *painter, bool show, const QPoint &pos ) 00371 { 00372 if ( show ) 00373 { 00374 QPointArray array(3); 00375 00376 painter->setPen( QPen() ); 00377 painter->setBrush( QBrush( colorGroup().buttonText() ) ); 00378 array.setPoint( 0, pos.x()+0, pos.y()+0 ); 00379 array.setPoint( 1, pos.x()+5, pos.y()+5 ); 00380 if ( orientation() == Vertical ) 00381 { 00382 array.setPoint( 2, pos.x()+5, pos.y()-5 ); 00383 } 00384 else 00385 { 00386 array.setPoint( 2, pos.x()-5, pos.y()+5 ); 00387 } 00388 00389 painter->drawPolygon( array ); 00390 } 00391 else 00392 { 00393 if ( orientation() == Vertical ) 00394 { 00395 repaint(pos.x(), pos.y()-5, 6, 11, true); 00396 } 00397 else 00398 { 00399 repaint(pos.x()-5, pos.y(), 11, 6, true); 00400 } 00401 } 00402 } 00403 00404 //---------------------------------------------------------------------------- 00405 00406 KGradientSelector::KGradientSelector( QWidget *parent, const char *name ) 00407 : KSelector( parent, name ) 00408 { 00409 init(); 00410 } 00411 00412 00413 KGradientSelector::KGradientSelector( Orientation o, QWidget *parent, 00414 const char *name ) 00415 : KSelector( o, parent, name ) 00416 { 00417 init(); 00418 } 00419 00420 00421 KGradientSelector::~KGradientSelector() 00422 {} 00423 00424 00425 void KGradientSelector::init() 00426 { 00427 color1.setRgb( 0, 0, 0 ); 00428 color2.setRgb( 255, 255, 255 ); 00429 00430 text1 = text2 = ""; 00431 } 00432 00433 00434 void KGradientSelector::drawContents( QPainter *painter ) 00435 { 00436 QImage image( contentsRect().width(), contentsRect().height(), 32 ); 00437 00438 QColor col; 00439 float scale; 00440 00441 int redDiff = color2.red() - color1.red(); 00442 int greenDiff = color2.green() - color1.green(); 00443 int blueDiff = color2.blue() - color1.blue(); 00444 00445 if ( orientation() == Vertical ) 00446 { 00447 for ( int y = 0; y < image.height(); y++ ) 00448 { 00449 scale = 1.0 * y / image.height(); 00450 col.setRgb( color1.red() + int(redDiff*scale), 00451 color1.green() + int(greenDiff*scale), 00452 color1.blue() + int(blueDiff*scale) ); 00453 00454 unsigned int *p = (uint *) image.scanLine( y ); 00455 for ( int x = 0; x < image.width(); x++ ) 00456 *p++ = col.rgb(); 00457 } 00458 } 00459 else 00460 { 00461 unsigned int *p = (uint *) image.scanLine( 0 ); 00462 00463 for ( int x = 0; x < image.width(); x++ ) 00464 { 00465 scale = 1.0 * x / image.width(); 00466 col.setRgb( color1.red() + int(redDiff*scale), 00467 color1.green() + int(greenDiff*scale), 00468 color1.blue() + int(blueDiff*scale) ); 00469 *p++ = col.rgb(); 00470 } 00471 00472 for ( int y = 1; y < image.height(); y++ ) 00473 memcpy( image.scanLine( y ), image.scanLine( y - 1), 00474 sizeof( unsigned int ) * image.width() ); 00475 } 00476 00477 QColor ditherPalette[8]; 00478 00479 for ( int s = 0; s < 8; s++ ) 00480 ditherPalette[s].setRgb( color1.red() + redDiff * s / 8, 00481 color1.green() + greenDiff * s / 8, 00482 color1.blue() + blueDiff * s / 8 ); 00483 00484 KImageEffect::dither( image, ditherPalette, 8 ); 00485 00486 QPixmap p; 00487 p.convertFromImage( image ); 00488 00489 painter->drawPixmap( contentsRect().x(), contentsRect().y(), p ); 00490 00491 if ( orientation() == Vertical ) 00492 { 00493 int yPos = contentsRect().top() + painter->fontMetrics().ascent() + 2; 00494 int xPos = contentsRect().left() + (contentsRect().width() - 00495 painter->fontMetrics().width( text2 )) / 2; 00496 QPen pen( color2 ); 00497 painter->setPen( pen ); 00498 painter->drawText( xPos, yPos, text2 ); 00499 00500 yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; 00501 xPos = contentsRect().left() + (contentsRect().width() - 00502 painter->fontMetrics().width( text1 )) / 2; 00503 pen.setColor( color1 ); 00504 painter->setPen( pen ); 00505 painter->drawText( xPos, yPos, text1 ); 00506 } 00507 else 00508 { 00509 int yPos = contentsRect().bottom()-painter->fontMetrics().descent()-2; 00510 00511 QPen pen( color2 ); 00512 painter->setPen( pen ); 00513 painter->drawText( contentsRect().left() + 2, yPos, text1 ); 00514 00515 pen.setColor( color1 ); 00516 painter->setPen( pen ); 00517 painter->drawText( contentsRect().right() - 00518 painter->fontMetrics().width( text2 ) - 2, yPos, text2 ); 00519 } 00520 } 00521 00522 //----------------------------------------------------------------------------- 00523 00524 void KXYSelector::virtual_hook( int, void* ) 00525 { /*BASE::virtual_hook( id, data );*/ } 00526 00527 void KSelector::virtual_hook( int, void* ) 00528 { /*BASE::virtual_hook( id, data );*/ } 00529 00530 void KGradientSelector::virtual_hook( int id, void* data ) 00531 { KSelector::virtual_hook( id, data ); } 00532 00533 #include "kselect.moc" 00534