23 files changed, 9952 insertions, 0 deletions
diff --git a/libopie2/opieui/.cvsignore b/libopie2/opieui/.cvsignore new file mode 100644 index 0000000..8f7300c --- a/dev/null +++ b/libopie2/opieui/.cvsignore @@ -0,0 +1,6 @@ +Makefile* +moc* +*moc +*.o +~* + diff --git a/libopie2/opieui/config.in b/libopie2/opieui/config.in new file mode 100644 index 0000000..d40b5d9 --- a/dev/null +++ b/libopie2/opieui/config.in @@ -0,0 +1,7 @@ + config LIBOPIE2UI + boolean "libopie2ui (user interface related classes)" + default "n" + depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE + comment "libopie2ui needs a libqpe and libopie2core" + depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE) + diff --git a/libopie2/opieui/odialog.cpp b/libopie2/opieui/odialog.cpp new file mode 100644 index 0000000..00a7a7e --- a/dev/null +++ b/libopie2/opieui/odialog.cpp @@ -0,0 +1,53 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include <opie2/odialog.h> + +int ODialog::mMarginSize = 5; // 11 like in KDialog is probably too much for PDA +int ODialog::mSpacingSize = 2; // 6 like in KDialog is probably too much for PDA + +ODialog::ODialog(QWidget *parent, const char *name, bool modal, WFlags f) + : QDialog(parent, name, modal, f) +{ +} + +int ODialog::marginHint() +{ + return( mMarginSize ); +} + + +int ODialog::spacingHint() +{ + return( mSpacingSize ); +} + +// Placeholder for even more sophisticed things diff --git a/libopie2/opieui/odialog.h b/libopie2/opieui/odialog.h new file mode 100644 index 0000000..38f25e8 --- a/dev/null +++ b/libopie2/opieui/odialog.h @@ -0,0 +1,89 @@ +/* + This file is part of the Opie Project + + (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef ODIALOG_H +#define ODIALOG_H + +class QLayoutItem; + +#include <qdialog.h> + +/** + * Dialog with extended nonmodal support and methods for OPIE standard + * compliance. + * + * The @ref marginHint() and @ref spacingHint() sizes shall be used + * whenever you layout the interior of a dialog. One special note. If + * you make your own action buttons (OK, Cancel etc), the space + * beteween the buttons shall be @ref spacingHint(), whereas the space + * above, below, to the right and to the left shall be @ref marginHint(). + * If you add a separator line above the buttons, there shall be a + * @ref marginHint() between the buttons and the separator and a + * @ref marginHint() above the separator as well. + * + * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + */ + +class ODialog : public QDialog +{ + Q_OBJECT + + public: + + /** + * Constructor. + * + * Takes the same arguments as @ref QDialog. + */ + ODialog(QWidget *parent = 0, const char *name = 0, + bool modal = false, WFlags f = 0); + + /** + * Return the number of pixels you shall use between a + * dialog edge and the outermost widget(s) according to the KDE standard. + **/ + static int marginHint(); + + /** + * Return the number of pixels you shall use between + * widgets inside a dialog according to the KDE standard. + */ + static int spacingHint(); + + private: + static int mMarginSize; + static int mSpacingSize; + + //class ODialogPrivate; + //ODialogPrivate *d; + +}; +#endif // ODIALOG_H diff --git a/libopie2/opieui/oimageeffect.cpp b/libopie2/opieui/oimageeffect.cpp new file mode 100644 index 0000000..3c28bbe --- a/dev/null +++ b/libopie2/opieui/oimageeffect.cpp @@ -0,0 +1,3794 @@ +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org> + (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + (C) 2000 Josef Weidendorfer <weidendo@in.tum.de> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +// $Id$ + +#include <math.h> + +#include <qimage.h> +#include <stdlib.h> +#include <iostream> + +#include "oimageeffect.h" + +#define MaxRGB 255L +#define DegreesToRadians(x) ((x)*M_PI/180.0) + +using namespace std; + +inline unsigned int intensityValue(unsigned int color) +{ + return((unsigned int)((0.299*qRed(color) + + 0.587*qGreen(color) + + 0.1140000000000001*qBlue(color)))); +} + +//====================================================================== +// +// Gradient effects +// +//====================================================================== + +QImage OImageEffect::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; + + QImage image(size, 32); + + if (size.width() == 0 || size.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::gradient: invalid image" << endl; +#endif + 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()); + + if( eff == VerticalGradient || eff == HorizontalGradient ){ + + uint *p; + uint rgb; + + register int rl = rca << 16; + register int gl = gca << 16; + register int bl = bca << 16; + + if( eff == VerticalGradient ) { + + int rcdelta = ((1<<16) / size.height()) * rDiff; + int gcdelta = ((1<<16) / size.height()) * gDiff; + int bcdelta = ((1<<16) / size.height()) * bDiff; + + for ( y = 0; y < size.height(); y++ ) { + p = (uint *) image.scanLine(y); + + rl += rcdelta; + gl += gcdelta; + bl += bcdelta; + + rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) ); + + for( x = 0; x < size.width(); x++ ) { + *p = rgb; + p++; + } + } + + } + 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; + + *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++; + } + } + } + + else { + + 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; + } + + 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]; + } + + // dither if necessary + if (ncols && (QPixmap::defaultDepth() < 15 )) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), + gca + gDiff * i / ( ncols - 1 ), + bca + bDiff * i / ( ncols - 1 ) ); + } + dither(image, dPal, ncols); + delete [] dPal; + } + + return image; +} + + +// ----------------------------------------------------------------------------- + +//CT this was (before Dirk A. Mueller's speedup changes) +// merely the same code as in the above method, but it's supposedly +// way less performant since it introduces a lot of supplementary tests +// and simple math operations for the calculus of the balance. +// (surprizingly, it isn't less performant, in the contrary :-) +// Yes, I could have merged them, but then the excellent performance of +// the balanced code would suffer with no other gain than a mere +// source code and byte code size economy. + +QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca, + const QColor &cb, GradientType eff, int xfactor, int yfactor, + int ncols) +{ + int dir; // general parameter used for direction switches + + bool _xanti = false , _yanti = false; + + if (xfactor < 0) _xanti = true; // negative on X direction + if (yfactor < 0) _yanti = true; // negative on Y direction + + xfactor = abs(xfactor); + yfactor = abs(yfactor); + + if (!xfactor) xfactor = 1; + if (!yfactor) yfactor = 1; + + if (xfactor > 200 ) xfactor = 200; + if (yfactor > 200 ) yfactor = 200; + + + // float xbal = xfactor/5000.; + // float ybal = yfactor/5000.; + float xbal = xfactor/30./size.width(); + float ybal = yfactor/30./size.height(); + float rat; + + int rDiff, gDiff, bDiff; + int rca, gca, bca, rcb, gcb, bcb; + + QImage image(size, 32); + + if (size.width() == 0 || size.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::unbalancedGradient : invalid image\n"; +#endif + return image; + } + + register int x, y; + unsigned int *scanline; + + 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){ + QColor cRow; + + uint *p; + uint rgbRow; + + if( eff == VerticalGradient) { + for ( y = 0; y < size.height(); y++ ) { + dir = _yanti ? y : size.height() - 1 - y; + p = (uint *) image.scanLine(dir); + rat = 1 - exp( - (float)y * ybal ); + + cRow.setRgb( rcb - (int) ( rDiff * rat ), + gcb - (int) ( gDiff * rat ), + bcb - (int) ( bDiff * rat ) ); + + rgbRow = cRow.rgb(); + + for( x = 0; x < size.width(); x++ ) { + *p = rgbRow; + p++; + } + } + } + else { + + unsigned int *src = (unsigned int *)image.scanLine(0); + for(x = 0; x < size.width(); x++ ) + { + dir = _xanti ? x : size.width() - 1 - x; + rat = 1 - exp( - (float)x * xbal ); + + src[dir] = qRgb(rcb - (int) ( rDiff * rat ), + gcb - (int) ( gDiff * rat ), + bcb - (int) ( bDiff * rat )); + } + + // 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) + { + scanline = (unsigned int *)image.scanLine(y); + for(x=0; x < size.width(); ++x) + scanline[x] = src[x]; + } + } + } + + else { + int w=size.width(), h=size.height(); + + unsigned char *xtable[3]; + unsigned char *ytable[3]; + 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]; + + if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) + { + for (x = 0; x < w; x++) { + dir = _xanti ? x : w - 1 - x; + rat = 1 - exp( - (float)x * xbal ); + + xtable[0][dir] = (unsigned char) ( rDiff/2 * rat ); + xtable[1][dir] = (unsigned char) ( gDiff/2 * rat ); + xtable[2][dir] = (unsigned char) ( bDiff/2 * rat ); + } + + for (y = 0; y < h; y++) { + dir = _yanti ? y : h - 1 - y; + rat = 1 - exp( - (float)y * ybal ); + + ytable[0][dir] = (unsigned char) ( rDiff/2 * rat ); + ytable[1][dir] = (unsigned char) ( gDiff/2 * rat ); + ytable[2][dir] = (unsigned char) ( bDiff/2 * rat ); + } + + for (y = 0; y < h; y++) { + unsigned int *scanline = (unsigned int *)image.scanLine(y); + for (x = 0; x < w; x++) { + scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]), + gcb - (xtable[1][x] + ytable[1][y]), + bcb - (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; + + for (x = 0; x < w; x++) + { + dir = _xanti ? x : w - 1 - x; + rat = 1 - exp( - (float)x * xbal ); + + xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); + xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); + xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); + } + + for (y = 0; y < h; y++) + { + dir = _yanti ? y : h - 1 - y; + + rat = 1 - exp( - (float)y * ybal ); + + ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat))); + ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat))); + ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat))); + } + + for (y = 0; y < h; y++) { + unsigned int *scanline = (unsigned int *)image.scanLine(y); + for (x = 0; x < w; x++) { + if (eff == PyramidGradient) + { + scanline[x] = 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) + { + scanline[x] = 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) + { + scanline[x] = 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) + { + scanline[x] = 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)); + } + } + } + } + + if (ncols && (QPixmap::defaultDepth() < 15 )) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), + gca + gDiff * i / ( ncols - 1 ), + bca + bDiff * i / ( ncols - 1 ) ); + } + dither(image, dPal, ncols); + delete [] dPal; + } + + delete [] xtable[0]; + delete [] xtable[1]; + delete [] xtable[2]; + delete [] ytable[0]; + delete [] ytable[1]; + delete [] ytable[2]; + + } + + return image; +} + + +//====================================================================== +// +// Intensity effects +// +//====================================================================== + + +/* This builds a 256 byte unsigned char lookup table with all + * the possible percent values prior to applying the effect, then uses + * integer math for the pixels. For any image larger than 9x9 this will be + * less expensive than doing a float operation on the 3 color components of + * each pixel. (mosfet) + */ + +QImage& OImageEffect::intensity(QImage &image, float percent) +{ + if (image.width() == 0 || image.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::intensity : invalid image\n"; +#endif + return image; + } + + int segColors = image.depth() > 8 ? 256 : image.numColors(); + unsigned char *segTbl = new unsigned char[segColors]; + int pixels = image.depth() > 8 ? image.width()*image.height() : + image.numColors(); + unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : + (unsigned int *)image.colorTable(); + + bool brighten = (percent >= 0); + if(percent < 0) + percent = -percent; + + if(brighten){ // keep overflow check out of loops + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp > 255) + tmp = 255; + segTbl[i] = tmp; + } + } + else{ + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp < 0) + tmp = 0; + segTbl[i] = tmp; + } + } + + if(brighten){ // same here + for(int i=0; i < pixels; ++i){ + int r = qRed(data[i]); + int g = qGreen(data[i]); + int b = qBlue(data[i]); + int a = qAlpha(data[i]); + r = r + segTbl[r] > 255 ? 255 : r + segTbl[r]; + g = g + segTbl[g] > 255 ? 255 : g + segTbl[g]; + b = b + segTbl[b] > 255 ? 255 : b + segTbl[b]; + data[i] = qRgba(r, g, b,a); + } + } + else{ + for(int i=0; i < pixels; ++i){ + int r = qRed(data[i]); + int g = qGreen(data[i]); + int b = qBlue(data[i]); + int a = qAlpha(data[i]); + r = r - segTbl[r] < 0 ? 0 : r - segTbl[r]; + g = g - segTbl[g] < 0 ? 0 : g - segTbl[g]; + b = b - segTbl[b] < 0 ? 0 : b - segTbl[b]; + data[i] = qRgba(r, g, b, a); + } + } + delete [] segTbl; + + return image; +} + +QImage& OImageEffect::channelIntensity(QImage &image, float percent, + RGBComponent channel) +{ + if (image.width() == 0 || image.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::channelIntensity : invalid image\n"; +#endif + return image; + } + + int segColors = image.depth() > 8 ? 256 : image.numColors(); + unsigned char *segTbl = new unsigned char[segColors]; + int pixels = image.depth() > 8 ? image.width()*image.height() : + image.numColors(); + unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : + (unsigned int *)image.colorTable(); + bool brighten = (percent >= 0); + if(percent < 0) + percent = -percent; + + if(brighten){ // keep overflow check out of loops + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp > 255) + tmp = 255; + segTbl[i] = tmp; + } + } + else{ + for(int i=0; i < segColors; ++i){ + int tmp = (int)(i*percent); + if(tmp < 0) + tmp = 0; + segTbl[i] = tmp; + } + } + + if(brighten){ // same here + if(channel == Red){ // and here ;-) + for(int i=0; i < pixels; ++i){ + int c = qRed(data[i]); + c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; + data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); + } + } + if(channel == Green){ + for(int i=0; i < pixels; ++i){ + int c = qGreen(data[i]); + c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; + data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); + } + } + else{ + for(int i=0; i < pixels; ++i){ + int c = qBlue(data[i]); + c = c + segTbl[c] > 255 ? 255 : c + segTbl[c]; + data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); + } + } + + } + else{ + if(channel == Red){ + for(int i=0; i < pixels; ++i){ + int c = qRed(data[i]); + c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; + data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); + } + } + if(channel == Green){ + for(int i=0; i < pixels; ++i){ + int c = qGreen(data[i]); + c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; + data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); + } + } + else{ + for(int i=0; i < pixels; ++i){ + int c = qBlue(data[i]); + c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; + data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); + } + } + } + delete [] segTbl; + + return image; +} + +// Modulate an image with an RBG channel of another image +// +QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse, + ModulationType type, int factor, RGBComponent channel) +{ + if (image.width() == 0 || image.height() == 0 || + modImage.width() == 0 || modImage.height() == 0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::modulate : invalid image\n"; +#endif + return image; + } + + int r, g, b, h, s, v, a; + QColor clr; + int mod=0; + unsigned int x1, x2, y1, y2; + register int x, y; + + // for image, we handle only depth 32 + if (image.depth()<32) image = image.convertDepth(32); + + // for modImage, we handle depth 8 and 32 + if (modImage.depth()<8) modImage = modImage.convertDepth(8); + + unsigned int *colorTable2 = (modImage.depth()==8) ? + modImage.colorTable():0; + unsigned int *data1, *data2; + unsigned char *data2b; + unsigned int color1, color2; + + x1 = image.width(); y1 = image.height(); + x2 = modImage.width(); y2 = modImage.height(); + + for (y = 0; y < (int)y1; y++) { + data1 = (unsigned int *) image.scanLine(y); + data2 = (unsigned int *) modImage.scanLine( y%y2 ); + data2b = (unsigned char *) modImage.scanLine( y%y2 ); + + x=0; + while(x < (int)x1) { + color2 = (colorTable2) ? colorTable2[*data2b] : *data2; + if (reverse) { + color1 = color2; + color2 = *data1; + } + else + color1 = *data1; + + if (type == Intensity || type == Contrast) { + r = qRed(color1); + g = qGreen(color1); + b = qBlue(color1); + if (channel != All) { + mod = (channel == Red) ? qRed(color2) : + (channel == Green) ? qGreen(color2) : + (channel == Blue) ? qBlue(color2) : + (channel == Gray) ? qGray(color2) : 0; + mod = mod*factor/50; + } + + if (type == Intensity) { + if (channel == All) { + r += r * factor/50 * qRed(color2)/256; + g += g * factor/50 * qGreen(color2)/256; + b += b * factor/50 * qBlue(color2)/256; + } + else { + r += r * mod/256; + g += g * mod/256; + b += b * mod/256; + } + } + else { // Contrast + if (channel == All) { + r += (r-128) * factor/50 * qRed(color2)/128; + g += (g-128) * factor/50 * qGreen(color2)/128; + b += (b-128) * factor/50 * qBlue(color2)/128; + } + else { + r += (r-128) * mod/128; + g += (g-128) * mod/128; + b += (b-128) * mod/128; + } + } + + if (r<0) r=0; if (r>255) r=255; + if (g<0) g=0; if (g>255) g=255; + if (b<0) b=0; if (b>255) b=255; + a = qAlpha(*data1); + *data1 = qRgba(r, g, b, a); + } + else if (type == Saturation || type == HueShift) { + clr.setRgb(color1); + clr.hsv(&h, &s, &v); + mod = (channel == Red) ? qRed(color2) : + (channel == Green) ? qGreen(color2) : + (channel == Blue) ? qBlue(color2) : + (channel == Gray) ? qGray(color2) : 0; + mod = mod*factor/50; + + if (type == Saturation) { + s -= s * mod/256; + if (s<0) s=0; if (s>255) s=255; + } + else { // HueShift + h += mod; + while(h<0) h+=360; + h %= 360; + } + + clr.setHsv(h, s, v); + a = qAlpha(*data1); + *data1 = clr.rgb() | ((uint)(a & 0xff) << 24); + } + data1++; data2++; data2b++; x++; + if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; } + } + } + return image; +} + + + +//====================================================================== +// +// Blend effects +// +//====================================================================== + + +// Nice and fast direct pixel manipulation +QImage& OImageEffect::blend(const QColor& clr, QImage& dst, float opacity) +{ + if (dst.width() <= 0 || dst.height() <= 0) + return dst; + + if (opacity < 0.0 || opacity > 1.0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n"; +#endif + return dst; + } + + int depth = dst.depth(); + if (depth != 32) + dst = dst.convertDepth(32); + + int pixels = dst.width() * dst.height(); + int rcol, gcol, bcol; + clr.rgb(&rcol, &gcol, &bcol); + +#ifdef WORDS_BIGENDIAN // ARGB (skip alpha) + register unsigned char *data = (unsigned char *)dst.bits() + 1; +#else // BGRA + register unsigned char *data = (unsigned char *)dst.bits(); +#endif + + for (register int i=0; i<pixels; i++) + { +#ifdef WORDS_BIGENDIAN + *(data++) += (unsigned char)((rcol - *data) * opacity); + *(data++) += (unsigned char)((gcol - *data) * opacity); + *(data++) += (unsigned char)((bcol - *data) * opacity); +#else + *(data++) += (unsigned char)((bcol - *data) * opacity); + *(data++) += (unsigned char)((gcol - *data) * opacity); + *(data++) += (unsigned char)((rcol - *data) * opacity); +#endif + data++; // skip alpha + } + return dst; +} + +// Nice and fast direct pixel manipulation +QImage& OImageEffect::blend(QImage& src, QImage& dst, float opacity) +{ + if (src.width() <= 0 || src.height() <= 0) + return dst; + if (dst.width() <= 0 || dst.height() <= 0) + return dst; + + if (src.width() != dst.width() || src.height() != dst.height()) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : src and destination images are not the same size\n"; +#endif + return dst; + } + + if (opacity < 0.0 || opacity > 1.0) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n"; +#endif + return dst; + } + + if (src.depth() != 32) src = src.convertDepth(32); + if (dst.depth() != 32) dst = dst.convertDepth(32); + + int pixels = src.width() * src.height(); +#ifdef WORDS_BIGENDIAN // ARGB (skip alpha) + register unsigned char *data1 = (unsigned char *)dst.bits() + 1; + register unsigned char *data2 = (unsigned char *)src.bits() + 1; +#else // BGRA + register unsigned char *data1 = (unsigned char *)dst.bits(); + register unsigned char *data2 = (unsigned char *)src.bits(); +#endif + + for (register int i=0; i<pixels; i++) + { +#ifdef WORDS_BIGENDIAN + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); +#else + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); + *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); +#endif + data1++; // skip alpha + data2++; + } + + return dst; +} + + +QImage& OImageEffect::blend(QImage &image, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir) +{ + if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) { +#ifndef NDEBUG + cerr << "WARNING: OImageEffect::blend : invalid image\n"; +#endif + return image; + } + + int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue(); + int r, g, b; + int ind; + + unsigned int xi, xf, yi, yf; + unsigned int a; + + // check the boundaries of the initial intesity param + float unaffected = 1; + if (initial_intensity > 1) initial_intensity = 1; + if (initial_intensity < -1) initial_intensity = -1; + if (initial_intensity < 0) { + unaffected = 1. + initial_intensity; + initial_intensity = 0; + } + + + float intensity = initial_intensity; + float var = 1. - initial_intensity; + + if (anti_dir) { + initial_intensity = intensity = 1.; + var = -var; + } + + register int x, y; + + unsigned int *data = (unsigned int *)image.bits(); + + int image_width = image.width(); //Those can't change + int image_height = image.height(); + + + if( eff == VerticalGradient || eff == HorizontalGradient ) { + + // set the image domain to apply the effect to + xi = 0, xf = image_width; + yi = 0, yf = image_height; + if (eff == VerticalGradient) { + if (anti_dir) yf = (int)(image_height * unaffected); + else yi = (int)(image_height * (1 - unaffected)); + } + else { + if (anti_dir) xf = (int)(image_width * unaffected); + else xi = (int)(image_height * (1 - unaffected)); + } + + var /= (eff == VerticalGradient?yf-yi:xf-xi); + + int ind_base; + for (y = yi; y < (int)yf; y++) { + intensity = eff == VerticalGradient? intensity + var : + initial_intensity; + ind_base = image_width * y ; + for (x = xi; x < (int)xf ; x++) { + if (eff == HorizontalGradient) intensity += var; + ind = x + ind_base; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + } + else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) { + float xvar = var / 2 / image_width; // / unaffected; + float yvar = var / 2 / image_height; // / unaffected; + float tmp; + + for (x = 0; x < image_width ; x++) { + tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1); + ind = x; + for (y = 0; y < image_height ; y++) { + intensity = initial_intensity + tmp + yvar * y; + + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + ind += image_width; + } + } + } + + else if (eff == RectangleGradient || eff == EllipticGradient) { + float xvar; + float yvar; + + for (x = 0; x < image_width / 2 + image_width % 2; x++) { + xvar = var / image_width * (image_width - x*2/unaffected-1); + for (y = 0; y < image_height / 2 + image_height % 2; y++) { + yvar = var / image_height * (image_height - y*2/unaffected -1); + + if (eff == RectangleGradient) + intensity = initial_intensity + QMAX(xvar, yvar); + else + intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); + if (intensity > 1) intensity = 1; + if (intensity < 0) intensity = 0; + + //NW + ind = x + image_width * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + //NE + ind = image_width - x - 1 + image_width * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + + //CT loop is doubled because of stupid central row/column issue. + // other solution? + for (x = 0; x < image_width / 2; x++) { + xvar = var / image_width * (image_width - x*2/unaffected-1); + for (y = 0; y < image_height / 2; y++) { + yvar = var / image_height * (image_height - y*2/unaffected -1); + + if (eff == RectangleGradient) + intensity = initial_intensity + QMAX(xvar, yvar); + else + intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); + if (intensity > 1) intensity = 1; + if (intensity < 0) intensity = 0; + + //SW + ind = x + image_width * (image_height - y -1) ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + //SE + ind = image_width-x-1 + image_width * (image_height - y - 1) ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + } +#ifndef NDEBUG + else cerr << "OImageEffect::blend effect not implemented" << endl; +#endif + return image; +} + +// Not very efficient as we create a third big image... +// +QImage& OImageEffect::blend(QImage &image1, QImage &image2, + GradientType gt, int xf, int yf) +{ + if (image1.width() == 0 || image1.height() == 0 || + image2.width() == 0 || image2.height() == 0) + return image1; + + QImage image3; + + image3 = OImageEffect::unbalancedGradient(image1.size(), + QColor(0,0,0), QColor(255,255,255), + gt, xf, yf, 0); + + return blend(image1,image2,image3, Red); // Channel to use is arbitrary +} + +// Blend image2 into image1, using an RBG channel of blendImage +// +QImage& OImageEffect::blend(QImage &image1, QImage &image2, + QImage &blendImage, RGBComponent channel) +{ + if (image1.width() == 0 || image1.height() == 0 || + image2.width() == 0 || image2.height() == 0 || + blendImage.width() == 0 || blendImage.height() == 0) { +#ifndef NDEBUG + cerr << "OImageEffect::blend effect invalid image" << endl; +#endif + return image1; + } + + int r, g, b; + int ind1, ind2, ind3; + + unsigned int x1, x2, x3, y1, y2, y3; + unsigned int a; + + register int x, y; + + // for image1 and image2, we only handle depth 32 + if (image1.depth()<32) image1 = image1.convertDepth(32); + if (image2.depth()<32) image2 = image2.convertDepth(32); + + // for blendImage, we handle depth 8 and 32 + if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8); + + unsigned int *colorTable3 = (blendImage.depth()==8) ? + blendImage.colorTable():0; + + unsigned int *data1 = (unsigned int *)image1.bits(); + unsigned int *data2 = (unsigned int *)image2.bits(); + unsigned int *data3 = (unsigned int *)blendImage.bits(); + unsigned char *data3b = (unsigned char *)blendImage.bits(); + unsigned int color3; + + x1 = image1.width(); y1 = image1.height(); + x2 = image2.width(); y2 = image2.height(); + x3 = blendImage.width(); y3 = blendImage.height(); + + for (y = 0; y < (int)y1; y++) { + ind1 = x1*y; + ind2 = x2*(y%y2); + ind3 = x3*(y%y3); + + x=0; + while(x < (int)x1) { + color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3]; + + a = (channel == Red) ? qRed(color3) : + (channel == Green) ? qGreen(color3) : + (channel == Blue) ? qBlue(color3) : qGray(color3); + + r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256; + g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256; + b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256; + + a = qAlpha(data1[ind1]); + data1[ind1] = qRgba(r, g, b, a); + + ind1++; ind2++; ind3++; x++; + if ( (x%x2) ==0) ind2 -= x2; + if ( (x%x3) ==0) ind3 -= x3; + } + } + return image1; +} + + +//====================================================================== +// +// Hash effects +// +//====================================================================== + +unsigned int OImageEffect::lHash(unsigned int c) +{ + unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); + unsigned char nr, ng, nb; + nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr; + ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng; + nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb; + + return qRgba(nr, ng, nb, a); +} + + +// ----------------------------------------------------------------------------- + +unsigned int OImageEffect::uHash(unsigned int c) +{ + unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); + unsigned char nr, ng, nb; + nr = r + (r >> 3); nr = nr < r ? ~0 : nr; + ng = g + (g >> 3); ng = ng < g ? ~0 : ng; + nb = b + (b >> 3); nb = nb < b ? ~0 : nb; + + return qRgba(nr, ng, nb, a); +} + + +// ----------------------------------------------------------------------------- + +QImage& OImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing) +{ + if (image.width() == 0 || image.height() == 0) { +#ifndef NDEBUG + cerr << "OImageEffect::hash effect invalid image" << endl; +#endif + return image; + } + + register int x, y; + unsigned int *data = (unsigned int *)image.bits(); + unsigned int ind; + + //CT no need to do it if not enough space + if ((lite == NorthLite || + lite == SouthLite)&& + (unsigned)image.height() < 2+spacing) return image; + if ((lite == EastLite || + lite == WestLite)&& + (unsigned)image.height() < 2+spacing) return image; + + if (lite == NorthLite || lite == SouthLite) { + for (y = 0 ; y < image.height(); y = y + 2 + spacing) { + for (x = 0; x < image.width(); x++) { + ind = x + image.width() * y; + data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]); + + ind = ind + image.width(); + data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + else if (lite == EastLite || lite == WestLite) { + for (y = 0 ; y < image.height(); y++) { + for (x = 0; x < image.width(); x = x + 2 + spacing) { + ind = x + image.width() * y; + data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]); + + ind++; + data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + else if (lite == NWLite || lite == SELite) { + for (y = 0 ; y < image.height(); y++) { + for (x = 0; + x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing); + x = x + 2 + spacing) { + ind = x + image.width() * y + ((y & 1)? 1 : 0); + data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]); + + ind++; + data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + else if (lite == SWLite || lite == NELite) { + for (y = 0 ; y < image.height(); y++) { + for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) { + ind = x + image.width() * y - ((y & 1)? 1 : 0); + data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]); + + ind++; + data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]); + } + } + } + + return image; +} + + +//====================================================================== +// +// Flatten effects +// +//====================================================================== + +QImage& OImageEffect::flatten(QImage &img, const QColor &ca, + const QColor &cb, int ncols) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + // a bitmap is easy... + if (img.depth() == 1) { + img.setColor(0, ca.rgb()); + img.setColor(1, cb.rgb()); + return img; + } + + int r1 = ca.red(); int r2 = cb.red(); + int g1 = ca.green(); int g2 = cb.green(); + int b1 = ca.blue(); int b2 = cb.blue(); + int min = 0, max = 255; + + QRgb col; + + // Get minimum and maximum greylevel. + if (img.numColors()) { + // pseudocolor + for (int i = 0; i < img.numColors(); i++) { + col = img.color(i); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + min = QMIN(min, mean); + max = QMAX(max, mean); + } + } else { + // truecolor + for (int y=0; y < img.height(); y++) + for (int x=0; x < img.width(); x++) { + col = img.pixel(x, y); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + min = QMIN(min, mean); + max = QMAX(max, mean); + } + } + + // Conversion factors + float sr = ((float) r2 - r1) / (max - min); + float sg = ((float) g2 - g1) / (max - min); + float sb = ((float) b2 - b1) / (max - min); + + + // Repaint the image + if (img.numColors()) { + for (int i=0; i < img.numColors(); i++) { + col = img.color(i); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + int r = (int) (sr * (mean - min) + r1 + 0.5); + int g = (int) (sg * (mean - min) + g1 + 0.5); + int b = (int) (sb * (mean - min) + b1 + 0.5); + img.setColor(i, qRgba(r, g, b, qAlpha(col))); + } + } else { + for (int y=0; y < img.height(); y++) + for (int x=0; x < img.width(); x++) { + col = img.pixel(x, y); + int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3; + int r = (int) (sr * (mean - min) + r1 + 0.5); + int g = (int) (sg * (mean - min) + g1 + 0.5); + int b = (int) (sb * (mean - min) + b1 + 0.5); + img.setPixel(x, y, qRgba(r, g, b, qAlpha(col))); + } + } + + + // Dither if necessary + if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols))) + return img; + + if (ncols == 1) ncols++; + if (ncols > 256) ncols = 256; + + QColor *pal = new QColor[ncols]; + sr = ((float) r2 - r1) / (ncols - 1); + sg = ((float) g2 - g1) / (ncols - 1); + sb = ((float) b2 - b1) / (ncols - 1); + + for (int i=0; i<ncols; i++) + pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i)); + + dither(img, pal, ncols); + + delete[] pal; + return img; +} + + +//====================================================================== +// +// Fade effects +// +//====================================================================== + +QImage& OImageEffect::fade(QImage &img, float val, const QColor &color) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + // We don't handle bitmaps + if (img.depth() == 1) + return img; + + unsigned char tbl[256]; + for (int i=0; i<256; i++) + tbl[i] = (int) (val * i + 0.5); + + int red = color.red(); + int green = color.green(); + int blue = color.blue(); + + QRgb col; + int r, g, b, cr, cg, cb; + + if (img.depth() <= 8) { + // pseudo color + for (int i=0; i<img.numColors(); i++) { + col = img.color(i); + cr = qRed(col); cg = qGreen(col); cb = qBlue(col); + if (cr > red) + r = cr - tbl[cr - red]; + else + r = cr + tbl[red - cr]; + if (cg > green) + g = cg - tbl[cg - green]; + else + g = cg + tbl[green - cg]; + if (cb > blue) + b = cb - tbl[cb - blue]; + else + b = cb + tbl[blue - cb]; + img.setColor(i, qRgba(r, g, b, qAlpha(col))); + } + + } else { + // truecolor + for (int y=0; y<img.height(); y++) { + QRgb *data = (QRgb *) img.scanLine(y); + for (int x=0; x<img.width(); x++) { + col = *data; + cr = qRed(col); cg = qGreen(col); cb = qBlue(col); + if (cr > red) + r = cr - tbl[cr - red]; + else + r = cr + tbl[red - cr]; + if (cg > green) + g = cg - tbl[cg - green]; + else + g = cg + tbl[green - cg]; + if (cb > blue) + b = cb - tbl[cb - blue]; + else + b = cb + tbl[blue - cb]; + *data++ = qRgba(r, g, b, qAlpha(col)); + } + } + } + + return img; +} + +//====================================================================== +// +// Color effects +// +//====================================================================== + +// This code is adapted from code (C) Rik Hemsley <rik@kde.org> +// +// The formula used (r + b + g) /3 is different from the qGray formula +// used by Qt. This is because our formula is much much faster. If, +// however, it turns out that this is producing sub-optimal images, +// then it will have to change (kurt) +// +// It does produce lower quality grayscale ;-) Use fast == true for the fast +// algorithm, false for the higher quality one (mosfet). +QImage& OImageEffect::toGray(QImage &img, bool fast) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + if(fast){ + if (img.depth() == 32) { + register uchar * r(img.bits()); + register uchar * g(img.bits() + 1); + register uchar * b(img.bits() + 2); + + uchar * end(img.bits() + img.numBytes()); + + while (r != end) { + + *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3 + + r += 4; + g += 4; + b += 4; + } + } + else + { + for (int i = 0; i < img.numColors(); i++) + { + register uint r = qRed(img.color(i)); + register uint g = qGreen(img.color(i)); + register uint b = qBlue(img.color(i)); + + register uint gray = (((r + g) >> 1) + b) >> 1; + img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i)))); + } + } + } + else{ + int pixels = img.depth() > 8 ? img.width()*img.height() : + img.numColors(); + unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + int val, i; + for(i=0; i < pixels; ++i){ + val = qGray(data[i]); + data[i] = qRgba(val, val, val, qAlpha(data[i])); + } + } + return img; +} + +// CT 29Jan2000 - desaturation algorithms +QImage& OImageEffect::desaturate(QImage &img, float desat) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + if (desat < 0) desat = 0.; + if (desat > 1) desat = 1.; + int pixels = img.depth() > 8 ? img.width()*img.height() : + img.numColors(); + unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + int h, s, v, i; + QColor clr; // keep constructor out of loop (mosfet) + for(i=0; i < pixels; ++i){ + clr.setRgb(data[i]); + clr.hsv(&h, &s, &v); + clr.setHsv(h, (int)(s * (1. - desat)), v); + data[i] = clr.rgb(); + } + return img; +} + +// Contrast stuff (mosfet) +QImage& OImageEffect::contrast(QImage &img, int c) +{ + if (img.width() == 0 || img.height() == 0) + return img; + + if(c > 255) + c = 255; + if(c < -255) + c = -255; + int pixels = img.depth() > 8 ? img.width()*img.height() : + img.numColors(); + unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() : + (unsigned int *)img.colorTable(); + int i, r, g, b; + for(i=0; i < pixels; ++i){ + r = qRed(data[i]); + g = qGreen(data[i]); + b = qBlue(data[i]); + if(qGray(data[i]) <= 127){ + if(r - c <= 255) + r -= c; + if(g - c <= 255) + g -= c; + if(b - c <= 255) + b -= c; + } + else{ + if(r + c <= 255) + r += c; + if(g + c <= 255) + g += c; + if(b + c <= 255) + b += c; + } + data[i] = qRgba(r, g, b, qAlpha(data[i])); + } + return(img); +} + +//====================================================================== +// +// Dithering effects +// +//====================================================================== + +// adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org) +// +// Floyd-Steinberg dithering +// Ref: Bitmapped Graphics Programming in C++ +// Marv Luse, Addison-Wesley Publishing, 1993. +QImage& OImageEffect::dither(QImage &img, const QColor *palette, int size) +{ + if (img.width() == 0 || img.height() == 0 || + palette == 0 || img.depth() <= 8) + return img; + + QImage dImage( img.width(), img.height(), 8, size ); + int i; + + dImage.setNumColors( size ); + for ( i = 0; i < size; i++ ) + dImage.setColor( i, palette[ i ].rgb() ); + + int *rerr1 = new int [ img.width() * 2 ]; + int *gerr1 = new int [ img.width() * 2 ]; + int *berr1 = new int [ img.width() * 2 ]; + + memset( rerr1, 0, sizeof( int ) * img.width() * 2 ); + memset( gerr1, 0, sizeof( int ) * img.width() * 2 ); + memset( berr1, 0, sizeof( int ) * img.width() * 2 ); + + int *rerr2 = rerr1 + img.width(); + int *gerr2 = gerr1 + img.width(); + int *berr2 = berr1 + img.width(); + + for ( int j = 0; j < img.height(); j++ ) + { + uint *ip = (uint * )img.scanLine( j ); + uchar *dp = dImage.scanLine( j ); + + for ( i = 0; i < img.width(); i++ ) + { + rerr1[i] = rerr2[i] + qRed( *ip ); + rerr2[i] = 0; + gerr1[i] = gerr2[i] + qGreen( *ip ); + gerr2[i] = 0; + berr1[i] = berr2[i] + qBlue( *ip ); + berr2[i] = 0; + ip++; + } + + *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size ); + + for ( i = 1; i < img.width()-1; i++ ) + { + int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); + *dp = indx; + + int rerr = rerr1[i]; + rerr -= palette[indx].red(); + int gerr = gerr1[i]; + gerr -= palette[indx].green(); + int berr = berr1[i]; + berr -= palette[indx].blue(); + + // diffuse red error + rerr1[ i+1 ] += ( rerr * 7 ) >> 4; + rerr2[ i-1 ] += ( rerr * 3 ) >> 4; + rerr2[ i ] += ( rerr * 5 ) >> 4; + rerr2[ i+1 ] += ( rerr ) >> 4; + + // diffuse green error + gerr1[ i+1 ] += ( gerr * 7 ) >> 4; + gerr2[ i-1 ] += ( gerr * 3 ) >> 4; + gerr2[ i ] += ( gerr * 5 ) >> 4; + gerr2[ i+1 ] += ( gerr ) >> 4; + + // diffuse red error + berr1[ i+1 ] += ( berr * 7 ) >> 4; + berr2[ i-1 ] += ( berr * 3 ) >> 4; + berr2[ i ] += ( berr * 5 ) >> 4; + berr2[ i+1 ] += ( berr ) >> 4; + + dp++; + } + + *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size ); + } + + delete [] rerr1; + delete [] gerr1; + delete [] berr1; + + img = dImage; + return img; +} + +int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size ) +{ + if (palette == 0) + return 0; + + int dr = palette[0].red() - r; + int dg = palette[0].green() - g; + int db = palette[0].blue() - b; + + int minDist = dr*dr + dg*dg + db*db; + int nearest = 0; + + for (int i = 1; i < size; i++ ) + { + dr = palette[i].red() - r; + dg = palette[i].green() - g; + db = palette[i].blue() - b; + + int dist = dr*dr + dg*dg + db*db; + + if ( dist < minDist ) + { + minDist = dist; + nearest = i; + } + } + + return nearest; +} + +bool OImageEffect::blend( + const QImage & upper, + const QImage & lower, + QImage & output +) +{ + if ( + upper.width() > lower.width() || + upper.height() > lower.height() || + upper.depth() != 32 || + lower.depth() != 32 + ) + { +#ifndef NDEBUG + cerr << "OImageEffect::blend : Sizes not correct\n" ; +#endif + return false; + } + + output = lower.copy(); + + register uchar *i, *o; + register int a; + register int col; + register int w = upper.width(); + int row(upper.height() - 1); + + do { + + i = upper.scanLine(row); + o = output.scanLine(row); + + col = w << 2; + --col; + + do { + + while (!(a = i[col]) && (col != 3)) { + --col; --col; --col; --col; + } + + --col; + o[col] += ((i[col] - o[col]) * a) >> 8; + + --col; + o[col] += ((i[col] - o[col]) * a) >> 8; + + --col; + o[col] += ((i[col] - o[col]) * a) >> 8; + + } while (col--); + + } while (row--); + + return true; +} + +#if 0 +// Not yet... +bool OImageEffect::blend( + const QImage & upper, + const QImage & lower, + QImage & output, + const QRect & destRect +) +{ + output = lower.copy(); + return output; +} + +#endif + +bool OImageEffect::blend( + int &x, int &y, + const QImage & upper, + const QImage & lower, + QImage & output +) +{ + int cx=0, cy=0, cw=upper.width(), ch=upper.height(); + + if ( upper.width() + x > lower.width() || + upper.height() + y > lower.height() || + x < 0 || y < 0 || + upper.depth() != 32 || lower.depth() != 32 ) + { + if ( x > lower.width() || y > lower.height() ) return false; + if ( upper.width()<=0 || upper.height() <= 0 ) return false; + if ( lower.width()<=0 || lower.height() <= 0 ) return false; + + if (x<0) {cx=-x; cw+=x; x=0; }; + if (cw + x > lower.width()) { cw=lower.width()-x; }; + if (y<0) {cy=-y; ch+=y; y=0; }; + if (ch + y > lower.height()) { ch=lower.height()-y; }; + + if ( cx >= upper.width() || cy >= upper.height() ) return true; + if ( cw <= 0 || ch <= 0 ) return true; + } + + output.create(cw,ch,32); +// output.setAlphaBuffer(true); // I should do some benchmarks to see if + // this is worth the effort + + register QRgb *i, *o, *b; + + register int a; + register int j,k; + for (j=0; j<ch; j++) + { + b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]); + i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]); + o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]); + + k=cw-1; + --b; --i; --o; + do + { + while ( !(a=qAlpha(*i)) && k>0 ) + { + i--; +// *o=0; + *o=*b; + --o; --b; + k--; + }; +// *o=0xFF; + *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8), + qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8), + qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8)); + --i; --o; --b; + } while (k--); + } + + return true; +} + +bool OImageEffect::blendOnLower( + int x, int y, + const QImage & upper, + const QImage & lower +) +{ + int cx=0, cy=0, cw=upper.width(), ch=upper.height(); + + if ( upper.depth() != 32 || lower.depth() != 32 ) return false; + if ( x + cw > lower.width() || + y + ch > lower.height() || + x < 0 || y < 0 ) + { + if ( x > lower.width() || y > lower.height() ) return true; + if ( upper.width()<=0 || upper.height() <= 0 ) return true; + if ( lower.width()<=0 || lower.height() <= 0 ) return true; + + if (x<0) {cx=-x; cw+=x; x=0; }; + if (cw + x > lower.width()) { cw=lower.width()-x; }; + if (y<0) {cy=-y; ch+=y; y=0; }; + if (ch + y > lower.height()) { ch=lower.height()-y; }; + + if ( cx >= upper.width() || cy >= upper.height() ) return true; + if ( cw <= 0 || ch <= 0 ) return true; + } + + register uchar *i, *b; + register int a; + register int k; + + for (int j=0; j<ch; j++) + { + b=&lower.scanLine(y+j) [ (x+cw) << 2 ]; + i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ]; + + k=cw-1; + --b; --i; + do + { +#ifndef WORDS_BIGENDIAN + while ( !(a=*i) && k>0 ) +#else + while ( !(a=*(i-3)) && k>0 ) +#endif + { + i-=4; b-=4; k--; + }; + +#ifndef WORDS_BIGENDIAN + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; +#else + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + --i; --b; + *b += ( ((*i - *b) * a) >> 8 ); + i -= 2; b -= 2; +#endif + } while (k--); + } + + return true; +} + +// For selected icons +QImage& OImageEffect::selectedImage( QImage &img, const QColor &col ) +{ + return blend( col, img, 0.5); +} + +// +// =================================================================== +// Effects originally ported from ImageMagick for PixiePlus, plus a few +// new ones. (mosfet 12/29/01) +// =================================================================== +// + +void OImageEffect::normalize(QImage &img) +{ + int *histogram, threshold_intensity, intense; + int x, y, i; + + unsigned int gray_value; + unsigned int *normalize_map; + unsigned int high, low; + + // allocate histogram and normalize map + histogram = (int *)calloc(MaxRGB+1, sizeof(int)); + normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int)); + if(!normalize_map || !histogram){ + qWarning("Unable to allocate normalize histogram and map"); + free(normalize_map); + free(histogram); + return; + } + + // form histogram + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + gray_value = intensityValue(data[x]); + histogram[gray_value]++; + } + } + } + else{ // PsudeoClass + unsigned char *data; + unsigned int *cTable = img.colorTable(); + for(y=0; y < img.height(); ++y){ + data = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + gray_value = intensityValue(*(cTable+data[x])); + histogram[gray_value]++; + } + } + } + + // find histogram boundaries by locating the 1 percent levels + threshold_intensity = (img.width()*img.height())/100; + intense = 0; + for(low=0; low < MaxRGB; ++low){ + intense+=histogram[low]; + if(intense > threshold_intensity) + break; + } + intense=0; + for(high=MaxRGB; high != 0; --high){ + intense+=histogram[high]; + if(intense > threshold_intensity) + break; + } + + if (low == high){ + // Unreasonable contrast; use zero threshold to determine boundaries. + threshold_intensity=0; + intense=0; + for(low=0; low < MaxRGB; ++low){ + intense+=histogram[low]; + if(intense > threshold_intensity) + break; + } + intense=0; + for(high=MaxRGB; high != 0; --high) + { + intense+=histogram[high]; + if(intense > threshold_intensity) + break; + } + if(low == high) + return; // zero span bound + } + + // Stretch the histogram to create the normalized image mapping. + for(i=0; i <= MaxRGB; i++){ + if (i < (int) low) + normalize_map[i]=0; + else{ + if(i > (int) high) + normalize_map[i]=MaxRGB; + else + normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low); + } + } + // Normalize + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + data[x] = qRgba(normalize_map[qRed(data[x])], + normalize_map[qGreen(data[x])], + normalize_map[qBlue(data[x])], + qAlpha(data[x])); + } + } + } + else{ // PsudeoClass + int colors = img.numColors(); + unsigned int *cTable = img.colorTable(); + for(i=0; i < colors; ++i){ + cTable[i] = qRgba(normalize_map[qRed(cTable[i])], + normalize_map[qGreen(cTable[i])], + normalize_map[qBlue(cTable[i])], + qAlpha(cTable[i])); + } + } + free(histogram); + free(normalize_map); +} + + +void OImageEffect::equalize(QImage &img) +{ + int *histogram, *map, *equalize_map; + int x, y, i, j; + + unsigned int high, low; + + // allocate histogram and maps + histogram = (int *)calloc(MaxRGB+1, sizeof(int)); + map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); + equalize_map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int)); + + if(!histogram || !map || !equalize_map){ + qWarning("Unable to allocate equalize histogram and maps"); + free(histogram); + free(map); + free(equalize_map); + return; + } + // form histogram + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + histogram[intensityValue(data[x])]++; + } + } + } + else{ // PsudeoClass + unsigned char *data; + unsigned int *cTable = img.colorTable(); + for(y=0; y < img.height(); ++y){ + data = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + histogram[intensityValue(*(cTable+data[x]))]++; + } + } + } + + // integrate the histogram to get the equalization map. + j=0; + for(i=0; i <= MaxRGB; i++){ + j+=histogram[i]; + map[i]=j; + } + free(histogram); + if(map[MaxRGB] == 0){ + free(equalize_map); + free(map); + return; + } + // equalize + low=map[0]; + high=map[MaxRGB]; + for(i=0; i <= MaxRGB; i++) + equalize_map[i]=(unsigned int) + ((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1)); + free(map); + // stretch the histogram + if(img.depth() > 8){ // DirectClass + unsigned int *data; + for(y=0; y < img.height(); ++y){ + data = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + data[x] = qRgba(equalize_map[qRed(data[x])], + equalize_map[qGreen(data[x])], + equalize_map[qBlue(data[x])], + qAlpha(data[x])); + } + } + } + else{ // PsudeoClass + int colors = img.numColors(); + unsigned int *cTable = img.colorTable(); + for(i=0; i < colors; ++i){ + cTable[i] = qRgba(equalize_map[qRed(cTable[i])], + equalize_map[qGreen(cTable[i])], + equalize_map[qBlue(cTable[i])], + qAlpha(cTable[i])); + } + } + free(equalize_map); +} + +QImage OImageEffect::sample(QImage &src, int w, int h) +{ + if(w == src.width() && h == src.height()) + return(src); + + double *x_offset, *y_offset; + int j, k, y; + register int x; + QImage dest(w, h, src.depth()); + + x_offset = (double *)malloc(w*sizeof(double)); + y_offset = (double *)malloc(h*sizeof(double)); + if(!x_offset || !y_offset){ + qWarning("Unable to allocate pixels buffer"); + free(x_offset); + free(y_offset); + return(src); + } + + // init pixel offsets + for(x=0; x < w; ++x) + x_offset[x] = x*src.width()/((double)w); + for(y=0; y < h; ++y) + y_offset[y] = y*src.height()/((double)h); + + // sample each row + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData, *destData; + unsigned int *pixels; + pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int)); + if(!pixels){ + qWarning("Unable to allocate pixels buffer"); + free(pixels); + free(x_offset); + free(y_offset); + return(src); + } + j = (-1); + for(y=0; y < h; ++y){ + destData = (unsigned int *)dest.scanLine(y); + if(j != y_offset[y]){ + // read a scan line + j = (int)(y_offset[y]); + srcData = (unsigned int *)src.scanLine(j); + (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int)); + } + // sample each column + for(x=0; x < w; ++x){ + k = (int)(x_offset[x]); + destData[x] = pixels[k]; + } + } + free(pixels); + } + else{ // PsudeoClass source image + unsigned char *srcData, *destData; + unsigned char *pixels; + pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char)); + if(!pixels){ + qWarning("Unable to allocate pixels buffer"); + free(pixels); + free(x_offset); + free(y_offset); + return(src); + } + // copy colortable + dest.setNumColors(src.numColors()); + (void)memcpy(dest.colorTable(), src.colorTable(), + src.numColors()*sizeof(unsigned int)); + + // sample image + j = (-1); + for(y=0; y < h; ++y){ + destData = (unsigned char *)dest.scanLine(y); + if(j != y_offset[y]){ + // read a scan line + j = (int)(y_offset[y]); + srcData = (unsigned char *)src.scanLine(j); + (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char)); + } + // sample each column + for(x=0; x < w; ++x){ + k = (int)(x_offset[x]); + destData[x] = pixels[k]; + } + } + free(pixels); + } + free(x_offset); + free(y_offset); + return(dest); +} + +void OImageEffect::threshold(QImage &img, unsigned int threshold) +{ + int i, count; + unsigned int *data; + if(img.depth() > 8){ // DirectClass + count = img.width()*img.height(); + data = (unsigned int *)img.bits(); + } + else{ // PsudeoClass + count = img.numColors(); + data = (unsigned int *)img.colorTable(); + } + for(i=0; i < count; ++i) + data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb(); +} + +QImage OImageEffect::charcoal(QImage &src, double factor) +{ + QImage dest(src); + dest.detach(); + toGray(dest); + dest = edge(dest, factor); + dest = blur(dest, factor); + normalize(dest); + dest.invertPixels(false); + return(dest); +} + +void OImageEffect::hull(const int x_offset, const int y_offset, + const int polarity, const int columns, + const int rows, + unsigned int *f, unsigned int *g) +{ + int x, y; + + unsigned int *p, *q, *r, *s; + unsigned int v; + if(f == NULL || g == NULL) + return; + p=f+(columns+2); + q=g+(columns+2); + r=p+(y_offset*(columns+2)+x_offset); + for (y=0; y < rows; y++){ + p++; + q++; + r++; + if(polarity > 0) + for (x=0; x < columns; x++){ + v=(*p); + if (*r > v) + v++; + *q=v; + p++; + q++; + r++; + } + else + for(x=0; x < columns; x++){ + v=(*p); + if (v > (unsigned int) (*r+1)) + v--; + *q=v; + p++; + q++; + r++; + } + p++; + q++; + r++; + } + p=f+(columns+2); + q=g+(columns+2); + r=q+(y_offset*(columns+2)+x_offset); + s=q-(y_offset*(columns+2)+x_offset); + for(y=0; y < rows; y++){ + p++; + q++; + r++; + s++; + if(polarity > 0) + for(x=0; x < (int) columns; x++){ + v=(*q); + if (((unsigned int) (*s+1) > v) && (*r > v)) + v++; + *p=v; + p++; + q++; + r++; + s++; + } + else + for (x=0; x < columns; x++){ + v=(*q); + if (((unsigned int) (*s+1) < v) && (*r < v)) + v--; + *p=v; + p++; + q++; + r++; + s++; + } + p++; + q++; + r++; + s++; + } +} + +QImage OImageEffect::despeckle(QImage &src) +{ + int i, j, x, y; + unsigned int *blue_channel, *red_channel, *green_channel, *buffer, + *alpha_channel; + int packets; + static const int + X[4]= {0, 1, 1,-1}, + Y[4]= {1, 0, 1, 1}; + + unsigned int *destData; + QImage dest(src.width(), src.height(), 32); + + packets = (src.width()+2)*(src.height()+2); + red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int)); + buffer = (unsigned int *)calloc(packets, sizeof(unsigned int)); + if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel || + !buffer){ + free(red_channel); + free(green_channel); + free(blue_channel); + free(alpha_channel); + free(buffer); + return(src); + } + + // copy image pixels to color component buffers + j = src.width()+2; + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y); + ++j; + for(x=0; x < src.width(); ++x){ + red_channel[j] = qRed(srcData[x]); + green_channel[j] = qGreen(srcData[x]); + blue_channel[j] = qBlue(srcData[x]); + alpha_channel[j] = qAlpha(srcData[x]); + ++j; + } + ++j; + } + } + else{ // PsudeoClass source image + unsigned char *srcData; + unsigned int *cTable = src.colorTable(); + unsigned int pixel; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned char *)src.scanLine(y); + ++j; + for(x=0; x < src.width(); ++x){ + pixel = *(cTable+srcData[x]); + red_channel[j] = qRed(pixel); + green_channel[j] = qGreen(pixel); + blue_channel[j] = qBlue(pixel); + alpha_channel[j] = qAlpha(pixel); + ++j; + } + ++j; + } + } + // reduce speckle in red channel + for(i=0; i < 4; i++){ + hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer); + hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer); + hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer); + hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer); + } + // reduce speckle in green channel + for (i=0; i < packets; i++) + buffer[i]=0; + for (i=0; i < 4; i++){ + hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer); + hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer); + hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer); + hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer); + } + // reduce speckle in blue channel + for (i=0; i < packets; i++) + buffer[i]=0; + for (i=0; i < 4; i++){ + hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer); + hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer); + hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer); + hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer); + } + // copy color component buffers to despeckled image + j = dest.width()+2; + for(y=0; y < dest.height(); ++y) + { + destData = (unsigned int *)dest.scanLine(y); + ++j; + for (x=0; x < dest.width(); ++x) + { + destData[x] = qRgba(red_channel[j], green_channel[j], + blue_channel[j], alpha_channel[j]); + ++j; + } + ++j; + } + free(buffer); + free(red_channel); + free(green_channel); + free(blue_channel); + free(alpha_channel); + return(dest); +} + +unsigned int OImageEffect::generateNoise(unsigned int pixel, + NoiseType noise_type) +{ +#define NoiseEpsilon 1.0e-5 +#define NoiseMask 0x7fff +#define SigmaUniform 4.0 +#define SigmaGaussian 4.0 +#define SigmaImpulse 0.10 +#define SigmaLaplacian 10.0 +#define SigmaMultiplicativeGaussian 0.5 +#define SigmaPoisson 0.05 +#define TauGaussian 20.0 + + double alpha, beta, sigma, value; + alpha=(double) (rand() & NoiseMask)/NoiseMask; + if (alpha == 0.0) + alpha=1.0; + switch(noise_type){ + case UniformNoise: + default: + { + value=(double) pixel+SigmaUniform*(alpha-0.5); + break; + } + case GaussianNoise: + { + double tau; + + beta=(double) (rand() & NoiseMask)/NoiseMask; + sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta); + tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta); + value=(double) pixel+ + (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau); + break; + } + case MultiplicativeGaussianNoise: + { + if (alpha <= NoiseEpsilon) + sigma=MaxRGB; + else + sigma=sqrt(-2.0*log(alpha)); + beta=(rand() & NoiseMask)/NoiseMask; + value=(double) pixel+ + pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta); + break; + } + case ImpulseNoise: + { + if (alpha < (SigmaImpulse/2.0)) + value=0; + else + if (alpha >= (1.0-(SigmaImpulse/2.0))) + value=MaxRGB; + else + value=pixel; + break; + } + case LaplacianNoise: + { + if (alpha <= 0.5) + { + if (alpha <= NoiseEpsilon) + value=(double) pixel-MaxRGB; + else + value=(double) pixel+SigmaLaplacian*log(2.0*alpha); + break; + } + beta=1.0-alpha; + if (beta <= (0.5*NoiseEpsilon)) + value=(double) pixel+MaxRGB; + else + value=(double) pixel-SigmaLaplacian*log(2.0*beta); + break; + } + case PoissonNoise: + { + register int + i; + + for (i=0; alpha > exp(-SigmaPoisson*pixel); i++) + { + beta=(double) (rand() & NoiseMask)/NoiseMask; + alpha=alpha*beta; + } + value=i/SigmaPoisson; + break; + } + } + if(value < 0.0) + return(0); + if(value > MaxRGB) + return(MaxRGB); + return((unsigned int) (value+0.5)); +} + +QImage OImageEffect::addNoise(QImage &src, NoiseType noise_type) +{ + int x, y; + QImage dest(src.width(), src.height(), 32); + unsigned int *destData; + + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + for(x=0; x < src.width(); ++x){ + destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type), + generateNoise(qGreen(srcData[x]), noise_type), + generateNoise(qBlue(srcData[x]), noise_type), + qAlpha(srcData[x])); + } + } + } + else{ // PsudeoClass source image + unsigned char *srcData; + unsigned int *cTable = src.colorTable(); + unsigned int pixel; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned char *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + for(x=0; x < src.width(); ++x){ + pixel = *(cTable+srcData[x]); + destData[x] = qRgba(generateNoise(qRed(pixel), noise_type), + generateNoise(qGreen(pixel), noise_type), + generateNoise(qBlue(pixel), noise_type), + qAlpha(pixel)); + } + } + + } + return(dest); +} + +unsigned int OImageEffect::interpolateColor(QImage *image, double x_offset, + double y_offset, + unsigned int background) +{ + double alpha, beta; + unsigned int p, q, r, s; + int x, y; + + x = (int)x_offset; + y = (int)y_offset; + if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height())) + return(background); + if(image->depth() > 8){ + if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { + unsigned int *t = (unsigned int *)image->scanLine(y); + p = t[x]; + q = t[x+1]; + r = t[x+image->width()]; + s = t[x+image->width()+1]; + } + else{ + unsigned int *t = (unsigned int *)image->scanLine(y); + p = background; + if((x >= 0) && (y >= 0)){ + p = t[x]; + } + q = background; + if(((x+1) < image->width()) && (y >= 0)){ + q = t[x+1]; + } + r = background; + if((x >= 0) && ((y+1) < image->height())){ + t = (unsigned int *)image->scanLine(y+1); + r = t[x+image->width()]; + } + s = background; + if(((x+1) < image->width()) && ((y+1) < image->height())){ + t = (unsigned int *)image->scanLine(y+1); + s = t[x+image->width()+1]; + } + + } + } + else{ + unsigned int *colorTable = (unsigned int *)image->colorTable(); + if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) { + unsigned char *t; + t = (unsigned char *)image->scanLine(y); + p = *(colorTable+t[x]); + q = *(colorTable+t[x+1]); + t = (unsigned char *)image->scanLine(y+1); + r = *(colorTable+t[x]); + s = *(colorTable+t[x+1]); + } + else{ + unsigned char *t; + p = background; + if((x >= 0) && (y >= 0)){ + t = (unsigned char *)image->scanLine(y); + p = *(colorTable+t[x]); + } + q = background; + if(((x+1) < image->width()) && (y >= 0)){ + t = (unsigned char *)image->scanLine(y); + q = *(colorTable+t[x+1]); + } + r = background; + if((x >= 0) && ((y+1) < image->height())){ + t = (unsigned char *)image->scanLine(y+1); + r = *(colorTable+t[x]); + } + s = background; + if(((x+1) < image->width()) && ((y+1) < image->height())){ + t = (unsigned char *)image->scanLine(y+1); + s = *(colorTable+t[x+1]); + } + + } + + } + x_offset -= floor(x_offset); + y_offset -= floor(y_offset); + alpha = 1.0-x_offset; + beta = 1.0-y_offset; + + return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))), + (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))), + (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))), + (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s))))); +} + +QImage OImageEffect::implode(QImage &src, double factor, + unsigned int background) +{ + double amount, distance, radius; + double x_center, x_distance, x_scale; + double y_center, y_distance, y_scale; + unsigned int *destData; + int x, y; + + QImage dest(src.width(), src.height(), 32); + + // compute scaling factor + x_scale = 1.0; + y_scale = 1.0; + x_center = (double)0.5*src.width(); + y_center = (double)0.5*src.height(); + radius=x_center; + if(src.width() > src.height()) + y_scale = (double)src.width()/src.height(); + else if(src.width() < src.height()){ + x_scale = (double) src.height()/src.width(); + radius = y_center; + } + amount=factor/10.0; + if(amount >= 0) + amount/=10.0; + if(src.depth() > 8){ // DirectClass source image + unsigned int *srcData; + for(y=0; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + y_distance=y_scale*(y-y_center); + for(x=0; x < src.width(); ++x){ + destData[x] = srcData[x]; + x_distance = x_scale*(x-x_center); + distance= x_distance*x_distance+y_distance*y_distance; + if(distance < (radius*radius)){ + double factor; + // Implode the pixel. + factor=1.0; + if(distance > 0.0) + factor= + pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); + destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, + factor*y_distance/y_scale+y_center, + background); + } + } + } + } + else{ // PsudeoClass source image + unsigned char *srcData; + unsigned char idx; + unsigned int *cTable = src.colorTable(); + for(y=0; y < src.height(); ++y){ + srcData = (unsigned char *)src.scanLine(y); + destData = (unsigned int *)dest.scanLine(y); + y_distance=y_scale*(y-y_center); + for(x=0; x < src.width(); ++x){ + idx = srcData[x]; + destData[x] = cTable[idx]; + x_distance = x_scale*(x-x_center); + distance= x_distance*x_distance+y_distance*y_distance; + if(distance < (radius*radius)){ + double factor; + // Implode the pixel. + factor=1.0; + if(distance > 0.0) + factor= + pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount); + destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center, + factor*y_distance/y_scale+y_center, + background); + } + } + } + + } + return(dest); +} + +QImage OImageEffect::rotate(QImage &img, RotateDirection r) +{ + QImage dest; + int x, y; + if(img.depth() > 8){ + unsigned int *srcData, *destData; + switch(r){ + case Rotate90: + dest.create(img.height(), img.width(), img.depth()); + for(y=0; y < img.height(); ++y){ + srcData = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned int *)dest.scanLine(x); + destData[img.height()-y-1] = srcData[x]; + } + } + break; + case Rotate180: + dest.create(img.width(), img.height(), img.depth()); + for(y=0; y < img.height(); ++y){ + srcData = (unsigned int *)img.scanLine(y); + destData = (unsigned int *)dest.scanLine(img.height()-y-1); + for(x=0; x < img.width(); ++x) + destData[img.width()-x-1] = srcData[x]; + } + break; + case Rotate270: + dest.create(img.height(), img.width(), img.depth()); + for(y=0; y < img.height(); ++y){ + srcData = (unsigned int *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned int *)dest.scanLine(img.width()-x-1); + destData[y] = srcData[x]; + } + } + break; + default: + dest = img; + break; + } + } + else{ + unsigned char *srcData, *destData; + unsigned int *srcTable, *destTable; + switch(r){ + case Rotate90: + dest.create(img.height(), img.width(), img.depth()); + dest.setNumColors(img.numColors()); + srcTable = (unsigned int *)img.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for(x=0; x < img.numColors(); ++x) + destTable[x] = srcTable[x]; + for(y=0; y < img.height(); ++y){ + srcData = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned char *)dest.scanLine(x); + destData[img.height()-y-1] = srcData[x]; + } + } + break; + case Rotate180: + dest.create(img.width(), img.height(), img.depth()); + dest.setNumColors(img.numColors()); + srcTable = (unsigned int *)img.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for(x=0; x < img.numColors(); ++x) + destTable[x] = srcTable[x]; + for(y=0; y < img.height(); ++y){ + srcData = (unsigned char *)img.scanLine(y); + destData = (unsigned char *)dest.scanLine(img.height()-y-1); + for(x=0; x < img.width(); ++x) + destData[img.width()-x-1] = srcData[x]; + } + break; + case Rotate270: + dest.create(img.height(), img.width(), img.depth()); + dest.setNumColors(img.numColors()); + srcTable = (unsigned int *)img.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for(x=0; x < img.numColors(); ++x) + destTable[x] = srcTable[x]; + for(y=0; y < img.height(); ++y){ + srcData = (unsigned char *)img.scanLine(y); + for(x=0; x < img.width(); ++x){ + destData = (unsigned char *)dest.scanLine(img.width()-x-1); + destData[y] = srcData[x]; + } + } + break; + default: + dest = img; + break; + } + + } + return(dest); +} + +void OImageEffect::solarize(QImage &img, double factor) +{ + int i, count; + int threshold; + unsigned int *data; + + threshold = (int)(factor*(MaxRGB+1)/100.0); + if(img.depth() < 32){ + data = (unsigned int *)img.colorTable(); + count = img.numColors(); + } + else{ + data = (unsigned int *)img.bits(); + count = img.width()*img.height(); + } + for(i=0; i < count; ++i){ + data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]), + qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]), + qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]), + qAlpha(data[i])); + } +} + +QImage OImageEffect::spread(QImage &src, unsigned int amount) +{ + int quantum, x, y; + int x_distance, y_distance; + if(src.width() < 3 || src.height() < 3) + return(src); + QImage dest(src); + dest.detach(); + quantum=(amount+1) >> 1; + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *q; + for(y=0; y < src.height(); y++){ + q = (unsigned int *)dest.scanLine(y); + for(x=0; x < src.width(); x++){ + x_distance = x + ((rand() & (amount+1))-quantum); + y_distance = y + ((rand() & (amount+1))-quantum); + x_distance = QMIN(x_distance, src.width()-1); + y_distance = QMIN(y_distance, src.height()-1); + if(x_distance < 0) + x_distance = 0; + if(y_distance < 0) + y_distance = 0; + p = (unsigned int *)src.scanLine(y_distance); + p += x_distance; + *q++=(*p); + } + } + } + else{ // PsudeoClass source image + // just do colortable values + unsigned char *p, *q; + for(y=0; y < src.height(); y++){ + q = (unsigned char *)dest.scanLine(y); + for(x=0; x < src.width(); x++){ + x_distance = x + ((rand() & (amount+1))-quantum); + y_distance = y + ((rand() & (amount+1))-quantum); + x_distance = QMIN(x_distance, src.width()-1); + y_distance = QMIN(y_distance, src.height()-1); + if(x_distance < 0) + x_distance = 0; + if(y_distance < 0) + y_distance = 0; + p = (unsigned char *)src.scanLine(y_distance); + p += x_distance; + *q++=(*p); + } + } + } + return(dest); +} + +QImage OImageEffect::swirl(QImage &src, double degrees, + unsigned int background) +{ + double cosine, distance, factor, radius, sine, x_center, x_distance, + x_scale, y_center, y_distance, y_scale; + int x, y; + unsigned int *q; + QImage dest(src.width(), src.height(), 32); + + // compute scaling factor + x_center = src.width()/2.0; + y_center = src.height()/2.0; + radius = QMAX(x_center,y_center); + x_scale=1.0; + y_scale=1.0; + if(src.width() > src.height()) + y_scale=(double)src.width()/src.height(); + else if(src.width() < src.height()) + x_scale=(double)src.height()/src.width(); + degrees=DegreesToRadians(degrees); + // swirl each row + if(src.depth() > 8){ // DirectClass source image + unsigned int *p; + for(y=0; y < src.height(); y++){ + p = (unsigned int *)src.scanLine(y); + q = (unsigned int *)dest.scanLine(y); + y_distance = y_scale*(y-y_center); + for(x=0; x < src.width(); x++){ + // determine if the pixel is within an ellipse + *q=(*p); + x_distance = x_scale*(x-x_center); + distance = x_distance*x_distance+y_distance*y_distance; + if (distance < (radius*radius)){ + // swirl + factor = 1.0-sqrt(distance)/radius; + sine = sin(degrees*factor*factor); + cosine = cos(degrees*factor*factor); + *q = interpolateColor(&src, + (cosine*x_distance-sine*y_distance)/x_scale+x_center, + (sine*x_distance+cosine*y_distance)/y_scale+y_center, + background); + } + p++; + q++; + } + } + } + else{ // PsudeoClass source image + unsigned char *p; + unsigned int *cTable = (unsigned int *)src.colorTable(); + for(y=0; y < src.height(); y++){ + p = (unsigned char *)src.scanLine(y); + q = (unsigned int *)dest.scanLine(y); + y_distance = y_scale*(y-y_center); + for(x=0; x < src.width(); x++){ + // determine if the pixel is within an ellipse + *q = *(cTable+(*p)); + x_distance = x_scale*(x-x_center); + distance = x_distance*x_distance+y_distance*y_distance; + if (distance < (radius*radius)){ + // swirl + factor = 1.0-sqrt(distance)/radius; + sine = sin(degrees*factor*factor); + cosine = cos(degrees*factor*factor); + *q = interpolateColor(&src, + (cosine*x_distance-sine*y_distance)/x_scale+x_center, + (sine*x_distance+cosine*y_distance)/y_scale+y_center, + background); + } + p++; + q++; + } + } + + } + return(dest); +} + +QImage OImageEffect::wave(QImage &src, double amplitude, double wavelength, + unsigned int background) +{ + double *sine_map; + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32); + // allocate sine map + sine_map = (double *)malloc(dest.width()*sizeof(double)); + if(!sine_map) + return(src); + for(x=0; x < dest.width(); ++x) + sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength); + // wave image + for(y=0; y < dest.height(); ++y){ + q = (unsigned int *)dest.scanLine(y); + for (x=0; x < dest.width(); x++){ + *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background); + ++q; + } + } + free(sine_map); + return(dest); +} + +QImage OImageEffect::oilPaint(QImage &src, int radius) +{ + // TODO 8bpp src! + if(src.depth() < 32){ + qWarning("Oil Paint source image < 32bpp. Convert before using!"); + return(src); + } + int j, k, i, x, y; + unsigned int *histogram; + unsigned int *s; + unsigned int count; + + unsigned int *srcData, *destData; + + QImage dest(src); + dest.detach(); + histogram = (unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int)); + if(!histogram) + return(src); + // paint each row + k=0; + for(y = radius; y < src.height(); ++y){ + srcData = (unsigned int *)src.scanLine(y-radius); + destData = (unsigned int *)dest.scanLine(y); + srcData += radius*src.width()+radius; + destData += radius; + for(x=radius; x < src.width()-radius; ++x){ + // determine most frequent color + count = 0; + for(i=0; i < MaxRGB+1; ++i) + histogram[i] = 0; + for(i=0; i < radius; ++i){ + s = srcData-(radius-1)*src.width()-i-1; + for(j =0; j < (2*i+1); ++j){ + k = intensityValue(*s); + histogram[k]++; + if(histogram[k] > count){ + *destData = *s; + count = histogram[k]; + } + ++s; + } + s = srcData+(radius-i)*src.width()-i-1; + for(j =0; j < (2*i+1); ++j){ + k = intensityValue(*s); + histogram[k]++; + if(histogram[k] > count){ + *destData = *s; + count = histogram[k]; + } + ++s; + } + } + s = srcData-radius; + for(j =0; j < (2*i+1); ++j){ + k = intensityValue(*s); + histogram[k]++; + if(histogram[k] > count){ + *destData = *s; + count = histogram[k]; + } + ++s; + } + ++srcData; + ++destData; + } + } + free(histogram); + return(dest); +} + +// +// The following methods work by computing a value from neighboring pixels +// (mosfet 12/28/01) +// + +QImage OImageEffect::edge(QImage &src, double factor) +{ +#define Edge(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + total_opacity+=(weight)*qAlpha(*s); \ + s++; + +#define Edge256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double total_blue, total_green, total_opacity, total_red, weight; + + int x, y; + + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + weight=factor/8.0; + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // edge detect this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Edge(-weight/8); Edge(-weight/8) Edge(-weight/8); + s=p+src.width(); + Edge(-weight/8); Edge(weight); Edge(-weight/8); + s=p+2*src.width(); + Edge(-weight/8); Edge(-weight/8); Edge(-weight/8); + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // edge detect this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Edge256(-weight/8); Edge256(-weight/8) Edge256(-weight/8); + s=p2; + Edge256(-weight/8); Edge256(weight); Edge256(-weight/8); + s=p3; + Edge256(-weight/8); Edge256(-weight/8); Edge256(-weight/8); + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity)); + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + return(dest); +} + +QImage OImageEffect::sharpen(QImage &src, double factor) +{ +#define Sharpen(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + total_opacity+=(weight)*qAlpha(*s); \ + s++; + +#define Sharpen256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double total_blue, total_green, total_opacity, total_red; + double quantum, weight; + unsigned char r, g, b, a; + + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + weight = ((100.0-factor)/2.0+13.0); + quantum = QMAX(weight-12.0, 1.0); + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // sharpen this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Sharpen(-1); Sharpen(-2); Sharpen(-1); + s=p+src.width(); + Sharpen(-2); Sharpen(weight); Sharpen(-2); + s=p+2*src.width(); + Sharpen(-1); Sharpen(-2); Sharpen(-1); + if(total_red < 0) + r=0; + else if(total_red > (int)(MaxRGB*quantum)) + r = (unsigned char)MaxRGB; + else + r = (unsigned char)((total_red+(quantum/2.0))/quantum); + + if(total_green < 0) + g = 0; + else if(total_green > (int)(MaxRGB*quantum)) + g = (unsigned char)MaxRGB; + else + g = (unsigned char)((total_green+(quantum/2.0))/quantum); + + if(total_blue < 0) + b = 0; + else if(total_blue > (int)(MaxRGB*quantum)) + b = (unsigned char)MaxRGB; + else + b = (unsigned char)((total_blue+(quantum/2.0))/quantum); + + if(total_opacity < 0) + a = 0; + else if(total_opacity > (int)(MaxRGB*quantum)) + a = (unsigned char)MaxRGB; + else + a= (unsigned char)((total_opacity+(quantum/2.0))/quantum); + + *q = qRgba(r, g, b, a); + + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // sharpen this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); + s=p2; + Sharpen256(-2); Sharpen256(weight); Sharpen256(-2); + s=p3; + Sharpen256(-1); Sharpen256(-2); Sharpen256(-1); + if(total_red < 0) + r=0; + else if(total_red > (int)(MaxRGB*quantum)) + r = (unsigned char)MaxRGB; + else + r = (unsigned char)((total_red+(quantum/2.0))/quantum); + + if(total_green < 0) + g = 0; + else if(total_green > (int)(MaxRGB*quantum)) + g = (unsigned char)MaxRGB; + else + g = (unsigned char)((total_green+(quantum/2.0))/quantum); + + if(total_blue < 0) + b = 0; + else if(total_blue > (int)(MaxRGB*quantum)) + b = (unsigned char)MaxRGB; + else + b = (unsigned char)((total_blue+(quantum/2.0))/quantum); + + if(total_opacity < 0) + a = 0; + else if(total_opacity > (int)(MaxRGB*quantum)) + a = (unsigned char)MaxRGB; + else + a = (unsigned char)((total_opacity+(quantum/2.0))/quantum); + + *q = qRgba(r, g, b, a); + + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + return(dest); +} + +QImage OImageEffect::emboss(QImage &src) +{ +#define Emboss(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + s++; + +#define Emboss256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double total_blue, total_green, total_red; + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // emboss this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + s=p; + Emboss(-1); Emboss(-2); Emboss( 0); + s=p+src.width(); + Emboss(-2); Emboss( 0); Emboss( 2); + s=p+2*src.width(); + Emboss( 0); Emboss( 2); Emboss( 1); + total_red += (MaxRGB+1)/2; + total_green += (MaxRGB+1)/2; + total_blue += (MaxRGB+1)/2; + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + 255); + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // emboss this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + s=p; + Emboss256(-1); Emboss256(-2); Emboss256(0); + s=p2; + Emboss256(-2); Emboss256(0); Emboss256(2); + s=p3; + Emboss256(0); Emboss256(2); Emboss256(1); + total_red += (MaxRGB+1)/2; + total_green += (MaxRGB+1)/2; + total_blue += (MaxRGB+1)/2; + *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red), + (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green), + (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue), + 255); + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + toGray(dest); + normalize(dest); + return(dest); +} + +QImage OImageEffect::shade(QImage &src, bool color_shading, double azimuth, + double elevation) +{ + struct PointInfo{ + double x, y, z; + }; + + double distance, normal_distance, shade; + int x, y; + + struct PointInfo light, normal; + + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + + azimuth = DegreesToRadians(azimuth); + elevation = DegreesToRadians(elevation); + light.x = MaxRGB*cos(azimuth)*cos(elevation); + light.y = MaxRGB*sin(azimuth)*cos(elevation); + light.z = MaxRGB*sin(elevation); + normal.z= 2*MaxRGB; // constant Z of surface normal + + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s0, *s1, *s2; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // shade this row of pixels. + *q++=(*(p+src.width())); + p++; + s0 = p; + s1 = p + src.width(); + s2 = p + 2*src.width(); + for(x=1; x < src.width()-1; ++x){ + // determine the surface normal and compute shading. + normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))- + (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))- + (double) intensityValue(*(s2+1)); + normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))- + (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)- + (double) intensityValue(*(s0+1)); + if((normal.x == 0) && (normal.y == 0)) + shade=light.z; + else{ + shade=0.0; + distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; + if (distance > 0.0){ + normal_distance= + normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; + if(fabs(normal_distance) > 0.0000001) + shade=distance/sqrt(normal_distance); + } + } + if(!color_shading){ + *q = qRgba((unsigned char)(shade), + (unsigned char)(shade), + (unsigned char)(shade), + qAlpha(*s1)); + } + else{ + *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)), + (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)), + (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)), + qAlpha(*s1)); + } + ++s0; + ++s1; + ++s2; + q++; + } + *q++=(*s1); + } + } + else{ // PsudeoClass source image + unsigned char *p, *s0, *s1, *s2; + int scanLineIdx; + unsigned int *cTable = (unsigned int *)src.colorTable(); + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + q = (unsigned int *)dest.scanLine(y); + // shade this row of pixels. + s0 = p; + s1 = (unsigned char *) src.scanLine(scanLineIdx+1); + s2 = (unsigned char *) src.scanLine(scanLineIdx+2); + *q++=(*(cTable+(*s1))); + ++p; + ++s0; + ++s1; + ++s2; + for(x=1; x < src.width()-1; ++x){ + // determine the surface normal and compute shading. + normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))- + (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))- + (double) intensityValue(*(cTable+(*(s2+1)))); + normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))- + (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))- + (double) intensityValue(*(cTable+(*(s0+1)))); + if((normal.x == 0) && (normal.y == 0)) + shade=light.z; + else{ + shade=0.0; + distance=normal.x*light.x+normal.y*light.y+normal.z*light.z; + if (distance > 0.0){ + normal_distance= + normal.x*normal.x+normal.y*normal.y+normal.z*normal.z; + if(fabs(normal_distance) > 0.0000001) + shade=distance/sqrt(normal_distance); + } + } + if(!color_shading){ + *q = qRgba((unsigned char)(shade), + (unsigned char)(shade), + (unsigned char)(shade), + qAlpha(*(cTable+(*s1)))); + } + else{ + *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)), + (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)), + (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)), + qAlpha(*s1)); + } + ++s0; + ++s1; + ++s2; + q++; + } + *q++=(*(cTable+(*s1))); + } + } + return(dest); +} + +QImage OImageEffect::blur(QImage &src, double factor) +{ + +#define Blur(weight) \ + total_red+=(weight)*qRed(*s); \ + total_green+=(weight)*qGreen(*s); \ + total_blue+=(weight)*qBlue(*s); \ + total_opacity+=(weight)*qAlpha(*s); \ + s++; + +#define Blur256(weight) \ + total_red+=(weight)*qRed(*(cTable+(*s))); \ + total_green+=(weight)*qGreen(*(cTable+(*s))); \ + total_blue+=(weight)*qBlue(*(cTable+(*s))); \ + total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \ + s++; + + if(src.width() < 3 || src.height() < 3) + return(src); + + double quantum, total_blue, total_green, total_opacity, total_red, weight; + + int x, y; + unsigned int *q; + + QImage dest(src.width(), src.height(), 32); + weight=((100.0-factor)/2)+1; + quantum = QMAX(weight+12.0, 1.0); + if(src.depth() > 8){ // DirectClass source image + unsigned int *p, *s; + for(y=0; y < src.height(); ++y){ + p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3)); + q = (unsigned int *)dest.scanLine(y); + // blur this row of pixels. + *q++=(*(p+src.width())); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Blur(1); Blur(2); Blur(1); + s=p+src.width(); + Blur(2); Blur(weight); Blur(2); + s=p+2*src.width(); + Blur(1); Blur(2); Blur(1); + *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), + (unsigned char)((total_green+(quantum/2))/quantum), + (unsigned char)((total_blue+(quantum/2))/quantum), + (unsigned char)((total_opacity+(quantum/2))/quantum)); + p++; + q++; + } + p++; + *q++=(*p); + } + } + else{ // PsudeoClass source image + unsigned char *p, *p2, *p3, *s; + unsigned int *cTable = src.colorTable(); + int scanLineIdx; + for(y=0; y < src.height(); ++y){ + scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3); + p = (unsigned char *)src.scanLine(scanLineIdx); + p2 = (unsigned char *)src.scanLine(scanLineIdx+1); + p3 = (unsigned char *)src.scanLine(scanLineIdx+2); + q = (unsigned int *)dest.scanLine(y); + // blur this row of pixels. + *q++=(*(cTable+(*p2))); + for(x=1; x < src.width()-1; ++x){ + // compute weighted average of target pixel color components. + total_red=0.0; + total_green=0.0; + total_blue=0.0; + total_opacity=0.0; + s=p; + Blur256(1); Blur256(2); Blur256(1); + s=p2; + Blur256(2); Blur256(weight); Blur256(2); + s=p3; + Blur256(1); Blur256(2); Blur256(1); + *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum), + (unsigned char)((total_green+(quantum/2))/quantum), + (unsigned char)((total_blue+(quantum/2))/quantum), + (unsigned char)((total_opacity+(quantum/2))/quantum)); + p++; + p2++; + p3++; + q++; + } + p++; + *q++=(*(cTable+(*p))); + } + } + return(dest); +} + +// High quality, expensive HSV contrast. You can do a faster one by just +// taking a grayscale threshold (ie: 128) and incrementing RGB color +// channels above it and decrementing those below it, but this gives much +// better results. (mosfet 12/28/01) +void OImageEffect::contrastHSV(QImage &img, bool sharpen) +{ + int i, sign; + unsigned int *data; + int count; + double brightness, scale, theta; + QColor c; + int h, s, v; + + sign = sharpen ? 1 : -1; + scale=0.5000000000000001; + if(img.depth() > 8){ + count = img.width()*img.height(); + data = (unsigned int *)img.bits(); + } + else{ + count = img.numColors(); + data = (unsigned int *)img.colorTable(); + } + for(i=0; i < count; ++i){ + c.setRgb(data[i]); + c.hsv(&h, &s, &v); + brightness = v/255.0; + theta=(brightness-0.5)*M_PI; + brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign); + if (brightness > 1.0) + brightness=1.0; + else + if (brightness < 0) + brightness=0.0; + v = (int)(brightness*255); + c.setHsv(h, s, v); + data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i])); + } +} + + + + diff --git a/libopie2/opieui/oimageeffect.h b/libopie2/opieui/oimageeffect.h new file mode 100644 index 0000000..313ea50 --- a/dev/null +++ b/libopie2/opieui/oimageeffect.h @@ -0,0 +1,558 @@ +//FIXME: Revise for Opie - do we really need such fancy stuff on PDA's? +//FIXME: Maybe not on SL5xxx, but surely on C700 :)) + +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@interaccess.com> + (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +// $Id$ + +#ifndef OIMAGEEFFECT_H +#define OIMAGEEFFECT_H + +class QImage; +class QSize; +class QColor; + +/** + * This class includes various @ref QImage based graphical effects. + * + * 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 OImageEffect +{ +public: + enum GradientType { VerticalGradient, HorizontalGradient, + DiagonalGradient, CrossDiagonalGradient, + PyramidGradient, RectangleGradient, + PipeCrossGradient, EllipticGradient }; + enum RGBComponent { Red, Green, Blue, Gray, All }; + + enum Lighting {NorthLite, NWLite, WestLite, SWLite, + SouthLite, SELite, EastLite, NELite}; + + enum ModulationType { Intensity, Saturation, HueShift, Contrast }; + + enum NoiseType { UniformNoise=0, GaussianNoise, MultiplicativeGaussianNoise, + ImpulseNoise, LaplacianNoise, PoissonNoise}; + + enum RotateDirection{ Rotate90, Rotate180, Rotate270 }; + + /** + * Create a gradient from color a to color b of the specified type. + * + * @param size The desired size of the gradient. + * @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. + */ + static QImage gradient(const QSize &size, const QColor &ca, + const QColor &cb, GradientType type, int ncols=3); + + /** + * Create an unbalanced gradient. + + * An unbalanced gradient is a gradient where the transition from + * color a to color b is not linear, but in this case, exponential. + * + * @param size The desired size of the gradient. + * @param ca Color a + * @param cb Color b + * @param type The type of gradient. + * @param xfactor The x decay length. Use a value between -200 and 200. + * @param yfactor The y decay length. + * @param ncols The number of colors. See OPixmapEffect:gradient. + */ + static QImage unbalancedGradient(const QSize &size, const QColor &ca, + const QColor &cb, GradientType type, int xfactor = 100, + int yfactor = 100, int ncols = 3); + + /** + * Blends a color into the destination image, using an opacity + * value for blending one into another. Very fast direct pixel + * manipulation is used. + * + * @author Karol Szwed (gallium@kde.org) + * @param clr source color to be blended into the destination image. + * @param dst destination image in which the source will be blended into. + * @param opacity opacity (in percent) which determines how much the source + * color will be blended into the destination image. + * @return The destination image (dst) containing the result. + */ + static QImage& blend(const QColor& clr, QImage& dst, float opacity); + + /** + * Blend the src image into the destination image, using an opacity + * value for blending one into another. Very fast direct pixel + * manipulation is used. + * + * @author Karol Szwed (gallium@kde.org) + * @param src source image to be blended into the destination image. + * @param dst destination image in which the source will be blended into. + * @param opacity opacity (in percent) which determines how much the source + * image will be blended into the destination image. + * @return The destination image (dst) containing the result. + */ + static QImage& blend(QImage& src, QImage& dst, float opacity); + + /** + * Blend the provided image into a background of the indicated color. + * + * @param initial_intensity this parameter takes values from -1 to 1: + * a) if positive: how much to fade the image in its + * less affected spot + * b) if negative: 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) + * @param image must be 32bpp + */ + static QImage& blend(QImage &image, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir=false); + + /** + * Blend an image into another one, using a gradient type + * for blending from one to another. + * + * @param image1 source1 and result of blending + * @param image2 source2 of blending + * @param gt gradient type for blending between source1 and source2 + * @param xf x decay length for unbalanced gradient tpye + * @param yf y decay length for unbalanced gradient tpye + */ + static QImage& blend(QImage &image1,QImage &image2, + GradientType gt, int xf=100, int yf=100); + + /** + * Blend an image into another one, using a color channel of a + * third image for the decision of blending from one to another. + * + * @param image1 Source 1 and result of blending + * @param image2 Source 2 of blending + * @param blendImage If the gray value of of pixel is 0, the result + * for this pixel is that of image1; for a gray value + * of 1, the pixel of image2 is used; for a value + * inbetween, a corresponding blending is used. + * @param channel The RBG channel to use for the blending decision. + */ + static QImage& blend(QImage &image1, QImage &image2, + QImage &blendImage, RGBComponent channel); + + /** + * Blend an image into another one, using alpha in the expected way. + * @author Rik Hemsley (rikkus) <rik@kde.org> + */ + static bool blend(const QImage & upper, const QImage & lower, QImage & output); +// Not yet... static bool blend(const QImage & image1, const QImage & image2, QImage & output, const QRect & destRect); + + /** + * Blend an image into another one, using alpha in the expected way and + * over coordinates @p x and @p y with respect to the lower image. + * The output is a QImage which is the @p upper image already blended + * with the @p lower one, so its size will be (in general) the same than + * @p upper instead of the same size than @p lower like the method above. + * In fact, the size of @p output is like upper's one only when it can be + * painted on lower, if there has to be some clipping, output's size will + * be the clipped area and x and y will be set to the correct up-left corner + * where the clipped rectangle begins. + */ + static bool blend(int &x, int &y, const QImage & upper, const QImage & lower, QImage & output); + /** + * Blend an image into another one, using alpha in the expected way and + * over coordinates @p x and @p y with respect to the lower image. + * The output is painted in the own @p lower image. This is an optimization + * of the blend method above provided by convenience. + */ + static bool blendOnLower(int x, int y, const QImage & upper, const QImage & lower); + + /** + * Modifies the intensity of a pixmap's RGB channel component. + * + * @author Daniel M. Duley (mosfet) + * @param image The QImage to process. + * @param percent Percent value. Use a negative value to dim. + * @param channel Which channel(s) should be modified + * @return The @p image, provided for convenience. + */ + static QImage& channelIntensity(QImage &image, float percent, + RGBComponent channel); + + /** + * Fade an image to a certain background color. + * + * The number of colors will not be changed. + * + * @param image The QImage to process. + * @param val The strength of the effect. 0 <= val <= 1. + * @param color The background color. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& fade(QImage &img, float val, const QColor &color); + + + /** + * This recolors a pixmap. The most dark color will become color a, + * the most bright one color b, and in between. + * + * @param image A QImage to process. + * @param ca Color a + * @param cb Color b + */ + static QImage& flatten(QImage &image, const QColor &ca, + const QColor &cb, int ncols=0); + + /** + * Build a hash on any given @ref QImage + * + * @param image The QImage to process + * @param lite The hash faces the indicated lighting (cardinal poles). + * @param spacing How many unmodified pixels inbetween hashes. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& hash(QImage &image, Lighting lite=NorthLite, + unsigned int spacing=0); + + /** + * Either brighten or dim the image by a specified percent. + * For example, .50 will modify the colors by 50%. + * + * @author Daniel M. Duley (mosfet) + * @param image The QImage to process. + * @param percent The percent value. Use a negative value to dim. + * @return Returns The @ref image(), provided for convenience. + */ + static QImage& intensity(QImage &image, float percent); + + /** + * Modulate the image with a color channel of another image. + * + * @param image The QImage to modulate and result. + * @param modImage The QImage to use for modulation. + * @param reverse Invert the meaning of image/modImage; result is image! + * @param type The modulation Type to use. + * @param factor The modulation amplitude; with 0 no effect [-200;200]. + * @param channel The RBG channel of image2 to use for modulation. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& modulate(QImage &image, QImage &modImage, bool reverse, + ModulationType type, int factor, RGBComponent channel); + + /** + * Convert an image to grayscale. + * + * @author Daniel M. Duley (mosfet) + * @param image The @ref QImage to process. + * @param fast Set to @p true in order to use a faster but non-photographic + * quality algorithm. Appropriate for things such as toolbar icons. + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& toGray(QImage &image, bool fast = false); + + /** + * Desaturate an image evenly. + * + * @param image The QImage to process. + * @param desat A value between 0 and 1 setting the degree of desaturation + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& desaturate(QImage &image, float desat = 0.3); + + /** + * Fast, but low quality contrast of an image. Also see contrastHSV. + * + * @author Daniel M. Duley (mosfet) + * @param image The QImage to process. + * @param c A contrast value between -255 to 255. + * @return The @ref image(), provided for convenience. + */ + static QImage& contrast(QImage &image, int c); + + /** + * Dither an image using Floyd-Steinberg dithering for low-color + * situations. + * + * @param image The QImage to process. + * @param palette The color palette to use + * @param size The size of the palette + * @return Returns the @ref image(), provided for convenience. + */ + static QImage& dither(QImage &img, const QColor *palette, int size); + + /** + * Calculate the image for a selected image, for instance a selected icon + * on the desktop. + * @param img the QImage to select + * @param col the selected color, usually from QColorGroup::highlight(). + */ + static QImage& selectedImage( QImage &img, const QColor &col ); + + /** + * High quality, expensive HSV contrast. You can do a faster one by just + * taking a intensity threshold (ie: 128) and incrementing RGB color + * channels above it and decrementing those below it, but this gives much + * better results. + * + * @author Daniel M. Duley (mosfet) + * @param img The QImage to process. + * @param sharpen If true sharpness is increase, (spiffed). Otherwise + * it is decreased, (dulled). + */ + static void contrastHSV(QImage &img, bool sharpen=true); + + /** + * Normalizes the pixel values to span the full range of color values. + * This is a contrast enhancement technique. + * @author Daniel M. Duley (mosfet) + */ + static void normalize(QImage &img); + + /** + * Performs histogram equalization on the reference + * image. + * @author Daniel M. Duley (mosfet) + */ + static void equalize(QImage &img); + + /** + * Thresholds the reference image. You can also threshold images by using + * ThresholdDither in the various QPixmap/QImage convert methods, but this + * lets you specify a threshold value. + * + * @author Daniel M. Duley (mosfet) + * @param img The QImage to process. + * @param value The threshold value. + */ + static void threshold(QImage &img, unsigned int value=128); + + /** + * Produces a 'solarization' effect seen when exposing a photographic + * film to light during the development process. + * + * @author Daniel M. Duley (mosfet) + * @param img The QImage to process. + * @param factor The extent of the solarization (0-99.9) + */ + static void solarize(QImage &img, double factor=50.0); + + /** + * Embosses the source image. This involves highlighting the edges + * and applying various other enhancements in order to get a metal + * effect. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @return The embossed image. The original is not changed. + */ + static QImage emboss(QImage &src); + + /** + * Minimizes speckle noise in the source image using the 8 hull + * algorithm. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @return The despeckled image. The original is not changed. + */ + static QImage despeckle(QImage &src); + + /** + * Produces a neat little "charcoal" effect. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The factor for detecting lines (0-99.0). + * @return The charcoal image. The original is not changed. + */ + static QImage charcoal(QImage &src, double factor=50.0); + + /** + * Rotates the image by the specified amount + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param r The rotate direction. + * @return The rotated image. The original is not changed. + */ + static QImage rotate(QImage &src, RotateDirection r); + + /** + * Scales an image using simple pixel sampling. This does not produce + * nearly as nice a result as QImage::smoothScale(), but has the + * advantage of being much faster - only a few milliseconds. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param w The new width. + * @param h The new height. + * @return The scaled image. The original is not changed. + */ + static QImage sample(QImage &src, int w, int h); + + /** + * Adds noise to an image. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param type The algorithm used to generate the noise. + * @return The image with noise added. The original is not changed. + */ + static QImage addNoise(QImage &src, NoiseType type = GaussianNoise); + + /** + * Blurs an image by convolving pixel neighborhoods. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The percent weight to give to the center pixel. + * @return The blurred image. The original is not changed. + */ + static QImage blur(QImage &src, double factor=50.0); + + /** + * Detects edges in an image using pixel neighborhoods and an edge + * detection mask. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The percent weight to give to the center pixel. + * @return The image with edges detected. The original is not changed. + */ + static QImage edge(QImage &src, double factor=50.0); + + /** + * Implodes an image by a specified percent. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The extent of the implosion. + * @param background An RGBA value to use for the background. After the + * effect some pixels may be "empty". This value is used for those pixels. + * @return The imploded image. The original is not changed. + */ + static QImage implode(QImage &src, double factor=30.0, + unsigned int background = 0xFFFFFFFF); + /** + * Produces an oil painting effect. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param radius The radius of the pixel neighborhood used in applying the + * effect. + * @return The new image. The original is not changed. + */ + static QImage oilPaint(QImage &src, int radius=3); + + /** + * Sharpens the pixels in the image using pixel neighborhoods. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param factor The percent weight to give to the center pixel. + * @return The sharpened image. The original is not changed. + */ + static QImage sharpen(QImage &src, double factor=30.0); + + /** + * Randomly displaces pixels. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param amount The vicinity for choosing a random pixel to swap. + * @return The image with pixels displaced. The original is not changed. + */ + static QImage spread(QImage &src, unsigned int amount=3); + + /** + * Shades the image using a distance light source. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param color_shading If true do color shading, otherwise do grayscale. + * @param azimuth Determines the light source and direction. + * @param elevation Determines the light source and direction. + * @return The shaded image. The original is not changed. + */ + static QImage shade(QImage &src, bool color_shading=true, double azimuth=30.0, + double elevation=30.0); + /** + * Swirls the image by a specified amount + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param degrees The tightness of the swirl. + * @param background An RGBA value to use for the background. After the + * effect some pixels may be "empty". This value is used for those pixels. + * @return The swirled image. The original is not changed. + */ + static QImage swirl(QImage &src, double degrees=50.0, unsigned int background = + 0xFFFFFFFF); + + /** + * Modifies the pixels along a sine wave. + * + * @author Daniel M. Duley (mosfet) + * @param src The QImage to process. + * @param amplitude The amplitude of the sine wave. + * @param wavelength The frequency of the sine wave. + * @return The new image. The original is not changed. + */ + static QImage wave(QImage &src, double amplitude=25.0, double frequency=150.0, + unsigned int background = 0xFFFFFFFF); + +private: + + /** + * Helper function to fast calc some altered (lighten, shaded) colors + * + */ + static unsigned int lHash(unsigned int c); + static unsigned int uHash(unsigned int c); + + /** + * Helper function to find the nearest color to the RBG triplet + */ + static int nearestColor( int r, int g, int b, const QColor *pal, int size ); + + static void hull(const int x_offset, const int y_offset, const int polarity, + const int width, const int height, + unsigned int *f, unsigned int *g); + static unsigned int generateNoise(unsigned int pixel, NoiseType type); + static unsigned int interpolateColor(QImage *image, double x, double y, + unsigned int background); +}; + +#endif diff --git a/libopie2/opieui/olistview.cpp b/libopie2/opieui/olistview.cpp new file mode 100644 index 0000000..2b2f09a --- a/dev/null +++ b/libopie2/opieui/olistview.cpp @@ -0,0 +1,423 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/* QT */ + +#include <qcolor.h> +#include <qheader.h> +#include <qpainter.h> +#include <qpixmap.h> + +/* OPIE */ + +#include <opie2/olistview.h> + +/*====================================================================================== + * OListView + *======================================================================================*/ + +OListView::OListView( QWidget *parent, const char *name ) + :QListView( parent, name ) +{ + //FIXME: get from global settings and calculate ==> see oglobalsettings.* + + m_alternateBackground = QColor( 238, 246, 255 ); + m_columnSeparator = QPen( QColor( 150, 160, 170 ), 0, DotLine ); + m_fullWidth = true; +} + +OListView::~OListView() +{ +} + +void OListView::setFullWidth( bool fullWidth ) +{ + m_fullWidth = m_fullWidth; + #if QT_VERSION > 290 + header()->setStretchEnabled( fullWidth, columns()-1 ); + #endif +} + +bool OListView::fullWidth() const +{ + return m_fullWidth; +} + +int OListView::addColumn( const QString& label, int width ) +{ + int result = QListView::addColumn( label, width ); + #if QT_VERSION > 290 + if (m_fullWidth) { + header()->setStretchEnabled( false, columns()-2 ); + header()->setStretchEnabled( true, columns()-1 ); + } + #endif + return result; +} + +int OListView::addColumn( const QIconSet& iconset, const QString& label, int width ) +{ + int result = QListView::addColumn( iconset, label, width ); + #if QT_VERSION > 290 + if (m_fullWidth) { + header()->setStretchEnabled( false, columns()-2 ); + header()->setStretchEnabled( true, columns()-1 ); + } + #endif + return result; +} + +void OListView::removeColumn( int index ) +{ + QListView::removeColumn(index); + #if QT_VERSION > 290 + if ( m_fullWidth && index == columns() ) + { + header()->setStretchEnabled( true, columns()-1 ); + } + #endif +} + +const QColor& OListView::alternateBackground() const +{ + return m_alternateBackground; +} + +void OListView::setAlternateBackground( const QColor &c ) +{ + m_alternateBackground = c; + repaint(); +} + +const QPen& OListView::columnSeparator() const +{ + return m_columnSeparator; +} + +void OListView::setColumnSeparator( const QPen& p ) +{ + m_columnSeparator = p; + repaint(); +} + +OListViewItem* OListView::childFactory() +{ + return new OListViewItem( this ); +} + +#ifndef QT_NO_DATASTREAM +void OListView::serializeTo( QDataStream& s ) const +{ + #warning Caution... the binary format is still under construction... + qDebug( "storing OListView..." ); + + // store number of columns and the labels + s << columns(); + for ( int i = 0; i < columns(); ++i ) + s << columnText( i ); + + // calculate the number of top-level items to serialize + int items = 0; + QListViewItem* item = firstChild(); + while ( item ) + { + item = item->nextSibling(); + items++; + } + + // store number of items and the items itself + s << items; + item = firstChild(); + for ( int i = 0; i < items; ++i ) + { + s << *static_cast<OListViewItem*>( item ); + item = item->nextSibling(); + } + + qDebug( "OListview stored." ); +} + +void OListView::serializeFrom( QDataStream& s ) +{ + #warning Caution... the binary format is still under construction... + qDebug( "loading OListView..." ); + + int cols; + s >> cols; + qDebug( "read number of columns = %d", cols ); + + while ( columns() < cols ) addColumn( QString::null ); + + for ( int i = 0; i < cols; ++i ) + { + QString coltext; + s >> coltext; + qDebug( "read text '%s' for column %d", (const char*) coltext, i ); + setColumnText( i, coltext ); + } + + int items; + s >> items; + qDebug( "read number of items = %d", items ); + + for ( int i = 0; i < items; ++i ) + { + OListViewItem* item = childFactory(); + s >> *item; + } + + qDebug( "OListView loaded." ); + +} + +QDataStream& operator<<( QDataStream& s, const OListView& lv ) +{ + lv.serializeTo( s ); +} + +QDataStream& operator>>( QDataStream& s, OListView& lv ) +{ + lv.serializeFrom( s ); +} +#endif // QT_NO_DATASTREAM + +/*====================================================================================== + * OListViewItem + *======================================================================================*/ + +OListViewItem::OListViewItem(QListView *parent) + : QListViewItem(parent) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent) + : QListViewItem(parent) +{ + init(); +} + +OListViewItem::OListViewItem(QListView *parent, QListViewItem *after) + : QListViewItem(parent, after) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent, QListViewItem *after) + : QListViewItem(parent, after) +{ + init(); +} + +OListViewItem::OListViewItem(QListView *parent, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::OListViewItem(QListView *parent, QListViewItem *after, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::OListViewItem(QListViewItem *parent, QListViewItem *after, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, QString label8) + : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8) +{ + init(); +} + +OListViewItem::~OListViewItem() +{ +} + +void OListViewItem::init() +{ + m_known = false; +} + +const QColor &OListViewItem::backgroundColor() +{ + return isAlternate() ? static_cast<OListView*>(listView())->alternateBackground() : + listView()->viewport()->colorGroup().base(); +} + +bool OListViewItem::isAlternate() +{ + OListView *lv = static_cast<OListView*>( listView() ); + + // check if the item above is an OListViewItem + OListViewItem *above = static_cast<OListViewItem*>( itemAbove() ); + /*if (! itemAbove()->inherits( "OListViewItem" )) return false;*/ + + // check if we have a valid alternate background color + if (!(lv && lv->alternateBackground().isValid())) return false; + + m_known = above ? above->m_known : true; + if (m_known) + { + m_odd = above ? !above->m_odd : false; + } + else + { + OListViewItem *item; + bool previous = true; + if (parent()) + { + item = static_cast<OListViewItem *>(parent()); + if ( item /*&& item->inherits( "OListViewItem" )*/ ) previous = item->m_odd; + item = static_cast<OListViewItem *>(parent()->firstChild()); + /* if ( !item.inherits( "OListViewItem" ) item = 0; */ + } + else + { + item = static_cast<OListViewItem *>(lv->firstChild()); + } + + while(item) + { + item->m_odd = previous = !previous; + item->m_known = true; + item = static_cast<OListViewItem *>(item->nextSibling()); + /* if (!item.inherits( "OListViewItem" ) ) break; */ + } + } + return m_odd; +} + +void OListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) +{ + QColorGroup _cg = cg; + const QPixmap *pm = listView()->viewport()->backgroundPixmap(); + if (pm && !pm->isNull()) + { + _cg.setBrush( QColorGroup::Base, QBrush(backgroundColor(), *pm) ); + p->setBrushOrigin( -listView()->contentsX(), -listView()->contentsY() ); + } + else if ( isAlternate() ) + { + _cg.setColor( QColorGroup::Base, static_cast<OListView*>( listView() )->alternateBackground() ); + } + QListViewItem::paintCell( p, _cg, column, width, alignment ); + + //FIXME: Use styling here! + + const QPen& pen = static_cast<OListView*>( listView() )->columnSeparator(); + p->setPen( pen ); + p->drawLine( width-1, 0, width-1, height() ); +} + +OListViewItem* OListViewItem::childFactory() +{ + return new OListViewItem( this ); +} + +#ifndef QT_NO_DATASTREAM +void OListViewItem::serializeTo( QDataStream& s ) const +{ + #warning Caution... the binary format is still under construction... + qDebug( "storing OListViewItem..." ); + + // store item text + for ( int i = 0; i < listView()->columns(); ++i ) + { + s << text( i ); + } + + // calculate the number of children to serialize + int items = 0; + QListViewItem* item = firstChild(); + while ( item ) + { + item = item->nextSibling(); + items++; + } + + // store number of items and the items itself + s << items; + item = firstChild(); + for ( int i = 0; i < items; ++i ) + { + s << *static_cast<OListViewItem*>( item ); + item = item->nextSibling(); + } + + qDebug( "OListviewItem stored." ); +} +void OListViewItem::serializeFrom( QDataStream& s ) +{ + #warning Caution... the binary format is still under construction... + qDebug( "loading OListViewItem..." ); + + for ( int i = 0; i < listView()->columns(); ++i ) + { + QString coltext; + s >> coltext; + qDebug( "read text '%s' for column %d", (const char*) coltext, i ); + setText( i, coltext ); + } + + int items; + s >> items; + qDebug( "read number of items = %d", items ); + + for ( int i = 0; i < items; ++i ) + { + OListViewItem* item = childFactory(); + s >> (*item); + } + + qDebug( "OListViewItem loaded." ); +} + +QDataStream& operator<<( QDataStream& s, const OListViewItem& lvi ) +{ + lvi.serializeTo( s ); +} + +QDataStream& operator>>( QDataStream& s, OListViewItem& lvi ) +{ + lvi.serializeFrom( s ); +} +#endif // QT_NO_DATASTREAM diff --git a/libopie2/opieui/olistview.h b/libopie2/opieui/olistview.h new file mode 100644 index 0000000..bafc67c --- a/dev/null +++ b/libopie2/opieui/olistview.h @@ -0,0 +1,235 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OLISTVIEW_H +#define OLISTVIEW_H + +#include <qcolor.h> +#include <qlistview.h> +#include <qpen.h> +#include <qdatastream.h> + +class OListViewItem; + +/** + * A @ref QListView variant featuring visual and functional enhancements + * like an alternate background for odd rows, an autostretch mode + * for the width of the widget ( >= Qt 3 only ) and persistence capabilities. + * + * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + * @short OListView list/tree widget. + */ + class OListView: public QListView +{ + public: + /** + * Constructor. + * + * The parameters @p parent and @p name are handled by + * @ref QListView, as usual. + */ + OListView ( QWidget *parent = 0, const char *name = 0 ); + + /** + * Destructor. + */ + virtual ~OListView(); + + /** + * Let the last column fit exactly all the available width. + */ + void setFullWidth( bool fullWidth ); + + /** + * Returns whether the last column is set to fit the available width. + */ + bool fullWidth() const; + + /** + * Reimplemented for full width support + */ + virtual int addColumn( const QString& label, int width = -1 ); + + /** + * Reimplemented for full width support + */ + virtual int addColumn( const QIconSet& iconset, const QString& label, int width = -1 ); + + /** + * Reimplemented for full width support + */ + virtual void removeColumn(int index); + + /** + * sets the alternate background background color. + * This only has an effect if the items are OListViewItems + * + * @param c the color to use for every other item. Set to an invalid + * color to disable alternate colors. + */ + void setAlternateBackground( const QColor &c ); + + /** + * sets the column separator pen. + * + * @param p the pen used to draw the column separator. + */ + void setColumnSeparator( const QPen &p ); + + /** + * @return the alternate background color + */ + const QColor& alternateBackground() const; + + /** + * @return the column separator pen + */ + const QPen& columnSeparator() const; + + /** + * create a list view item as child of this object + * @return the new object + */ + virtual OListViewItem* childFactory(); + + #ifndef QT_NO_DATASTREAM + /** + * serialize this object to a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeTo( QDataStream& s ) const; + + /** + * serialize this object from a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeFrom( QDataStream& s ); + #endif + + private: + QColor m_alternateBackground; + bool m_fullWidth; + QPen m_columnSeparator; +}; + +#ifndef QT_NO_DATASTREAM +/** + * \relates QListView + * Writes a listview to the stream and returns a reference to the stream. + */ +QDataStream& operator<<( QDataStream& s, const OListView& lv ); +/** + * \relates QListView + * Reads a listview from the stream and returns a reference to the stream. + */ +QDataStream& operator>>( QDataStream& s, OListView& lv ); +#endif // QT_NO_DATASTREAM + +//****************************** OListViewItem ****************************************************************** + +class OListViewItem: public QListViewItem +{ + public: + OListViewItem( QListView * parent ); + OListViewItem( QListViewItem * parent ); + OListViewItem( QListView * parent, QListViewItem * after ); + OListViewItem( QListViewItem * parent, QListViewItem * after ); + + OListViewItem( QListView * parent, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + OListViewItem( QListViewItem * parent, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + OListViewItem( QListView * parent, QListViewItem * after, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + OListViewItem( QListViewItem * parent, QListViewItem * after, + QString, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null ); + + virtual ~OListViewItem(); + + const QColor& backgroundColor(); + bool isAlternate(); + void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int alignment ); + void init(); + + /** + * create a list view item as child of this object + * @return the new object + */ + virtual OListViewItem* childFactory(); + + #ifndef QT_NO_DATASTREAM + /** + * serialize this object to or from a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeTo( QDataStream& s ) const; + + /** + * serialize this object to or from a @ref QDataStream + * @param s the stream used to serialize this object. + */ + virtual void serializeFrom( QDataStream& s ); + #endif + + private: + bool m_known; + bool m_odd; +}; + +#ifndef QT_NO_DATASTREAM +/** + * \relates QListViewItem + * Writes a listview item and all subitems recursively to the stream + * and returns a reference to the stream. + */ +QDataStream& operator<<( QDataStream &s, const OListViewItem& lvi ); +/** + * \relates QListViewItem + * Reads a listview item from the stream and returns a reference to the stream. + */ +QDataStream& operator>>( QDataStream &s, OListViewItem& lvi ); +#endif // QT_NO_DATASTREAM + +#endif // OLISTVIEW_H diff --git a/libopie2/opieui/opieui.pro b/libopie2/opieui/opieui.pro new file mode 100644 index 0000000..dffbbde --- a/dev/null +++ b/libopie2/opieui/opieui.pro @@ -0,0 +1,46 @@ +TEMPLATE = lib +CONFIG += qt warn_on debug +DESTDIR = $(QTDIR)/lib +HEADERS = ocompletionbox.h \ + ocombobox.h \ + oeditlistbox.h \ + olineedit.h \ + olistview.h \ + oimageeffect.h \ + opixmapeffect.h \ + opopupmenu.h \ + opixmapprovider.h \ + oselector.h \ + oversatileview.h \ + oversatileviewitem.h \ + #ojanuswidget.h \ + odialog.h \ + oseparator.h + +SOURCES = ocompletionbox.cpp \ + ocombobox.cpp \ + oeditlistbox.cpp \ + olineedit.cpp \ + olistview.cpp \ + oimageeffect.cpp \ + opixmapeffect.cpp \ + opopupmenu.cpp \ + opixmapprovider.cpp \ + oselector.cpp \ + oversatileview.cpp \ + oversatileviewitem.cpp \ + #ojanuswidget.cpp \ + odialog.cpp \ + oseparator.cpp + +INTERFACES = +TARGET = opieui2 +VERSION = 1.8.1 +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lopiecore2 +MOC_DIR = moc +OBJECTS_DIR = obj + +include ( $(OPIEDIR)/include.pro ) + diff --git a/libopie2/opieui/opixmapeffect.cpp b/libopie2/opieui/opixmapeffect.cpp new file mode 100644 index 0000000..05f851d --- a/dev/null +++ b/libopie2/opieui/opixmapeffect.cpp @@ -0,0 +1,328 @@ +/* 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$ + +/* QT */ + +#include <qimage.h> +#include <qpainter.h> + +/* OPIE */ + +#include <opie2/opixmapeffect.h> +#include <opie2/oimageeffect.h> + +//====================================================================== +// +// Gradient effects +// +//====================================================================== + + +OPixmap& OPixmapEffect::gradient(OPixmap &pixmap, const QColor &ca, + const QColor &cb, GradientType eff, int ncols) +{ + if(pixmap.depth() > 8 && + (eff == VerticalGradient || eff == HorizontalGradient)) { + + int rDiff, gDiff, bDiff; + int rca, gca, bca /*, rcb, gcb, bcb*/; + + 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()); + + 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; + + QPainter p(&pixmap); + + // 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); + } + break; + case HorizontalGradient: + for( x = 0; x < pixmap.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); + } + break; + default: + ; + } + } + else { + QImage image = OImageEffect::gradient(pixmap.size(), ca, cb, + (OImageEffect::GradientType) eff, ncols); + pixmap.convertFromImage(image); + } + + return pixmap; +} + + +// ----------------------------------------------------------------------------- + +OPixmap& OPixmapEffect::unbalancedGradient(OPixmap &pixmap, const QColor &ca, + const QColor &cb, GradientType eff, int xfactor, int yfactor, + int ncols) +{ + QImage image = OImageEffect::unbalancedGradient(pixmap.size(), ca, cb, + (OImageEffect::GradientType) eff, + xfactor, yfactor, ncols); + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Intensity effects +// +//====================================================================== + + + +OPixmap& OPixmapEffect::intensity(OPixmap &pixmap, float percent) +{ + QImage image = pixmap.convertToImage(); + OImageEffect::intensity(image, percent); + pixmap.convertFromImage(image); + + return pixmap; +} + + +// ----------------------------------------------------------------------------- + +OPixmap& OPixmapEffect::channelIntensity(OPixmap &pixmap, float percent, + RGBComponent channel) +{ + QImage image = pixmap.convertToImage(); + OImageEffect::channelIntensity(image, percent, + (OImageEffect::RGBComponent) channel); + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Blend effects +// +//====================================================================== + + +OPixmap& OPixmapEffect::blend(OPixmap &pixmap, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir, int ncols) +{ + + QImage image = pixmap.convertToImage(); + if (image.depth() <=8) + image = image.convertDepth(32); //Sloww.. + + OImageEffect::blend(image, initial_intensity, bgnd, + (OImageEffect::GradientType) eff, anti_dir); + + unsigned int tmp; + + if(pixmap.depth() <= 8 ) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + tmp = 0 + 255 * i / ( ncols - 1 ); + dPal[i].setRgb ( tmp, tmp, tmp ); + } + OImageEffect::dither(image, dPal, ncols); + pixmap.convertFromImage(image); + delete [] dPal; + } + else + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Hash effects +// +//====================================================================== + +OPixmap& OPixmapEffect::hash(OPixmap &pixmap, Lighting lite, + unsigned int spacing, int ncols) +{ + QImage image = pixmap.convertToImage(); + OImageEffect::hash(image, (OImageEffect::Lighting) lite, spacing); + + unsigned int tmp; + + if(pixmap.depth() <= 8 ) { + if ( ncols < 2 || ncols > 256 ) + ncols = 3; + QColor *dPal = new QColor[ncols]; + for (int i=0; i<ncols; i++) { + tmp = 0 + 255 * i / ( ncols - 1 ); + dPal[i].setRgb ( tmp, tmp, tmp ); + } + OImageEffect::dither(image, dPal, ncols); + pixmap.convertFromImage(image); + delete [] dPal; + } + else + pixmap.convertFromImage(image); + + return pixmap; +} + + +//====================================================================== +// +// Pattern effects +// +//====================================================================== + +#if 0 +void OPixmapEffect::pattern(OPixmap &pixmap, const QColor &ca, + const QColor &cb, unsigned pat[8]) +{ + QImage img = pattern(pixmap.size(), ca, cb, pat); + pixmap.convertFromImage(img); +} +#endif + +// ----------------------------------------------------------------------------- + +OPixmap OPixmapEffect::pattern(const OPixmap& pmtile, QSize size, + const QColor &ca, const QColor &cb, int ncols) +{ + if (pmtile.depth() > 8) + ncols = 0; + + QImage img = pmtile.convertToImage(); + OImageEffect::flatten(img, ca, cb, ncols); + OPixmap pixmap; + pixmap.convertFromImage(img); + + return OPixmapEffect::createTiled(pixmap, size); +} + + +// ----------------------------------------------------------------------------- + +OPixmap OPixmapEffect::createTiled(const OPixmap& pixmap, QSize size) +{ + OPixmap pix; + + QPainter p(&pix); + p.drawTiledPixmap(0, 0, size.width(), size.height(), pixmap); + + return pix; +} + + +//====================================================================== +// +// Fade effects +// +//====================================================================== + +OPixmap& OPixmapEffect::fade(OPixmap &pixmap, double val, const QColor &color) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::fade(img, val, color); + pixmap.convertFromImage(img); + + return pixmap; +} + + +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::toGray(OPixmap &pixmap, bool fast) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::toGray(img, fast); + pixmap.convertFromImage(img); + + return pixmap; +} + +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::desaturate(OPixmap &pixmap, float desat) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::desaturate(img, desat); + pixmap.convertFromImage(img); + + return pixmap; +} +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::contrast(OPixmap &pixmap, int c) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::contrast(img, c); + pixmap.convertFromImage(img); + + return pixmap; +} + +//====================================================================== +// +// Dither effects +// +//====================================================================== + +// ----------------------------------------------------------------------------- +OPixmap& OPixmapEffect::dither(OPixmap &pixmap, const QColor *palette, int size) +{ + QImage img = pixmap.convertToImage(); + OImageEffect::dither(img, palette, size); + pixmap.convertFromImage(img); + + return pixmap; +} + +//====================================================================== +// +// Other effects +// +//====================================================================== + +OPixmap OPixmapEffect::selectedPixmap( const OPixmap &pix, const QColor &col ) +{ + QImage img = pix.convertToImage(); + OImageEffect::selectedImage(img, col); + OPixmap outPix; + outPix.convertFromImage(img); + return outPix; +} diff --git a/libopie2/opieui/opixmapeffect.h b/libopie2/opieui/opixmapeffect.h new file mode 100644 index 0000000..283fe2d --- a/dev/null +++ b/libopie2/opieui/opixmapeffect.h @@ -0,0 +1,215 @@ +/* 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$ + +#ifndef __OPIXMAP_EFFECT_H +#define __OPIXMAP_EFFECT_H + + +#include <qsize.h> +typedef QPixmap OPixmap; +class QColor; + +/** + * This class includes various pixmap-based graphical effects. + * + * 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 OPixmapEffect +{ +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}; + + /** + * Creates 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 OPixmap& gradient(OPixmap& pixmap, const QColor &ca, const QColor &cb, + GradientType type, int ncols=3); + + /** + * Creates an unbalanced gradient. + * + * An unbalanced gradient is a gradient where the transition from + * color a to color b is not linear, but in this case, exponential. + * + * @param pixmap The pixmap that should be written. + * @param ca Color a. + * @param cb Color b. + * @param type The type of gradient. + * @param xfactor The x decay length. Use a value between -200 and 200. + * @param yfactor The y decay length. + * @param ncols The number of colors. See #gradient. + * @return The generated pixmap, for convencience. + */ + static OPixmap& unbalancedGradient(OPixmap& pixmap, const QColor &ca, + const QColor &cb, GradientType type, int xfactor = 100, + int yfactor = 100, int ncols=3); + + /** + * Creates a pixmap of a given size with the given pixmap. + * + * if the + * given size is bigger than the size of the pixmap, the pixmap is + * tiled. + * + * @param pixmap This is the source pixmap + * @param size The size the new pixmap should have. + * @return The generated, tiled pixmap. + */ + static OPixmap createTiled(const OPixmap& pixmap, QSize size); + + /** + * Either brightens or dims a pixmap by a specified ratio. + * + * @param pixmap The pixmap to process. + * @param ratio The ratio to use. Use negative value to dim. + * @return Returns The @ref pixmap(), provided for convenience. + */ + static OPixmap& intensity(OPixmap& pixmap, float ratio); + + /** + * Modifies the intensity of a pixmap's RGB channel component. + * + * @param pixmap The pixmap to process. + * @param ratio value. Use negative value to dim. + * @param channel Which channel(s) should be modified + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& channelIntensity(OPixmap& pixmap, float ratio, + RGBComponent channel); + + /** + * Blends 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 OPixmap& blend(OPixmap& pixmap, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir=false, int ncols=3); + + /** + * Builds a hash on any given pixmap. + * + * @param pixmap The pixmap to process. + * @param lite The hash faces the indicated lighting (cardinal poles) + * @param spacing How many unmodified pixels inbetween hashes. + * @return Returns The @ref pixmap(), provided for convenience. + */ + static OPixmap& hash(OPixmap& pixmap, Lighting lite=NorthLite, + unsigned int spacing=0, int ncols=3); + + /** + * Creates a pattern from a pixmap. + * + * The given pixmap is "flattened" + * between color a to color b. + * + * @param pixmap The pixmap to process. + * @param ca Color a. + * @param cb Color b. + * @param ncols The number of colors to use. The image will be + * dithered to this depth. Pass zero to prevent dithering. + * @return The @ref pixmap(), provided for convenience. + */ + static OPixmap pattern(const OPixmap& pixmap, QSize size, + const QColor &ca, const QColor &cb, int ncols=8); + + /** + * Recolors a pixmap. + * + * The most dark color will become color a, + * the most bright one color b, and in between. + * + * @param pixmap The pixmap to process. + * @param ca Color a. + * @param cb Color b. + * @param ncols The number of colors to use. Pass zero to prevent + * dithering. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& fade(OPixmap& pixmap, double val, const QColor &color); + + /** + * Converts a pixmap to grayscale. + * + * @param pixmap The pixmap to process. + * @param fast Set to @p true in order to use a faster but non-photographic + * quality algorithm. Appropriate for things such as toolbar icons. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& toGray(OPixmap& pixmap, bool fast=false); + + /** + * Desaturates a pixmap. + * + * @param pixmap The pixmap to process. + * @param desat A value between 0 and 1 setting the degree of desaturation + * @return Returns The @ref pixmap(), provided for convenience. + */ + static OPixmap& desaturate(OPixmap& pixmap, float desat = 0.3); + + /** + * Modifies the contrast of a pixmap. + * + * @param pixmap The pixmap to process. + * @param c A contrast value between -255 and 255. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& contrast(OPixmap& pixmap, int c); + + /** + * Dithers a pixmap using Floyd-Steinberg dithering for low-color + * situations. + * + * @param pixmap The pixmap to process. + * @param palette The color palette to use. + * @param size The size of the palette. + * @return Returns the @ref pixmap(), provided for convenience. + */ + static OPixmap& dither(OPixmap &pixmap, const QColor *palette, int size); + + /** + * Calculate a 'selected' pixmap, for instance a selected icon + * on the desktop. + * @param pixmap the pixmap to select + * @param col the selected color, usually from QColorGroup::highlight(). + */ + static OPixmap selectedPixmap( const OPixmap &pixmap, const QColor &col ); +}; + + +#endif diff --git a/libopie2/opieui/opixmapprovider.cpp b/libopie2/opieui/opixmapprovider.cpp new file mode 100644 index 0000000..7be9e3b --- a/dev/null +++ b/libopie2/opieui/opixmapprovider.cpp @@ -0,0 +1,27 @@ +/* This file is part of the KDE libraries + + Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <opie2/opixmapprovider.h> + +OPixmapProvider::~OPixmapProvider() {} + +void OPixmapProvider::virtual_hook( int , void* ) +{ /*BASE::virtual_hook( id, data );*/ } + diff --git a/libopie2/opieui/opixmapprovider.h b/libopie2/opieui/opixmapprovider.h new file mode 100644 index 0000000..5b76647 --- a/dev/null +++ b/libopie2/opieui/opixmapprovider.h @@ -0,0 +1,54 @@ +/* This file is part of the KDE libraries + + Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef OPIXMAPPROVIDER_H +#define OPIXMAPPROVIDER_H + +#include <qpixmap.h> + +/** + * A tiny abstract class with just one method: + * @ref pixmapFor() + * + * It will be called whenever an icon is searched for @p text. + * + * Used e.g. by @ref KHistoryCombo + * + * @author Carsten Pfeiffer <pfeiffer@kde.org> + * @short an abstract interface for looking up icons + */ +class OPixmapProvider +{ +public: + virtual ~OPixmapProvider(); + /** + * You may subclass this and return a pixmap of size @p size for @p text. + * @param text the text that is associated with the pixmap + * @param size the size of the icon in pixels, 0 for defaylt size. + * See @ref KIcon::StdSize. + * @return the pixmap for the arguments, or null if there is none + */ + virtual QPixmap pixmapFor( const QString& text, int size = 0 ) = 0; +protected: + virtual void virtual_hook( int id, void* data ); +}; + + +#endif // OPIXMAPPROVIDER_H diff --git a/libopie2/opieui/opopupmenu.cpp b/libopie2/opieui/opopupmenu.cpp new file mode 100644 index 0000000..ac73188 --- a/dev/null +++ b/libopie2/opieui/opopupmenu.cpp @@ -0,0 +1,604 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org> + Copyright (C) 2002 Hamish Rodda <meddie@yoyo.its.monash.edu.au> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/* QT */ + +#include <qapplication.h> +#include <qcursor.h> +#include <qpainter.h> +#include <qdrawutil.h> +#include <qtimer.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qregexp.h> +#include <qstyle.h> + +/* OPIE */ + +#include <opie2/opopupmenu.h> +#include <opie2/oconfig.h> + +OPopupTitle::OPopupTitle(QWidget *parent, const char *name) + : QWidget(parent, name) +{ + setMinimumSize(16, fontMetrics().height()+8); +} + +OPopupTitle::OPopupTitle(OPixmapEffect::GradientType /* gradient */, + const QColor &/* color */, const QColor &/* textColor */, + QWidget *parent, const char *name) + : QWidget(parent, name) +{ + setMinimumSize(16, fontMetrics().height()+8); +} + +OPopupTitle::OPopupTitle(const OPixmap & /* background */, const QColor &/* color */, + const QColor &/* textColor */, QWidget *parent, + const char *name) + : QWidget(parent, name) +{ + setMinimumSize(16, fontMetrics().height()+8); +} + +void OPopupTitle::setTitle(const QString &text, const QPixmap *icon) +{ + titleStr = text; + if (icon) + miniicon = *icon; + else + miniicon.resize(0, 0); + + int w = miniicon.width()+fontMetrics().width(titleStr); + int h = QMAX( fontMetrics().height(), miniicon.height() ); + setMinimumSize( w+16, h+8 ); +} + +void OPopupTitle::setText( const QString &text ) +{ + titleStr = text; + int w = miniicon.width()+fontMetrics().width(titleStr); + int h = QMAX( fontMetrics().height(), miniicon.height() ); + setMinimumSize( w+16, h+8 ); +} + +void OPopupTitle::setIcon( const QPixmap &pix ) +{ + miniicon = pix; + int w = miniicon.width()+fontMetrics().width(titleStr); + int h = QMAX( fontMetrics().height(), miniicon.height() ); + setMinimumSize( w+16, h+8 ); +} + +void OPopupTitle::paintEvent(QPaintEvent *) +{ + QRect r(rect()); + QPainter p(this); + #if QT_VERSION > 290 + qApp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active()); + #else + #warning OPopupMenu is not fully functional on Qt2 + #endif + + if (!miniicon.isNull()) + p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon); + + if (!titleStr.isNull()) + { + p.setPen(palette().active().text()); + QFont f = p.font(); + f.setBold(true); + p.setFont(f); + if(!miniicon.isNull()) + { + p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8), + height(), AlignLeft | AlignVCenter | SingleLine, + titleStr); + } + else + { + p.drawText(0, 0, width(), height(), + AlignCenter | SingleLine, titleStr); + } + } + + p.setPen(palette().active().highlight()); + p.drawLine(0, 0, r.right(), 0); +} + +QSize OPopupTitle::sizeHint() const +{ + return(minimumSize()); +} + +class OPopupMenu::OPopupMenuPrivate +{ +public: + OPopupMenuPrivate () + : noMatches(false) + , shortcuts(false) + , autoExec(false) + , lastHitIndex(-1) + , m_ctxMenu(0) + {} + + ~OPopupMenuPrivate () + { + delete m_ctxMenu; + } + + QString m_lastTitle; + + // variables for keyboard navigation + QTimer clearTimer; + + bool noMatches : 1; + bool shortcuts : 1; + bool autoExec : 1; + + QString keySeq; + QString originalText; + + int lastHitIndex; + + // support for RMB menus on menus + QPopupMenu* m_ctxMenu; + static bool s_continueCtxMenuShow; + static int s_highlightedItem; + static OPopupMenu* s_contextedMenu; +}; + +int OPopupMenu::OPopupMenuPrivate::s_highlightedItem(-1); +OPopupMenu* OPopupMenu::OPopupMenuPrivate::s_contextedMenu(0); +bool OPopupMenu::OPopupMenuPrivate::s_continueCtxMenuShow(true); + +OPopupMenu::OPopupMenu(QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + d = new OPopupMenuPrivate; + resetKeyboardVars(); + connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars())); +} + +OPopupMenu::~OPopupMenu() +{ + if (OPopupMenuPrivate::s_contextedMenu == this) + { + OPopupMenuPrivate::s_contextedMenu = 0; + OPopupMenuPrivate::s_highlightedItem = -1; + } + + delete d; +} + +int OPopupMenu::insertTitle(const QString &text, int id, int index) +{ + OPopupTitle *titleItem = new OPopupTitle(); + titleItem->setTitle(text); + int ret = insertItem(titleItem, id, index); + setItemEnabled(id, false); + return ret; +} + +int OPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id, + int index) +{ + OPopupTitle *titleItem = new OPopupTitle(); + titleItem->setTitle(text, &icon); + int ret = insertItem(titleItem, id, index); + setItemEnabled(id, false); + return ret; +} + +void OPopupMenu::changeTitle(int id, const QString &text) +{ + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + ((OPopupTitle *)item->widget())->setTitle(text); +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id ); +#endif + } +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id ); +#endif +} + +void OPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text) +{ + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + ((OPopupTitle *)item->widget())->setTitle(text, &icon); +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id ); +#endif + } +#ifndef NDEBUG + else + qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id ); +#endif +} + +QString OPopupMenu::title(int id) const +{ + if(id == -1) // obsolete + return(d->m_lastTitle); + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + return(((OPopupTitle *)item->widget())->title()); + else + qWarning("OPopupMenu: title() called with non-title id %d.", id); + } + else + qWarning("OPopupMenu: title() called with invalid id %d.", id); + return(QString::null); +} + +QPixmap OPopupMenu::titlePixmap(int id) const +{ + QMenuItem *item = findItem(id); + if(item){ + if(item->widget()) + return(((OPopupTitle *)item->widget())->icon()); + else + qWarning("KPopupMenu: titlePixmap() called with non-title id %d.", id); + } + else + qWarning("KPopupMenu: titlePixmap() called with invalid id %d.", id); + QPixmap tmp; + return(tmp); +} + +/** + * This is re-implemented for keyboard navigation. + */ +void OPopupMenu::closeEvent(QCloseEvent*e) +{ + if (d->shortcuts) + resetKeyboardVars(); + QPopupMenu::closeEvent(e); +} + +void OPopupMenu::keyPressEvent(QKeyEvent* e) +{ + if (!d->shortcuts) { + // continue event processing by Qpopup + //e->ignore(); + QPopupMenu::keyPressEvent(e); + return; + } + + int i = 0; + bool firstpass = true; + QString keyString = e->text(); + + // check for common commands dealt with by QPopup + int key = e->key(); + if (key == Key_Escape || key == Key_Return || key == Key_Enter + || key == Key_Up || key == Key_Down || key == Key_Left + || key == Key_Right || key == Key_F1) { + + resetKeyboardVars(); + // continue event processing by Qpopup + //e->ignore(); + QPopupMenu::keyPressEvent(e); + return; + } + + // check to see if the user wants to remove a key from the sequence (backspace) + // or clear the sequence (delete) + if (!d->keySeq.isNull()) { + + if (key == Key_Backspace) { + + if (d->keySeq.length() == 1) { + resetKeyboardVars(); + return; + } + + // keep the last sequence in keyString + keyString = d->keySeq.left(d->keySeq.length() - 1); + + // allow sequence matching to be tried again + resetKeyboardVars(); + + } else if (key == Key_Delete) { + resetKeyboardVars(); + + // clear active item + setActiveItem(0); + return; + + } else if (d->noMatches) { + // clear if there are no matches + resetKeyboardVars(); + + // clear active item + setActiveItem(0); + + } else { + // the key sequence is not a null string + // therefore the lastHitIndex is valid + i = d->lastHitIndex; + } + } else if (key == Key_Backspace && parentMenu) { + // backspace with no chars in the buffer... go back a menu. + hide(); + resetKeyboardVars(); + return; + } + + d->keySeq += keyString; + int seqLen = d->keySeq.length(); + + for (; i < (int)count(); i++) { + // compare typed text with text of this entry + int j = idAt(i); + + // don't search disabled entries + if (!isItemEnabled(j)) + continue; + + QString thisText; + + // retrieve the right text + // (the last selected item one may have additional ampersands) + if (i == d->lastHitIndex) + thisText = d->originalText; + else + thisText = text(j); + + // if there is an accelerator present, remove it + if ((int)accel(j) != 0) + thisText = thisText.replace(QRegExp("&"), ""); + + // chop text to the search length + thisText = thisText.left(seqLen); + + // do the search + if (thisText.find(d->keySeq, 0, false) == 0) { + + if (firstpass) { + // match + setActiveItem(i); + + // check to see if we're underlining a different item + if (d->lastHitIndex != i) + // yes; revert the underlining + changeItem(idAt(d->lastHitIndex), d->originalText); + + // set the original text if it's a different item + if (d->lastHitIndex != i || d->lastHitIndex == -1) + d->originalText = text(j); + + // underline the currently selected item + changeItem(j, underlineText(d->originalText, d->keySeq.length())); + + // remeber what's going on + d->lastHitIndex = i; + + // start/restart the clear timer + d->clearTimer.start(5000, true); + + // go around for another try, to see if we can execute + firstpass = false; + } else { + // don't allow execution + return; + } + } + + // fall through to allow execution + } + + if (!firstpass) { + if (d->autoExec) { + // activate anything + activateItemAt(d->lastHitIndex); + resetKeyboardVars(); + + } else if (findItem(idAt(d->lastHitIndex)) && + findItem(idAt(d->lastHitIndex))->popup()) { + // only activate sub-menus + activateItemAt(d->lastHitIndex); + resetKeyboardVars(); + } + + return; + } + + // no matches whatsoever, clean up + resetKeyboardVars(true); + //e->ignore(); + QPopupMenu::keyPressEvent(e); +} + +QString OPopupMenu::underlineText(const QString& text, uint length) +{ + QString ret = text; + for (uint i = 0; i < length; i++) { + if (ret[2*i] != '&') + ret.insert(2*i, "&"); + } + return ret; +} + +void OPopupMenu::resetKeyboardVars(bool noMatches /* = false */) +{ + // Clean up keyboard variables + if (d->lastHitIndex != -1) { + changeItem(idAt(d->lastHitIndex), d->originalText); + d->lastHitIndex = -1; + } + + if (!noMatches) { + d->keySeq = QString::null; + } + + d->noMatches = noMatches; +} + +void OPopupMenu::setKeyboardShortcutsEnabled(bool enable) +{ + d->shortcuts = enable; +} + +void OPopupMenu::setKeyboardShortcutsExecute(bool enable) +{ + d->autoExec = enable; +} +/** + * End keyboard navigation. + */ + +/** + * RMB menus on menus + */ +QPopupMenu* OPopupMenu::contextMenu() +{ + if (!d->m_ctxMenu) + { + d->m_ctxMenu = new QPopupMenu(this); + installEventFilter(this); + connect(d->m_ctxMenu, SIGNAL(aboutToHide()), this, SLOT(ctxMenuHiding())); + } + + return d->m_ctxMenu; +} + +void OPopupMenu::cancelContextMenuShow() +{ + OPopupMenuPrivate::s_continueCtxMenuShow = false; +} + +int OPopupMenu::contextMenuFocusItem() +{ + return OPopupMenuPrivate::s_highlightedItem; +} + +OPopupMenu* OPopupMenu::contextMenuFocus() +{ + return OPopupMenuPrivate::s_contextedMenu; +} + +void OPopupMenu::itemHighlighted(int /* whichItem */) +{ + if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible()) + { + return; + } + + d->m_ctxMenu->hide(); + showCtxMenu(mapFromGlobal(QCursor::pos())); +} + +void OPopupMenu::showCtxMenu(QPoint pos) +{ + OPopupMenuPrivate::s_highlightedItem = idAt(pos); + + if (OPopupMenuPrivate::s_highlightedItem == -1) + { + OPopupMenuPrivate::s_contextedMenu = 0; + return; + } + + emit aboutToShowContextMenu(this, OPopupMenuPrivate::s_highlightedItem, d->m_ctxMenu); + + if (!OPopupMenuPrivate::s_continueCtxMenuShow) + { + OPopupMenuPrivate::s_continueCtxMenuShow = true; + return; + } + + OPopupMenuPrivate::s_contextedMenu = this; + d->m_ctxMenu->popup(this->mapToGlobal(pos)); + connect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int))); +} + +void OPopupMenu::ctxMenuHiding() +{ + disconnect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int))); + OPopupMenuPrivate::s_continueCtxMenuShow = true; +} + +bool OPopupMenu::eventFilter(QObject* obj, QEvent* event) +{ + if (d->m_ctxMenu && obj == this) + { + if (event->type() == QEvent::MouseButtonRelease) + { + if (d->m_ctxMenu->isVisible()) + { + return true; + } + } + #if QT_VERSION > 290 + else if (event->type() == QEvent::ContextMenu) + #else + else if ( (event->type() == QEvent::MouseButtonPress) && + ( (QMouseEvent*) event )->button() == QMouseEvent::RightButton ) + #endif + { + showCtxMenu(mapFromGlobal(QCursor::pos())); + return true; + } + } + + return QWidget::eventFilter(obj, event); +} + +void OPopupMenu::hideEvent(QHideEvent*) +{ + if (d->m_ctxMenu) + { + d->m_ctxMenu->hide(); + } +} +/** + * end of RMB menus on menus support + */ + +// Obsolete +OPopupMenu::OPopupMenu(const QString& title, QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + d = new OPopupMenuPrivate; + setTitle(title); +} + +// Obsolete +void OPopupMenu::setTitle(const QString &title) +{ + OPopupTitle *titleItem = new OPopupTitle(); + titleItem->setTitle(title); + insertItem(titleItem); + d->m_lastTitle = title; +} + +void OPopupTitle::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void OPopupMenu::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + diff --git a/libopie2/opieui/opopupmenu.h b/libopie2/opieui/opopupmenu.h new file mode 100644 index 0000000..94f05f4 --- a/dev/null +++ b/libopie2/opieui/opopupmenu.h @@ -0,0 +1,256 @@ +/* This file is part of the ODE libraries + Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#ifndef _OPOPUP_H +#define _OPOPUP_H + +#define INCLUDE_MENUITEM_DEF + +/* QT */ + +#include <qpopupmenu.h> + +/* OPIE */ + +#include <opie2/opixmapeffect.h> + +/** + * Title widget for use in @ref OPopupMenu. + * + * You usually don't have to create this manually since + * @ref OPopupMenu::insertTitle will do it for you, but it is allowed if + * you wish to customize it's look. + * + * @author Daniel M. Duley <mosfet@kde.org> + * @short OPopupMenu title widget. + */ +class OPopupTitle : public QWidget +{ + Q_OBJECT + +public: + /** + * Constructs a title widget with the user specified gradient, pixmap, + * and colors. + */ + OPopupTitle(QWidget *parent=0, const char *name=0); + /** + * @deprecated + * Constructs a title widget with the specified gradient and colors. + */ + OPopupTitle(OPixmapEffect::GradientType gradient, const QColor &color, + const QColor &textColor, QWidget *parent=0, + const char *name=0); + /** + * @deprecated + * Constructs a title widget with the specified pixmap and colors. + */ + OPopupTitle(const OPixmap &background, const QColor &color, + const QColor &textColor, QWidget *parent=0, + const char *name=0); + /** + * Sets the title string and optional icon for the title widget. + * + * You will want to call this before inserting into a menu. + */ + void setTitle(const QString &text, const QPixmap *icon=NULL); + /** + * Returns the current title. + */ + QString title() const { return(titleStr); } + /** + * Returns the current icon. + */ + QPixmap icon() const { return(miniicon); } + + QSize sizeHint() const; + +public slots: + /// @since 3.1 + void setText( const QString &text ); + /// @since 3.1 + void setIcon( const QPixmap &pix ); + +protected: + void paintEvent(QPaintEvent *ev); + + QString titleStr; + QPixmap miniicon; + + // Remove in KDE4 + OPixmapEffect::GradientType grType; + QPixmap fill; + QColor fgColor, bgColor, grHigh, grLow; + bool useGradient; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class OPopupTitlePrivate; + OPopupTitlePrivate *d; +}; + +/** + * OPopupMenu is a class for menus with standard title items and keyboard + * accessibility for popups with many options and/or varying options. It acts + * identically to QPopupMenu, with the addition of insertTitle(), + * changeTitle(), setKeyboardShortcutsEnabled() and + * setKeyboardShortcutsExecute() methods. + * + * The titles support a text string, an icon, plus user defined gradients, + * colors, and background pixmaps. + * + * The keyboard search algorithm is incremental with additional underlining + * for user feedback. + * + * @short A menu with title items. + * @author Daniel M. Duley <mosfet@kde.org> + * @author Hamish Rodda <meddie@yoyo.its.monash.edu.au> + */ +class OPopupMenu : public QPopupMenu { + Q_OBJECT +public: + /** + * Constructs a OPopupMenu. + */ + OPopupMenu(QWidget *parent=0, const char *name=0); + + /** + * Destructs the object + */ + ~OPopupMenu(); + + /** + * Inserts a title item with no icon. + */ + int insertTitle(const QString &text, int id=-1, int index=-1); + /** + * Inserts a title item with the given icon and title. + */ + int insertTitle(const QPixmap &icon, const QString &text, int id=-1, + int index=-1); + /** + * Changes the title of the item at the specified id. If a icon was + * previously set it is cleared. + */ + void changeTitle(int id, const QString &text); + /** + * Changes the title and icon of the title item at the specified id. + */ + void changeTitle(int id, const QPixmap &icon, const QString &text); + /** + * Returns the title of the title item at the specified id. The default + * id of -1 is for backwards compatibility only, you should always specify + * the id. + */ + QString title(int id=-1) const; + /** + * Returns the icon of the title item at the specified id. + */ + QPixmap titlePixmap(int id) const; + + /** + * Enables keyboard navigation by searching for the entered key sequence. + * Also underlines the currently selected item, providing feedback on the search. + * + * Defaults to off. + * + * WARNING: calls to text() of currently keyboard-selected items will + * contain additional ampersand characters. + * + * WARNING: though pre-existing keyboard shortcuts will not interfere with the + * operation of this feature, they may be confusing to the user as the existing + * shortcuts will not work. + * @since 3.1 + */ + void setKeyboardShortcutsEnabled(bool enable); + + /** + * Enables execution of the menu item once it is uniquely specified. + * Defaults to off. + * @since 3.1 + */ + void setKeyboardShortcutsExecute(bool enable); + + /** + * Obsolete method provided for backwards compatibility only. Use the + * normal constructor and insertTitle instead. + */ + OPopupMenu(const QString &title, QWidget *parent=0, const char *name=0); + /** + * Obsolete method provided for backwards compatibility only. Use + * insertTitle and changeTitle instead. + */ + void setTitle(const QString &title); + + /** + * Returns the context menu associated with this menu + * @since 3.2 + */ + QPopupMenu* contextMenu(); + + /** + * Hides the context menu if shown + * @since 3.2 + */ + void cancelContextMenuShow(); + + /** + * Returns the OPopupMenu associated with the current context menu + * @since 3.2 + */ + static OPopupMenu* contextMenuFocus(); + + /** + * returns the ID of the menuitem associated with the current context menu + * @since 3.2 + */ + static int contextMenuFocusItem(); + +signals: + /** + * connect to this signal to be notified when a context menu is about to be shown + * @param menu The menu that the context menu is about to be shown for + * @param menuItem The menu item that the context menu is currently on + * @param ctxMenu The context menu itself + * @since 3.2 + */ + void aboutToShowContextMenu(OPopupMenu* menu, int menuItem, QPopupMenu* ctxMenu); + +protected: + virtual void closeEvent(QCloseEvent *); + virtual void keyPressEvent(QKeyEvent* e); + virtual bool eventFilter(QObject* obj, QEvent* event); + virtual void hideEvent(QHideEvent*); + + virtual void virtual_hook( int id, void* data ); + +protected slots: + /// @since 3.1 + QString underlineText(const QString& text, uint length); + /// @since 3.1 + void resetKeyboardVars(bool noMatches = false); + void itemHighlighted(int whichItem); + void showCtxMenu(QPoint pos); + void ctxMenuHiding(); + +private: + class OPopupMenuPrivate; + OPopupMenuPrivate *d; +}; + +#endif diff --git a/libopie2/opieui/oselector.cpp b/libopie2/opieui/oselector.cpp new file mode 100644 index 0000000..ec5af6b --- a/dev/null +++ b/libopie2/opieui/oselector.cpp @@ -0,0 +1,716 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Martin Jones (mjones@kde.org) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/* QT */ + +#include <qimage.h> +#include <qpainter.h> +#include <qdrawutil.h> + +/* OPIE */ + +#include <opie2/oimageeffect.h> +#include <opie2/oselector.h> + +#define STORE_W 8 +#define STORE_W2 STORE_W * 2 + +//----------------------------------------------------------------------------- +/* + * 2D value selector. + * The contents of the selector are drawn by derived class. + */ + +OXYSelector::OXYSelector( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + xPos = 0; + yPos = 0; + minX = 0; + minY = 0; + maxX = 100; + maxY = 100; + store.setOptimization( QPixmap::BestOptim ); + store.resize( STORE_W2, STORE_W2 ); +} + + +OXYSelector::~OXYSelector() +{} + + +void OXYSelector::setRange( int _minX, int _minY, int _maxX, int _maxY ) +{ + px = 2; + py = 2; + minX = _minX; + minY = _minY; + maxX = _maxX; + maxY = _maxY; +} + +void OXYSelector::setValues( int _xPos, int _yPos ) +{ + xPos = _xPos; + yPos = _yPos; + + if ( xPos > maxX ) + xPos = maxX; + else if ( xPos < minX ) + xPos = minX; + + if ( yPos > maxY ) + yPos = maxY; + else if ( yPos < minY ) + yPos = minY; + + int xp = 2 + (width() - 4) * xPos / (maxX - minX); + int yp = height() - 2 - (height() - 4) * yPos / (maxY - minY); + + setPosition( xp, yp ); +} + +QRect OXYSelector::contentsRect() const +{ + return QRect( 2, 2, width()-4, height()-4 ); +} + +void OXYSelector::paintEvent( QPaintEvent *ev ) +{ + QRect cursorRect( px - STORE_W, py - STORE_W, STORE_W2, STORE_W2); + QRect paintRect = ev->rect(); + + QPainter painter; + painter.begin( this ); + + QBrush brush; + qDrawShadePanel( &painter, 0, 0, width(), height(), colorGroup(), + TRUE, 2, &brush ); + + drawContents( &painter ); + if (paintRect.contains(cursorRect)) + { + bitBlt( &store, 0, 0, this, px - STORE_W, py - STORE_W, + STORE_W2, STORE_W2, CopyROP ); + drawCursor( &painter, px, py ); + } + else if (paintRect.intersects(cursorRect)) + { + repaint( cursorRect, false); + } + + painter.end(); +} + +void OXYSelector::mousePressEvent( QMouseEvent *e ) +{ + int xVal, yVal; + valuesFromPosition( e->pos().x() - 2, e->pos().y() - 2, xVal, yVal ); + setValues( xVal, yVal ); + + emit valueChanged( xPos, yPos ); +} + +void OXYSelector::mouseMoveEvent( QMouseEvent *e ) +{ + int xVal, yVal; + valuesFromPosition( e->pos().x() - 2, e->pos().y() - 2, xVal, yVal ); + setValues( xVal, yVal ); + + emit valueChanged( xPos, yPos ); +} + +void OXYSelector::wheelEvent( QWheelEvent *e ) +{ + #if QT_VERSION > 290 + if ( e->orientation() == Qt::Horizontal ) + setValues( xValue() + e->delta()/120, yValue() ); + else + setValues( xValue(), yValue() + e->delta()/120 ); + + emit valueChanged( xPos, yPos ); + #endif +} + +void OXYSelector::valuesFromPosition( int x, int y, int &xVal, int &yVal ) const +{ + xVal = ( (maxX-minX) * (x-2) ) / ( width()-4 ); + yVal = maxY - ( ( (maxY-minY) * (y-2) ) / ( height()-4 ) ); + + if ( xVal > maxX ) + xVal = maxX; + else if ( xVal < minX ) + xVal = minX; + + if ( yVal > maxY ) + yVal = maxY; + else if ( yVal < minY ) + yVal = minY; +} + +void OXYSelector::setPosition( int xp, int yp ) +{ + if ( xp < 2 ) + xp = 2; + else if ( xp > width() - 2 ) + xp = width() - 2; + + if ( yp < 2 ) + yp = 2; + else if ( yp > height() - 2 ) + yp = height() - 2; + + QPainter painter; + painter.begin( this ); + + bitBlt( this, px - STORE_W, py - STORE_W, &store, 0, 0, + STORE_W2, STORE_W2, CopyROP ); + bitBlt( &store, 0, 0, this, xp - STORE_W, yp - STORE_W, + STORE_W2, STORE_W2, CopyROP ); + drawCursor( &painter, xp, yp ); + px = xp; + py = yp; + + painter.end(); +} + +void OXYSelector::drawContents( QPainter * ) +{} + + +void OXYSelector::drawCursor( QPainter *p, int xp, int yp ) +{ + p->setPen( QPen( white ) ); + + p->drawLine( xp - 6, yp - 6, xp - 2, yp - 2 ); + p->drawLine( xp - 6, yp + 6, xp - 2, yp + 2 ); + p->drawLine( xp + 6, yp - 6, xp + 2, yp - 2 ); + p->drawLine( xp + 6, yp + 6, xp + 2, yp + 2 ); +} + +//----------------------------------------------------------------------------- +/* + * 1D value selector with contents drawn by derived class. + * See OColorDialog for example. + */ + + +OSelector::OSelector( QWidget *parent, const char *name ) + : QWidget( parent, name ), QRangeControl() +{ + _orientation = Horizontal; + _indent = TRUE; +} + +OSelector::OSelector( Orientation o, QWidget *parent, const char *name ) + : QWidget( parent, name ), QRangeControl() +{ + _orientation = o; + _indent = TRUE; +} + + +OSelector::~OSelector() +{} + + +QRect OSelector::contentsRect() const +{ + if ( orientation() == Vertical ) + return QRect( 2, 5, width()-9, height()-10 ); + else + return QRect( 5, 2, width()-10, height()-9 ); +} + +void OSelector::paintEvent( QPaintEvent * ) +{ + QPainter painter; + + painter.begin( this ); + + drawContents( &painter ); + + QBrush brush; + + if ( indent() ) + { + if ( orientation() == Vertical ) + qDrawShadePanel( &painter, 0, 3, width()-5, height()-6, + colorGroup(), TRUE, 2, &brush ); + else + qDrawShadePanel( &painter, 3, 0, width()-6, height()-5, + colorGroup(), TRUE, 2, &brush ); + } + + QPoint pos = calcArrowPos( value() ); + drawArrow( &painter, TRUE, pos ); + + painter.end(); +} + +void OSelector::mousePressEvent( QMouseEvent *e ) +{ + moveArrow( e->pos() ); +} + +void OSelector::mouseMoveEvent( QMouseEvent *e ) +{ + moveArrow( e->pos() ); +} + +void OSelector::wheelEvent( QWheelEvent *e ) +{ + int val = value() + e->delta()/120; + emit valueChanged( val ); + setValue( val ); +} + +void OSelector::valueChange() +{ + QPainter painter; + QPoint pos; + + painter.begin( this ); + + pos = calcArrowPos( prevValue() ); + drawArrow( &painter, FALSE, pos ); + + pos = calcArrowPos( value() ); + drawArrow( &painter, TRUE, pos ); + + painter.end(); +} + +void OSelector::moveArrow( const QPoint &pos ) +{ + int val; + + if ( orientation() == Vertical ) + val = ( maxValue() - minValue() ) * (height()-pos.y()-3) + / (height()-10) + minValue(); + else + val = ( maxValue() - minValue() ) * (width()-pos.x()-3) + / (width()-10) + minValue(); + + if ( val > maxValue() ) + val = maxValue(); + if ( val < minValue() ) + val = minValue(); + + emit valueChanged( val ); + setValue( val ); +} + +QPoint OSelector::calcArrowPos( int val ) +{ + QPoint p; + + if ( orientation() == Vertical ) + { + p.setY( height() - ( (height()-10) * val + / ( maxValue() - minValue() ) + 5 ) ); + p.setX( width() - 5 ); + } + else + { + p.setX( width() - ( (width()-10) * val + / ( maxValue() - minValue() ) + 5 ) ); + p.setY( height() - 5 ); + } + + return p; +} + +void OSelector::drawContents( QPainter * ) +{} + +void OSelector::drawArrow( QPainter *painter, bool show, const QPoint &pos ) +{ + if ( show ) + { + QPointArray array(3); + + painter->setPen( QPen() ); + painter->setBrush( QBrush( colorGroup().buttonText() ) ); + if ( orientation() == Vertical ) + { + array.setPoint( 0, pos.x()+0, pos.y()+0 ); + array.setPoint( 1, pos.x()+5, pos.y()+5 ); + array.setPoint( 2, pos.x()+5, pos.y()-5 ); + } + else + { + array.setPoint( 0, pos.x()+0, pos.y()+0 ); + array.setPoint( 1, pos.x()+5, pos.y()+5 ); + array.setPoint( 2, pos.x()-5, pos.y()+5 ); + } + + painter->drawPolygon( array ); + } + else + { + if ( orientation() == Vertical ) + { + repaint(pos.x(), pos.y()-5, 6, 11, true); + } + else + { + repaint(pos.x()-5, pos.y(), 11, 6, true); + } + } +} + +//---------------------------------------------------------------------------- + +OGradientSelector::OGradientSelector( QWidget *parent, const char *name ) + : OSelector( parent, name ) +{ + init(); +} + + +OGradientSelector::OGradientSelector( Orientation o, QWidget *parent, + const char *name ) + : OSelector( o, parent, name ) +{ + init(); +} + + +OGradientSelector::~OGradientSelector() +{} + + +void OGradientSelector::init() +{ + color1.setRgb( 0, 0, 0 ); + color2.setRgb( 255, 255, 255 ); + + text1 = text2 = ""; +} + + +void OGradientSelector::drawContents( QPainter *painter ) +{ + QImage image( contentsRect().width(), contentsRect().height(), 32 ); + + QColor col; + float scale; + + int redDiff = color2.red() - color1.red(); + int greenDiff = color2.green() - color1.green(); + int blueDiff = color2.blue() - color1.blue(); + + if ( orientation() == Vertical ) + { + for ( int y = 0; y < image.height(); y++ ) + { + scale = 1.0 * y / image.height(); + col.setRgb( color1.red() + int(redDiff*scale), + color1.green() + int(greenDiff*scale), + color1.blue() + int(blueDiff*scale) ); + + unsigned int *p = (uint *) image.scanLine( y ); + for ( int x = 0; x < image.width(); x++ ) + *p++ = col.rgb(); + } + } + else + { + unsigned int *p = (uint *) image.scanLine( 0 ); + + for ( int x = 0; x < image.width(); x++ ) + { + scale = 1.0 * x / image.width(); + col.setRgb( color1.red() + int(redDiff*scale), + color1.green() + int(greenDiff*scale), + color1.blue() + int(blueDiff*scale) ); + *p++ = col.rgb(); + } + + for ( int y = 1; y < image.height(); y++ ) + memcpy( image.scanLine( y ), image.scanLine( y - 1), + sizeof( unsigned int ) * image.width() ); + } + + QColor ditherPalette[8]; + + for ( int s = 0; s < 8; s++ ) + ditherPalette[s].setRgb( color1.red() + redDiff * s / 8, + color1.green() + greenDiff * s / 8, + color1.blue() + blueDiff * s / 8 ); + + OImageEffect::dither( image, ditherPalette, 8 ); + + QPixmap p; + p.convertFromImage( image ); + + painter->drawPixmap( contentsRect().x(), contentsRect().y(), p ); + + if ( orientation() == Vertical ) + { + int yPos = contentsRect().top() + painter->fontMetrics().ascent() + 2; + int xPos = contentsRect().left() + (contentsRect().width() - + painter->fontMetrics().width( text2 )) / 2; + QPen pen( color2 ); + painter->setPen( pen ); + painter->drawText( xPos, yPos, text2 ); + + yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; + xPos = contentsRect().left() + (contentsRect().width() - + painter->fontMetrics().width( text1 )) / 2; + pen.setColor( color1 ); + painter->setPen( pen ); + painter->drawText( xPos, yPos, text1 ); + } + else + { + int yPos = contentsRect().bottom()-painter->fontMetrics().descent()-2; + + QPen pen( color2 ); + painter->setPen( pen ); + painter->drawText( contentsRect().left() + 2, yPos, text1 ); + + pen.setColor( color1 ); + painter->setPen( pen ); + painter->drawText( contentsRect().right() - + painter->fontMetrics().width( text2 ) - 2, yPos, text2 ); + } +} + +//----------------------------------------------------------------------------- + +static QColor *standardPalette = 0; + +#define STANDARD_PAL_SIZE 17 + +OColor::OColor() +: QColor() +{ + r = 0; g = 0; b = 0; h = 0; s = 0; v = 0; +}; + +OColor::OColor( const OColor &col) +: QColor( col ) +{ + h = col.h; s = col.s; v = col.v; + r = col.r; g = col.g; b = col.b; +}; + +OColor::OColor( const QColor &col) +: QColor( col ) +{ + QColor::rgb(&r, &g, &b); + QColor::hsv(&h, &s, &v); +}; + +bool OColor::operator==(const OColor& col) const +{ + return (h == col.h) && (s == col.s) && (v == col.v) && + (r == col.r) && (g == col.g) && (b == col.b); +} + +OColor& OColor::operator=(const OColor& col) +{ + *(QColor *)this = col; + h = col.h; s = col.s; v = col.v; + r = col.r; g = col.g; b = col.b; + return *this; +} + +void +OColor::setHsv(int _h, int _s, int _v) +{ + h = _h; s = _s; v = _v; + QColor::setHsv(h, s, v); + QColor::rgb(&r, &g, &b); +}; + +void +OColor::setRgb(int _r, int _g, int _b) +{ + r = _r; g = _g; b = _b; + QColor::setRgb(r, g, b); + QColor::hsv(&h, &s, &v); +} + +void +OColor::rgb(int *_r, int *_g, int *_b) const +{ + *_r = r; *_g = g; *_b = b; +} + +void +OColor::hsv(int *_h, int *_s, int *_v) const +{ + *_h = h; *_s = s; *_v = v; +} + +static void createStandardPalette() +{ + if ( standardPalette ) + return; + + standardPalette = new QColor[STANDARD_PAL_SIZE]; + + int i = 0; + + standardPalette[i++] = Qt::red; + standardPalette[i++] = Qt::green; + standardPalette[i++] = Qt::blue; + standardPalette[i++] = Qt::cyan; + standardPalette[i++] = Qt::magenta; + standardPalette[i++] = Qt::yellow; + standardPalette[i++] = Qt::darkRed; + standardPalette[i++] = Qt::darkGreen; + standardPalette[i++] = Qt::darkBlue; + standardPalette[i++] = Qt::darkCyan; + standardPalette[i++] = Qt::darkMagenta; + standardPalette[i++] = Qt::darkYellow; + standardPalette[i++] = Qt::white; + standardPalette[i++] = Qt::lightGray; + standardPalette[i++] = Qt::gray; + standardPalette[i++] = Qt::darkGray; + standardPalette[i++] = Qt::black; +} + + +OHSSelector::OHSSelector( QWidget *parent, const char *name ) + : OXYSelector( parent, name ) +{ + setRange( 0, 0, 359, 255 ); +} + +void OHSSelector::updateContents() +{ + drawPalette(&pixmap); +} + +void OHSSelector::resizeEvent( QResizeEvent * ) +{ + updateContents(); +} + +void OHSSelector::drawContents( QPainter *painter ) +{ + painter->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap ); +} + +void OHSSelector::drawPalette( QPixmap *pixmap ) +{ + int xSize = contentsRect().width(), ySize = contentsRect().height(); + QImage image( xSize, ySize, 32 ); + QColor col; + int h, s; + uint *p; + + for ( s = ySize-1; s >= 0; s-- ) + { + p = (uint *) image.scanLine( ySize - s - 1 ); + for( h = 0; h < xSize; h++ ) + { + col.setHsv( 359*h/(xSize-1), 255*s/(ySize-1), 192 ); + *p = col.rgb(); + p++; + } + } + + if ( QColor::numBitPlanes() <= 8 ) + { + createStandardPalette(); + OImageEffect::dither( image, standardPalette, STANDARD_PAL_SIZE ); + } + pixmap->convertFromImage( image ); +} + + +//----------------------------------------------------------------------------- + +OValueSelector::OValueSelector( QWidget *parent, const char *name ) + : OSelector( OSelector::Vertical, parent, name ), _hue(0), _sat(0) +{ + setRange( 0, 255 ); + pixmap.setOptimization( QPixmap::BestOptim ); +} + +OValueSelector::OValueSelector(Orientation o, QWidget *parent, const char *name + ) + : OSelector( o, parent, name), _hue(0), _sat(0) +{ + setRange( 0, 255 ); + pixmap.setOptimization( QPixmap::BestOptim ); +} + +void OValueSelector::updateContents() +{ + drawPalette(&pixmap); +} + +void OValueSelector::resizeEvent( QResizeEvent * ) +{ + updateContents(); +} + +void OValueSelector::drawContents( QPainter *painter ) +{ + painter->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap ); +} + +void OValueSelector::drawPalette( QPixmap *pixmap ) +{ + int xSize = contentsRect().width(), ySize = contentsRect().height(); + QImage image( xSize, ySize, 32 ); + QColor col; + uint *p; + QRgb rgb; + + if ( orientation() == OSelector::Horizontal ) + { + for ( int v = 0; v < ySize; v++ ) + { + p = (uint *) image.scanLine( ySize - v - 1 ); + + for( int x = 0; x < xSize; x++ ) + { + col.setHsv( _hue, _sat, 255*x/(xSize-1) ); + rgb = col.rgb(); + *p++ = rgb; + } + } + } + + if( orientation() == OSelector::Vertical ) + { + for ( int v = 0; v < ySize; v++ ) + { + p = (uint *) image.scanLine( ySize - v - 1 ); + col.setHsv( _hue, _sat, 255*v/(ySize-1) ); + rgb = col.rgb(); + for ( int i = 0; i < xSize; i++ ) + *p++ = rgb; + } + } + + if ( QColor::numBitPlanes() <= 8 ) + { + createStandardPalette(); + OImageEffect::dither( image, standardPalette, STANDARD_PAL_SIZE ); + } + pixmap->convertFromImage( image ); +} diff --git a/libopie2/opieui/oselector.h b/libopie2/opieui/oselector.h new file mode 100644 index 0000000..f832239 --- a/dev/null +++ b/libopie2/opieui/oselector.h @@ -0,0 +1,518 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Martin Jones (mjones@kde.org) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +//----------------------------------------------------------------------------- +// Selector widgets for KDE Color Selector, but probably useful for other +// stuff also. + +#ifndef __OSELECT_H__ +#define __OSELECT_H__ + +#include <qwidget.h> +#include <qrangecontrol.h> +#include <qpixmap.h> + +/** + * OXYSelector is the base class for other widgets which + * provides the ability to choose from a two-dimensional + * range of values. The currently chosen value is indicated + * by a cross. An example is the @ref OHSSelector which + * allows to choose from a range of colors, and which is + * used in OColorDialog. + * + * A custom drawing routine for the widget surface has + * to be provided by the subclass. + */ +class OXYSelector : public QWidget +{ + Q_OBJECT + +public: + /** + * Constructs a two-dimensional selector widget which + * has a value range of [0..100] in both directions. + */ + OXYSelector( QWidget *parent=0, const char *name=0 ); + /** + * Destructs the widget. + */ + ~OXYSelector(); + + /** + * Sets the current values in horizontal and + * vertical direction. + */ + void setValues( int xPos, int yPos ); + /** + * Sets the range of possible values. + */ + void setRange( int minX, int minY, int maxX, int maxY ); + + /** + * @return the current value in horizontal direction. + */ + int xValue() const { return xPos; } + /** + * @return the current value in vertical direction. + */ + int yValue() const { return yPos; } + + /** + * @return the rectangle on which subclasses should draw. + */ + QRect contentsRect() const; + +signals: + /** + * This signal is emitted whenever the user chooses a value, + * e.g. by clicking with the mouse on the widget. + */ + void valueChanged( int x, int y ); + +protected: + /** + * Override this function to draw the contents of the widget. + * The default implementation does nothing. + * + * Draw within @ref contentsRect() only. + */ + virtual void drawContents( QPainter * ); + /** + * Override this function to draw the cursor which + * indicates the currently selected value pair. + */ + virtual void drawCursor( QPainter *p, int xp, int yp ); + /** + * @reimplemented + */ + virtual void paintEvent( QPaintEvent *e ); + /** + * @reimplemented + */ + virtual void mousePressEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void mouseMoveEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void wheelEvent( QWheelEvent * ); + /** + * Converts a pixel position to its corresponding values. + */ + void valuesFromPosition( int x, int y, int& xVal, int& yVal ) const; + +private: + void setPosition( int xp, int yp ); + int px; + int py; + int xPos; + int yPos; + int minX; + int maxX; + int minY; + int maxY; + QPixmap store; + +private: + class OXYSelectorPrivate; + OXYSelectorPrivate *d; +}; + + +/** + * OSelector is the base class for other widgets which + * provides the ability to choose from a one-dimensional + * range of values. An example is the @ref OGradientSelector + * which allows to choose from a range of colors. + * + * A custom drawing routine for the widget surface has + * to be provided by the subclass. + */ +class OSelector : public QWidget, public QRangeControl +{ + Q_OBJECT + Q_PROPERTY( int value READ value WRITE setValue ) + Q_PROPERTY( int minValue READ minValue WRITE setMinValue ) + Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue ) +public: + + /** + * Constructs a horizontal one-dimensional selection widget. + */ + OSelector( QWidget *parent=0, const char *name=0 ); + /** + * Constructs a one-dimensional selection widget with + * a given orientation. + */ + OSelector( Orientation o, QWidget *parent = 0L, const char *name = 0L ); + /* + * Destructs the widget. + */ + ~OSelector(); + + /** + * @return the orientation of the widget. + */ + Orientation orientation() const + { return _orientation; } + + /** + * @return the rectangle on which subclasses should draw. + */ + QRect contentsRect() const; + + /** + * Sets the indent option of the widget to i. + * This determines whether a shaded frame is drawn. + */ + void setIndent( bool i ) + { _indent = i; } + /** + * @return whether the indent option is set. + */ + bool indent() const + { return _indent; } + + /** + * Sets the value. + */ + void setValue(int value) + { QRangeControl::setValue(value); } + + /** + * @returns the value. + */ + int value() const + { return QRangeControl::value(); } + + /** + * Sets the min value. + */ + #if ( QT_VERSION > 290 ) + void setMinValue(int value) { QRangeControl::setMinValue(value); } + #else + void setMinValue(int value) { QRangeControl::setRange(value,QRangeControl::maxValue()); } + #endif + + /** + * @return the min value. + */ + int minValue() const + { return QRangeControl::minValue(); } + + /** + * Sets the max value. + */ + #if ( QT_VERSION > 290 ) + void setMaxValue(int value) { QRangeControl::setMaxValue(value); } + #else + void setMaxValue(int value) { QRangeControl::setRange(QRangeControl::minValue(),value); } + #endif + + /** + * @return the max value. + */ + int maxValue() const + { return QRangeControl::maxValue(); } + +signals: + /** + * This signal is emitted whenever the user chooses a value, + * e.g. by clicking with the mouse on the widget. + */ + void valueChanged( int value ); + +protected: + /** + * Override this function to draw the contents of the control. + * The default implementation does nothing. + * + * Draw only within contentsRect(). + */ + virtual void drawContents( QPainter * ); + /** + * Override this function to draw the cursor which + * indicates the current value. This function is + * always called twice, once with argument show=false + * to clear the old cursor, once with argument show=true + * to draw the new one. + */ + virtual void drawArrow( QPainter *painter, bool show, const QPoint &pos ); + + /** + * @reimplemented + */ + virtual void valueChange(); + /** + * @reimplemented + */ + virtual void paintEvent( QPaintEvent * ); + /** + * @reimplemented + */ + virtual void mousePressEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void mouseMoveEvent( QMouseEvent *e ); + /** + * @reimplemented + */ + virtual void wheelEvent( QWheelEvent * ); + +private: + QPoint calcArrowPos( int val ); + void moveArrow( const QPoint &pos ); + + Orientation _orientation; + bool _indent; + +private: + class OSelectorPrivate; + OSelectorPrivate *d; +}; + + +/** + * The OGradientSelector widget allows the user to choose + * from a one-dimensional range of colors which is given as a + * gradient between two colors provided by the programmer. + */ +class OGradientSelector : public OSelector +{ + Q_OBJECT + + Q_PROPERTY( QColor firstColor READ firstColor WRITE setFirstColor ) + Q_PROPERTY( QColor secondColor READ secondColor WRITE setSecondColor ) + Q_PROPERTY( QString firstText READ firstText WRITE setFirstText ) + Q_PROPERTY( QString secondText READ secondText WRITE setSecondText ) + +public: + /** + * Constructs a horizontal color selector which + * contains a gradient between white and black. + */ + OGradientSelector( QWidget *parent=0, const char *name=0 ); + /** + * Constructs a colors selector with orientation o which + * contains a gradient between white and black. + */ + OGradientSelector( Orientation o, QWidget *parent=0, const char *name=0 ); + /** + * Destructs the widget. + */ + ~OGradientSelector(); + /** + * Sets the two colors which span the gradient. + */ + void setColors( const QColor &col1, const QColor &col2 ) + { color1 = col1; color2 = col2; update();} + void setText( const QString &t1, const QString &t2 ) + { text1 = t1; text2 = t2; update(); } + + /** + * Set each color on its own. + */ + void setFirstColor( const QColor &col ) + { color1 = col; update(); } + void setSecondColor( const QColor &col ) + { color2 = col; update(); } + + /** + * Set each description on its own + */ + void setFirstText( const QString &t ) + { text1 = t; update(); } + void setSecondText( const QString &t ) + { text2 = t; update(); } + + const QColor firstColor() const + { return color1; } + const QColor secondColor() const + { return color2; } + + const QString firstText() const + { return text1; } + const QString secondText() const + { return text2; } + +protected: + /** + * @reimplemented + */ + virtual void drawContents( QPainter * ); + + /** + * @reimplemented + */ + virtual QSize minimumSize() const + { return sizeHint(); } + +private: + void init(); + QColor color1; + QColor color2; + QString text1; + QString text2; + +private: + class OGradientSelectorPrivate; + OGradientSelectorPrivate *d; +}; + +/** + * Widget for Hue/Saturation selection. + * The actual values can be fetched using the inherited xValue and yValue + * methods. + * + * @see OXYSelector, OValueSelector, OColorDialog + * @author Martin Jones (mjones@kde.org) + * @version $Id$ +*/ +class OHSSelector : public OXYSelector +{ + Q_OBJECT + +public: + /** + * Constructs a hue/saturation selection widget. + */ + OHSSelector( QWidget *parent=0, const char *name=0 ); + +protected: + /** + * Draws the contents of the widget on a pixmap, + * which is used for buffering. + */ + virtual void drawPalette( QPixmap *pixmap ); + /** + * @reimplemented + */ + virtual void resizeEvent( QResizeEvent * ); + /** + * Reimplemented from OXYSelector. This drawing is + * buffered in a pixmap here. As real drawing + * routine, drawPalette() is used. + */ + virtual void drawContents( QPainter *painter ); + +private: + void updateContents(); + QPixmap pixmap; + +private: + class OHSSelectorPrivate; + OHSSelectorPrivate *d; +}; + + +class OValueSelectorPrivate; +/** + * Widget for color value selection. + * + * @see OHSSelector, OColorDialog + * @author Martin Jones (mjones@kde.org) + * @version $Id$ + */ +class OValueSelector : public OSelector +{ + Q_OBJECT + +public: + /** + * Constructs a widget for color selection. + */ + OValueSelector( QWidget *parent=0, const char *name=0 ); + /** + * Constructs a widget for color selection with a given orientation + */ + OValueSelector( Orientation o, QWidget *parent = 0, const char *name = 0 ); + + int hue() const + { return _hue; } + void setHue( int h ) + { _hue = h; } + int saturation() const + { return _sat; } + void setSaturation( int s ) + { _sat = s; } + + void updateContents(); +protected: + /** + * Draws the contents of the widget on a pixmap, + * which is used for buffering. + */ + virtual void drawPalette( QPixmap *pixmap ); + /** + * @reimplemented + */ + virtual void resizeEvent( QResizeEvent * ); + /** + * Reimplemented from OSelector. The drawing is + * buffered in a pixmap here. As real drawing + * routine, drawPalette() is used. + */ + virtual void drawContents( QPainter *painter ); + +private: + int _hue; + int _sat; + QPixmap pixmap; + +private: + class OValueSelectorPrivate; + OValueSelectorPrivate *d; +}; + + +class OColor : public QColor +{ +public: + OColor(); + OColor( const OColor &col); + OColor( const QColor &col); + + OColor& operator=( const OColor& col); + + bool operator==( const OColor& col) const; + + void setHsv(int _h, int _s, int _v); + void setRgb(int _r, int _g, int _b); + + void rgb(int *_r, int *_g, int *_b) const; + void hsv(int *_h, int *_s, int *_v) const; +protected: + int h; + int s; + int v; + int r; + int g; + int b; + +private: + class OColorPrivate; + OColorPrivate *d; +}; + + + +#endif // __OSELECT_H__ + diff --git a/libopie2/opieui/oseparator.cpp b/libopie2/opieui/oseparator.cpp new file mode 100644 index 0000000..85181dc --- a/dev/null +++ b/libopie2/opieui/oseparator.cpp @@ -0,0 +1,128 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + Copyright (C) 1997 Michael Roth <mroth@wirlweb.de> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/* QT */ + +#include <qstyle.h> + +/* OPIE */ + +#include <opie2/oseparator.h> + +OSeparator::OSeparator(QWidget* parent, const char* name, WFlags f) + : QFrame(parent, name, f) +{ + setLineWidth(1); + setMidLineWidth(0); + setOrientation( HLine ); +} + + + +OSeparator::OSeparator(int orientation, QWidget* parent, const char* name, WFlags f) + : QFrame(parent, name, f) +{ + setLineWidth(1); + setMidLineWidth(0); + setOrientation( orientation ); +} + + + +void OSeparator::setOrientation(int orientation) +{ + switch(orientation) + { + case Vertical: + case VLine: + setFrameStyle( QFrame::VLine | QFrame::Sunken ); + setMinimumSize(2, 0); + break; + + default: + qWarning( "OSeparator::setOrientation(): invalid orientation, using default orientation HLine" ); + + case Horizontal: + case HLine: + setFrameStyle( QFrame::HLine | QFrame::Sunken ); + setMinimumSize(0, 2); + break; + } +} + + + +int OSeparator::orientation() const +{ + if ( frameStyle() & VLine ) + return VLine; + + if ( frameStyle() & HLine ) + return HLine; + + return 0; +} + +void OSeparator::drawFrame(QPainter *p) +{ + QPoint p1, p2; + QRect r = frameRect(); + const QColorGroup & g = colorGroup(); + + if ( frameStyle() & HLine ) { + p1 = QPoint( r.x(), r.height()/2 ); + p2 = QPoint( r.x()+r.width(), p1.y() ); + } + else { + p1 = QPoint( r.x()+r.width()/2, 0 ); + p2 = QPoint( p1.x(), r.height() ); + } + +#if QT_VERSION < 300 + style().drawSeparator( p, p1.x(), p1.y(), p2.x(), p2.y(), g, true, 1, midLineWidth() ); +#else + QStyleOption opt( lineWidth(), midLineWidth() ); + style().drawPrimitive( QStyle::PE_Separator, p, QRect( p1, p2 ), g, QStyle::Style_Sunken, opt ); +#endif +} + + +QSize OSeparator::sizeHint() const +{ + if ( frameStyle() & VLine ) + return QSize(2, 0); + + if ( frameStyle() & HLine ) + return QSize(0, 2); + + return QSize(-1, -1); +} diff --git a/libopie2/opieui/oseparator.h b/libopie2/opieui/oseparator.h new file mode 100644 index 0000000..e59b3f4 --- a/dev/null +++ b/libopie2/opieui/oseparator.h @@ -0,0 +1,90 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + Copyright (C) 1997 Michael Roth <mroth@wirlweb.de> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OSEPARATOR_H +#define OSEPARATOR_H + +#include <qframe.h> + +/** + * Standard horizontal or vertical separator. + * + * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + * @author Michael Roth <mroth@wirlweb.de> + * @version $Id$ +*/ +class OSeparator : public QFrame +{ + Q_OBJECT + Q_PROPERTY( int orientation READ orientation WRITE setOrientation ) + public: + /** + * Constructor. + **/ + OSeparator(QWidget* parent=0, const char* name=0, WFlags f=0); + /** + * Constructor. + * + * @param orientation Set the orientation of the separator. + * Possible values are HLine or Horizontal and VLine or Vertical. + **/ + OSeparator(int orientation, QWidget* parent=0, const char* name=0, + WFlags f=0); + + /** + * Returns the orientation of the separator. + * + * Possible values are VLine and HLine. + **/ + int orientation() const; + + /** + * Set the orientation of the separator to @p orient + * + * Possible values are VLine and HLine. + */ + void setOrientation(int orient); + + /** + * The recommended height (width) for a horizontal (vertical) separator. + **/ + virtual QSize sizeHint() const; + +protected: + virtual void drawFrame( QPainter * ); + +private: + class OSeparatorPrivate* d; +}; + + +#endif // OSEPARATOR_H diff --git a/libopie2/opieui/oversatileview.cpp b/libopie2/opieui/oversatileview.cpp new file mode 100644 index 0000000..32855be --- a/dev/null +++ b/libopie2/opieui/oversatileview.cpp @@ -0,0 +1,1179 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/* QT */ + +#include <qaction.h> +#include <qbrush.h> +#include <qfont.h> +#include <qiconset.h> +#include <qiconview.h> +#include <qlistview.h> +#include <qpalette.h> +#include <qpoint.h> +#include <qpopupmenu.h> +#include <qrect.h> +#include <qsize.h> +#include <qstring.h> +#include <qwidgetstack.h> + +/* OPIE */ + +#include <opie2/oversatileview.h> +#include <opie2/oversatileviewitem.h> +#include <opie2/olistview.h> + +/* XPM */ +static const char * view_icon_xpm[] = { +"16 16 16 1", +" c None", +". c #87BD88", +"+ c #8BBE8B", +"@ c #81BA81", +"# c #6DAF6D", +"$ c #87BD87", +"% c #FCFDFC", +"& c #AED0AE", +"* c #4E9C4C", +"= c #91BD91", +"- c #72B172", +"; c #448643", +"> c #519F50", +", c #499247", +"' c #356A35", +") c #686868", +" ", +" .+@# .+@# ", +" $%&* $%&* ", +" @=-; @=-; ", +" #>,' #>,' ", +" ", +" )))))) )))))) ", +" ", +" ", +" .+@# .+@# ", +" $%&* $%&* ", +" @=-; @=-; ", +" #>,' #>,' ", +" ", +" )))))) )))))) ", +" "}; + +/* XPM */ +static const char * view_tree_xpm[] = { +"16 16 17 1", +" c None", +". c #3A3A3A", +"+ c #87BD88", +"@ c #8BBE8B", +"# c #81BA81", +"$ c #6DAF6D", +"% c #87BD87", +"& c #FCFDFC", +"* c #AED0AE", +"= c #4E9C4C", +"- c #91BD91", +"; c #72B172", +"> c #448643", +", c #686868", +"' c #519F50", +") c #499247", +"! c #356A35", +" . ", +" . ", +" . +@#$ ", +" . %&*= ", +" .. #-;> ,, ,,,", +" . $')! ", +" . ", +" . ", +" . ", +" . +@#$ ", +" . %&*= ", +" .. #-;> ,, ,,,", +" $')! ", +" ", +" ", +" "}; + +OVersatileView::OVersatileView( QWidget* parent, const char* name, int mode ) + :QWidgetStack( parent, name ), + _viewmode( mode ), _warningpolicy( None ), + _treeleaf(), _treeopened(), _treeclosed(), + _iconleaf(), _iconopened(), _iconclosed() +{ + // + // Create child widgets and set some reasonable default styles + // + + _listview = new OListView( this, "oversatileview embedded listview" ); + _iconview = new QIconView( this, "oversatileview embedded iconview" ); + + _listview->setAllColumnsShowFocus( true ); + _listview->setRootIsDecorated( true ); + _listview->setShowSortIndicator( true ); + _iconview->setGridX( 90 ); + _iconview->setGridY( 42 ); + _iconview->setAutoArrange( true ); + + #ifdef QWS // TODO: Let this depend on current geometry (rotation) + _iconview->setArrangement( QIconView::TopToBottom ); + #else + _iconview->setArrangement( QIconView::LeftToRight ); + #endif + + _iconview->setResizeMode( QIconView::Adjust ); + + // qt-embedded: map stylus right on hold to right button press + + #ifdef QWS + ( (QPEApplication*) qApp)->setStylusOperation( _iconview->viewport(), QPEApplication::RightOnHold ); + ( (QPEApplication*) qApp)->setStylusOperation( _listview->viewport(), QPEApplication::RightOnHold ); + #endif + + setViewMode( mode ); // TODO: Read last style from config + // setSynchronization( true ); // TODO: Implement this + + // create context menu allowing to switch between the views + + _contextmenu = new QPopupMenu( 0, "oversatileview contextmenu" ); + _contextmenu->setCaption( "Style" ); + _contextmenu->setCheckable( true ); + QActionGroup* ag = new QActionGroup( _contextmenu, "style option group" ); + QAction* a1 = new QAction( "View Items in Icon Style", QIconSet( QPixmap( view_icon_xpm ) ), + "View Icons", 0, ag, "viewicon action", true ); + QAction* a2 = new QAction( "View Items in Tree Style", QIconSet( QPixmap( view_tree_xpm ) ), + "View Tree", 0, ag, "viewtree action", true ); + ag->addTo( _contextmenu ); + if ( mode == Icons ) + a1->setOn( true ); + else if ( mode == Tree ) + a2->setOn( true ); + connect( a1, SIGNAL( activated() ), this, SLOT( setIconViewMode() ) ); + connect( a2, SIGNAL( activated() ), this, SLOT( setTreeViewMode() ) ); + + #if (QT_VERSION >= 0x030000) + connect( _listview, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint&, int ) ), this, SLOT( contextMenuRequested( QListViewItem*, const QPoint&, int ) ) ); + connect( _iconview, SIGNAL( contextMenuRequested( QIconViewItem*, const QPoint& ) ), this, SLOT( contextMenuRequested( QIconViewItem*, const QPoint& ) ) ); + #else + connect( _listview, SIGNAL( rightButtonPressed( QListViewItem*, const QPoint&, int ) ), this, SLOT( contextMenuRequested( QListViewItem*, const QPoint&, int ) ) ); + connect( _iconview, SIGNAL( rightButtonPressed( QIconViewItem*, const QPoint& ) ), this, SLOT( contextMenuRequested( QIconViewItem*, const QPoint& ) ) ); + #endif + + // + // signal forwarders + // + // unfortunately we can't short-circuit all the QListView and QIconView signals + // to OVersatileView signals, because the signal/slot mechanism doesn't allow + // type-conversion :-( + + // common signals for listview + + connect( _listview, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) ); + connect( _listview, SIGNAL( selectionChanged( QListViewItem * ) ), this, SLOT( selectionChanged( QListViewItem * ) ) ); + connect( _listview, SIGNAL( currentChanged( QListViewItem * ) ), this, SLOT( currentChanged( QListViewItem * ) ) ); + connect( _listview, SIGNAL( clicked( QListViewItem * ) ), this, SLOT( clicked( QListViewItem * ) ) ); + connect( _listview, SIGNAL( pressed( QListViewItem * ) ), this, SLOT( pressed( QListViewItem * ) ) ); + + connect( _listview, SIGNAL( doubleClicked( QListViewItem * ) ), this, SLOT( doubleClicked( QListViewItem * ) ) ); + connect( _listview, SIGNAL( returnPressed( QListViewItem * ) ), this, SLOT( returnPressed( QListViewItem * ) ) ); + + connect( _listview, SIGNAL( onItem( QListViewItem * ) ), this, SLOT( onItem( QListViewItem * ) ) ); + connect( _listview, SIGNAL( onViewport() ), this, SIGNAL( onViewport() ) ); + + // common signals for iconview + + connect( _iconview, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) ); + connect( _iconview, SIGNAL( selectionChanged( QIconViewItem * ) ), this, SLOT( selectionChanged( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( currentChanged( QIconViewItem * ) ), this, SLOT( currentChanged( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( clicked( QIconViewItem * ) ), this, SLOT( clicked( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( pressed( QIconViewItem * ) ), this, SLOT( pressed( QIconViewItem * ) ) ); + + connect( _iconview, SIGNAL( doubleClicked( QIconViewItem * ) ), this, SLOT( doubleClicked( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( returnPressed( QIconViewItem * ) ), this, SLOT( returnPressed( QIconViewItem * ) ) ); + + connect( _iconview, SIGNAL( onItem( QIconViewItem * ) ), this, SLOT( onItem( QIconViewItem * ) ) ); + connect( _iconview, SIGNAL( onViewport() ), this, SIGNAL( onViewport() ) ); + + // listview only signals + + connect( _listview, SIGNAL( expanded( QListViewItem * ) ), this, SLOT( expanded( QListViewItem * ) ) ); + connect( _listview, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( collapsed( QListViewItem * ) ) ); + + // iconview only signals + + connect( _iconview, SIGNAL( moved() ), this, SIGNAL( moved() ) ); +} + +OVersatileView::~OVersatileView() +{ +} + +QPopupMenu* OVersatileView::contextMenu() const +{ + return _contextmenu; +} + +void OVersatileView::contextMenuRequested( QListViewItem* item, const QPoint& pos, int col ) +{ + // can't use QObject::inherits here, because ListViewItems, beit Q, O or K, + // do not inherit from QObject - assuming here the programmer is + // disciplined enough to only add OVersatileViewItems to an OVersatileView + popupContextMenu( static_cast<OVersatileViewItem*>( item ), pos, col ); +} + +void OVersatileView::contextMenuRequested( QIconViewItem* item, const QPoint& pos ) +{ + // see above + popupContextMenu( static_cast<OVersatileViewItem*>( item ), pos, -1 ); +} + +void OVersatileView::popupContextMenu( OVersatileViewItem* item, const QPoint& pos, int col ) +{ + if ( not item ) + _contextmenu->exec( pos ); + else + emit( contextMenuRequested( item, pos, col ) ); +} + +void OVersatileView::setSynchronization( bool sync ) +{ + _synchronization = sync; +} + +bool OVersatileView::synchronization() +{ + return _synchronization; +} + +void OVersatileView::setDefaultPixmaps( int mode, QPixmap& leaf, QPixmap& opened, QPixmap& closed ) +{ + if ( mode == Tree ) + { + _treeleaf = leaf; + _treeopened = opened; + _treeclosed = closed; + } + else if ( mode == Icons ) + { + _iconleaf = leaf; + _iconopened = opened; + _iconclosed = closed; + } + else + { + qDebug( "OVersatileView::setDefaultPixmaps(): invalid mode" ); + } +} + +QIconView* OVersatileView::iconView() const +{ + return _iconview; +} + +OListView* OVersatileView::listView() const +{ + return _listview; +} + +void OVersatileView::setViewMode( int mode ) +{ + if ( mode == Tree ) + { + _viewmode = mode; + raiseWidget( _listview ); + } + else if ( mode == Icons ) + { + _viewmode = mode; + raiseWidget( _iconview ); + } + else + { + qDebug( "OVersatileView::setViewMode(): invalid mode" ); + } +} + +void OVersatileView::setIconViewMode() +{ + setViewMode( Icons ); +} + +void OVersatileView::setTreeViewMode() +{ + setViewMode( Tree ); +} + +bool OVersatileView::isValidViewMode( int mode ) const +{ + switch ( _warningpolicy ) + { + case OVersatileView::None: + { + return true; + } + case OVersatileView::Warn: + { + if ( _viewmode != mode ) + { + qDebug( "OVersatileView::isValidViewMode(): Requested operation not valid in current mode." ); + return true; + } + } + case OVersatileView::WarnReturn: + { + if ( _viewmode != mode ) + { + qDebug( "OVersatileView::isValidViewMode(): Requested operation not valid in current mode." ); + return false; + } + } + default: + { + qWarning( "OVersatileView::isValidViewMode(): Inconsistent object state!" ); + return true; + } + } +} +void OVersatileView::setWarningPolicy( int policy ) const +{ + _warningpolicy = policy; +} +bool OVersatileView::warningPolicy() const +{ + return _warningpolicy; +} +//==============================================================================================// +// Stupid Signal forwarders... +// Folks, this is why I like python with its dynamic typing: +// I can code the following dozens of lines C++ in four Python lines... +//==============================================================================================// + +void OVersatileView::selectionChanged( QListViewItem * item ) +{ + emit( selectionChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::selectionChanged( QIconViewItem * item ) +{ + emit( selectionChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::currentChanged( QListViewItem * item ) +{ + emit( currentChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::currentChanged( QIconViewItem * item ) +{ + emit( currentChanged( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::clicked( QListViewItem * item ) +{ + emit( clicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::clicked( QIconViewItem * item ) +{ + emit( clicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::pressed( QListViewItem * item ) +{ + emit( pressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::pressed( QIconViewItem * item ) +{ + emit( pressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::doubleClicked( QListViewItem * item ) +{ + emit( doubleClicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::doubleClicked( QIconViewItem * item ) +{ + emit( doubleClicked( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::returnPressed( QListViewItem * item ) +{ + emit( returnPressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::returnPressed( QIconViewItem * item ) +{ + emit( returnPressed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::onItem( QListViewItem * item ) +{ + emit( onItem( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::onItem( QIconViewItem * item ) +{ + emit( onItem( static_cast<OVersatileViewItem*>( item ) ) ); +} + +void OVersatileView::expanded( QListViewItem *item ) // QListView +{ + //qDebug( "OVersatileView::expanded(): opening tree..." ); + if ( not _treeopened.isNull() ) + item->setPixmap( 0, _treeopened ); + emit( expanded( static_cast<OVersatileViewItem*>( item ) ) ); +} +void OVersatileView::collapsed( QListViewItem *item ) // QListView +{ + if ( not _treeclosed.isNull() ) + item->setPixmap( 0, _treeclosed ); + emit( collapsed( static_cast<OVersatileViewItem*>( item ) ) ); +} + +//=============================================================================================// +// OVersatileView Case I - API only existing in QListView or QIconView but not in both! +//==============================================================================================// + +int OVersatileView::treeStepSize() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->treeStepSize(); +} + void OVersatileView::setTreeStepSize( int size ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setTreeStepSize( size ); +} + +QHeader * OVersatileView::header() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return _listview->header(); +} + + int OVersatileView::addColumn( const QString &label, int size ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->addColumn( label, size ); +} + + int OVersatileView::addColumn( const QIconSet& iconset, const QString &label, int size ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->addColumn( iconset, label, size ); +} + +void OVersatileView::removeColumn( int index ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->removeColumn( index ); +} + void OVersatileView::setColumnText( int column, const QString &label ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnText( column, label ); +} + void OVersatileView::setColumnText( int column, const QIconSet& iconset, const QString &label ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnText( column, iconset, label ); +} +QString OVersatileView::columnText( int column ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return QString::null; + } + return _listview->columnText( column ); +} + void OVersatileView::setColumnWidth( int column, int width ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnWidth( column, width ); +} +int OVersatileView::columnWidth( int column ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->columnWidth( column ); +} + void OVersatileView::setColumnWidthMode( int column, WidthMode mode ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnWidth( column, mode ); +} +int OVersatileView::columns() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->columns(); +} + + void OVersatileView::setColumnAlignment( int column, int align ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setColumnAlignment( column, align ); +} +int OVersatileView::columnAlignment( int column ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->columnAlignment( column ); +} + +OVersatileViewItem * OVersatileView::itemAt( const QPoint & screenPos ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _listview->itemAt( screenPos ) ); +} +QRect OVersatileView::itemRect( const OVersatileViewItem * item ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return QRect( -1, -1, -1, -1 ); + } + return _listview->itemRect( item ); +} +int OVersatileView::itemPos( const OVersatileViewItem * item ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->itemPos( item ); +} + +bool OVersatileView::isSelected( const OVersatileViewItem * item ) const // QListView // also in QIconViewItem but !in QIconView *shrug* +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->isSelected( item ); +} + + void OVersatileView::setMultiSelection( bool enable ) +{ + _listview->setMultiSelection( enable ); +} +bool OVersatileView::isMultiSelection() const +{ + return _listview->isMultiSelection(); +} + +OVersatileViewItem * OVersatileView::selectedItem() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _listview->selectedItem() ); +} + void OVersatileView::setOpen( OVersatileViewItem * item, bool open ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setOpen( item, open ); +} +bool OVersatileView::isOpen( const OVersatileViewItem * item ) const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->isOpen( item ); +} + +OVersatileViewItem * OVersatileView::firstChild() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _listview->firstChild() ); +} +int OVersatileView::childCount() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->childCount(); +} + + void OVersatileView::setAllColumnsShowFocus( bool focus ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setAllColumnsShowFocus( focus ); +} +bool OVersatileView::allColumnsShowFocus() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->allColumnsShowFocus(); +} + + void OVersatileView::setItemMargin( int margin ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setItemMargin( margin ); +} +int OVersatileView::itemMargin() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return -1; + } + return _listview->itemMargin(); +} + + void OVersatileView::setRootIsDecorated( bool decorate ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setRootIsDecorated( decorate ); +} +bool OVersatileView::rootIsDecorated() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->rootIsDecorated(); +} + +void OVersatileView::setShowSortIndicator( bool show ) // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->setShowSortIndicator( show ); +} +bool OVersatileView::showSortIndicator() const // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return false; + } + return _listview->showSortIndicator(); +} + +void OVersatileView::triggerUpdate() // QListView +{ + if ( not isValidViewMode( Tree ) ) + { + return; + } + _listview->triggerUpdate(); +} + +// +// only in QIconView +// + +uint OVersatileView::count() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return _iconview->count(); +} + +int OVersatileView::index( const OVersatileViewItem *item ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->index( item ); +} + +OVersatileViewItem* OVersatileView::firstItem() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->firstItem() ); +} +OVersatileViewItem* OVersatileView::lastItem() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->lastItem() ); +} + +OVersatileViewItem* OVersatileView::findItem( const QPoint &pos ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findItem( pos ) ); +} +OVersatileViewItem* OVersatileView::findItem( const QString &text ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findItem( text ) ); +} + +OVersatileViewItem* OVersatileView::findFirstVisibleItem( const QRect &r ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findFirstVisibleItem( r ) ); +} +OVersatileViewItem* OVersatileView::findLastVisibleItem( const QRect &r ) const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return 0; + } + return static_cast<OVersatileViewItem*>( _iconview->findLastVisibleItem( r ) ); +} + + void OVersatileView::setGridX( int rx ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setGridX( rx ); +} + void OVersatileView::setGridY( int ry ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setGridY( ry ); +} +int OVersatileView::gridX() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->gridX(); +} +int OVersatileView::gridY() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->gridY(); +} + void OVersatileView::setSpacing( int sp ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setSpacing( sp ); +} +int OVersatileView::spacing() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->spacing(); +} + void OVersatileView::setItemTextPos( QIconView::ItemTextPos pos ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setItemTextPos( pos ); +} +QIconView::ItemTextPos OVersatileView::itemTextPos() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return (QIconView::ItemTextPos) -1; + } + return _iconview->itemTextPos(); +} + void OVersatileView::setItemTextBackground( const QBrush &b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setItemTextBackground( b ); +} +QBrush OVersatileView::itemTextBackground() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return QBrush(); + } + return _iconview->itemTextBackground(); +} + void OVersatileView::setArrangement( QIconView::Arrangement am ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setArrangement( am ); +} +QIconView::Arrangement OVersatileView::arrangement() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return (QIconView::Arrangement) -1; + } + return _iconview->arrangement(); +} + void OVersatileView::setResizeMode( QIconView::ResizeMode am ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setResizeMode( am ); +} +QIconView::ResizeMode OVersatileView::resizeMode() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return (QIconView::ResizeMode) -1; + } + return _iconview->resizeMode(); +} + void OVersatileView::setMaxItemWidth( int w ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setMaxItemWidth( w ); +} +int OVersatileView::maxItemWidth() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->maxItemWidth(); +} + void OVersatileView::setMaxItemTextLength( int w ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setMaxItemTextLength( w ); +} +int OVersatileView::maxItemTextLength() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return -1; + } + return _iconview->maxItemTextLength(); +} + void OVersatileView::setAutoArrange( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setAutoArrange( b ); +} +bool OVersatileView::autoArrange() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->autoArrange(); +} + void OVersatileView::setShowToolTips( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setShowToolTips( b ); +} +bool OVersatileView::showToolTips() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->showToolTips(); +} + +bool OVersatileView::sorting() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->sorting(); +} +bool OVersatileView::sortDirection() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->sortDirection(); +} + + void OVersatileView::setItemsMovable( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setItemsMovable( b ); +} +bool OVersatileView::itemsMovable() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->itemsMovable(); +} +void OVersatileView::setWordWrapIconText( bool b ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->setWordWrapIconText( b ); +} +bool OVersatileView::wordWrapIconText() const // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return false; + } + return _iconview->wordWrapIconText(); +} + +void OVersatileView::arrangeItemsInGrid( const QSize &grid, bool update ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->arrangeItemsInGrid( grid, update ); +} +void OVersatileView::arrangeItemsInGrid( bool update ) // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->arrangeItemsInGrid( update ); +} +void OVersatileView::updateContents() // QIconView +{ + if ( not isValidViewMode( Icons ) ) + { + return; + } + _iconview->updateContents(); +} + +//==============================================================================================// +// OVersatileView Case II - QListView / QIconView common API +//==============================================================================================// + +void OVersatileView::clear() +{ + _iconview->clear(); + _listview->clear(); +} + +void OVersatileView::setFont( const QFont & font ) +{ + _iconview->setFont( font ); + _listview->setFont( font ); +} +void OVersatileView::setPalette( const QPalette & palette ) +{ + _iconview->setPalette( palette ); + _listview->setPalette( palette ); +} + +void OVersatileView::takeItem( OVersatileViewItem * item ) +{ + _iconview->takeItem( item ); + _listview->takeItem( item ); +} + +void OVersatileView::setSelectionMode( SelectionMode mode ) +{ + _iconview->setSelectionMode( (QIconView::SelectionMode) mode ); + _listview->setSelectionMode( (QListView::SelectionMode) mode ); +} +OVersatileView::SelectionMode OVersatileView::selectionMode() const +{ + return (OVersatileView::SelectionMode) _iconview->selectionMode(); +} + +void OVersatileView::selectAll( bool select ) +{ + _iconview->selectAll( select ); +} +void OVersatileView::clearSelection() +{ + _iconview->clearSelection(); + _listview->clearSelection(); +} +void OVersatileView::invertSelection() +{ + _iconview->invertSelection(); + _listview->invertSelection(); +} + +void OVersatileView::ensureItemVisible( const OVersatileViewItem * item ) +{ + _iconview->ensureItemVisible( const_cast<OVersatileViewItem*>( item ) ); + _listview->ensureItemVisible( item ); +} +void OVersatileView::repaintItem( const OVersatileViewItem * item ) const +{ + _iconview->repaintItem( const_cast<OVersatileViewItem*>( item ) ); + _listview->repaintItem( item ); +} + +void OVersatileView::setCurrentItem( OVersatileViewItem * item ) +{ + _iconview->setCurrentItem( item ); + _listview->setCurrentItem( item ); +} +OVersatileViewItem * OVersatileView::currentItem() const +{ + return static_cast<OVersatileViewItem*>( _listview->currentItem() ); +} + +// bool eventFilter( QObject * o, QEvent * ) // use QWidgetStack implementation + +// QSize minimumSizeHint() const // use QWidgetStack implementation +// QSizePolicy sizePolicy() const // use QWidgetStack implementation +// QSize sizeHint() const // use QWidgetStack implementation + +//==============================================================================================// +// OVersatileView Case III - APIs which differ slightly +//==============================================================================================// + +/* + + void OVersatileView::insertItem( OVersatileViewItem * ) // QListView + void OVersatileView::insertItem( OVersatileViewItem *item, OVersatileViewItem *after = 0L ) // QIconView + + void OVersatileView::setSelected( OVersatileViewItem *, bool ) // QListView + void OVersatileView::setSelected( OVersatileViewItem *item, bool s, bool cb = FALSE ) // QIconView + + void OVersatileView::setSorting( int column, bool increasing = TRUE ) // QListView +void OVersatileView::setSorting( bool sort, bool ascending = TRUE ) // QIconView + +void OVersatileView::sort() // #### make in next major release // QListView + void OVersatileView::sort( bool ascending = TRUE ) // QIconView + +*/ + + diff --git a/libopie2/opieui/oversatileview.h b/libopie2/opieui/oversatileview.h new file mode 100644 index 0000000..1df8154 --- a/dev/null +++ b/libopie2/opieui/oversatileview.h @@ -0,0 +1,394 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OVERSATILEVIEW_H +#define OVERSATILEVIEW_H + +/* QT */ + +#include <qwidgetstack.h> +#include <qiconview.h> + +/* OPIE */ + +#include <qpe/qpeapplication.h> + +/* FORWARDS */ + +class QHeader; +class QIconSet; +class QIconViewItem; +class OListView; +class QListViewItem; +class QPopupMenu; +class QString; + +#ifndef QT_NO_DRAGANDDROP +class QIconDragItem; +#endif + +class OVersatileView : public QWidgetStack +{ + Q_OBJECT + + friend class OVersatileViewItem; + + //==============================================================================================// + // OVersatileView High Level API + //==============================================================================================// + + public: + OVersatileView( QWidget* parent = 0, const char* name = 0, int mode = 0 ); + ~OVersatileView(); + + QPopupMenu* contextMenu() const; + + void setSynchronization( bool sync ); + bool synchronization(); + + enum ViewMode { Tree = 0, Icons }; + int viewMode(); + + QIconView* iconView() const; + OListView* listView() const; + + enum WarningPolicy { None = 0, Warn, WarnReturn }; + + void setWarningPolicy( int ) const; // warn, if calling a method which doesn't apply to the current viewmode + bool warningPolicy() const; + + void setDefaultPixmaps( int mode, QPixmap& leaf, QPixmap& opened, QPixmap& closed ); + + public slots: + void setViewMode( int mode ); + void setIconViewMode(); + void setTreeViewMode(); + + protected: + virtual bool isValidViewMode( int mode ) const; + virtual void popupContextMenu( OVersatileViewItem* item, const QPoint& pos, int col = 0 ); + + private: + int _viewmode; + bool _synchronization; + mutable int _warningpolicy; + + OListView* _listview; + QIconView* _iconview; + + QPixmap _treeleaf; + QPixmap _treeopened; + QPixmap _treeclosed; + + QPixmap _iconleaf; + QPixmap _iconopened; + QPixmap _iconclosed; + + QPopupMenu* _contextmenu; + + int _iconstyle; + int _treestyle; + + private slots: + + void contextMenuRequested( QListViewItem*, const QPoint&, int ); + void contextMenuRequested( QIconViewItem*, const QPoint& ); + + // type converting signal forwarders + + void selectionChanged( QListViewItem * ); + void currentChanged( QListViewItem * ); + void clicked( QListViewItem * ); + void pressed( QListViewItem * ); + void doubleClicked( QListViewItem * ); + void returnPressed( QListViewItem * ); + void onItem( QListViewItem * ); + + void selectionChanged( QIconViewItem * ); + void currentChanged( QIconViewItem * ); + void clicked( QIconViewItem * ); + void pressed( QIconViewItem * ); + void doubleClicked( QIconViewItem * ); + void returnPressed( QIconViewItem * ); + void onItem( QIconViewItem * ); + + void expanded( QListViewItem * item ); // QListView + void collapsed( QListViewItem * item ); // QListView + + signals: + + void contextMenuRequested( OVersatileViewItem * item, const QPoint& pos, int col ); + + /*#ifndef QT_NO_DRAGANDDROP + void dropped( QDropEvent *e, const QValueList<QIconDragItem> &lst ); // QIconView + #endif + void itemRenamed( OVersatileViewItem *item, const QString & ); // QIconView + void itemRenamed( OVersatileViewItem *item ); // QIconView + */ + + //==============================================================================================// + // "Derived" API - Case 1: Methods existing either only in QListView or only in QIconView + //==============================================================================================// + +public: + + /* + enum Arrangement { // QIconView + LeftToRight = 0, + TopToBottom + }; + enum ResizeMode { // QIconView + Fixed = 0, + Adjust + }; + enum ItemTextPos { // QIconView + Bottom = 0, + Right + }; + */ + + // + // only in QListView + // + + int treeStepSize() const; // QListView + virtual void setTreeStepSize( int ); // QListView + + QHeader * header() const; // QListView + + virtual int addColumn( const QString &label, int size = -1); // QListView + virtual int addColumn( const QIconSet& iconset, const QString &label, int size = -1); // QListView + void removeColumn( int index ); // #### make virtual in next major release! // QListView + virtual void setColumnText( int column, const QString &label ); // QListView + virtual void setColumnText( int column, const QIconSet& iconset, const QString &label ); // QListView + QString columnText( int column ) const; // QListView + virtual void setColumnWidth( int column, int width ); // QListView + int columnWidth( int column ) const; // QListView + enum WidthMode { Manual, Maximum }; // QListView + virtual void setColumnWidthMode( int column, WidthMode ); // QListView + WidthMode columnWidthMode( int column ) const; // QListView + int columns() const; // QListView + + virtual void setColumnAlignment( int, int ); // QListView + int columnAlignment( int ) const; // QListView + + OVersatileViewItem * itemAt( const QPoint & screenPos ) const; // QListView + QRect itemRect( const OVersatileViewItem * ) const; // QListView + int itemPos( const OVersatileViewItem * ); // QListView + + bool isSelected( const OVersatileViewItem * ) const; // QListView // also in QIconViewItem but not in QIconView *shrug* + + virtual void setMultiSelection( bool enable ); // QListView + bool isMultiSelection() const; // QListView + + OVersatileViewItem * selectedItem() const; // QListView + virtual void setOpen( OVersatileViewItem *, bool ); // QListView + bool isOpen( const OVersatileViewItem * ) const; // QListView + + OVersatileViewItem * firstChild() const; // QListView + int childCount() const; // QListView + + virtual void setAllColumnsShowFocus( bool ); // QListView + bool allColumnsShowFocus() const; // QListView + + virtual void setItemMargin( int ); // QListView + int itemMargin() const; // QListView + + virtual void setRootIsDecorated( bool ); // QListView + bool rootIsDecorated() const; // QListView + + void setShowSortIndicator( bool show ); // QListView + bool showSortIndicator() const; // QListView + + int index( const OVersatileViewItem *item ) const; // QIconView + + public slots: + void triggerUpdate(); // QListView + + signals: + void expanded( OVersatileViewItem *item ); // QListView + void collapsed( OVersatileViewItem *item ); // QListView + + // + // only in QIconView + // + + public: + uint count() const; // QIconView + + OVersatileViewItem *firstItem() const; // QIconView + OVersatileViewItem *lastItem() const; // QIconView + + OVersatileViewItem *findItem( const QPoint &pos ) const; // QIconView + OVersatileViewItem *findItem( const QString &text ) const; // QIconView + + OVersatileViewItem* findFirstVisibleItem( const QRect &r ) const; // QIconView + OVersatileViewItem* findLastVisibleItem( const QRect &r ) const; // QIconView + + virtual void setGridX( int rx ); // QIconView + virtual void setGridY( int ry ); // QIconView + int gridX() const; // QIconView + int gridY() const; // QIconView + virtual void setSpacing( int sp ); // QIconView + int spacing() const; // QIconView + virtual void setItemTextPos( QIconView::ItemTextPos pos ); // QIconView + QIconView::ItemTextPos itemTextPos() const; // QIconView + virtual void setItemTextBackground( const QBrush &b ); // QIconView + QBrush itemTextBackground() const; // QIconView + virtual void setArrangement( QIconView::Arrangement am ); // QIconView + QIconView::Arrangement arrangement() const; // QIconView + virtual void setResizeMode( QIconView::ResizeMode am ); // QIconView + QIconView::ResizeMode resizeMode() const; // QIconView + virtual void setMaxItemWidth( int w ); // QIconView + int maxItemWidth() const; // QIconView + virtual void setMaxItemTextLength( int w ); // QIconView + int maxItemTextLength() const; // QIconView + virtual void setAutoArrange( bool b ); // QIconView + bool autoArrange() const; // QIconView + virtual void setShowToolTips( bool b ); // QIconView + bool showToolTips() const; // QIconView + + bool sorting() const; // QIconView + bool sortDirection() const; // QIconView + + virtual void setItemsMovable( bool b ); // QIconView + bool itemsMovable() const; // QIconView + virtual void setWordWrapIconText( bool b ); // QIconView + bool wordWrapIconText() const; // QIconView + + public slots: + virtual void arrangeItemsInGrid( const QSize &grid, bool update = TRUE ); // QIconView + virtual void arrangeItemsInGrid( bool update = TRUE ); // QIconView + virtual void updateContents(); // QIconView + + signals: + /*#ifndef QT_NO_DRAGANDDROP + void dropped( QDropEvent *e, const QValueList<QIconDragItem> &lst ); // QIconView + #endif + */ + void moved(); // QIconView + void itemRenamed( OVersatileViewItem *item, const QString & ); // QIconView + void itemRenamed( OVersatileViewItem *item ); // QIconView + + //==============================================================================================// + // "Derived" API - Case 2: Methods existing in QListView and QIconView with the same signatures + //==============================================================================================// + + public: + enum SelectionMode { + Single = 0, + Multi, + Extended, + NoSelection + }; + + virtual void clear(); + + virtual void setFont( const QFont & ); + virtual void setPalette( const QPalette & ); + + virtual void takeItem( OVersatileViewItem * ); + + void setSelectionMode( SelectionMode mode ); + SelectionMode selectionMode() const; + + virtual void selectAll( bool select ); + virtual void clearSelection(); + virtual void invertSelection(); + + void ensureItemVisible( const OVersatileViewItem * ); + virtual void repaintItem( const OVersatileViewItem * ) const; + + virtual void setCurrentItem( OVersatileViewItem * ); + OVersatileViewItem * currentItem() const; + + // bool eventFilter( QObject * o, QEvent * ); // use QWidgetStack implementation + + // QSize minimumSizeHint() const; // use QWidgetStack implementation + // QSizePolicy sizePolicy() const; // use QWidgetStack implementation + // QSize sizeHint() const; // use QWidgetStack implementation + + signals: + void selectionChanged(); + void selectionChanged( OVersatileViewItem * ); + void currentChanged( OVersatileViewItem * ); + void clicked( OVersatileViewItem * ); + void pressed( OVersatileViewItem * ); + + void doubleClicked( OVersatileViewItem * ); + void returnPressed( OVersatileViewItem * ); + + void onItem( OVersatileViewItem * ); + void onViewport(); + + //==============================================================================================// + // "Derived" API - Case 2: Methods existing in QListView and QIconView with differing signatures + //==============================================================================================// + + /* + + public: + virtual void insertItem( OVersatileViewItem * ); // QListView + virtual void insertItem( OVersatileViewItem *item, OVersatileViewItem *after = 0L ); // QIconView + + virtual void setSelected( OVersatileViewItem *, bool ); // QListView + virtual void setSelected( OVersatileViewItem *item, bool s, bool cb = FALSE ); // QIconView + + virtual void setSorting( int column, bool increasing = TRUE ); // QListView + void setSorting( bool sort, bool ascending = TRUE ); // QIconView + + void sort(); // #### make virtual in next major release // QListView + virtual void sort( bool ascending = TRUE ); // QIconView + + */ + + signals: + void clicked( OVersatileViewItem *, const QPoint &, int ); // QListView + void clicked( OVersatileViewItem *, const QPoint & ); // QIconView + + void pressed( OVersatileViewItem *, const QPoint &, int ); // QListView + void pressed( OVersatileViewItem *, const QPoint & ); // QIconView + + void rightButtonClicked( OVersatileViewItem* item, const QPoint& pos ); // QIconView + void rightButtonClicked( OVersatileViewItem *, const QPoint&, int ); // QListView + + void rightButtonPressed( OVersatileViewItem* item, const QPoint& pos ); // QIconView + void rightButtonPressed( OVersatileViewItem *, const QPoint&, int ); // QListView + + void mouseButtonPressed( int, OVersatileViewItem *, const QPoint& , int ); // QListView + void mouseButtonPressed( int button, OVersatileViewItem* item, const QPoint& pos ); // QIconView + + void mouseButtonClicked( int, OVersatileViewItem *, const QPoint&, int ); // QListView + void mouseButtonClicked( int button, OVersatileViewItem* item, const QPoint& pos ); // QIconView + +}; + +#endif + diff --git a/libopie2/opieui/oversatileviewitem.cpp b/libopie2/opieui/oversatileviewitem.cpp new file mode 100644 index 0000000..379ce24 --- a/dev/null +++ b/libopie2/opieui/oversatileviewitem.cpp @@ -0,0 +1,132 @@ +/* + This file is part of the Opie Project + + =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include <opie2/oversatileviewitem.h> +#include <opie2/oversatileview.h> + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent ) + :OListViewItem( parent->_listview ), QIconViewItem( parent->_iconview ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after ) + :OListViewItem( parent->_listview, after ), QIconViewItem( parent->_iconview, after ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent->_listview, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_iconview, a ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, OVersatileViewItem* after, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent->_listview, after, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_iconview, after, a ), + _versatileview( parent ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileViewItem * parent, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_versatileview->_iconview, a ), + _versatileview( parent->_versatileview ) +{ + init(); +} + +OVersatileViewItem::OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem* after, + QString a, QString b, QString c, QString d, + QString e, QString f, QString g, QString h ) + :OListViewItem( parent, after, a, b, c, d, e, f, g, h ), + QIconViewItem( parent->_versatileview->_iconview, after, a ), + _versatileview( parent->_versatileview ) +{ + init(); +} + +OVersatileViewItem::~OVersatileViewItem() +{ +} + +OVersatileView* OVersatileViewItem::versatileView() const +{ + return _versatileview; +} + +void OVersatileViewItem::init() +{ + if ( not firstChild() ) + { + // I'm a sweet yellow and browne autumn leaf + + OListViewItem::setPixmap( 0, _versatileview->_treeleaf ); + QIconViewItem::setPixmap( _versatileview->_iconleaf ); + } + else + { + // I'm a node and I have a little baby child + + if ( isOpen() ) + { + OListViewItem::setPixmap( 0, _versatileview->_treeopened ); + QIconViewItem::setPixmap( _versatileview->_iconopened ); + } + else + { + OListViewItem::setPixmap( 0, _versatileview->_treeclosed ); + QIconViewItem::setPixmap( _versatileview->_iconclosed ); + } + } + +} + +void OVersatileViewItem::setRenameEnabled( bool allow ) +{ + #if (QT_VERSION >= 0x030000) + OListViewItem::setRenameEnabled( 0, allow ); // TODO: Backport to Qt-Embedded 2.x? + #endif + QIconViewItem::setRenameEnabled( allow ); +} + + diff --git a/libopie2/opieui/oversatileviewitem.h b/libopie2/opieui/oversatileviewitem.h new file mode 100644 index 0000000..ee8ee20 --- a/dev/null +++ b/libopie2/opieui/oversatileviewitem.h @@ -0,0 +1,100 @@ +/* + This file is part of the Opie Project + + Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#ifndef OVERSATILEVIEWITEM_H +#define OVERSATILEVIEWITEM_H + +/* QT */ + +#include <qiconview.h> + +/* OPIE */ + +#include <opie2/olistview.h> + +class OVersatileView; + +class OVersatileViewItem : public OListViewItem, public QIconViewItem +{ + public: + OVersatileViewItem( OVersatileView * parent ); + + OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after ); + + OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem * after ); + + OVersatileViewItem( OVersatileView * parent, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + OVersatileViewItem( OVersatileViewItem * parent, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem * after, QString, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null, QString = QString::null, + QString = QString::null ); + + virtual ~OVersatileViewItem(); + + OVersatileView* versatileView() const; + + // TODO: Implement the remaining constructors from QIconView + + /* OIconViewItem( QIconView *parent, const QString &text, const QPixmap &icon ); + OIconViewItem( QIconView *parent, QIconViewItem *after, const QString &text, const QPixmap &icon ); + */ + + virtual void setRenameEnabled( bool ); + + // TODO: Implement the remaining method multiplexers + + private: + OVersatileView* _versatileview; + + private: + void init(); + +}; + +#endif |