summaryrefslogtreecommitdiff
authorsandman <sandman>2002-11-01 16:07:10 (UTC)
committer sandman <sandman>2002-11-01 16:07:10 (UTC)
commit9e4d914ade0af86707531a80e93a870e52738ce6 (patch) (side-by-side diff)
tree13bcdec43e9d1afc7392ce44cd72ff1289f0c8eb
parent28b70b2b7f8fa03ba0991fb73dccf7b46e5c3d1f (diff)
downloadopie-9e4d914ade0af86707531a80e93a870e52738ce6.zip
opie-9e4d914ade0af86707531a80e93a870e52738ce6.tar.gz
opie-9e4d914ade0af86707531a80e93a870e52738ce6.tar.bz2
Some fixes and enhancements:
- don't rely on clipping information from Qt/E -- this doesn't work - theme style has support for all KDE gradient types now
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--noncore/styles/theme/ogfxeffect.cpp243
-rw-r--r--noncore/styles/theme/ogfxeffect.h3
-rw-r--r--noncore/styles/theme/othemestyle.cpp7
3 files changed, 220 insertions, 33 deletions
diff --git a/noncore/styles/theme/ogfxeffect.cpp b/noncore/styles/theme/ogfxeffect.cpp
index 55f3c1f..cc5bbcd 100644
--- a/noncore/styles/theme/ogfxeffect.cpp
+++ b/noncore/styles/theme/ogfxeffect.cpp
@@ -1,115 +1,298 @@
/* This file is part of the KDE libraries
Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
(C) 1998, 1999 Daniel M. Duley <mosfet@kde.org>
(C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
*/
// $Id$
#include <qimage.h>
#include <qpainter.h>
#include <qpe/qmath.h>
#include "ogfxeffect.h"
//======================================================================
//
// Gradient effects
//
//======================================================================
QPixmap& OGfxEffect::gradient(QPixmap &pixmap, const QColor &ca,
- const QColor &cb, GradientType eff, int /*ncols*/)
+ const QColor &cb, GradientType eff, int ncols)
{
- if(pixmap.depth() > 8 &&
- (eff == VerticalGradient || eff == HorizontalGradient)) {
+ QImage image = gradient(pixmap.size(), ca, cb, eff, ncols);
+ pixmap.convertFromImage(image);
+
+ return pixmap;
+}
+QImage OGfxEffect::gradient(const QSize &size, const QColor &ca,
+ const QColor &cb, GradientType eff, int /*ncols*/)
+{
int rDiff, gDiff, bDiff;
- int rca, gca, bca /*, rcb, gcb, bcb*/;
+ int rca, gca, bca, rcb, gcb, bcb;
+
+ QImage image(size, 32);
+
+ if (size.width() == 0 || size.height() == 0) {
+ qDebug ( "WARNING: OGfxEffect::gradient: invalid image" );
+ return image;
+ }
register int x, y;
- rDiff = (/*rcb = */ cb.red()) - (rca = ca.red());
- gDiff = (/*gcb = */ cb.green()) - (gca = ca.green());
- bDiff = (/*bcb = */ cb.blue()) - (bca = ca.blue());
+ rDiff = (rcb = cb.red()) - (rca = ca.red());
+ gDiff = (gcb = cb.green()) - (gca = ca.green());
+ bDiff = (bcb = cb.blue()) - (bca = ca.blue());
+
+ if( eff == VerticalGradient || eff == HorizontalGradient ){
+
+ uint *p;
+ uint rgb;
register int rl = rca << 16;
register int gl = gca << 16;
register int bl = bca << 16;
- int rcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * rDiff;
- int gcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * gDiff;
- int bcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * bDiff;
+ if( eff == VerticalGradient ) {
+
+ int rcdelta = ((1<<16) / size.height()) * rDiff;
+ int gcdelta = ((1<<16) / size.height()) * gDiff;
+ int bcdelta = ((1<<16) / size.height()) * bDiff;
- QPainter p(&pixmap);
+ for ( y = 0; y < size.height(); y++ ) {
+ p = (uint *) image.scanLine(y);
- // these for-loops could be merged, but the if's in the inner loop
- // would make it slow
- switch(eff) {
- case VerticalGradient:
- for ( y = 0; y < pixmap.height(); y++ ) {
rl += rcdelta;
gl += gcdelta;
bl += bcdelta;
- p.setPen(QColor(rl>>16, gl>>16, bl>>16));
- p.drawLine(0, y, pixmap.width()-1, y);
+ rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
+
+ for( x = 0; x < size.width(); x++ ) {
+ *p = rgb;
+ p++;
+ }
+ }
+
}
- break;
- case HorizontalGradient:
- for( x = 0; x < pixmap.width(); x++) {
+ else { // must be HorizontalGradient
+
+ unsigned int *o_src = (unsigned int *)image.scanLine(0);
+ unsigned int *src = o_src;
+
+ int rcdelta = ((1<<16) / size.width()) * rDiff;
+ int gcdelta = ((1<<16) / size.width()) * gDiff;
+ int bcdelta = ((1<<16) / size.width()) * bDiff;
+
+ for( x = 0; x < size.width(); x++) {
+
rl += rcdelta;
gl += gcdelta;
bl += bcdelta;
- p.setPen(QColor(rl>>16, gl>>16, bl>>16));
- p.drawLine(x, 0, x, pixmap.height()-1);
+ *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
+ }
+
+ src = o_src;
+
+ // Believe it or not, manually copying in a for loop is faster
+ // than calling memcpy for each scanline (on the order of ms...).
+ // I think this is due to the function call overhead (mosfet).
+
+ for (y = 1; y < size.height(); ++y) {
+
+ p = (unsigned int *)image.scanLine(y);
+ src = o_src;
+ for(x=0; x < size.width(); ++x)
+ *p++ = *src++;
}
- break;
- default:
- ;
}
}
+
else {
-// QImage image = OGfxEffect::gradient(pixmap.size(), ca, cb,
-// (OGfxEffect::GradientType) eff, ncols);
-// pixmap.convertFromImage(image);
+
+ float rfd, gfd, bfd;
+ float rd = rca, gd = gca, bd = bca;
+
+ unsigned char *xtable[3];
+ unsigned char *ytable[3];
+
+ unsigned int w = size.width(), h = size.height();
+ xtable[0] = new unsigned char[w];
+ xtable[1] = new unsigned char[w];
+ xtable[2] = new unsigned char[w];
+ ytable[0] = new unsigned char[h];
+ ytable[1] = new unsigned char[h];
+ ytable[2] = new unsigned char[h];
+ w*=2, h*=2;
+
+ if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
+ // Diagonal dgradient code inspired by BlackBox (mosfet)
+ // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
+ // Mike Cole <mike@mydot.com>.
+
+ rfd = (float)rDiff/w;
+ gfd = (float)gDiff/w;
+ bfd = (float)bDiff/w;
+
+ int dir;
+ for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
+ dir = eff == DiagonalGradient? x : size.width() - x - 1;
+ xtable[0][dir] = (unsigned char) rd;
+ xtable[1][dir] = (unsigned char) gd;
+ xtable[2][dir] = (unsigned char) bd;
+ }
+ rfd = (float)rDiff/h;
+ gfd = (float)gDiff/h;
+ bfd = (float)bDiff/h;
+ rd = gd = bd = 0;
+ for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
+ ytable[0][y] = (unsigned char) rd;
+ ytable[1][y] = (unsigned char) gd;
+ ytable[2][y] = (unsigned char) bd;
}
- return pixmap;
+ for (y = 0; y < size.height(); y++) {
+ unsigned int *scanline = (unsigned int *)image.scanLine(y);
+ for (x = 0; x < size.width(); x++) {
+ scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
+ xtable[1][x] + ytable[1][y],
+ xtable[2][x] + ytable[2][y]);
+ }
+ }
+ }
+
+ else if (eff == RectangleGradient ||
+ eff == PyramidGradient ||
+ eff == PipeCrossGradient ||
+ eff == EllipticGradient)
+ {
+ int rSign = rDiff>0? 1: -1;
+ int gSign = gDiff>0? 1: -1;
+ int bSign = bDiff>0? 1: -1;
+
+ rfd = (float)rDiff / size.width();
+ gfd = (float)gDiff / size.width();
+ bfd = (float)bDiff / size.width();
+
+ rd = (float)rDiff/2;
+ gd = (float)gDiff/2;
+ bd = (float)bDiff/2;
+
+ for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
+ {
+ xtable[0][x] = (unsigned char) abs((int)rd);
+ xtable[1][x] = (unsigned char) abs((int)gd);
+ xtable[2][x] = (unsigned char) abs((int)bd);
+ }
+
+ rfd = (float)rDiff/size.height();
+ gfd = (float)gDiff/size.height();
+ bfd = (float)bDiff/size.height();
+
+ rd = (float)rDiff/2;
+ gd = (float)gDiff/2;
+ bd = (float)bDiff/2;
+
+ for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
+ {
+ ytable[0][y] = (unsigned char) abs((int)rd);
+ ytable[1][y] = (unsigned char) abs((int)gd);
+ ytable[2][y] = (unsigned char) abs((int)bd);
+ }
+ unsigned int rgb;
+ int h = (size.height()+1)>>1;
+ for (y = 0; y < h; y++) {
+ unsigned int *sl1 = (unsigned int *)image.scanLine(y);
+ unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y));
+
+ int w = (size.width()+1)>>1;
+ int x2 = size.width()-1;
+
+ for (x = 0; x < w; x++, x2--) {
+ rgb = 0;
+ if (eff == PyramidGradient) {
+ rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
+ gcb-gSign*(xtable[1][x]+ytable[1][y]),
+ bcb-bSign*(xtable[2][x]+ytable[2][y]));
+ }
+ if (eff == RectangleGradient) {
+ rgb = qRgb(rcb - rSign *
+ QMAX(xtable[0][x], ytable[0][y]) * 2,
+ gcb - gSign *
+ QMAX(xtable[1][x], ytable[1][y]) * 2,
+ bcb - bSign *
+ QMAX(xtable[2][x], ytable[2][y]) * 2);
+ }
+ if (eff == PipeCrossGradient) {
+ rgb = qRgb(rcb - rSign *
+ QMIN(xtable[0][x], ytable[0][y]) * 2,
+ gcb - gSign *
+ QMIN(xtable[1][x], ytable[1][y]) * 2,
+ bcb - bSign *
+ QMIN(xtable[2][x], ytable[2][y]) * 2);
+ }
+ if (eff == EllipticGradient) {
+ rgb = qRgb(rcb - rSign *
+ (int)sqrt((xtable[0][x]*xtable[0][x] +
+ ytable[0][y]*ytable[0][y])*2.0),
+ gcb - gSign *
+ (int)sqrt((xtable[1][x]*xtable[1][x] +
+ ytable[1][y]*ytable[1][y])*2.0),
+ bcb - bSign *
+ (int)sqrt((xtable[2][x]*xtable[2][x] +
+ ytable[2][y]*ytable[2][y])*2.0));
+ }
+
+ sl1[x] = sl2[x] = rgb;
+ sl1[x2] = sl2[x2] = rgb;
+ }
+ }
+ }
+
+ delete [] xtable[0];
+ delete [] xtable[1];
+ delete [] xtable[2];
+ delete [] ytable[0];
+ delete [] ytable[1];
+ delete [] ytable[2];
+ }
+ return image;
}
//======================================================================
//
// Blend effects
//
//======================================================================
QPixmap& OGfxEffect::blend(QPixmap &pixmap, float initial_intensity,
const QColor &bgnd, GradientType eff,
bool anti_dir, int /*ncols*/)
{
QImage image = pixmap.convertToImage();
OGfxEffect::blend(image, initial_intensity, bgnd, eff, anti_dir);
if ( pixmap. depth ( ) <= 8 )
image. convertDepth ( pixmap. depth ( ));
pixmap.convertFromImage(image);
return pixmap;
}
QImage& OGfxEffect::blend(QImage &image, float initial_intensity,
const QColor &bgnd, GradientType eff,
bool anti_dir)
{
if (image.width() == 0 || image.height() == 0) {
qDebug ( "Invalid image\n" );
diff --git a/noncore/styles/theme/ogfxeffect.h b/noncore/styles/theme/ogfxeffect.h
index 45a8482..755537f 100644
--- a/noncore/styles/theme/ogfxeffect.h
+++ b/noncore/styles/theme/ogfxeffect.h
@@ -19,60 +19,63 @@
* Everything is
* static, so there is no need to create an instance of this class. You can
* just call the static methods. They are encapsulated here merely to provide
* a common namespace.
*/
class OGfxEffect
{
public:
enum GradientType { VerticalGradient, HorizontalGradient,
DiagonalGradient, CrossDiagonalGradient,
PyramidGradient, RectangleGradient,
PipeCrossGradient, EllipticGradient };
enum RGBComponent { Red, Green, Blue };
enum Lighting {NorthLite, NWLite, WestLite, SWLite,
SouthLite, SELite, EastLite, NELite};
/**
* Create a gradient from color a to color b of the specified type.
*
* @param pixmap The pixmap to process.
* @param ca Color a.
* @param cb Color b.
* @param type The type of gradient.
* @param ncols The number of colors to use when not running on a
* truecolor display. The gradient will be dithered to this number of
* colors. Pass 0 to prevent dithering.
* @return Returns the generated pixmap, for convenience.
*/
static QPixmap& gradient(QPixmap& pixmap, const QColor &ca, const QColor &cb,
GradientType type, int ncols=3);
+ static QImage gradient (const QSize &size, const QColor &ca, const QColor &cb,
+ GradientType type, int ncols=3);
+
/**
* Blend the provided pixmap into a background of the indicated color
*
* @param pixmap The pixmap to process.
* @param initial_intensity this parameter takes values from -1 to 1:
* @li If positive, it tells how much to fade the image in its
* less affected spot.
* @li If negative, it tells roughly indicates how much of the image
* remains unaffected
* @param bgnd Indicates the color of the background to blend in.
* @param eff Lets you choose what kind of blending you like.
* @param anti_dir Blend in the opposite direction (makes no much sense
* with concentric blending effects).
* @return Returns the @ref pixmap(), provided for convenience.
*/
static QPixmap& blend(QPixmap& pixmap, float initial_intensity,
const QColor &bgnd, GradientType eff,
bool anti_dir=false, int ncols=3);
static QImage& blend(QImage &image, float initial_intensity,
const QColor &bgnd, GradientType eff,
bool anti_dir);
};
#endif
diff --git a/noncore/styles/theme/othemestyle.cpp b/noncore/styles/theme/othemestyle.cpp
index d97b026..8c7a71b 100644
--- a/noncore/styles/theme/othemestyle.cpp
+++ b/noncore/styles/theme/othemestyle.cpp
@@ -1181,73 +1181,74 @@ void OThemeStyle::drawPopupMenuItem( QPainter* p, bool checkable, int maxpmw,
static const int motifItemFrame = 2; // menu item frame width
static const int motifItemHMargin = 5; // menu item hor text margin
static const int motifItemVMargin = 4; // menu item ver text margin
static const int motifArrowHMargin = 6; // arrow horizontal margin
static const int windowsRightBorder = 12; // right border on windowsstatic const int windowsCheckMarkWidth = 12; // checkmarks width on windows
bool dis = !enabled;
const QColorGroup &g = dis ? *colorGroup( pal.normal(), MenuItem ) :
*colorGroup( pal.normal(), MenuItemDown );
QColorGroup itemg = dis ? *colorGroup( pal.disabled(), MenuItem )
: act ? *colorGroup( pal.active(), MenuItemDown )
: *colorGroup( pal.normal(), MenuItem );
maxpmw = QMAX( maxpmw, 20 );
int checkcol = maxpmw;
if ( mi && mi->isSeparator() ) {
p->setPen( g.dark() );
p->drawLine( x, y, x + w, y );
p->setPen( g.light() );
p->drawLine( x, y + 1, x + w, y + 1 );
return ;
}
if ( act ) {
drawBaseButton( p, x, y, w, h, g, true, false, MenuItemDown );
}
else {
drawShade( p, x, y, w, h, *colorGroup( g, MenuItem ), false, false,
highlightWidth( MenuItem ), borderWidth( MenuItem ),
shade() );
int dw = decoWidth( MenuItem );
- if ( !isPixmap( MenuItem ) )
+ if ( !isPixmap( MenuItem ) ) {
p->fillRect( x + dw, y + dw, w - dw * 2, h - dw * 2,
colorGroup( g, MenuItem ) ->
brush( QColorGroup::Background ) );
+ }
else {
// process inactive item pixmaps as one large item
p->drawTiledPixmap( x + dw, y + dw, w - dw * 2, h - dw * 2, *scalePixmap
- // (w, p->window().height(), MenuItem),
- ( w, p->clipRegion().boundingRect().height(), MenuItem ),
+ (w, ((QWidget *)p->device())->height(), MenuItem),
+ //( w, p->clipRegion().boundingRect().height(), MenuItem ), // cliping does not work in Qt/E
x, y );
}
if ( checkable && mi && mi->isChecked() ) {
// draw 'pressed' border around checkable items
// This is extremely important for items that have an iconset
// because the checkmark isn't drawn in that case
// An alternative would be superimposing the checkmark over
// the iconset instead or not drawing the iconset at all.
int mw = checkcol + motifItemFrame;
drawShade( p, x, y, mw, h, g, true, false,
highlightWidth( MenuItemDown ),
borderWidth( MenuItemDown ), shade() );
}
}
if ( !mi )
return ;
if ( mi->iconSet() ) {
QIconSet::Mode mode = dis ? QIconSet::Disabled : QIconSet::Normal;
if ( act && !dis )
mode = QIconSet::Active;
QPixmap pixmap = mi->iconSet() ->pixmap( QIconSet::Small, mode );
int pixw = pixmap.width();
int pixh = pixmap.height();
QRect cr( x, y, checkcol, h );
QRect pmr( 0, 0, pixw, pixh );
pmr.moveCenter( cr.center() );
p->setPen( itemg.text() );
p->drawPixmap( pmr.topLeft(), pixmap );
}
else if ( checkable ) {