summaryrefslogtreecommitdiff
path: root/libopie2/opieui
Side-by-side diff
Diffstat (limited to 'libopie2/opieui') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opieui/.cvsignore6
-rw-r--r--libopie2/opieui/config.in7
-rw-r--r--libopie2/opieui/odialog.cpp53
-rw-r--r--libopie2/opieui/odialog.h89
-rw-r--r--libopie2/opieui/oimageeffect.cpp3794
-rw-r--r--libopie2/opieui/oimageeffect.h558
-rw-r--r--libopie2/opieui/olistview.cpp423
-rw-r--r--libopie2/opieui/olistview.h235
-rw-r--r--libopie2/opieui/opieui.pro46
-rw-r--r--libopie2/opieui/opixmapeffect.cpp328
-rw-r--r--libopie2/opieui/opixmapeffect.h215
-rw-r--r--libopie2/opieui/opixmapprovider.cpp27
-rw-r--r--libopie2/opieui/opixmapprovider.h54
-rw-r--r--libopie2/opieui/opopupmenu.cpp604
-rw-r--r--libopie2/opieui/opopupmenu.h256
-rw-r--r--libopie2/opieui/oselector.cpp716
-rw-r--r--libopie2/opieui/oselector.h518
-rw-r--r--libopie2/opieui/oseparator.cpp128
-rw-r--r--libopie2/opieui/oseparator.h90
-rw-r--r--libopie2/opieui/oversatileview.cpp1179
-rw-r--r--libopie2/opieui/oversatileview.h394
-rw-r--r--libopie2/opieui/oversatileviewitem.cpp132
-rw-r--r--libopie2/opieui/oversatileviewitem.h100
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