summaryrefslogtreecommitdiff
path: root/libopie2/opieui
Unidiff
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 @@
1Makefile*
2moc*
3*moc
4*.o
5~*
6
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 @@
1 config LIBOPIE2UI
2 boolean "libopie2ui (user interface related classes)"
3 default "n"
4 depends ( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE
5 comment "libopie2ui needs a libqpe and libopie2core"
6 depends !(( LIBQPE || LIBQPE-X11 ) && LIBOPIE2CORE)
7
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 @@
1/*
2                 This file is part of the Opie Project
3
4              Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 =.
6 .=l.
7           .>+-=
8 _;:,     .>    :=|. This program is free software; you can
9.> <`_,   >  .   <= redistribute it and/or modify it under
10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
11.="- .-=="i,     .._ License as published by the Free Software
12 - .   .-<_>     .<> Foundation; either version 2 of the License,
13     ._= =}       : or (at your option) any later version.
14    .%`+i>       _;_.
15    .i_,=:_.      -<s. This program is distributed in the hope that
16     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
17    : ..    .:,     . . . without even the implied warranty of
18    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
19  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
20..}^=.=       =       ; Library General Public License for more
21++=   -.     .`     .: details.
22 :     =  ...= . :.=-
23 -.   .:....=;==+<; You should have received a copy of the GNU
24  -_. . .   )=.  = Library General Public License along with
25    --        :-=` this library; see the file COPYING.LIB.
26 If not, write to the Free Software Foundation,
27 Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA.
29
30*/
31
32#include <opie2/odialog.h>
33
34int ODialog::mMarginSize = 5; // 11 like in KDialog is probably too much for PDA
35int ODialog::mSpacingSize = 2; // 6 like in KDialog is probably too much for PDA
36
37ODialog::ODialog(QWidget *parent, const char *name, bool modal, WFlags f)
38 : QDialog(parent, name, modal, f)
39{
40}
41
42int ODialog::marginHint()
43{
44 return( mMarginSize );
45}
46
47
48int ODialog::spacingHint()
49{
50 return( mSpacingSize );
51}
52
53// 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 @@
1/*
2                 This file is part of the Opie Project
3
4              (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 =.
6 .=l.
7           .>+-=
8 _;:,     .>    :=|. This program is free software; you can
9.> <`_,   >  .   <= redistribute it and/or modify it under
10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
11.="- .-=="i,     .._ License as published by the Free Software
12 - .   .-<_>     .<> Foundation; either version 2 of the License,
13     ._= =}       : or (at your option) any later version.
14    .%`+i>       _;_.
15    .i_,=:_.      -<s. This program is distributed in the hope that
16     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
17    : ..    .:,     . . . without even the implied warranty of
18    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
19  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
20..}^=.=       =       ; Library General Public License for more
21++=   -.     .`     .: details.
22 :     =  ...= . :.=-
23 -.   .:....=;==+<; You should have received a copy of the GNU
24  -_. . .   )=.  = Library General Public License along with
25    --        :-=` this library; see the file COPYING.LIB.
26 If not, write to the Free Software Foundation,
27 Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA.
29
30*/
31
32#ifndef ODIALOG_H
33#define ODIALOG_H
34
35class QLayoutItem;
36
37#include <qdialog.h>
38
39/**
40 * Dialog with extended nonmodal support and methods for OPIE standard
41 * compliance.
42 *
43 * The @ref marginHint() and @ref spacingHint() sizes shall be used
44 * whenever you layout the interior of a dialog. One special note. If
45 * you make your own action buttons (OK, Cancel etc), the space
46 * beteween the buttons shall be @ref spacingHint(), whereas the space
47 * above, below, to the right and to the left shall be @ref marginHint().
48 * If you add a separator line above the buttons, there shall be a
49 * @ref marginHint() between the buttons and the separator and a
50 * @ref marginHint() above the separator as well.
51 *
52 * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
53 */
54
55class ODialog : public QDialog
56{
57 Q_OBJECT
58
59 public:
60
61 /**
62 * Constructor.
63 *
64 * Takes the same arguments as @ref QDialog.
65 */
66 ODialog(QWidget *parent = 0, const char *name = 0,
67 bool modal = false, WFlags f = 0);
68
69 /**
70 * Return the number of pixels you shall use between a
71 * dialog edge and the outermost widget(s) according to the KDE standard.
72 **/
73 static int marginHint();
74
75 /**
76 * Return the number of pixels you shall use between
77 * widgets inside a dialog according to the KDE standard.
78 */
79 static int spacingHint();
80
81 private:
82 static int mMarginSize;
83 static int mSpacingSize;
84
85 //class ODialogPrivate;
86 //ODialogPrivate *d;
87
88};
89#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 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org>
3 (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
4 (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
5 (C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions
9are met:
10
111. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
132. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16
17THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28*/
29
30// $Id$
31
32#include <math.h>
33
34#include <qimage.h>
35#include <stdlib.h>
36#include <iostream>
37
38#include "oimageeffect.h"
39
40#define MaxRGB 255L
41#define DegreesToRadians(x) ((x)*M_PI/180.0)
42
43using namespace std;
44
45inline unsigned int intensityValue(unsigned int color)
46{
47 return((unsigned int)((0.299*qRed(color) +
48 0.587*qGreen(color) +
49 0.1140000000000001*qBlue(color))));
50}
51
52//======================================================================
53//
54// Gradient effects
55//
56//======================================================================
57
58QImage OImageEffect::gradient(const QSize &size, const QColor &ca,
59 const QColor &cb, GradientType eff, int ncols)
60{
61 int rDiff, gDiff, bDiff;
62 int rca, gca, bca, rcb, gcb, bcb;
63
64 QImage image(size, 32);
65
66 if (size.width() == 0 || size.height() == 0) {
67#ifndef NDEBUG
68 cerr << "WARNING: OImageEffect::gradient: invalid image" << endl;
69#endif
70 return image;
71 }
72
73 register int x, y;
74
75 rDiff = (rcb = cb.red()) - (rca = ca.red());
76 gDiff = (gcb = cb.green()) - (gca = ca.green());
77 bDiff = (bcb = cb.blue()) - (bca = ca.blue());
78
79 if( eff == VerticalGradient || eff == HorizontalGradient ){
80
81 uint *p;
82 uint rgb;
83
84 register int rl = rca << 16;
85 register int gl = gca << 16;
86 register int bl = bca << 16;
87
88 if( eff == VerticalGradient ) {
89
90 int rcdelta = ((1<<16) / size.height()) * rDiff;
91 int gcdelta = ((1<<16) / size.height()) * gDiff;
92 int bcdelta = ((1<<16) / size.height()) * bDiff;
93
94 for ( y = 0; y < size.height(); y++ ) {
95 p = (uint *) image.scanLine(y);
96
97 rl += rcdelta;
98 gl += gcdelta;
99 bl += bcdelta;
100
101 rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) );
102
103 for( x = 0; x < size.width(); x++ ) {
104 *p = rgb;
105 p++;
106 }
107 }
108
109 }
110 else { // must be HorizontalGradient
111
112 unsigned int *o_src = (unsigned int *)image.scanLine(0);
113 unsigned int *src = o_src;
114
115 int rcdelta = ((1<<16) / size.width()) * rDiff;
116 int gcdelta = ((1<<16) / size.width()) * gDiff;
117 int bcdelta = ((1<<16) / size.width()) * bDiff;
118
119 for( x = 0; x < size.width(); x++) {
120
121 rl += rcdelta;
122 gl += gcdelta;
123 bl += bcdelta;
124
125 *src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
126 }
127
128 src = o_src;
129
130 // Believe it or not, manually copying in a for loop is faster
131 // than calling memcpy for each scanline (on the order of ms...).
132 // I think this is due to the function call overhead (mosfet).
133
134 for (y = 1; y < size.height(); ++y) {
135
136 p = (unsigned int *)image.scanLine(y);
137 src = o_src;
138 for(x=0; x < size.width(); ++x)
139 *p++ = *src++;
140 }
141 }
142 }
143
144 else {
145
146 float rfd, gfd, bfd;
147 float rd = rca, gd = gca, bd = bca;
148
149 unsigned char *xtable[3];
150 unsigned char *ytable[3];
151
152 unsigned int w = size.width(), h = size.height();
153 xtable[0] = new unsigned char[w];
154 xtable[1] = new unsigned char[w];
155 xtable[2] = new unsigned char[w];
156 ytable[0] = new unsigned char[h];
157 ytable[1] = new unsigned char[h];
158 ytable[2] = new unsigned char[h];
159 w*=2, h*=2;
160
161 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
162 // Diagonal dgradient code inspired by BlackBox (mosfet)
163 // BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
164 // Mike Cole <mike@mydot.com>.
165
166 rfd = (float)rDiff/w;
167 gfd = (float)gDiff/w;
168 bfd = (float)bDiff/w;
169
170 int dir;
171 for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
172 dir = eff == DiagonalGradient? x : size.width() - x - 1;
173 xtable[0][dir] = (unsigned char) rd;
174 xtable[1][dir] = (unsigned char) gd;
175 xtable[2][dir] = (unsigned char) bd;
176 }
177 rfd = (float)rDiff/h;
178 gfd = (float)gDiff/h;
179 bfd = (float)bDiff/h;
180 rd = gd = bd = 0;
181 for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
182 ytable[0][y] = (unsigned char) rd;
183 ytable[1][y] = (unsigned char) gd;
184 ytable[2][y] = (unsigned char) bd;
185 }
186
187 for (y = 0; y < size.height(); y++) {
188 unsigned int *scanline = (unsigned int *)image.scanLine(y);
189 for (x = 0; x < size.width(); x++) {
190 scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
191 xtable[1][x] + ytable[1][y],
192 xtable[2][x] + ytable[2][y]);
193 }
194 }
195 }
196
197 else if (eff == RectangleGradient ||
198 eff == PyramidGradient ||
199 eff == PipeCrossGradient ||
200 eff == EllipticGradient)
201 {
202 int rSign = rDiff>0? 1: -1;
203 int gSign = gDiff>0? 1: -1;
204 int bSign = bDiff>0? 1: -1;
205
206 rfd = (float)rDiff / size.width();
207 gfd = (float)gDiff / size.width();
208 bfd = (float)bDiff / size.width();
209
210 rd = (float)rDiff/2;
211 gd = (float)gDiff/2;
212 bd = (float)bDiff/2;
213
214 for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
215 {
216 xtable[0][x] = (unsigned char) abs((int)rd);
217 xtable[1][x] = (unsigned char) abs((int)gd);
218 xtable[2][x] = (unsigned char) abs((int)bd);
219 }
220
221 rfd = (float)rDiff/size.height();
222 gfd = (float)gDiff/size.height();
223 bfd = (float)bDiff/size.height();
224
225 rd = (float)rDiff/2;
226 gd = (float)gDiff/2;
227 bd = (float)bDiff/2;
228
229 for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
230 {
231 ytable[0][y] = (unsigned char) abs((int)rd);
232 ytable[1][y] = (unsigned char) abs((int)gd);
233 ytable[2][y] = (unsigned char) abs((int)bd);
234 }
235 unsigned int rgb;
236 int h = (size.height()+1)>>1;
237 for (y = 0; y < h; y++) {
238 unsigned int *sl1 = (unsigned int *)image.scanLine(y);
239 unsigned int *sl2 = (unsigned int *)image.scanLine(QMAX(size.height()-y-1, y));
240
241 int w = (size.width()+1)>>1;
242 int x2 = size.width()-1;
243
244 for (x = 0; x < w; x++, x2--) {
245 rgb = 0;
246 if (eff == PyramidGradient) {
247 rgb = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
248 gcb-gSign*(xtable[1][x]+ytable[1][y]),
249 bcb-bSign*(xtable[2][x]+ytable[2][y]));
250 }
251 if (eff == RectangleGradient) {
252 rgb = qRgb(rcb - rSign *
253 QMAX(xtable[0][x], ytable[0][y]) * 2,
254 gcb - gSign *
255 QMAX(xtable[1][x], ytable[1][y]) * 2,
256 bcb - bSign *
257 QMAX(xtable[2][x], ytable[2][y]) * 2);
258 }
259 if (eff == PipeCrossGradient) {
260 rgb = qRgb(rcb - rSign *
261 QMIN(xtable[0][x], ytable[0][y]) * 2,
262 gcb - gSign *
263 QMIN(xtable[1][x], ytable[1][y]) * 2,
264 bcb - bSign *
265 QMIN(xtable[2][x], ytable[2][y]) * 2);
266 }
267 if (eff == EllipticGradient) {
268 rgb = qRgb(rcb - rSign *
269 (int)sqrt((xtable[0][x]*xtable[0][x] +
270 ytable[0][y]*ytable[0][y])*2.0),
271 gcb - gSign *
272 (int)sqrt((xtable[1][x]*xtable[1][x] +
273 ytable[1][y]*ytable[1][y])*2.0),
274 bcb - bSign *
275 (int)sqrt((xtable[2][x]*xtable[2][x] +
276 ytable[2][y]*ytable[2][y])*2.0));
277 }
278
279 sl1[x] = sl2[x] = rgb;
280 sl1[x2] = sl2[x2] = rgb;
281 }
282 }
283 }
284
285 delete [] xtable[0];
286 delete [] xtable[1];
287 delete [] xtable[2];
288 delete [] ytable[0];
289 delete [] ytable[1];
290 delete [] ytable[2];
291 }
292
293 // dither if necessary
294 if (ncols && (QPixmap::defaultDepth() < 15 )) {
295 if ( ncols < 2 || ncols > 256 )
296 ncols = 3;
297 QColor *dPal = new QColor[ncols];
298 for (int i=0; i<ncols; i++) {
299 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
300 gca + gDiff * i / ( ncols - 1 ),
301 bca + bDiff * i / ( ncols - 1 ) );
302 }
303 dither(image, dPal, ncols);
304 delete [] dPal;
305 }
306
307 return image;
308}
309
310
311// -----------------------------------------------------------------------------
312
313//CT this was (before Dirk A. Mueller's speedup changes)
314// merely the same code as in the above method, but it's supposedly
315// way less performant since it introduces a lot of supplementary tests
316// and simple math operations for the calculus of the balance.
317// (surprizingly, it isn't less performant, in the contrary :-)
318// Yes, I could have merged them, but then the excellent performance of
319// the balanced code would suffer with no other gain than a mere
320// source code and byte code size economy.
321
322QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca,
323 const QColor &cb, GradientType eff, int xfactor, int yfactor,
324 int ncols)
325{
326 int dir; // general parameter used for direction switches
327
328 bool _xanti = false , _yanti = false;
329
330 if (xfactor < 0) _xanti = true; // negative on X direction
331 if (yfactor < 0) _yanti = true; // negative on Y direction
332
333 xfactor = abs(xfactor);
334 yfactor = abs(yfactor);
335
336 if (!xfactor) xfactor = 1;
337 if (!yfactor) yfactor = 1;
338
339 if (xfactor > 200 ) xfactor = 200;
340 if (yfactor > 200 ) yfactor = 200;
341
342
343 // float xbal = xfactor/5000.;
344 // float ybal = yfactor/5000.;
345 float xbal = xfactor/30./size.width();
346 float ybal = yfactor/30./size.height();
347 float rat;
348
349 int rDiff, gDiff, bDiff;
350 int rca, gca, bca, rcb, gcb, bcb;
351
352 QImage image(size, 32);
353
354 if (size.width() == 0 || size.height() == 0) {
355#ifndef NDEBUG
356 cerr << "WARNING: OImageEffect::unbalancedGradient : invalid image\n";
357#endif
358 return image;
359 }
360
361 register int x, y;
362 unsigned int *scanline;
363
364 rDiff = (rcb = cb.red()) - (rca = ca.red());
365 gDiff = (gcb = cb.green()) - (gca = ca.green());
366 bDiff = (bcb = cb.blue()) - (bca = ca.blue());
367
368 if( eff == VerticalGradient || eff == HorizontalGradient){
369 QColor cRow;
370
371 uint *p;
372 uint rgbRow;
373
374 if( eff == VerticalGradient) {
375 for ( y = 0; y < size.height(); y++ ) {
376 dir = _yanti ? y : size.height() - 1 - y;
377 p = (uint *) image.scanLine(dir);
378 rat = 1 - exp( - (float)y * ybal );
379
380 cRow.setRgb( rcb - (int) ( rDiff * rat ),
381 gcb - (int) ( gDiff * rat ),
382 bcb - (int) ( bDiff * rat ) );
383
384 rgbRow = cRow.rgb();
385
386 for( x = 0; x < size.width(); x++ ) {
387 *p = rgbRow;
388 p++;
389 }
390 }
391 }
392 else {
393
394 unsigned int *src = (unsigned int *)image.scanLine(0);
395 for(x = 0; x < size.width(); x++ )
396 {
397 dir = _xanti ? x : size.width() - 1 - x;
398 rat = 1 - exp( - (float)x * xbal );
399
400 src[dir] = qRgb(rcb - (int) ( rDiff * rat ),
401 gcb - (int) ( gDiff * rat ),
402 bcb - (int) ( bDiff * rat ));
403 }
404
405 // Believe it or not, manually copying in a for loop is faster
406 // than calling memcpy for each scanline (on the order of ms...).
407 // I think this is due to the function call overhead (mosfet).
408
409 for(y = 1; y < size.height(); ++y)
410 {
411 scanline = (unsigned int *)image.scanLine(y);
412 for(x=0; x < size.width(); ++x)
413 scanline[x] = src[x];
414 }
415 }
416 }
417
418 else {
419 int w=size.width(), h=size.height();
420
421 unsigned char *xtable[3];
422 unsigned char *ytable[3];
423 xtable[0] = new unsigned char[w];
424 xtable[1] = new unsigned char[w];
425 xtable[2] = new unsigned char[w];
426 ytable[0] = new unsigned char[h];
427 ytable[1] = new unsigned char[h];
428 ytable[2] = new unsigned char[h];
429
430 if ( eff == DiagonalGradient || eff == CrossDiagonalGradient)
431 {
432 for (x = 0; x < w; x++) {
433 dir = _xanti ? x : w - 1 - x;
434 rat = 1 - exp( - (float)x * xbal );
435
436 xtable[0][dir] = (unsigned char) ( rDiff/2 * rat );
437 xtable[1][dir] = (unsigned char) ( gDiff/2 * rat );
438 xtable[2][dir] = (unsigned char) ( bDiff/2 * rat );
439 }
440
441 for (y = 0; y < h; y++) {
442 dir = _yanti ? y : h - 1 - y;
443 rat = 1 - exp( - (float)y * ybal );
444
445 ytable[0][dir] = (unsigned char) ( rDiff/2 * rat );
446 ytable[1][dir] = (unsigned char) ( gDiff/2 * rat );
447 ytable[2][dir] = (unsigned char) ( bDiff/2 * rat );
448 }
449
450 for (y = 0; y < h; y++) {
451 unsigned int *scanline = (unsigned int *)image.scanLine(y);
452 for (x = 0; x < w; x++) {
453 scanline[x] = qRgb(rcb - (xtable[0][x] + ytable[0][y]),
454 gcb - (xtable[1][x] + ytable[1][y]),
455 bcb - (xtable[2][x] + ytable[2][y]));
456 }
457 }
458 }
459
460 else if (eff == RectangleGradient ||
461 eff == PyramidGradient ||
462 eff == PipeCrossGradient ||
463 eff == EllipticGradient)
464 {
465 int rSign = rDiff>0? 1: -1;
466 int gSign = gDiff>0? 1: -1;
467 int bSign = bDiff>0? 1: -1;
468
469 for (x = 0; x < w; x++)
470 {
471 dir = _xanti ? x : w - 1 - x;
472 rat = 1 - exp( - (float)x * xbal );
473
474 xtable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
475 xtable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
476 xtable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
477 }
478
479 for (y = 0; y < h; y++)
480 {
481 dir = _yanti ? y : h - 1 - y;
482
483 rat = 1 - exp( - (float)y * ybal );
484
485 ytable[0][dir] = (unsigned char) abs((int)(rDiff*(0.5-rat)));
486 ytable[1][dir] = (unsigned char) abs((int)(gDiff*(0.5-rat)));
487 ytable[2][dir] = (unsigned char) abs((int)(bDiff*(0.5-rat)));
488 }
489
490 for (y = 0; y < h; y++) {
491 unsigned int *scanline = (unsigned int *)image.scanLine(y);
492 for (x = 0; x < w; x++) {
493 if (eff == PyramidGradient)
494 {
495 scanline[x] = qRgb(rcb-rSign*(xtable[0][x]+ytable[0][y]),
496 gcb-gSign*(xtable[1][x]+ytable[1][y]),
497 bcb-bSign*(xtable[2][x]+ytable[2][y]));
498 }
499 if (eff == RectangleGradient)
500 {
501 scanline[x] = qRgb(rcb - rSign *
502 QMAX(xtable[0][x], ytable[0][y]) * 2,
503 gcb - gSign *
504 QMAX(xtable[1][x], ytable[1][y]) * 2,
505 bcb - bSign *
506 QMAX(xtable[2][x], ytable[2][y]) * 2);
507 }
508 if (eff == PipeCrossGradient)
509 {
510 scanline[x] = qRgb(rcb - rSign *
511 QMIN(xtable[0][x], ytable[0][y]) * 2,
512 gcb - gSign *
513 QMIN(xtable[1][x], ytable[1][y]) * 2,
514 bcb - bSign *
515 QMIN(xtable[2][x], ytable[2][y]) * 2);
516 }
517 if (eff == EllipticGradient)
518 {
519 scanline[x] = qRgb(rcb - rSign *
520 (int)sqrt((xtable[0][x]*xtable[0][x] +
521 ytable[0][y]*ytable[0][y])*2.0),
522 gcb - gSign *
523 (int)sqrt((xtable[1][x]*xtable[1][x] +
524 ytable[1][y]*ytable[1][y])*2.0),
525 bcb - bSign *
526 (int)sqrt((xtable[2][x]*xtable[2][x] +
527 ytable[2][y]*ytable[2][y])*2.0));
528 }
529 }
530 }
531 }
532
533 if (ncols && (QPixmap::defaultDepth() < 15 )) {
534 if ( ncols < 2 || ncols > 256 )
535 ncols = 3;
536 QColor *dPal = new QColor[ncols];
537 for (int i=0; i<ncols; i++) {
538 dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ),
539 gca + gDiff * i / ( ncols - 1 ),
540 bca + bDiff * i / ( ncols - 1 ) );
541 }
542 dither(image, dPal, ncols);
543 delete [] dPal;
544 }
545
546 delete [] xtable[0];
547 delete [] xtable[1];
548 delete [] xtable[2];
549 delete [] ytable[0];
550 delete [] ytable[1];
551 delete [] ytable[2];
552
553 }
554
555 return image;
556}
557
558
559//======================================================================
560//
561// Intensity effects
562//
563//======================================================================
564
565
566/* This builds a 256 byte unsigned char lookup table with all
567 * the possible percent values prior to applying the effect, then uses
568 * integer math for the pixels. For any image larger than 9x9 this will be
569 * less expensive than doing a float operation on the 3 color components of
570 * each pixel. (mosfet)
571 */
572
573QImage& OImageEffect::intensity(QImage &image, float percent)
574{
575 if (image.width() == 0 || image.height() == 0) {
576#ifndef NDEBUG
577 cerr << "WARNING: OImageEffect::intensity : invalid image\n";
578#endif
579 return image;
580 }
581
582 int segColors = image.depth() > 8 ? 256 : image.numColors();
583 unsigned char *segTbl = new unsigned char[segColors];
584 int pixels = image.depth() > 8 ? image.width()*image.height() :
585 image.numColors();
586 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
587 (unsigned int *)image.colorTable();
588
589 bool brighten = (percent >= 0);
590 if(percent < 0)
591 percent = -percent;
592
593 if(brighten){ // keep overflow check out of loops
594 for(int i=0; i < segColors; ++i){
595 int tmp = (int)(i*percent);
596 if(tmp > 255)
597 tmp = 255;
598 segTbl[i] = tmp;
599 }
600 }
601 else{
602 for(int i=0; i < segColors; ++i){
603 int tmp = (int)(i*percent);
604 if(tmp < 0)
605 tmp = 0;
606 segTbl[i] = tmp;
607 }
608 }
609
610 if(brighten){ // same here
611 for(int i=0; i < pixels; ++i){
612 int r = qRed(data[i]);
613 int g = qGreen(data[i]);
614 int b = qBlue(data[i]);
615 int a = qAlpha(data[i]);
616 r = r + segTbl[r] > 255 ? 255 : r + segTbl[r];
617 g = g + segTbl[g] > 255 ? 255 : g + segTbl[g];
618 b = b + segTbl[b] > 255 ? 255 : b + segTbl[b];
619 data[i] = qRgba(r, g, b,a);
620 }
621 }
622 else{
623 for(int i=0; i < pixels; ++i){
624 int r = qRed(data[i]);
625 int g = qGreen(data[i]);
626 int b = qBlue(data[i]);
627 int a = qAlpha(data[i]);
628 r = r - segTbl[r] < 0 ? 0 : r - segTbl[r];
629 g = g - segTbl[g] < 0 ? 0 : g - segTbl[g];
630 b = b - segTbl[b] < 0 ? 0 : b - segTbl[b];
631 data[i] = qRgba(r, g, b, a);
632 }
633 }
634 delete [] segTbl;
635
636 return image;
637}
638
639QImage& OImageEffect::channelIntensity(QImage &image, float percent,
640 RGBComponent channel)
641{
642 if (image.width() == 0 || image.height() == 0) {
643#ifndef NDEBUG
644 cerr << "WARNING: OImageEffect::channelIntensity : invalid image\n";
645#endif
646 return image;
647 }
648
649 int segColors = image.depth() > 8 ? 256 : image.numColors();
650 unsigned char *segTbl = new unsigned char[segColors];
651 int pixels = image.depth() > 8 ? image.width()*image.height() :
652 image.numColors();
653 unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() :
654 (unsigned int *)image.colorTable();
655 bool brighten = (percent >= 0);
656 if(percent < 0)
657 percent = -percent;
658
659 if(brighten){ // keep overflow check out of loops
660 for(int i=0; i < segColors; ++i){
661 int tmp = (int)(i*percent);
662 if(tmp > 255)
663 tmp = 255;
664 segTbl[i] = tmp;
665 }
666 }
667 else{
668 for(int i=0; i < segColors; ++i){
669 int tmp = (int)(i*percent);
670 if(tmp < 0)
671 tmp = 0;
672 segTbl[i] = tmp;
673 }
674 }
675
676 if(brighten){ // same here
677 if(channel == Red){ // and here ;-)
678 for(int i=0; i < pixels; ++i){
679 int c = qRed(data[i]);
680 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
681 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
682 }
683 }
684 if(channel == Green){
685 for(int i=0; i < pixels; ++i){
686 int c = qGreen(data[i]);
687 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
688 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
689 }
690 }
691 else{
692 for(int i=0; i < pixels; ++i){
693 int c = qBlue(data[i]);
694 c = c + segTbl[c] > 255 ? 255 : c + segTbl[c];
695 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
696 }
697 }
698
699 }
700 else{
701 if(channel == Red){
702 for(int i=0; i < pixels; ++i){
703 int c = qRed(data[i]);
704 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
705 data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i]));
706 }
707 }
708 if(channel == Green){
709 for(int i=0; i < pixels; ++i){
710 int c = qGreen(data[i]);
711 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
712 data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i]));
713 }
714 }
715 else{
716 for(int i=0; i < pixels; ++i){
717 int c = qBlue(data[i]);
718 c = c - segTbl[c] < 0 ? 0 : c - segTbl[c];
719 data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i]));
720 }
721 }
722 }
723 delete [] segTbl;
724
725 return image;
726}
727
728// Modulate an image with an RBG channel of another image
729//
730QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse,
731 ModulationType type, int factor, RGBComponent channel)
732{
733 if (image.width() == 0 || image.height() == 0 ||
734 modImage.width() == 0 || modImage.height() == 0) {
735#ifndef NDEBUG
736 cerr << "WARNING: OImageEffect::modulate : invalid image\n";
737#endif
738 return image;
739 }
740
741 int r, g, b, h, s, v, a;
742 QColor clr;
743 int mod=0;
744 unsigned int x1, x2, y1, y2;
745 register int x, y;
746
747 // for image, we handle only depth 32
748 if (image.depth()<32) image = image.convertDepth(32);
749
750 // for modImage, we handle depth 8 and 32
751 if (modImage.depth()<8) modImage = modImage.convertDepth(8);
752
753 unsigned int *colorTable2 = (modImage.depth()==8) ?
754 modImage.colorTable():0;
755 unsigned int *data1, *data2;
756 unsigned char *data2b;
757 unsigned int color1, color2;
758
759 x1 = image.width(); y1 = image.height();
760 x2 = modImage.width(); y2 = modImage.height();
761
762 for (y = 0; y < (int)y1; y++) {
763 data1 = (unsigned int *) image.scanLine(y);
764 data2 = (unsigned int *) modImage.scanLine( y%y2 );
765 data2b = (unsigned char *) modImage.scanLine( y%y2 );
766
767 x=0;
768 while(x < (int)x1) {
769 color2 = (colorTable2) ? colorTable2[*data2b] : *data2;
770 if (reverse) {
771 color1 = color2;
772 color2 = *data1;
773 }
774 else
775 color1 = *data1;
776
777 if (type == Intensity || type == Contrast) {
778 r = qRed(color1);
779 g = qGreen(color1);
780 b = qBlue(color1);
781 if (channel != All) {
782 mod = (channel == Red) ? qRed(color2) :
783 (channel == Green) ? qGreen(color2) :
784 (channel == Blue) ? qBlue(color2) :
785 (channel == Gray) ? qGray(color2) : 0;
786 mod = mod*factor/50;
787 }
788
789 if (type == Intensity) {
790 if (channel == All) {
791 r += r * factor/50 * qRed(color2)/256;
792 g += g * factor/50 * qGreen(color2)/256;
793 b += b * factor/50 * qBlue(color2)/256;
794 }
795 else {
796 r += r * mod/256;
797 g += g * mod/256;
798 b += b * mod/256;
799 }
800 }
801 else { // Contrast
802 if (channel == All) {
803 r += (r-128) * factor/50 * qRed(color2)/128;
804 g += (g-128) * factor/50 * qGreen(color2)/128;
805 b += (b-128) * factor/50 * qBlue(color2)/128;
806 }
807 else {
808 r += (r-128) * mod/128;
809 g += (g-128) * mod/128;
810 b += (b-128) * mod/128;
811 }
812 }
813
814 if (r<0) r=0; if (r>255) r=255;
815 if (g<0) g=0; if (g>255) g=255;
816 if (b<0) b=0; if (b>255) b=255;
817 a = qAlpha(*data1);
818 *data1 = qRgba(r, g, b, a);
819 }
820 else if (type == Saturation || type == HueShift) {
821 clr.setRgb(color1);
822 clr.hsv(&h, &s, &v);
823 mod = (channel == Red) ? qRed(color2) :
824 (channel == Green) ? qGreen(color2) :
825 (channel == Blue) ? qBlue(color2) :
826 (channel == Gray) ? qGray(color2) : 0;
827 mod = mod*factor/50;
828
829 if (type == Saturation) {
830 s -= s * mod/256;
831 if (s<0) s=0; if (s>255) s=255;
832 }
833 else { // HueShift
834 h += mod;
835 while(h<0) h+=360;
836 h %= 360;
837 }
838
839 clr.setHsv(h, s, v);
840 a = qAlpha(*data1);
841 *data1 = clr.rgb() | ((uint)(a & 0xff) << 24);
842 }
843 data1++; data2++; data2b++; x++;
844 if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; }
845 }
846 }
847 return image;
848}
849
850
851
852//======================================================================
853//
854// Blend effects
855//
856//======================================================================
857
858
859// Nice and fast direct pixel manipulation
860QImage& OImageEffect::blend(const QColor& clr, QImage& dst, float opacity)
861{
862 if (dst.width() <= 0 || dst.height() <= 0)
863 return dst;
864
865 if (opacity < 0.0 || opacity > 1.0) {
866#ifndef NDEBUG
867 cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n";
868#endif
869 return dst;
870 }
871
872 int depth = dst.depth();
873 if (depth != 32)
874 dst = dst.convertDepth(32);
875
876 int pixels = dst.width() * dst.height();
877 int rcol, gcol, bcol;
878 clr.rgb(&rcol, &gcol, &bcol);
879
880#ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
881 register unsigned char *data = (unsigned char *)dst.bits() + 1;
882#else // BGRA
883 register unsigned char *data = (unsigned char *)dst.bits();
884#endif
885
886 for (register int i=0; i<pixels; i++)
887 {
888#ifdef WORDS_BIGENDIAN
889 *(data++) += (unsigned char)((rcol - *data) * opacity);
890 *(data++) += (unsigned char)((gcol - *data) * opacity);
891 *(data++) += (unsigned char)((bcol - *data) * opacity);
892#else
893 *(data++) += (unsigned char)((bcol - *data) * opacity);
894 *(data++) += (unsigned char)((gcol - *data) * opacity);
895 *(data++) += (unsigned char)((rcol - *data) * opacity);
896#endif
897 data++; // skip alpha
898 }
899 return dst;
900}
901
902// Nice and fast direct pixel manipulation
903QImage& OImageEffect::blend(QImage& src, QImage& dst, float opacity)
904{
905 if (src.width() <= 0 || src.height() <= 0)
906 return dst;
907 if (dst.width() <= 0 || dst.height() <= 0)
908 return dst;
909
910 if (src.width() != dst.width() || src.height() != dst.height()) {
911#ifndef NDEBUG
912 cerr << "WARNING: OImageEffect::blend : src and destination images are not the same size\n";
913#endif
914 return dst;
915 }
916
917 if (opacity < 0.0 || opacity > 1.0) {
918#ifndef NDEBUG
919 cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n";
920#endif
921 return dst;
922 }
923
924 if (src.depth() != 32) src = src.convertDepth(32);
925 if (dst.depth() != 32) dst = dst.convertDepth(32);
926
927 int pixels = src.width() * src.height();
928#ifdef WORDS_BIGENDIAN // ARGB (skip alpha)
929 register unsigned char *data1 = (unsigned char *)dst.bits() + 1;
930 register unsigned char *data2 = (unsigned char *)src.bits() + 1;
931#else // BGRA
932 register unsigned char *data1 = (unsigned char *)dst.bits();
933 register unsigned char *data2 = (unsigned char *)src.bits();
934#endif
935
936 for (register int i=0; i<pixels; i++)
937 {
938#ifdef WORDS_BIGENDIAN
939 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
940 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
941 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
942#else
943 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
944 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
945 *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity);
946#endif
947 data1++; // skip alpha
948 data2++;
949 }
950
951 return dst;
952}
953
954
955QImage& OImageEffect::blend(QImage &image, float initial_intensity,
956 const QColor &bgnd, GradientType eff,
957 bool anti_dir)
958{
959 if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) {
960#ifndef NDEBUG
961 cerr << "WARNING: OImageEffect::blend : invalid image\n";
962#endif
963 return image;
964 }
965
966 int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue();
967 int r, g, b;
968 int ind;
969
970 unsigned int xi, xf, yi, yf;
971 unsigned int a;
972
973 // check the boundaries of the initial intesity param
974 float unaffected = 1;
975 if (initial_intensity > 1) initial_intensity = 1;
976 if (initial_intensity < -1) initial_intensity = -1;
977 if (initial_intensity < 0) {
978 unaffected = 1. + initial_intensity;
979 initial_intensity = 0;
980 }
981
982
983 float intensity = initial_intensity;
984 float var = 1. - initial_intensity;
985
986 if (anti_dir) {
987 initial_intensity = intensity = 1.;
988 var = -var;
989 }
990
991 register int x, y;
992
993 unsigned int *data = (unsigned int *)image.bits();
994
995 int image_width = image.width(); //Those can't change
996 int image_height = image.height();
997
998
999 if( eff == VerticalGradient || eff == HorizontalGradient ) {
1000
1001 // set the image domain to apply the effect to
1002 xi = 0, xf = image_width;
1003 yi = 0, yf = image_height;
1004 if (eff == VerticalGradient) {
1005 if (anti_dir) yf = (int)(image_height * unaffected);
1006 else yi = (int)(image_height * (1 - unaffected));
1007 }
1008 else {
1009 if (anti_dir) xf = (int)(image_width * unaffected);
1010 else xi = (int)(image_height * (1 - unaffected));
1011 }
1012
1013 var /= (eff == VerticalGradient?yf-yi:xf-xi);
1014
1015 int ind_base;
1016 for (y = yi; y < (int)yf; y++) {
1017 intensity = eff == VerticalGradient? intensity + var :
1018 initial_intensity;
1019 ind_base = image_width * y ;
1020 for (x = xi; x < (int)xf ; x++) {
1021 if (eff == HorizontalGradient) intensity += var;
1022 ind = x + ind_base;
1023 r = qRed (data[ind]) + (int)(intensity *
1024 (r_bgnd - qRed (data[ind])));
1025 g = qGreen(data[ind]) + (int)(intensity *
1026 (g_bgnd - qGreen(data[ind])));
1027 b = qBlue (data[ind]) + (int)(intensity *
1028 (b_bgnd - qBlue (data[ind])));
1029 if (r > 255) r = 255; if (r < 0 ) r = 0;
1030 if (g > 255) g = 255; if (g < 0 ) g = 0;
1031 if (b > 255) b = 255; if (b < 0 ) b = 0;
1032 a = qAlpha(data[ind]);
1033 data[ind] = qRgba(r, g, b, a);
1034 }
1035 }
1036 }
1037 else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) {
1038 float xvar = var / 2 / image_width; // / unaffected;
1039 float yvar = var / 2 / image_height; // / unaffected;
1040 float tmp;
1041
1042 for (x = 0; x < image_width ; x++) {
1043 tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1);
1044 ind = x;
1045 for (y = 0; y < image_height ; y++) {
1046 intensity = initial_intensity + tmp + yvar * y;
1047
1048 r = qRed (data[ind]) + (int)(intensity *
1049 (r_bgnd - qRed (data[ind])));
1050 g = qGreen(data[ind]) + (int)(intensity *
1051 (g_bgnd - qGreen(data[ind])));
1052 b = qBlue (data[ind]) + (int)(intensity *
1053 (b_bgnd - qBlue (data[ind])));
1054 if (r > 255) r = 255; if (r < 0 ) r = 0;
1055 if (g > 255) g = 255; if (g < 0 ) g = 0;
1056 if (b > 255) b = 255; if (b < 0 ) b = 0;
1057 a = qAlpha(data[ind]);
1058 data[ind] = qRgba(r, g, b, a);
1059
1060 ind += image_width;
1061 }
1062 }
1063 }
1064
1065 else if (eff == RectangleGradient || eff == EllipticGradient) {
1066 float xvar;
1067 float yvar;
1068
1069 for (x = 0; x < image_width / 2 + image_width % 2; x++) {
1070 xvar = var / image_width * (image_width - x*2/unaffected-1);
1071 for (y = 0; y < image_height / 2 + image_height % 2; y++) {
1072 yvar = var / image_height * (image_height - y*2/unaffected -1);
1073
1074 if (eff == RectangleGradient)
1075 intensity = initial_intensity + QMAX(xvar, yvar);
1076 else
1077 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
1078 if (intensity > 1) intensity = 1;
1079 if (intensity < 0) intensity = 0;
1080
1081 //NW
1082 ind = x + image_width * y ;
1083 r = qRed (data[ind]) + (int)(intensity *
1084 (r_bgnd - qRed (data[ind])));
1085 g = qGreen(data[ind]) + (int)(intensity *
1086 (g_bgnd - qGreen(data[ind])));
1087 b = qBlue (data[ind]) + (int)(intensity *
1088 (b_bgnd - qBlue (data[ind])));
1089 if (r > 255) r = 255; if (r < 0 ) r = 0;
1090 if (g > 255) g = 255; if (g < 0 ) g = 0;
1091 if (b > 255) b = 255; if (b < 0 ) b = 0;
1092 a = qAlpha(data[ind]);
1093 data[ind] = qRgba(r, g, b, a);
1094
1095 //NE
1096 ind = image_width - x - 1 + image_width * y ;
1097 r = qRed (data[ind]) + (int)(intensity *
1098 (r_bgnd - qRed (data[ind])));
1099 g = qGreen(data[ind]) + (int)(intensity *
1100 (g_bgnd - qGreen(data[ind])));
1101 b = qBlue (data[ind]) + (int)(intensity *
1102 (b_bgnd - qBlue (data[ind])));
1103 if (r > 255) r = 255; if (r < 0 ) r = 0;
1104 if (g > 255) g = 255; if (g < 0 ) g = 0;
1105 if (b > 255) b = 255; if (b < 0 ) b = 0;
1106 a = qAlpha(data[ind]);
1107 data[ind] = qRgba(r, g, b, a);
1108 }
1109 }
1110
1111 //CT loop is doubled because of stupid central row/column issue.
1112 // other solution?
1113 for (x = 0; x < image_width / 2; x++) {
1114 xvar = var / image_width * (image_width - x*2/unaffected-1);
1115 for (y = 0; y < image_height / 2; y++) {
1116 yvar = var / image_height * (image_height - y*2/unaffected -1);
1117
1118 if (eff == RectangleGradient)
1119 intensity = initial_intensity + QMAX(xvar, yvar);
1120 else
1121 intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar);
1122 if (intensity > 1) intensity = 1;
1123 if (intensity < 0) intensity = 0;
1124
1125 //SW
1126 ind = x + image_width * (image_height - y -1) ;
1127 r = qRed (data[ind]) + (int)(intensity *
1128 (r_bgnd - qRed (data[ind])));
1129 g = qGreen(data[ind]) + (int)(intensity *
1130 (g_bgnd - qGreen(data[ind])));
1131 b = qBlue (data[ind]) + (int)(intensity *
1132 (b_bgnd - qBlue (data[ind])));
1133 if (r > 255) r = 255; if (r < 0 ) r = 0;
1134 if (g > 255) g = 255; if (g < 0 ) g = 0;
1135 if (b > 255) b = 255; if (b < 0 ) b = 0;
1136 a = qAlpha(data[ind]);
1137 data[ind] = qRgba(r, g, b, a);
1138
1139 //SE
1140 ind = image_width-x-1 + image_width * (image_height - y - 1) ;
1141 r = qRed (data[ind]) + (int)(intensity *
1142 (r_bgnd - qRed (data[ind])));
1143 g = qGreen(data[ind]) + (int)(intensity *
1144 (g_bgnd - qGreen(data[ind])));
1145 b = qBlue (data[ind]) + (int)(intensity *
1146 (b_bgnd - qBlue (data[ind])));
1147 if (r > 255) r = 255; if (r < 0 ) r = 0;
1148 if (g > 255) g = 255; if (g < 0 ) g = 0;
1149 if (b > 255) b = 255; if (b < 0 ) b = 0;
1150 a = qAlpha(data[ind]);
1151 data[ind] = qRgba(r, g, b, a);
1152 }
1153 }
1154 }
1155#ifndef NDEBUG
1156 else cerr << "OImageEffect::blend effect not implemented" << endl;
1157#endif
1158 return image;
1159}
1160
1161// Not very efficient as we create a third big image...
1162//
1163QImage& OImageEffect::blend(QImage &image1, QImage &image2,
1164 GradientType gt, int xf, int yf)
1165{
1166 if (image1.width() == 0 || image1.height() == 0 ||
1167 image2.width() == 0 || image2.height() == 0)
1168 return image1;
1169
1170 QImage image3;
1171
1172 image3 = OImageEffect::unbalancedGradient(image1.size(),
1173 QColor(0,0,0), QColor(255,255,255),
1174 gt, xf, yf, 0);
1175
1176 return blend(image1,image2,image3, Red); // Channel to use is arbitrary
1177}
1178
1179// Blend image2 into image1, using an RBG channel of blendImage
1180//
1181QImage& OImageEffect::blend(QImage &image1, QImage &image2,
1182 QImage &blendImage, RGBComponent channel)
1183{
1184 if (image1.width() == 0 || image1.height() == 0 ||
1185 image2.width() == 0 || image2.height() == 0 ||
1186 blendImage.width() == 0 || blendImage.height() == 0) {
1187#ifndef NDEBUG
1188 cerr << "OImageEffect::blend effect invalid image" << endl;
1189#endif
1190 return image1;
1191 }
1192
1193 int r, g, b;
1194 int ind1, ind2, ind3;
1195
1196 unsigned int x1, x2, x3, y1, y2, y3;
1197 unsigned int a;
1198
1199 register int x, y;
1200
1201 // for image1 and image2, we only handle depth 32
1202 if (image1.depth()<32) image1 = image1.convertDepth(32);
1203 if (image2.depth()<32) image2 = image2.convertDepth(32);
1204
1205 // for blendImage, we handle depth 8 and 32
1206 if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8);
1207
1208 unsigned int *colorTable3 = (blendImage.depth()==8) ?
1209 blendImage.colorTable():0;
1210
1211 unsigned int *data1 = (unsigned int *)image1.bits();
1212 unsigned int *data2 = (unsigned int *)image2.bits();
1213 unsigned int *data3 = (unsigned int *)blendImage.bits();
1214 unsigned char *data3b = (unsigned char *)blendImage.bits();
1215 unsigned int color3;
1216
1217 x1 = image1.width(); y1 = image1.height();
1218 x2 = image2.width(); y2 = image2.height();
1219 x3 = blendImage.width(); y3 = blendImage.height();
1220
1221 for (y = 0; y < (int)y1; y++) {
1222 ind1 = x1*y;
1223 ind2 = x2*(y%y2);
1224 ind3 = x3*(y%y3);
1225
1226 x=0;
1227 while(x < (int)x1) {
1228 color3 = (colorTable3) ? colorTable3[data3b[ind3]] : data3[ind3];
1229
1230 a = (channel == Red) ? qRed(color3) :
1231 (channel == Green) ? qGreen(color3) :
1232 (channel == Blue) ? qBlue(color3) : qGray(color3);
1233
1234 r = (a*qRed(data1[ind1]) + (256-a)*qRed(data2[ind2]))/256;
1235 g = (a*qGreen(data1[ind1]) + (256-a)*qGreen(data2[ind2]))/256;
1236 b = (a*qBlue(data1[ind1]) + (256-a)*qBlue(data2[ind2]))/256;
1237
1238 a = qAlpha(data1[ind1]);
1239 data1[ind1] = qRgba(r, g, b, a);
1240
1241 ind1++; ind2++; ind3++; x++;
1242 if ( (x%x2) ==0) ind2 -= x2;
1243 if ( (x%x3) ==0) ind3 -= x3;
1244 }
1245 }
1246 return image1;
1247}
1248
1249
1250//======================================================================
1251//
1252// Hash effects
1253//
1254//======================================================================
1255
1256unsigned int OImageEffect::lHash(unsigned int c)
1257{
1258 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
1259 unsigned char nr, ng, nb;
1260 nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr;
1261 ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng;
1262 nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb;
1263
1264 return qRgba(nr, ng, nb, a);
1265}
1266
1267
1268// -----------------------------------------------------------------------------
1269
1270unsigned int OImageEffect::uHash(unsigned int c)
1271{
1272 unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c);
1273 unsigned char nr, ng, nb;
1274 nr = r + (r >> 3); nr = nr < r ? ~0 : nr;
1275 ng = g + (g >> 3); ng = ng < g ? ~0 : ng;
1276 nb = b + (b >> 3); nb = nb < b ? ~0 : nb;
1277
1278 return qRgba(nr, ng, nb, a);
1279}
1280
1281
1282// -----------------------------------------------------------------------------
1283
1284QImage& OImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing)
1285{
1286 if (image.width() == 0 || image.height() == 0) {
1287#ifndef NDEBUG
1288 cerr << "OImageEffect::hash effect invalid image" << endl;
1289#endif
1290 return image;
1291 }
1292
1293 register int x, y;
1294 unsigned int *data = (unsigned int *)image.bits();
1295 unsigned int ind;
1296
1297 //CT no need to do it if not enough space
1298 if ((lite == NorthLite ||
1299 lite == SouthLite)&&
1300 (unsigned)image.height() < 2+spacing) return image;
1301 if ((lite == EastLite ||
1302 lite == WestLite)&&
1303 (unsigned)image.height() < 2+spacing) return image;
1304
1305 if (lite == NorthLite || lite == SouthLite) {
1306 for (y = 0 ; y < image.height(); y = y + 2 + spacing) {
1307 for (x = 0; x < image.width(); x++) {
1308 ind = x + image.width() * y;
1309 data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]);
1310
1311 ind = ind + image.width();
1312 data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]);
1313 }
1314 }
1315 }
1316
1317 else if (lite == EastLite || lite == WestLite) {
1318 for (y = 0 ; y < image.height(); y++) {
1319 for (x = 0; x < image.width(); x = x + 2 + spacing) {
1320 ind = x + image.width() * y;
1321 data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]);
1322
1323 ind++;
1324 data[ind] = lite==EastLite?lHash(data[ind]):uHash(data[ind]);
1325 }
1326 }
1327 }
1328
1329 else if (lite == NWLite || lite == SELite) {
1330 for (y = 0 ; y < image.height(); y++) {
1331 for (x = 0;
1332 x < (int)(image.width() - ((y & 1)? 1 : 0) * spacing);
1333 x = x + 2 + spacing) {
1334 ind = x + image.width() * y + ((y & 1)? 1 : 0);
1335 data[ind] = lite==NWLite?uHash(data[ind]):lHash(data[ind]);
1336
1337 ind++;
1338 data[ind] = lite==NWLite?lHash(data[ind]):uHash(data[ind]);
1339 }
1340 }
1341 }
1342
1343 else if (lite == SWLite || lite == NELite) {
1344 for (y = 0 ; y < image.height(); y++) {
1345 for (x = 0 + ((y & 1)? 1 : 0); x < image.width(); x = x + 2 + spacing) {
1346 ind = x + image.width() * y - ((y & 1)? 1 : 0);
1347 data[ind] = lite==SWLite?uHash(data[ind]):lHash(data[ind]);
1348
1349 ind++;
1350 data[ind] = lite==SWLite?lHash(data[ind]):uHash(data[ind]);
1351 }
1352 }
1353 }
1354
1355 return image;
1356}
1357
1358
1359//======================================================================
1360//
1361// Flatten effects
1362//
1363//======================================================================
1364
1365QImage& OImageEffect::flatten(QImage &img, const QColor &ca,
1366 const QColor &cb, int ncols)
1367{
1368 if (img.width() == 0 || img.height() == 0)
1369 return img;
1370
1371 // a bitmap is easy...
1372 if (img.depth() == 1) {
1373 img.setColor(0, ca.rgb());
1374 img.setColor(1, cb.rgb());
1375 return img;
1376 }
1377
1378 int r1 = ca.red(); int r2 = cb.red();
1379 int g1 = ca.green(); int g2 = cb.green();
1380 int b1 = ca.blue(); int b2 = cb.blue();
1381 int min = 0, max = 255;
1382
1383 QRgb col;
1384
1385 // Get minimum and maximum greylevel.
1386 if (img.numColors()) {
1387 // pseudocolor
1388 for (int i = 0; i < img.numColors(); i++) {
1389 col = img.color(i);
1390 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1391 min = QMIN(min, mean);
1392 max = QMAX(max, mean);
1393 }
1394 } else {
1395 // truecolor
1396 for (int y=0; y < img.height(); y++)
1397 for (int x=0; x < img.width(); x++) {
1398 col = img.pixel(x, y);
1399 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1400 min = QMIN(min, mean);
1401 max = QMAX(max, mean);
1402 }
1403 }
1404
1405 // Conversion factors
1406 float sr = ((float) r2 - r1) / (max - min);
1407 float sg = ((float) g2 - g1) / (max - min);
1408 float sb = ((float) b2 - b1) / (max - min);
1409
1410
1411 // Repaint the image
1412 if (img.numColors()) {
1413 for (int i=0; i < img.numColors(); i++) {
1414 col = img.color(i);
1415 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1416 int r = (int) (sr * (mean - min) + r1 + 0.5);
1417 int g = (int) (sg * (mean - min) + g1 + 0.5);
1418 int b = (int) (sb * (mean - min) + b1 + 0.5);
1419 img.setColor(i, qRgba(r, g, b, qAlpha(col)));
1420 }
1421 } else {
1422 for (int y=0; y < img.height(); y++)
1423 for (int x=0; x < img.width(); x++) {
1424 col = img.pixel(x, y);
1425 int mean = (qRed(col) + qGreen(col) + qBlue(col)) / 3;
1426 int r = (int) (sr * (mean - min) + r1 + 0.5);
1427 int g = (int) (sg * (mean - min) + g1 + 0.5);
1428 int b = (int) (sb * (mean - min) + b1 + 0.5);
1429 img.setPixel(x, y, qRgba(r, g, b, qAlpha(col)));
1430 }
1431 }
1432
1433
1434 // Dither if necessary
1435 if ( (ncols <= 0) || ((img.numColors() != 0) && (img.numColors() <= ncols)))
1436 return img;
1437
1438 if (ncols == 1) ncols++;
1439 if (ncols > 256) ncols = 256;
1440
1441 QColor *pal = new QColor[ncols];
1442 sr = ((float) r2 - r1) / (ncols - 1);
1443 sg = ((float) g2 - g1) / (ncols - 1);
1444 sb = ((float) b2 - b1) / (ncols - 1);
1445
1446 for (int i=0; i<ncols; i++)
1447 pal[i] = QColor(r1 + int(sr*i), g1 + int(sg*i), b1 + int(sb*i));
1448
1449 dither(img, pal, ncols);
1450
1451 delete[] pal;
1452 return img;
1453}
1454
1455
1456//======================================================================
1457//
1458// Fade effects
1459//
1460//======================================================================
1461
1462QImage& OImageEffect::fade(QImage &img, float val, const QColor &color)
1463{
1464 if (img.width() == 0 || img.height() == 0)
1465 return img;
1466
1467 // We don't handle bitmaps
1468 if (img.depth() == 1)
1469 return img;
1470
1471 unsigned char tbl[256];
1472 for (int i=0; i<256; i++)
1473 tbl[i] = (int) (val * i + 0.5);
1474
1475 int red = color.red();
1476 int green = color.green();
1477 int blue = color.blue();
1478
1479 QRgb col;
1480 int r, g, b, cr, cg, cb;
1481
1482 if (img.depth() <= 8) {
1483 // pseudo color
1484 for (int i=0; i<img.numColors(); i++) {
1485 col = img.color(i);
1486 cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
1487 if (cr > red)
1488 r = cr - tbl[cr - red];
1489 else
1490 r = cr + tbl[red - cr];
1491 if (cg > green)
1492 g = cg - tbl[cg - green];
1493 else
1494 g = cg + tbl[green - cg];
1495 if (cb > blue)
1496 b = cb - tbl[cb - blue];
1497 else
1498 b = cb + tbl[blue - cb];
1499 img.setColor(i, qRgba(r, g, b, qAlpha(col)));
1500 }
1501
1502 } else {
1503 // truecolor
1504 for (int y=0; y<img.height(); y++) {
1505 QRgb *data = (QRgb *) img.scanLine(y);
1506 for (int x=0; x<img.width(); x++) {
1507 col = *data;
1508 cr = qRed(col); cg = qGreen(col); cb = qBlue(col);
1509 if (cr > red)
1510 r = cr - tbl[cr - red];
1511 else
1512 r = cr + tbl[red - cr];
1513 if (cg > green)
1514 g = cg - tbl[cg - green];
1515 else
1516 g = cg + tbl[green - cg];
1517 if (cb > blue)
1518 b = cb - tbl[cb - blue];
1519 else
1520 b = cb + tbl[blue - cb];
1521 *data++ = qRgba(r, g, b, qAlpha(col));
1522 }
1523 }
1524 }
1525
1526 return img;
1527}
1528
1529//======================================================================
1530//
1531// Color effects
1532//
1533//======================================================================
1534
1535// This code is adapted from code (C) Rik Hemsley <rik@kde.org>
1536//
1537// The formula used (r + b + g) /3 is different from the qGray formula
1538// used by Qt. This is because our formula is much much faster. If,
1539// however, it turns out that this is producing sub-optimal images,
1540// then it will have to change (kurt)
1541//
1542// It does produce lower quality grayscale ;-) Use fast == true for the fast
1543// algorithm, false for the higher quality one (mosfet).
1544QImage& OImageEffect::toGray(QImage &img, bool fast)
1545{
1546 if (img.width() == 0 || img.height() == 0)
1547 return img;
1548
1549 if(fast){
1550 if (img.depth() == 32) {
1551 register uchar * r(img.bits());
1552 register uchar * g(img.bits() + 1);
1553 register uchar * b(img.bits() + 2);
1554
1555 uchar * end(img.bits() + img.numBytes());
1556
1557 while (r != end) {
1558
1559 *r = *g = *b = (((*r + *g) >> 1) + *b) >> 1; // (r + b + g) / 3
1560
1561 r += 4;
1562 g += 4;
1563 b += 4;
1564 }
1565 }
1566 else
1567 {
1568 for (int i = 0; i < img.numColors(); i++)
1569 {
1570 register uint r = qRed(img.color(i));
1571 register uint g = qGreen(img.color(i));
1572 register uint b = qBlue(img.color(i));
1573
1574 register uint gray = (((r + g) >> 1) + b) >> 1;
1575 img.setColor(i, qRgba(gray, gray, gray, qAlpha(img.color(i))));
1576 }
1577 }
1578 }
1579 else{
1580 int pixels = img.depth() > 8 ? img.width()*img.height() :
1581 img.numColors();
1582 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
1583 (unsigned int *)img.colorTable();
1584 int val, i;
1585 for(i=0; i < pixels; ++i){
1586 val = qGray(data[i]);
1587 data[i] = qRgba(val, val, val, qAlpha(data[i]));
1588 }
1589 }
1590 return img;
1591}
1592
1593// CT 29Jan2000 - desaturation algorithms
1594QImage& OImageEffect::desaturate(QImage &img, float desat)
1595{
1596 if (img.width() == 0 || img.height() == 0)
1597 return img;
1598
1599 if (desat < 0) desat = 0.;
1600 if (desat > 1) desat = 1.;
1601 int pixels = img.depth() > 8 ? img.width()*img.height() :
1602 img.numColors();
1603 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
1604 (unsigned int *)img.colorTable();
1605 int h, s, v, i;
1606 QColor clr; // keep constructor out of loop (mosfet)
1607 for(i=0; i < pixels; ++i){
1608 clr.setRgb(data[i]);
1609 clr.hsv(&h, &s, &v);
1610 clr.setHsv(h, (int)(s * (1. - desat)), v);
1611 data[i] = clr.rgb();
1612 }
1613 return img;
1614}
1615
1616// Contrast stuff (mosfet)
1617QImage& OImageEffect::contrast(QImage &img, int c)
1618{
1619 if (img.width() == 0 || img.height() == 0)
1620 return img;
1621
1622 if(c > 255)
1623 c = 255;
1624 if(c < -255)
1625 c = -255;
1626 int pixels = img.depth() > 8 ? img.width()*img.height() :
1627 img.numColors();
1628 unsigned int *data = img.depth() > 8 ? (unsigned int *)img.bits() :
1629 (unsigned int *)img.colorTable();
1630 int i, r, g, b;
1631 for(i=0; i < pixels; ++i){
1632 r = qRed(data[i]);
1633 g = qGreen(data[i]);
1634 b = qBlue(data[i]);
1635 if(qGray(data[i]) <= 127){
1636 if(r - c <= 255)
1637 r -= c;
1638 if(g - c <= 255)
1639 g -= c;
1640 if(b - c <= 255)
1641 b -= c;
1642 }
1643 else{
1644 if(r + c <= 255)
1645 r += c;
1646 if(g + c <= 255)
1647 g += c;
1648 if(b + c <= 255)
1649 b += c;
1650 }
1651 data[i] = qRgba(r, g, b, qAlpha(data[i]));
1652 }
1653 return(img);
1654}
1655
1656//======================================================================
1657//
1658// Dithering effects
1659//
1660//======================================================================
1661
1662// adapted from kFSDither (C) 1997 Martin Jones (mjones@kde.org)
1663//
1664// Floyd-Steinberg dithering
1665// Ref: Bitmapped Graphics Programming in C++
1666// Marv Luse, Addison-Wesley Publishing, 1993.
1667QImage& OImageEffect::dither(QImage &img, const QColor *palette, int size)
1668{
1669 if (img.width() == 0 || img.height() == 0 ||
1670 palette == 0 || img.depth() <= 8)
1671 return img;
1672
1673 QImage dImage( img.width(), img.height(), 8, size );
1674 int i;
1675
1676 dImage.setNumColors( size );
1677 for ( i = 0; i < size; i++ )
1678 dImage.setColor( i, palette[ i ].rgb() );
1679
1680 int *rerr1 = new int [ img.width() * 2 ];
1681 int *gerr1 = new int [ img.width() * 2 ];
1682 int *berr1 = new int [ img.width() * 2 ];
1683
1684 memset( rerr1, 0, sizeof( int ) * img.width() * 2 );
1685 memset( gerr1, 0, sizeof( int ) * img.width() * 2 );
1686 memset( berr1, 0, sizeof( int ) * img.width() * 2 );
1687
1688 int *rerr2 = rerr1 + img.width();
1689 int *gerr2 = gerr1 + img.width();
1690 int *berr2 = berr1 + img.width();
1691
1692 for ( int j = 0; j < img.height(); j++ )
1693 {
1694 uint *ip = (uint * )img.scanLine( j );
1695 uchar *dp = dImage.scanLine( j );
1696
1697 for ( i = 0; i < img.width(); i++ )
1698 {
1699 rerr1[i] = rerr2[i] + qRed( *ip );
1700 rerr2[i] = 0;
1701 gerr1[i] = gerr2[i] + qGreen( *ip );
1702 gerr2[i] = 0;
1703 berr1[i] = berr2[i] + qBlue( *ip );
1704 berr2[i] = 0;
1705 ip++;
1706 }
1707
1708 *dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size );
1709
1710 for ( i = 1; i < img.width()-1; i++ )
1711 {
1712 int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
1713 *dp = indx;
1714
1715 int rerr = rerr1[i];
1716 rerr -= palette[indx].red();
1717 int gerr = gerr1[i];
1718 gerr -= palette[indx].green();
1719 int berr = berr1[i];
1720 berr -= palette[indx].blue();
1721
1722 // diffuse red error
1723 rerr1[ i+1 ] += ( rerr * 7 ) >> 4;
1724 rerr2[ i-1 ] += ( rerr * 3 ) >> 4;
1725 rerr2[ i ] += ( rerr * 5 ) >> 4;
1726 rerr2[ i+1 ] += ( rerr ) >> 4;
1727
1728 // diffuse green error
1729 gerr1[ i+1 ] += ( gerr * 7 ) >> 4;
1730 gerr2[ i-1 ] += ( gerr * 3 ) >> 4;
1731 gerr2[ i ] += ( gerr * 5 ) >> 4;
1732 gerr2[ i+1 ] += ( gerr ) >> 4;
1733
1734 // diffuse red error
1735 berr1[ i+1 ] += ( berr * 7 ) >> 4;
1736 berr2[ i-1 ] += ( berr * 3 ) >> 4;
1737 berr2[ i ] += ( berr * 5 ) >> 4;
1738 berr2[ i+1 ] += ( berr ) >> 4;
1739
1740 dp++;
1741 }
1742
1743 *dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
1744 }
1745
1746 delete [] rerr1;
1747 delete [] gerr1;
1748 delete [] berr1;
1749
1750 img = dImage;
1751 return img;
1752}
1753
1754int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size )
1755{
1756 if (palette == 0)
1757 return 0;
1758
1759 int dr = palette[0].red() - r;
1760 int dg = palette[0].green() - g;
1761 int db = palette[0].blue() - b;
1762
1763 int minDist = dr*dr + dg*dg + db*db;
1764 int nearest = 0;
1765
1766 for (int i = 1; i < size; i++ )
1767 {
1768 dr = palette[i].red() - r;
1769 dg = palette[i].green() - g;
1770 db = palette[i].blue() - b;
1771
1772 int dist = dr*dr + dg*dg + db*db;
1773
1774 if ( dist < minDist )
1775 {
1776 minDist = dist;
1777 nearest = i;
1778 }
1779 }
1780
1781 return nearest;
1782}
1783
1784bool OImageEffect::blend(
1785 const QImage & upper,
1786 const QImage & lower,
1787 QImage & output
1788)
1789{
1790 if (
1791 upper.width() > lower.width() ||
1792 upper.height() > lower.height() ||
1793 upper.depth() != 32 ||
1794 lower.depth() != 32
1795 )
1796 {
1797#ifndef NDEBUG
1798 cerr << "OImageEffect::blend : Sizes not correct\n" ;
1799#endif
1800 return false;
1801 }
1802
1803 output = lower.copy();
1804
1805 register uchar *i, *o;
1806 register int a;
1807 register int col;
1808 register int w = upper.width();
1809 int row(upper.height() - 1);
1810
1811 do {
1812
1813 i = upper.scanLine(row);
1814 o = output.scanLine(row);
1815
1816 col = w << 2;
1817 --col;
1818
1819 do {
1820
1821 while (!(a = i[col]) && (col != 3)) {
1822 --col; --col; --col; --col;
1823 }
1824
1825 --col;
1826 o[col] += ((i[col] - o[col]) * a) >> 8;
1827
1828 --col;
1829 o[col] += ((i[col] - o[col]) * a) >> 8;
1830
1831 --col;
1832 o[col] += ((i[col] - o[col]) * a) >> 8;
1833
1834 } while (col--);
1835
1836 } while (row--);
1837
1838 return true;
1839}
1840
1841#if 0
1842// Not yet...
1843bool OImageEffect::blend(
1844 const QImage & upper,
1845 const QImage & lower,
1846 QImage & output,
1847 const QRect & destRect
1848)
1849{
1850 output = lower.copy();
1851 return output;
1852}
1853
1854#endif
1855
1856bool OImageEffect::blend(
1857 int &x, int &y,
1858 const QImage & upper,
1859 const QImage & lower,
1860 QImage & output
1861)
1862{
1863 int cx=0, cy=0, cw=upper.width(), ch=upper.height();
1864
1865 if ( upper.width() + x > lower.width() ||
1866 upper.height() + y > lower.height() ||
1867 x < 0 || y < 0 ||
1868 upper.depth() != 32 || lower.depth() != 32 )
1869 {
1870 if ( x > lower.width() || y > lower.height() ) return false;
1871 if ( upper.width()<=0 || upper.height() <= 0 ) return false;
1872 if ( lower.width()<=0 || lower.height() <= 0 ) return false;
1873
1874 if (x<0) {cx=-x; cw+=x; x=0; };
1875 if (cw + x > lower.width()) { cw=lower.width()-x; };
1876 if (y<0) {cy=-y; ch+=y; y=0; };
1877 if (ch + y > lower.height()) { ch=lower.height()-y; };
1878
1879 if ( cx >= upper.width() || cy >= upper.height() ) return true;
1880 if ( cw <= 0 || ch <= 0 ) return true;
1881 }
1882
1883 output.create(cw,ch,32);
1884// output.setAlphaBuffer(true); // I should do some benchmarks to see if
1885 // this is worth the effort
1886
1887 register QRgb *i, *o, *b;
1888
1889 register int a;
1890 register int j,k;
1891 for (j=0; j<ch; j++)
1892 {
1893 b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]);
1894 i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]);
1895 o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]);
1896
1897 k=cw-1;
1898 --b; --i; --o;
1899 do
1900 {
1901 while ( !(a=qAlpha(*i)) && k>0 )
1902 {
1903 i--;
1904 //*o=0;
1905 *o=*b;
1906 --o; --b;
1907 k--;
1908 };
1909// *o=0xFF;
1910 *o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8),
1911 qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8),
1912 qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8));
1913 --i; --o; --b;
1914 } while (k--);
1915 }
1916
1917 return true;
1918}
1919
1920bool OImageEffect::blendOnLower(
1921 int x, int y,
1922 const QImage & upper,
1923 const QImage & lower
1924)
1925{
1926 int cx=0, cy=0, cw=upper.width(), ch=upper.height();
1927
1928 if ( upper.depth() != 32 || lower.depth() != 32 ) return false;
1929 if ( x + cw > lower.width() ||
1930 y + ch > lower.height() ||
1931 x < 0 || y < 0 )
1932 {
1933 if ( x > lower.width() || y > lower.height() ) return true;
1934 if ( upper.width()<=0 || upper.height() <= 0 ) return true;
1935 if ( lower.width()<=0 || lower.height() <= 0 ) return true;
1936
1937 if (x<0) {cx=-x; cw+=x; x=0; };
1938 if (cw + x > lower.width()) { cw=lower.width()-x; };
1939 if (y<0) {cy=-y; ch+=y; y=0; };
1940 if (ch + y > lower.height()) { ch=lower.height()-y; };
1941
1942 if ( cx >= upper.width() || cy >= upper.height() ) return true;
1943 if ( cw <= 0 || ch <= 0 ) return true;
1944 }
1945
1946 register uchar *i, *b;
1947 register int a;
1948 register int k;
1949
1950 for (int j=0; j<ch; j++)
1951 {
1952 b=&lower.scanLine(y+j) [ (x+cw) << 2 ];
1953 i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ];
1954
1955 k=cw-1;
1956 --b; --i;
1957 do
1958 {
1959#ifndef WORDS_BIGENDIAN
1960 while ( !(a=*i) && k>0 )
1961#else
1962 while ( !(a=*(i-3)) && k>0 )
1963#endif
1964 {
1965 i-=4; b-=4; k--;
1966 };
1967
1968#ifndef WORDS_BIGENDIAN
1969 --i; --b;
1970 *b += ( ((*i - *b) * a) >> 8 );
1971 --i; --b;
1972 *b += ( ((*i - *b) * a) >> 8 );
1973 --i; --b;
1974 *b += ( ((*i - *b) * a) >> 8 );
1975 --i; --b;
1976#else
1977 *b += ( ((*i - *b) * a) >> 8 );
1978 --i; --b;
1979 *b += ( ((*i - *b) * a) >> 8 );
1980 --i; --b;
1981 *b += ( ((*i - *b) * a) >> 8 );
1982 i -= 2; b -= 2;
1983#endif
1984 } while (k--);
1985 }
1986
1987 return true;
1988}
1989
1990// For selected icons
1991QImage& OImageEffect::selectedImage( QImage &img, const QColor &col )
1992{
1993 return blend( col, img, 0.5);
1994}
1995
1996//
1997// ===================================================================
1998// Effects originally ported from ImageMagick for PixiePlus, plus a few
1999// new ones. (mosfet 12/29/01)
2000// ===================================================================
2001//
2002
2003void OImageEffect::normalize(QImage &img)
2004{
2005 int *histogram, threshold_intensity, intense;
2006 int x, y, i;
2007
2008 unsigned int gray_value;
2009 unsigned int *normalize_map;
2010 unsigned int high, low;
2011
2012 // allocate histogram and normalize map
2013 histogram = (int *)calloc(MaxRGB+1, sizeof(int));
2014 normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int));
2015 if(!normalize_map || !histogram){
2016 qWarning("Unable to allocate normalize histogram and map");
2017 free(normalize_map);
2018 free(histogram);
2019 return;
2020 }
2021
2022 // form histogram
2023 if(img.depth() > 8){ // DirectClass
2024 unsigned int *data;
2025 for(y=0; y < img.height(); ++y){
2026 data = (unsigned int *)img.scanLine(y);
2027 for(x=0; x < img.width(); ++x){
2028 gray_value = intensityValue(data[x]);
2029 histogram[gray_value]++;
2030 }
2031 }
2032 }
2033 else{ // PsudeoClass
2034 unsigned char *data;
2035 unsigned int *cTable = img.colorTable();
2036 for(y=0; y < img.height(); ++y){
2037 data = (unsigned char *)img.scanLine(y);
2038 for(x=0; x < img.width(); ++x){
2039 gray_value = intensityValue(*(cTable+data[x]));
2040 histogram[gray_value]++;
2041 }
2042 }
2043 }
2044
2045 // find histogram boundaries by locating the 1 percent levels
2046 threshold_intensity = (img.width()*img.height())/100;
2047 intense = 0;
2048 for(low=0; low < MaxRGB; ++low){
2049 intense+=histogram[low];
2050 if(intense > threshold_intensity)
2051 break;
2052 }
2053 intense=0;
2054 for(high=MaxRGB; high != 0; --high){
2055 intense+=histogram[high];
2056 if(intense > threshold_intensity)
2057 break;
2058 }
2059
2060 if (low == high){
2061 // Unreasonable contrast; use zero threshold to determine boundaries.
2062 threshold_intensity=0;
2063 intense=0;
2064 for(low=0; low < MaxRGB; ++low){
2065 intense+=histogram[low];
2066 if(intense > threshold_intensity)
2067 break;
2068 }
2069 intense=0;
2070 for(high=MaxRGB; high != 0; --high)
2071 {
2072 intense+=histogram[high];
2073 if(intense > threshold_intensity)
2074 break;
2075 }
2076 if(low == high)
2077 return; // zero span bound
2078 }
2079
2080 // Stretch the histogram to create the normalized image mapping.
2081 for(i=0; i <= MaxRGB; i++){
2082 if (i < (int) low)
2083 normalize_map[i]=0;
2084 else{
2085 if(i > (int) high)
2086 normalize_map[i]=MaxRGB;
2087 else
2088 normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low);
2089 }
2090 }
2091 // Normalize
2092 if(img.depth() > 8){ // DirectClass
2093 unsigned int *data;
2094 for(y=0; y < img.height(); ++y){
2095 data = (unsigned int *)img.scanLine(y);
2096 for(x=0; x < img.width(); ++x){
2097 data[x] = qRgba(normalize_map[qRed(data[x])],
2098 normalize_map[qGreen(data[x])],
2099 normalize_map[qBlue(data[x])],
2100 qAlpha(data[x]));
2101 }
2102 }
2103 }
2104 else{ // PsudeoClass
2105 int colors = img.numColors();
2106 unsigned int *cTable = img.colorTable();
2107 for(i=0; i < colors; ++i){
2108 cTable[i] = qRgba(normalize_map[qRed(cTable[i])],
2109 normalize_map[qGreen(cTable[i])],
2110 normalize_map[qBlue(cTable[i])],
2111 qAlpha(cTable[i]));
2112 }
2113 }
2114 free(histogram);
2115 free(normalize_map);
2116}
2117
2118
2119void OImageEffect::equalize(QImage &img)
2120{
2121 int *histogram, *map, *equalize_map;
2122 int x, y, i, j;
2123
2124 unsigned int high, low;
2125
2126 // allocate histogram and maps
2127 histogram = (int *)calloc(MaxRGB+1, sizeof(int));
2128 map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
2129 equalize_map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
2130
2131 if(!histogram || !map || !equalize_map){
2132 qWarning("Unable to allocate equalize histogram and maps");
2133 free(histogram);
2134 free(map);
2135 free(equalize_map);
2136 return;
2137 }
2138 // form histogram
2139 if(img.depth() > 8){ // DirectClass
2140 unsigned int *data;
2141 for(y=0; y < img.height(); ++y){
2142 data = (unsigned int *)img.scanLine(y);
2143 for(x=0; x < img.width(); ++x){
2144 histogram[intensityValue(data[x])]++;
2145 }
2146 }
2147 }
2148 else{ // PsudeoClass
2149 unsigned char *data;
2150 unsigned int *cTable = img.colorTable();
2151 for(y=0; y < img.height(); ++y){
2152 data = (unsigned char *)img.scanLine(y);
2153 for(x=0; x < img.width(); ++x){
2154 histogram[intensityValue(*(cTable+data[x]))]++;
2155 }
2156 }
2157 }
2158
2159 // integrate the histogram to get the equalization map.
2160 j=0;
2161 for(i=0; i <= MaxRGB; i++){
2162 j+=histogram[i];
2163 map[i]=j;
2164 }
2165 free(histogram);
2166 if(map[MaxRGB] == 0){
2167 free(equalize_map);
2168 free(map);
2169 return;
2170 }
2171 // equalize
2172 low=map[0];
2173 high=map[MaxRGB];
2174 for(i=0; i <= MaxRGB; i++)
2175 equalize_map[i]=(unsigned int)
2176 ((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1));
2177 free(map);
2178 // stretch the histogram
2179 if(img.depth() > 8){ // DirectClass
2180 unsigned int *data;
2181 for(y=0; y < img.height(); ++y){
2182 data = (unsigned int *)img.scanLine(y);
2183 for(x=0; x < img.width(); ++x){
2184 data[x] = qRgba(equalize_map[qRed(data[x])],
2185 equalize_map[qGreen(data[x])],
2186 equalize_map[qBlue(data[x])],
2187 qAlpha(data[x]));
2188 }
2189 }
2190 }
2191 else{ // PsudeoClass
2192 int colors = img.numColors();
2193 unsigned int *cTable = img.colorTable();
2194 for(i=0; i < colors; ++i){
2195 cTable[i] = qRgba(equalize_map[qRed(cTable[i])],
2196 equalize_map[qGreen(cTable[i])],
2197 equalize_map[qBlue(cTable[i])],
2198 qAlpha(cTable[i]));
2199 }
2200 }
2201 free(equalize_map);
2202}
2203
2204QImage OImageEffect::sample(QImage &src, int w, int h)
2205{
2206 if(w == src.width() && h == src.height())
2207 return(src);
2208
2209 double *x_offset, *y_offset;
2210 int j, k, y;
2211 register int x;
2212 QImage dest(w, h, src.depth());
2213
2214 x_offset = (double *)malloc(w*sizeof(double));
2215 y_offset = (double *)malloc(h*sizeof(double));
2216 if(!x_offset || !y_offset){
2217 qWarning("Unable to allocate pixels buffer");
2218 free(x_offset);
2219 free(y_offset);
2220 return(src);
2221 }
2222
2223 // init pixel offsets
2224 for(x=0; x < w; ++x)
2225 x_offset[x] = x*src.width()/((double)w);
2226 for(y=0; y < h; ++y)
2227 y_offset[y] = y*src.height()/((double)h);
2228
2229 // sample each row
2230 if(src.depth() > 8){ // DirectClass source image
2231 unsigned int *srcData, *destData;
2232 unsigned int *pixels;
2233 pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int));
2234 if(!pixels){
2235 qWarning("Unable to allocate pixels buffer");
2236 free(pixels);
2237 free(x_offset);
2238 free(y_offset);
2239 return(src);
2240 }
2241 j = (-1);
2242 for(y=0; y < h; ++y){
2243 destData = (unsigned int *)dest.scanLine(y);
2244 if(j != y_offset[y]){
2245 // read a scan line
2246 j = (int)(y_offset[y]);
2247 srcData = (unsigned int *)src.scanLine(j);
2248 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int));
2249 }
2250 // sample each column
2251 for(x=0; x < w; ++x){
2252 k = (int)(x_offset[x]);
2253 destData[x] = pixels[k];
2254 }
2255 }
2256 free(pixels);
2257 }
2258 else{ // PsudeoClass source image
2259 unsigned char *srcData, *destData;
2260 unsigned char *pixels;
2261 pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char));
2262 if(!pixels){
2263 qWarning("Unable to allocate pixels buffer");
2264 free(pixels);
2265 free(x_offset);
2266 free(y_offset);
2267 return(src);
2268 }
2269 // copy colortable
2270 dest.setNumColors(src.numColors());
2271 (void)memcpy(dest.colorTable(), src.colorTable(),
2272 src.numColors()*sizeof(unsigned int));
2273
2274 // sample image
2275 j = (-1);
2276 for(y=0; y < h; ++y){
2277 destData = (unsigned char *)dest.scanLine(y);
2278 if(j != y_offset[y]){
2279 // read a scan line
2280 j = (int)(y_offset[y]);
2281 srcData = (unsigned char *)src.scanLine(j);
2282 (void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char));
2283 }
2284 // sample each column
2285 for(x=0; x < w; ++x){
2286 k = (int)(x_offset[x]);
2287 destData[x] = pixels[k];
2288 }
2289 }
2290 free(pixels);
2291 }
2292 free(x_offset);
2293 free(y_offset);
2294 return(dest);
2295}
2296
2297void OImageEffect::threshold(QImage &img, unsigned int threshold)
2298{
2299 int i, count;
2300 unsigned int *data;
2301 if(img.depth() > 8){ // DirectClass
2302 count = img.width()*img.height();
2303 data = (unsigned int *)img.bits();
2304 }
2305 else{ // PsudeoClass
2306 count = img.numColors();
2307 data = (unsigned int *)img.colorTable();
2308 }
2309 for(i=0; i < count; ++i)
2310 data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb();
2311}
2312
2313QImage OImageEffect::charcoal(QImage &src, double factor)
2314{
2315 QImage dest(src);
2316 dest.detach();
2317 toGray(dest);
2318 dest = edge(dest, factor);
2319 dest = blur(dest, factor);
2320 normalize(dest);
2321 dest.invertPixels(false);
2322 return(dest);
2323}
2324
2325void OImageEffect::hull(const int x_offset, const int y_offset,
2326 const int polarity, const int columns,
2327 const int rows,
2328 unsigned int *f, unsigned int *g)
2329{
2330 int x, y;
2331
2332 unsigned int *p, *q, *r, *s;
2333 unsigned int v;
2334 if(f == NULL || g == NULL)
2335 return;
2336 p=f+(columns+2);
2337 q=g+(columns+2);
2338 r=p+(y_offset*(columns+2)+x_offset);
2339 for (y=0; y < rows; y++){
2340 p++;
2341 q++;
2342 r++;
2343 if(polarity > 0)
2344 for (x=0; x < columns; x++){
2345 v=(*p);
2346 if (*r > v)
2347 v++;
2348 *q=v;
2349 p++;
2350 q++;
2351 r++;
2352 }
2353 else
2354 for(x=0; x < columns; x++){
2355 v=(*p);
2356 if (v > (unsigned int) (*r+1))
2357 v--;
2358 *q=v;
2359 p++;
2360 q++;
2361 r++;
2362 }
2363 p++;
2364 q++;
2365 r++;
2366 }
2367 p=f+(columns+2);
2368 q=g+(columns+2);
2369 r=q+(y_offset*(columns+2)+x_offset);
2370 s=q-(y_offset*(columns+2)+x_offset);
2371 for(y=0; y < rows; y++){
2372 p++;
2373 q++;
2374 r++;
2375 s++;
2376 if(polarity > 0)
2377 for(x=0; x < (int) columns; x++){
2378 v=(*q);
2379 if (((unsigned int) (*s+1) > v) && (*r > v))
2380 v++;
2381 *p=v;
2382 p++;
2383 q++;
2384 r++;
2385 s++;
2386 }
2387 else
2388 for (x=0; x < columns; x++){
2389 v=(*q);
2390 if (((unsigned int) (*s+1) < v) && (*r < v))
2391 v--;
2392 *p=v;
2393 p++;
2394 q++;
2395 r++;
2396 s++;
2397 }
2398 p++;
2399 q++;
2400 r++;
2401 s++;
2402 }
2403}
2404
2405QImage OImageEffect::despeckle(QImage &src)
2406{
2407 int i, j, x, y;
2408 unsigned int *blue_channel, *red_channel, *green_channel, *buffer,
2409 *alpha_channel;
2410 int packets;
2411 static const int
2412 X[4]= {0, 1, 1,-1},
2413 Y[4]= {1, 0, 1, 1};
2414
2415 unsigned int *destData;
2416 QImage dest(src.width(), src.height(), 32);
2417
2418 packets = (src.width()+2)*(src.height()+2);
2419 red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2420 green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2421 blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2422 alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
2423 buffer = (unsigned int *)calloc(packets, sizeof(unsigned int));
2424 if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel ||
2425 !buffer){
2426 free(red_channel);
2427 free(green_channel);
2428 free(blue_channel);
2429 free(alpha_channel);
2430 free(buffer);
2431 return(src);
2432 }
2433
2434 // copy image pixels to color component buffers
2435 j = src.width()+2;
2436 if(src.depth() > 8){ // DirectClass source image
2437 unsigned int *srcData;
2438 for(y=0; y < src.height(); ++y){
2439 srcData = (unsigned int *)src.scanLine(y);
2440 ++j;
2441 for(x=0; x < src.width(); ++x){
2442 red_channel[j] = qRed(srcData[x]);
2443 green_channel[j] = qGreen(srcData[x]);
2444 blue_channel[j] = qBlue(srcData[x]);
2445 alpha_channel[j] = qAlpha(srcData[x]);
2446 ++j;
2447 }
2448 ++j;
2449 }
2450 }
2451 else{ // PsudeoClass source image
2452 unsigned char *srcData;
2453 unsigned int *cTable = src.colorTable();
2454 unsigned int pixel;
2455 for(y=0; y < src.height(); ++y){
2456 srcData = (unsigned char *)src.scanLine(y);
2457 ++j;
2458 for(x=0; x < src.width(); ++x){
2459 pixel = *(cTable+srcData[x]);
2460 red_channel[j] = qRed(pixel);
2461 green_channel[j] = qGreen(pixel);
2462 blue_channel[j] = qBlue(pixel);
2463 alpha_channel[j] = qAlpha(pixel);
2464 ++j;
2465 }
2466 ++j;
2467 }
2468 }
2469 // reduce speckle in red channel
2470 for(i=0; i < 4; i++){
2471 hull(X[i],Y[i],1,src.width(),src.height(),red_channel,buffer);
2472 hull(-X[i],-Y[i],1,src.width(),src.height(),red_channel,buffer);
2473 hull(-X[i],-Y[i],-1,src.width(),src.height(),red_channel,buffer);
2474 hull(X[i],Y[i],-1,src.width(),src.height(),red_channel,buffer);
2475 }
2476 // reduce speckle in green channel
2477 for (i=0; i < packets; i++)
2478 buffer[i]=0;
2479 for (i=0; i < 4; i++){
2480 hull(X[i],Y[i],1,src.width(),src.height(),green_channel,buffer);
2481 hull(-X[i],-Y[i],1,src.width(),src.height(),green_channel,buffer);
2482 hull(-X[i],-Y[i],-1,src.width(),src.height(),green_channel,buffer);
2483 hull(X[i],Y[i],-1,src.width(),src.height(),green_channel,buffer);
2484 }
2485 // reduce speckle in blue channel
2486 for (i=0; i < packets; i++)
2487 buffer[i]=0;
2488 for (i=0; i < 4; i++){
2489 hull(X[i],Y[i],1,src.width(),src.height(),blue_channel,buffer);
2490 hull(-X[i],-Y[i],1,src.width(),src.height(),blue_channel,buffer);
2491 hull(-X[i],-Y[i],-1,src.width(),src.height(),blue_channel,buffer);
2492 hull(X[i],Y[i],-1,src.width(),src.height(),blue_channel,buffer);
2493 }
2494 // copy color component buffers to despeckled image
2495 j = dest.width()+2;
2496 for(y=0; y < dest.height(); ++y)
2497 {
2498 destData = (unsigned int *)dest.scanLine(y);
2499 ++j;
2500 for (x=0; x < dest.width(); ++x)
2501 {
2502 destData[x] = qRgba(red_channel[j], green_channel[j],
2503 blue_channel[j], alpha_channel[j]);
2504 ++j;
2505 }
2506 ++j;
2507 }
2508 free(buffer);
2509 free(red_channel);
2510 free(green_channel);
2511 free(blue_channel);
2512 free(alpha_channel);
2513 return(dest);
2514}
2515
2516unsigned int OImageEffect::generateNoise(unsigned int pixel,
2517 NoiseType noise_type)
2518{
2519#define NoiseEpsilon 1.0e-5
2520#define NoiseMask 0x7fff
2521#define SigmaUniform 4.0
2522#define SigmaGaussian 4.0
2523#define SigmaImpulse 0.10
2524#define SigmaLaplacian 10.0
2525#define SigmaMultiplicativeGaussian 0.5
2526#define SigmaPoisson 0.05
2527#define TauGaussian 20.0
2528
2529 double alpha, beta, sigma, value;
2530 alpha=(double) (rand() & NoiseMask)/NoiseMask;
2531 if (alpha == 0.0)
2532 alpha=1.0;
2533 switch(noise_type){
2534 case UniformNoise:
2535 default:
2536 {
2537 value=(double) pixel+SigmaUniform*(alpha-0.5);
2538 break;
2539 }
2540 case GaussianNoise:
2541 {
2542 double tau;
2543
2544 beta=(double) (rand() & NoiseMask)/NoiseMask;
2545 sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta);
2546 tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta);
2547 value=(double) pixel+
2548 (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau);
2549 break;
2550 }
2551 case MultiplicativeGaussianNoise:
2552 {
2553 if (alpha <= NoiseEpsilon)
2554 sigma=MaxRGB;
2555 else
2556 sigma=sqrt(-2.0*log(alpha));
2557 beta=(rand() & NoiseMask)/NoiseMask;
2558 value=(double) pixel+
2559 pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta);
2560 break;
2561 }
2562 case ImpulseNoise:
2563 {
2564 if (alpha < (SigmaImpulse/2.0))
2565 value=0;
2566 else
2567 if (alpha >= (1.0-(SigmaImpulse/2.0)))
2568 value=MaxRGB;
2569 else
2570 value=pixel;
2571 break;
2572 }
2573 case LaplacianNoise:
2574 {
2575 if (alpha <= 0.5)
2576 {
2577 if (alpha <= NoiseEpsilon)
2578 value=(double) pixel-MaxRGB;
2579 else
2580 value=(double) pixel+SigmaLaplacian*log(2.0*alpha);
2581 break;
2582 }
2583 beta=1.0-alpha;
2584 if (beta <= (0.5*NoiseEpsilon))
2585 value=(double) pixel+MaxRGB;
2586 else
2587 value=(double) pixel-SigmaLaplacian*log(2.0*beta);
2588 break;
2589 }
2590 case PoissonNoise:
2591 {
2592 register int
2593 i;
2594
2595 for (i=0; alpha > exp(-SigmaPoisson*pixel); i++)
2596 {
2597 beta=(double) (rand() & NoiseMask)/NoiseMask;
2598 alpha=alpha*beta;
2599 }
2600 value=i/SigmaPoisson;
2601 break;
2602 }
2603 }
2604 if(value < 0.0)
2605 return(0);
2606 if(value > MaxRGB)
2607 return(MaxRGB);
2608 return((unsigned int) (value+0.5));
2609}
2610
2611QImage OImageEffect::addNoise(QImage &src, NoiseType noise_type)
2612{
2613 int x, y;
2614 QImage dest(src.width(), src.height(), 32);
2615 unsigned int *destData;
2616
2617 if(src.depth() > 8){ // DirectClass source image
2618 unsigned int *srcData;
2619 for(y=0; y < src.height(); ++y){
2620 srcData = (unsigned int *)src.scanLine(y);
2621 destData = (unsigned int *)dest.scanLine(y);
2622 for(x=0; x < src.width(); ++x){
2623 destData[x] = qRgba(generateNoise(qRed(srcData[x]), noise_type),
2624 generateNoise(qGreen(srcData[x]), noise_type),
2625 generateNoise(qBlue(srcData[x]), noise_type),
2626 qAlpha(srcData[x]));
2627 }
2628 }
2629 }
2630 else{ // PsudeoClass source image
2631 unsigned char *srcData;
2632 unsigned int *cTable = src.colorTable();
2633 unsigned int pixel;
2634 for(y=0; y < src.height(); ++y){
2635 srcData = (unsigned char *)src.scanLine(y);
2636 destData = (unsigned int *)dest.scanLine(y);
2637 for(x=0; x < src.width(); ++x){
2638 pixel = *(cTable+srcData[x]);
2639 destData[x] = qRgba(generateNoise(qRed(pixel), noise_type),
2640 generateNoise(qGreen(pixel), noise_type),
2641 generateNoise(qBlue(pixel), noise_type),
2642 qAlpha(pixel));
2643 }
2644 }
2645
2646 }
2647 return(dest);
2648}
2649
2650unsigned int OImageEffect::interpolateColor(QImage *image, double x_offset,
2651 double y_offset,
2652 unsigned int background)
2653{
2654 double alpha, beta;
2655 unsigned int p, q, r, s;
2656 int x, y;
2657
2658 x = (int)x_offset;
2659 y = (int)y_offset;
2660 if((x < -1) || (x >= image->width()) || (y < -1) || (y >= image->height()))
2661 return(background);
2662 if(image->depth() > 8){
2663 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
2664 unsigned int *t = (unsigned int *)image->scanLine(y);
2665 p = t[x];
2666 q = t[x+1];
2667 r = t[x+image->width()];
2668 s = t[x+image->width()+1];
2669 }
2670 else{
2671 unsigned int *t = (unsigned int *)image->scanLine(y);
2672 p = background;
2673 if((x >= 0) && (y >= 0)){
2674 p = t[x];
2675 }
2676 q = background;
2677 if(((x+1) < image->width()) && (y >= 0)){
2678 q = t[x+1];
2679 }
2680 r = background;
2681 if((x >= 0) && ((y+1) < image->height())){
2682 t = (unsigned int *)image->scanLine(y+1);
2683 r = t[x+image->width()];
2684 }
2685 s = background;
2686 if(((x+1) < image->width()) && ((y+1) < image->height())){
2687 t = (unsigned int *)image->scanLine(y+1);
2688 s = t[x+image->width()+1];
2689 }
2690
2691 }
2692 }
2693 else{
2694 unsigned int *colorTable = (unsigned int *)image->colorTable();
2695 if((x >= 0) && (y >= 0) && (x < (image->width()-1)) && (y < (image->height()-1))) {
2696 unsigned char *t;
2697 t = (unsigned char *)image->scanLine(y);
2698 p = *(colorTable+t[x]);
2699 q = *(colorTable+t[x+1]);
2700 t = (unsigned char *)image->scanLine(y+1);
2701 r = *(colorTable+t[x]);
2702 s = *(colorTable+t[x+1]);
2703 }
2704 else{
2705 unsigned char *t;
2706 p = background;
2707 if((x >= 0) && (y >= 0)){
2708 t = (unsigned char *)image->scanLine(y);
2709 p = *(colorTable+t[x]);
2710 }
2711 q = background;
2712 if(((x+1) < image->width()) && (y >= 0)){
2713 t = (unsigned char *)image->scanLine(y);
2714 q = *(colorTable+t[x+1]);
2715 }
2716 r = background;
2717 if((x >= 0) && ((y+1) < image->height())){
2718 t = (unsigned char *)image->scanLine(y+1);
2719 r = *(colorTable+t[x]);
2720 }
2721 s = background;
2722 if(((x+1) < image->width()) && ((y+1) < image->height())){
2723 t = (unsigned char *)image->scanLine(y+1);
2724 s = *(colorTable+t[x+1]);
2725 }
2726
2727 }
2728
2729 }
2730 x_offset -= floor(x_offset);
2731 y_offset -= floor(y_offset);
2732 alpha = 1.0-x_offset;
2733 beta = 1.0-y_offset;
2734
2735 return(qRgba((unsigned char)(beta*(alpha*qRed(p)+x_offset*qRed(q))+y_offset*(alpha*qRed(r)+x_offset*qRed(s))),
2736 (unsigned char)(beta*(alpha*qGreen(p)+x_offset*qGreen(q))+y_offset*(alpha*qGreen(r)+x_offset*qGreen(s))),
2737 (unsigned char)(beta*(alpha*qBlue(p)+x_offset*qBlue(q))+y_offset*(alpha*qBlue(r)+x_offset*qBlue(s))),
2738 (unsigned char)(beta*(alpha*qAlpha(p)+x_offset*qAlpha(q))+y_offset*(alpha*qAlpha(r)+x_offset*qAlpha(s)))));
2739}
2740
2741QImage OImageEffect::implode(QImage &src, double factor,
2742 unsigned int background)
2743{
2744 double amount, distance, radius;
2745 double x_center, x_distance, x_scale;
2746 double y_center, y_distance, y_scale;
2747 unsigned int *destData;
2748 int x, y;
2749
2750 QImage dest(src.width(), src.height(), 32);
2751
2752 // compute scaling factor
2753 x_scale = 1.0;
2754 y_scale = 1.0;
2755 x_center = (double)0.5*src.width();
2756 y_center = (double)0.5*src.height();
2757 radius=x_center;
2758 if(src.width() > src.height())
2759 y_scale = (double)src.width()/src.height();
2760 else if(src.width() < src.height()){
2761 x_scale = (double) src.height()/src.width();
2762 radius = y_center;
2763 }
2764 amount=factor/10.0;
2765 if(amount >= 0)
2766 amount/=10.0;
2767 if(src.depth() > 8){ // DirectClass source image
2768 unsigned int *srcData;
2769 for(y=0; y < src.height(); ++y){
2770 srcData = (unsigned int *)src.scanLine(y);
2771 destData = (unsigned int *)dest.scanLine(y);
2772 y_distance=y_scale*(y-y_center);
2773 for(x=0; x < src.width(); ++x){
2774 destData[x] = srcData[x];
2775 x_distance = x_scale*(x-x_center);
2776 distance= x_distance*x_distance+y_distance*y_distance;
2777 if(distance < (radius*radius)){
2778 double factor;
2779 // Implode the pixel.
2780 factor=1.0;
2781 if(distance > 0.0)
2782 factor=
2783 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
2784 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
2785 factor*y_distance/y_scale+y_center,
2786 background);
2787 }
2788 }
2789 }
2790 }
2791 else{ // PsudeoClass source image
2792 unsigned char *srcData;
2793 unsigned char idx;
2794 unsigned int *cTable = src.colorTable();
2795 for(y=0; y < src.height(); ++y){
2796 srcData = (unsigned char *)src.scanLine(y);
2797 destData = (unsigned int *)dest.scanLine(y);
2798 y_distance=y_scale*(y-y_center);
2799 for(x=0; x < src.width(); ++x){
2800 idx = srcData[x];
2801 destData[x] = cTable[idx];
2802 x_distance = x_scale*(x-x_center);
2803 distance= x_distance*x_distance+y_distance*y_distance;
2804 if(distance < (radius*radius)){
2805 double factor;
2806 // Implode the pixel.
2807 factor=1.0;
2808 if(distance > 0.0)
2809 factor=
2810 pow(sin(0.5000000000000001*M_PI*sqrt(distance)/radius),-amount);
2811 destData[x] = interpolateColor(&src, factor*x_distance/x_scale+x_center,
2812 factor*y_distance/y_scale+y_center,
2813 background);
2814 }
2815 }
2816 }
2817
2818 }
2819 return(dest);
2820}
2821
2822QImage OImageEffect::rotate(QImage &img, RotateDirection r)
2823{
2824 QImage dest;
2825 int x, y;
2826 if(img.depth() > 8){
2827 unsigned int *srcData, *destData;
2828 switch(r){
2829 case Rotate90:
2830 dest.create(img.height(), img.width(), img.depth());
2831 for(y=0; y < img.height(); ++y){
2832 srcData = (unsigned int *)img.scanLine(y);
2833 for(x=0; x < img.width(); ++x){
2834 destData = (unsigned int *)dest.scanLine(x);
2835 destData[img.height()-y-1] = srcData[x];
2836 }
2837 }
2838 break;
2839 case Rotate180:
2840 dest.create(img.width(), img.height(), img.depth());
2841 for(y=0; y < img.height(); ++y){
2842 srcData = (unsigned int *)img.scanLine(y);
2843 destData = (unsigned int *)dest.scanLine(img.height()-y-1);
2844 for(x=0; x < img.width(); ++x)
2845 destData[img.width()-x-1] = srcData[x];
2846 }
2847 break;
2848 case Rotate270:
2849 dest.create(img.height(), img.width(), img.depth());
2850 for(y=0; y < img.height(); ++y){
2851 srcData = (unsigned int *)img.scanLine(y);
2852 for(x=0; x < img.width(); ++x){
2853 destData = (unsigned int *)dest.scanLine(img.width()-x-1);
2854 destData[y] = srcData[x];
2855 }
2856 }
2857 break;
2858 default:
2859 dest = img;
2860 break;
2861 }
2862 }
2863 else{
2864 unsigned char *srcData, *destData;
2865 unsigned int *srcTable, *destTable;
2866 switch(r){
2867 case Rotate90:
2868 dest.create(img.height(), img.width(), img.depth());
2869 dest.setNumColors(img.numColors());
2870 srcTable = (unsigned int *)img.colorTable();
2871 destTable = (unsigned int *)dest.colorTable();
2872 for(x=0; x < img.numColors(); ++x)
2873 destTable[x] = srcTable[x];
2874 for(y=0; y < img.height(); ++y){
2875 srcData = (unsigned char *)img.scanLine(y);
2876 for(x=0; x < img.width(); ++x){
2877 destData = (unsigned char *)dest.scanLine(x);
2878 destData[img.height()-y-1] = srcData[x];
2879 }
2880 }
2881 break;
2882 case Rotate180:
2883 dest.create(img.width(), img.height(), img.depth());
2884 dest.setNumColors(img.numColors());
2885 srcTable = (unsigned int *)img.colorTable();
2886 destTable = (unsigned int *)dest.colorTable();
2887 for(x=0; x < img.numColors(); ++x)
2888 destTable[x] = srcTable[x];
2889 for(y=0; y < img.height(); ++y){
2890 srcData = (unsigned char *)img.scanLine(y);
2891 destData = (unsigned char *)dest.scanLine(img.height()-y-1);
2892 for(x=0; x < img.width(); ++x)
2893 destData[img.width()-x-1] = srcData[x];
2894 }
2895 break;
2896 case Rotate270:
2897 dest.create(img.height(), img.width(), img.depth());
2898 dest.setNumColors(img.numColors());
2899 srcTable = (unsigned int *)img.colorTable();
2900 destTable = (unsigned int *)dest.colorTable();
2901 for(x=0; x < img.numColors(); ++x)
2902 destTable[x] = srcTable[x];
2903 for(y=0; y < img.height(); ++y){
2904 srcData = (unsigned char *)img.scanLine(y);
2905 for(x=0; x < img.width(); ++x){
2906 destData = (unsigned char *)dest.scanLine(img.width()-x-1);
2907 destData[y] = srcData[x];
2908 }
2909 }
2910 break;
2911 default:
2912 dest = img;
2913 break;
2914 }
2915
2916 }
2917 return(dest);
2918}
2919
2920void OImageEffect::solarize(QImage &img, double factor)
2921{
2922 int i, count;
2923 int threshold;
2924 unsigned int *data;
2925
2926 threshold = (int)(factor*(MaxRGB+1)/100.0);
2927 if(img.depth() < 32){
2928 data = (unsigned int *)img.colorTable();
2929 count = img.numColors();
2930 }
2931 else{
2932 data = (unsigned int *)img.bits();
2933 count = img.width()*img.height();
2934 }
2935 for(i=0; i < count; ++i){
2936 data[i] = qRgba(qRed(data[i]) > threshold ? MaxRGB-qRed(data[i]) : qRed(data[i]),
2937 qGreen(data[i]) > threshold ? MaxRGB-qGreen(data[i]) : qGreen(data[i]),
2938 qBlue(data[i]) > threshold ? MaxRGB-qBlue(data[i]) : qBlue(data[i]),
2939 qAlpha(data[i]));
2940 }
2941}
2942
2943QImage OImageEffect::spread(QImage &src, unsigned int amount)
2944{
2945 int quantum, x, y;
2946 int x_distance, y_distance;
2947 if(src.width() < 3 || src.height() < 3)
2948 return(src);
2949 QImage dest(src);
2950 dest.detach();
2951 quantum=(amount+1) >> 1;
2952 if(src.depth() > 8){ // DirectClass source image
2953 unsigned int *p, *q;
2954 for(y=0; y < src.height(); y++){
2955 q = (unsigned int *)dest.scanLine(y);
2956 for(x=0; x < src.width(); x++){
2957 x_distance = x + ((rand() & (amount+1))-quantum);
2958 y_distance = y + ((rand() & (amount+1))-quantum);
2959 x_distance = QMIN(x_distance, src.width()-1);
2960 y_distance = QMIN(y_distance, src.height()-1);
2961 if(x_distance < 0)
2962 x_distance = 0;
2963 if(y_distance < 0)
2964 y_distance = 0;
2965 p = (unsigned int *)src.scanLine(y_distance);
2966 p += x_distance;
2967 *q++=(*p);
2968 }
2969 }
2970 }
2971 else{ // PsudeoClass source image
2972 // just do colortable values
2973 unsigned char *p, *q;
2974 for(y=0; y < src.height(); y++){
2975 q = (unsigned char *)dest.scanLine(y);
2976 for(x=0; x < src.width(); x++){
2977 x_distance = x + ((rand() & (amount+1))-quantum);
2978 y_distance = y + ((rand() & (amount+1))-quantum);
2979 x_distance = QMIN(x_distance, src.width()-1);
2980 y_distance = QMIN(y_distance, src.height()-1);
2981 if(x_distance < 0)
2982 x_distance = 0;
2983 if(y_distance < 0)
2984 y_distance = 0;
2985 p = (unsigned char *)src.scanLine(y_distance);
2986 p += x_distance;
2987 *q++=(*p);
2988 }
2989 }
2990 }
2991 return(dest);
2992}
2993
2994QImage OImageEffect::swirl(QImage &src, double degrees,
2995 unsigned int background)
2996{
2997 double cosine, distance, factor, radius, sine, x_center, x_distance,
2998 x_scale, y_center, y_distance, y_scale;
2999 int x, y;
3000 unsigned int *q;
3001 QImage dest(src.width(), src.height(), 32);
3002
3003 // compute scaling factor
3004 x_center = src.width()/2.0;
3005 y_center = src.height()/2.0;
3006 radius = QMAX(x_center,y_center);
3007 x_scale=1.0;
3008 y_scale=1.0;
3009 if(src.width() > src.height())
3010 y_scale=(double)src.width()/src.height();
3011 else if(src.width() < src.height())
3012 x_scale=(double)src.height()/src.width();
3013 degrees=DegreesToRadians(degrees);
3014 // swirl each row
3015 if(src.depth() > 8){ // DirectClass source image
3016 unsigned int *p;
3017 for(y=0; y < src.height(); y++){
3018 p = (unsigned int *)src.scanLine(y);
3019 q = (unsigned int *)dest.scanLine(y);
3020 y_distance = y_scale*(y-y_center);
3021 for(x=0; x < src.width(); x++){
3022 // determine if the pixel is within an ellipse
3023 *q=(*p);
3024 x_distance = x_scale*(x-x_center);
3025 distance = x_distance*x_distance+y_distance*y_distance;
3026 if (distance < (radius*radius)){
3027 // swirl
3028 factor = 1.0-sqrt(distance)/radius;
3029 sine = sin(degrees*factor*factor);
3030 cosine = cos(degrees*factor*factor);
3031 *q = interpolateColor(&src,
3032 (cosine*x_distance-sine*y_distance)/x_scale+x_center,
3033 (sine*x_distance+cosine*y_distance)/y_scale+y_center,
3034 background);
3035 }
3036 p++;
3037 q++;
3038 }
3039 }
3040 }
3041 else{ // PsudeoClass source image
3042 unsigned char *p;
3043 unsigned int *cTable = (unsigned int *)src.colorTable();
3044 for(y=0; y < src.height(); y++){
3045 p = (unsigned char *)src.scanLine(y);
3046 q = (unsigned int *)dest.scanLine(y);
3047 y_distance = y_scale*(y-y_center);
3048 for(x=0; x < src.width(); x++){
3049 // determine if the pixel is within an ellipse
3050 *q = *(cTable+(*p));
3051 x_distance = x_scale*(x-x_center);
3052 distance = x_distance*x_distance+y_distance*y_distance;
3053 if (distance < (radius*radius)){
3054 // swirl
3055 factor = 1.0-sqrt(distance)/radius;
3056 sine = sin(degrees*factor*factor);
3057 cosine = cos(degrees*factor*factor);
3058 *q = interpolateColor(&src,
3059 (cosine*x_distance-sine*y_distance)/x_scale+x_center,
3060 (sine*x_distance+cosine*y_distance)/y_scale+y_center,
3061 background);
3062 }
3063 p++;
3064 q++;
3065 }
3066 }
3067
3068 }
3069 return(dest);
3070}
3071
3072QImage OImageEffect::wave(QImage &src, double amplitude, double wavelength,
3073 unsigned int background)
3074{
3075 double *sine_map;
3076 int x, y;
3077 unsigned int *q;
3078
3079 QImage dest(src.width(), src.height() + (int)(2*fabs(amplitude)), 32);
3080 // allocate sine map
3081 sine_map = (double *)malloc(dest.width()*sizeof(double));
3082 if(!sine_map)
3083 return(src);
3084 for(x=0; x < dest.width(); ++x)
3085 sine_map[x]=fabs(amplitude)+amplitude*sin((2*M_PI*x)/wavelength);
3086 // wave image
3087 for(y=0; y < dest.height(); ++y){
3088 q = (unsigned int *)dest.scanLine(y);
3089 for (x=0; x < dest.width(); x++){
3090 *q=interpolateColor(&src, x, (int)(y-sine_map[x]), background);
3091 ++q;
3092 }
3093 }
3094 free(sine_map);
3095 return(dest);
3096}
3097
3098QImage OImageEffect::oilPaint(QImage &src, int radius)
3099{
3100 // TODO 8bpp src!
3101 if(src.depth() < 32){
3102 qWarning("Oil Paint source image < 32bpp. Convert before using!");
3103 return(src);
3104 }
3105 int j, k, i, x, y;
3106 unsigned int *histogram;
3107 unsigned int *s;
3108 unsigned int count;
3109
3110 unsigned int *srcData, *destData;
3111
3112 QImage dest(src);
3113 dest.detach();
3114 histogram = (unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int));
3115 if(!histogram)
3116 return(src);
3117 // paint each row
3118 k=0;
3119 for(y = radius; y < src.height(); ++y){
3120 srcData = (unsigned int *)src.scanLine(y-radius);
3121 destData = (unsigned int *)dest.scanLine(y);
3122 srcData += radius*src.width()+radius;
3123 destData += radius;
3124 for(x=radius; x < src.width()-radius; ++x){
3125 // determine most frequent color
3126 count = 0;
3127 for(i=0; i < MaxRGB+1; ++i)
3128 histogram[i] = 0;
3129 for(i=0; i < radius; ++i){
3130 s = srcData-(radius-1)*src.width()-i-1;
3131 for(j =0; j < (2*i+1); ++j){
3132 k = intensityValue(*s);
3133 histogram[k]++;
3134 if(histogram[k] > count){
3135 *destData = *s;
3136 count = histogram[k];
3137 }
3138 ++s;
3139 }
3140 s = srcData+(radius-i)*src.width()-i-1;
3141 for(j =0; j < (2*i+1); ++j){
3142 k = intensityValue(*s);
3143 histogram[k]++;
3144 if(histogram[k] > count){
3145 *destData = *s;
3146 count = histogram[k];
3147 }
3148 ++s;
3149 }
3150 }
3151 s = srcData-radius;
3152 for(j =0; j < (2*i+1); ++j){
3153 k = intensityValue(*s);
3154 histogram[k]++;
3155 if(histogram[k] > count){
3156 *destData = *s;
3157 count = histogram[k];
3158 }
3159 ++s;
3160 }
3161 ++srcData;
3162 ++destData;
3163 }
3164 }
3165 free(histogram);
3166 return(dest);
3167}
3168
3169//
3170// The following methods work by computing a value from neighboring pixels
3171// (mosfet 12/28/01)
3172//
3173
3174QImage OImageEffect::edge(QImage &src, double factor)
3175{
3176#define Edge(weight) \
3177 total_red+=(weight)*qRed(*s); \
3178 total_green+=(weight)*qGreen(*s); \
3179 total_blue+=(weight)*qBlue(*s); \
3180 total_opacity+=(weight)*qAlpha(*s); \
3181 s++;
3182
3183#define Edge256(weight) \
3184 total_red+=(weight)*qRed(*(cTable+(*s))); \
3185 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3186 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3187 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
3188 s++;
3189
3190 if(src.width() < 3 || src.height() < 3)
3191 return(src);
3192
3193 double total_blue, total_green, total_opacity, total_red, weight;
3194
3195 int x, y;
3196
3197 unsigned int *q;
3198
3199 QImage dest(src.width(), src.height(), 32);
3200 weight=factor/8.0;
3201 if(src.depth() > 8){ // DirectClass source image
3202 unsigned int *p, *s;
3203 for(y=0; y < src.height(); ++y){
3204 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3205 q = (unsigned int *)dest.scanLine(y);
3206 // edge detect this row of pixels.
3207 *q++=(*(p+src.width()));
3208 for(x=1; x < src.width()-1; ++x){
3209 // compute weighted average of target pixel color components.
3210 total_red=0.0;
3211 total_green=0.0;
3212 total_blue=0.0;
3213 total_opacity=0.0;
3214 s=p;
3215 Edge(-weight/8); Edge(-weight/8) Edge(-weight/8);
3216 s=p+src.width();
3217 Edge(-weight/8); Edge(weight); Edge(-weight/8);
3218 s=p+2*src.width();
3219 Edge(-weight/8); Edge(-weight/8); Edge(-weight/8);
3220 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3221 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3222 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3223 (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity));
3224 p++;
3225 q++;
3226 }
3227 p++;
3228 *q++=(*p);
3229 }
3230 }
3231 else{ // PsudeoClass source image
3232 unsigned char *p, *p2, *p3, *s;
3233 unsigned int *cTable = src.colorTable();
3234 int scanLineIdx;
3235 for(y=0; y < src.height(); ++y){
3236 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3237 p = (unsigned char *)src.scanLine(scanLineIdx);
3238 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3239 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3240 q = (unsigned int *)dest.scanLine(y);
3241 // edge detect this row of pixels.
3242 *q++=(*(cTable+(*p2)));
3243 for(x=1; x < src.width()-1; ++x){
3244 // compute weighted average of target pixel color components.
3245 total_red=0.0;
3246 total_green=0.0;
3247 total_blue=0.0;
3248 total_opacity=0.0;
3249 s=p;
3250 Edge256(-weight/8); Edge256(-weight/8) Edge256(-weight/8);
3251 s=p2;
3252 Edge256(-weight/8); Edge256(weight); Edge256(-weight/8);
3253 s=p3;
3254 Edge256(-weight/8); Edge256(-weight/8); Edge256(-weight/8);
3255 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3256 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3257 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3258 (unsigned char)((total_opacity < 0) ? 0 : (total_opacity > MaxRGB) ? MaxRGB : total_opacity));
3259 p++;
3260 p2++;
3261 p3++;
3262 q++;
3263 }
3264 p++;
3265 *q++=(*(cTable+(*p)));
3266 }
3267 }
3268 return(dest);
3269}
3270
3271QImage OImageEffect::sharpen(QImage &src, double factor)
3272{
3273#define Sharpen(weight) \
3274 total_red+=(weight)*qRed(*s); \
3275 total_green+=(weight)*qGreen(*s); \
3276 total_blue+=(weight)*qBlue(*s); \
3277 total_opacity+=(weight)*qAlpha(*s); \
3278 s++;
3279
3280#define Sharpen256(weight) \
3281 total_red+=(weight)*qRed(*(cTable+(*s))); \
3282 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3283 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3284 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
3285 s++;
3286
3287 if(src.width() < 3 || src.height() < 3)
3288 return(src);
3289
3290 double total_blue, total_green, total_opacity, total_red;
3291 double quantum, weight;
3292 unsigned char r, g, b, a;
3293
3294 int x, y;
3295 unsigned int *q;
3296
3297 QImage dest(src.width(), src.height(), 32);
3298 weight = ((100.0-factor)/2.0+13.0);
3299 quantum = QMAX(weight-12.0, 1.0);
3300 if(src.depth() > 8){ // DirectClass source image
3301 unsigned int *p, *s;
3302 for(y=0; y < src.height(); ++y){
3303 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3304 q = (unsigned int *)dest.scanLine(y);
3305 // sharpen this row of pixels.
3306 *q++=(*(p+src.width()));
3307 for(x=1; x < src.width()-1; ++x){
3308 // compute weighted average of target pixel color components.
3309 total_red=0.0;
3310 total_green=0.0;
3311 total_blue=0.0;
3312 total_opacity=0.0;
3313 s=p;
3314 Sharpen(-1); Sharpen(-2); Sharpen(-1);
3315 s=p+src.width();
3316 Sharpen(-2); Sharpen(weight); Sharpen(-2);
3317 s=p+2*src.width();
3318 Sharpen(-1); Sharpen(-2); Sharpen(-1);
3319 if(total_red < 0)
3320 r=0;
3321 else if(total_red > (int)(MaxRGB*quantum))
3322 r = (unsigned char)MaxRGB;
3323 else
3324 r = (unsigned char)((total_red+(quantum/2.0))/quantum);
3325
3326 if(total_green < 0)
3327 g = 0;
3328 else if(total_green > (int)(MaxRGB*quantum))
3329 g = (unsigned char)MaxRGB;
3330 else
3331 g = (unsigned char)((total_green+(quantum/2.0))/quantum);
3332
3333 if(total_blue < 0)
3334 b = 0;
3335 else if(total_blue > (int)(MaxRGB*quantum))
3336 b = (unsigned char)MaxRGB;
3337 else
3338 b = (unsigned char)((total_blue+(quantum/2.0))/quantum);
3339
3340 if(total_opacity < 0)
3341 a = 0;
3342 else if(total_opacity > (int)(MaxRGB*quantum))
3343 a = (unsigned char)MaxRGB;
3344 else
3345 a= (unsigned char)((total_opacity+(quantum/2.0))/quantum);
3346
3347 *q = qRgba(r, g, b, a);
3348
3349 p++;
3350 q++;
3351 }
3352 p++;
3353 *q++=(*p);
3354 }
3355 }
3356 else{ // PsudeoClass source image
3357 unsigned char *p, *p2, *p3, *s;
3358 unsigned int *cTable = src.colorTable();
3359 int scanLineIdx;
3360 for(y=0; y < src.height(); ++y){
3361 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3362 p = (unsigned char *)src.scanLine(scanLineIdx);
3363 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3364 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3365 q = (unsigned int *)dest.scanLine(y);
3366 // sharpen this row of pixels.
3367 *q++=(*(cTable+(*p2)));
3368 for(x=1; x < src.width()-1; ++x){
3369 // compute weighted average of target pixel color components.
3370 total_red=0.0;
3371 total_green=0.0;
3372 total_blue=0.0;
3373 total_opacity=0.0;
3374 s=p;
3375 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1);
3376 s=p2;
3377 Sharpen256(-2); Sharpen256(weight); Sharpen256(-2);
3378 s=p3;
3379 Sharpen256(-1); Sharpen256(-2); Sharpen256(-1);
3380 if(total_red < 0)
3381 r=0;
3382 else if(total_red > (int)(MaxRGB*quantum))
3383 r = (unsigned char)MaxRGB;
3384 else
3385 r = (unsigned char)((total_red+(quantum/2.0))/quantum);
3386
3387 if(total_green < 0)
3388 g = 0;
3389 else if(total_green > (int)(MaxRGB*quantum))
3390 g = (unsigned char)MaxRGB;
3391 else
3392 g = (unsigned char)((total_green+(quantum/2.0))/quantum);
3393
3394 if(total_blue < 0)
3395 b = 0;
3396 else if(total_blue > (int)(MaxRGB*quantum))
3397 b = (unsigned char)MaxRGB;
3398 else
3399 b = (unsigned char)((total_blue+(quantum/2.0))/quantum);
3400
3401 if(total_opacity < 0)
3402 a = 0;
3403 else if(total_opacity > (int)(MaxRGB*quantum))
3404 a = (unsigned char)MaxRGB;
3405 else
3406 a = (unsigned char)((total_opacity+(quantum/2.0))/quantum);
3407
3408 *q = qRgba(r, g, b, a);
3409
3410 p++;
3411 p2++;
3412 p3++;
3413 q++;
3414 }
3415 p++;
3416 *q++=(*(cTable+(*p)));
3417 }
3418 }
3419 return(dest);
3420}
3421
3422QImage OImageEffect::emboss(QImage &src)
3423{
3424#define Emboss(weight) \
3425 total_red+=(weight)*qRed(*s); \
3426 total_green+=(weight)*qGreen(*s); \
3427 total_blue+=(weight)*qBlue(*s); \
3428 s++;
3429
3430#define Emboss256(weight) \
3431 total_red+=(weight)*qRed(*(cTable+(*s))); \
3432 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3433 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3434 s++;
3435
3436 if(src.width() < 3 || src.height() < 3)
3437 return(src);
3438
3439 double total_blue, total_green, total_red;
3440 int x, y;
3441 unsigned int *q;
3442
3443 QImage dest(src.width(), src.height(), 32);
3444 if(src.depth() > 8){ // DirectClass source image
3445 unsigned int *p, *s;
3446 for(y=0; y < src.height(); ++y){
3447 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3448 q = (unsigned int *)dest.scanLine(y);
3449 // emboss this row of pixels.
3450 *q++=(*(p+src.width()));
3451 for(x=1; x < src.width()-1; ++x){
3452 // compute weighted average of target pixel color components.
3453 total_red=0.0;
3454 total_green=0.0;
3455 total_blue=0.0;
3456 s=p;
3457 Emboss(-1); Emboss(-2); Emboss( 0);
3458 s=p+src.width();
3459 Emboss(-2); Emboss( 0); Emboss( 2);
3460 s=p+2*src.width();
3461 Emboss( 0); Emboss( 2); Emboss( 1);
3462 total_red += (MaxRGB+1)/2;
3463 total_green += (MaxRGB+1)/2;
3464 total_blue += (MaxRGB+1)/2;
3465 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3466 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3467 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3468 255);
3469 p++;
3470 q++;
3471 }
3472 p++;
3473 *q++=(*p);
3474 }
3475 }
3476 else{ // PsudeoClass source image
3477 unsigned char *p, *p2, *p3, *s;
3478 unsigned int *cTable = src.colorTable();
3479 int scanLineIdx;
3480 for(y=0; y < src.height(); ++y){
3481 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3482 p = (unsigned char *)src.scanLine(scanLineIdx);
3483 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3484 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3485 q = (unsigned int *)dest.scanLine(y);
3486 // emboss this row of pixels.
3487 *q++=(*(cTable+(*p2)));
3488 for(x=1; x < src.width()-1; ++x){
3489 // compute weighted average of target pixel color components.
3490 total_red=0.0;
3491 total_green=0.0;
3492 total_blue=0.0;
3493 s=p;
3494 Emboss256(-1); Emboss256(-2); Emboss256(0);
3495 s=p2;
3496 Emboss256(-2); Emboss256(0); Emboss256(2);
3497 s=p3;
3498 Emboss256(0); Emboss256(2); Emboss256(1);
3499 total_red += (MaxRGB+1)/2;
3500 total_green += (MaxRGB+1)/2;
3501 total_blue += (MaxRGB+1)/2;
3502 *q = qRgba((unsigned char)((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red),
3503 (unsigned char)((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green),
3504 (unsigned char)((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue),
3505 255);
3506 p++;
3507 p2++;
3508 p3++;
3509 q++;
3510 }
3511 p++;
3512 *q++=(*(cTable+(*p)));
3513 }
3514 }
3515 toGray(dest);
3516 normalize(dest);
3517 return(dest);
3518}
3519
3520QImage OImageEffect::shade(QImage &src, bool color_shading, double azimuth,
3521 double elevation)
3522{
3523 struct PointInfo{
3524 double x, y, z;
3525 };
3526
3527 double distance, normal_distance, shade;
3528 int x, y;
3529
3530 struct PointInfo light, normal;
3531
3532 unsigned int *q;
3533
3534 QImage dest(src.width(), src.height(), 32);
3535
3536 azimuth = DegreesToRadians(azimuth);
3537 elevation = DegreesToRadians(elevation);
3538 light.x = MaxRGB*cos(azimuth)*cos(elevation);
3539 light.y = MaxRGB*sin(azimuth)*cos(elevation);
3540 light.z = MaxRGB*sin(elevation);
3541 normal.z= 2*MaxRGB; // constant Z of surface normal
3542
3543 if(src.depth() > 8){ // DirectClass source image
3544 unsigned int *p, *s0, *s1, *s2;
3545 for(y=0; y < src.height(); ++y){
3546 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3547 q = (unsigned int *)dest.scanLine(y);
3548 // shade this row of pixels.
3549 *q++=(*(p+src.width()));
3550 p++;
3551 s0 = p;
3552 s1 = p + src.width();
3553 s2 = p + 2*src.width();
3554 for(x=1; x < src.width()-1; ++x){
3555 // determine the surface normal and compute shading.
3556 normal.x=intensityValue(*(s0-1))+intensityValue(*(s1-1))+intensityValue(*(s2-1))-
3557 (double) intensityValue(*(s0+1))-(double) intensityValue(*(s1+1))-
3558 (double) intensityValue(*(s2+1));
3559 normal.y=intensityValue(*(s2-1))+intensityValue(*s2)+intensityValue(*(s2+1))-
3560 (double) intensityValue(*(s0-1))-(double) intensityValue(*s0)-
3561 (double) intensityValue(*(s0+1));
3562 if((normal.x == 0) && (normal.y == 0))
3563 shade=light.z;
3564 else{
3565 shade=0.0;
3566 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3567 if (distance > 0.0){
3568 normal_distance=
3569 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
3570 if(fabs(normal_distance) > 0.0000001)
3571 shade=distance/sqrt(normal_distance);
3572 }
3573 }
3574 if(!color_shading){
3575 *q = qRgba((unsigned char)(shade),
3576 (unsigned char)(shade),
3577 (unsigned char)(shade),
3578 qAlpha(*s1));
3579 }
3580 else{
3581 *q = qRgba((unsigned char)((shade*qRed(*s1))/(MaxRGB+1)),
3582 (unsigned char)((shade*qGreen(*s1))/(MaxRGB+1)),
3583 (unsigned char)((shade*qBlue(*s1))/(MaxRGB+1)),
3584 qAlpha(*s1));
3585 }
3586 ++s0;
3587 ++s1;
3588 ++s2;
3589 q++;
3590 }
3591 *q++=(*s1);
3592 }
3593 }
3594 else{ // PsudeoClass source image
3595 unsigned char *p, *s0, *s1, *s2;
3596 int scanLineIdx;
3597 unsigned int *cTable = (unsigned int *)src.colorTable();
3598 for(y=0; y < src.height(); ++y){
3599 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3600 p = (unsigned char *)src.scanLine(scanLineIdx);
3601 q = (unsigned int *)dest.scanLine(y);
3602 // shade this row of pixels.
3603 s0 = p;
3604 s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
3605 s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
3606 *q++=(*(cTable+(*s1)));
3607 ++p;
3608 ++s0;
3609 ++s1;
3610 ++s2;
3611 for(x=1; x < src.width()-1; ++x){
3612 // determine the surface normal and compute shading.
3613 normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
3614 (double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
3615 (double) intensityValue(*(cTable+(*(s2+1))));
3616 normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
3617 (double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
3618 (double) intensityValue(*(cTable+(*(s0+1))));
3619 if((normal.x == 0) && (normal.y == 0))
3620 shade=light.z;
3621 else{
3622 shade=0.0;
3623 distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3624 if (distance > 0.0){
3625 normal_distance=
3626 normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
3627 if(fabs(normal_distance) > 0.0000001)
3628 shade=distance/sqrt(normal_distance);
3629 }
3630 }
3631 if(!color_shading){
3632 *q = qRgba((unsigned char)(shade),
3633 (unsigned char)(shade),
3634 (unsigned char)(shade),
3635 qAlpha(*(cTable+(*s1))));
3636 }
3637 else{
3638 *q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
3639 (unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
3640 (unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
3641 qAlpha(*s1));
3642 }
3643 ++s0;
3644 ++s1;
3645 ++s2;
3646 q++;
3647 }
3648 *q++=(*(cTable+(*s1)));
3649 }
3650 }
3651 return(dest);
3652}
3653
3654QImage OImageEffect::blur(QImage &src, double factor)
3655{
3656
3657#define Blur(weight) \
3658 total_red+=(weight)*qRed(*s); \
3659 total_green+=(weight)*qGreen(*s); \
3660 total_blue+=(weight)*qBlue(*s); \
3661 total_opacity+=(weight)*qAlpha(*s); \
3662 s++;
3663
3664#define Blur256(weight) \
3665 total_red+=(weight)*qRed(*(cTable+(*s))); \
3666 total_green+=(weight)*qGreen(*(cTable+(*s))); \
3667 total_blue+=(weight)*qBlue(*(cTable+(*s))); \
3668 total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
3669 s++;
3670
3671 if(src.width() < 3 || src.height() < 3)
3672 return(src);
3673
3674 double quantum, total_blue, total_green, total_opacity, total_red, weight;
3675
3676 int x, y;
3677 unsigned int *q;
3678
3679 QImage dest(src.width(), src.height(), 32);
3680 weight=((100.0-factor)/2)+1;
3681 quantum = QMAX(weight+12.0, 1.0);
3682 if(src.depth() > 8){ // DirectClass source image
3683 unsigned int *p, *s;
3684 for(y=0; y < src.height(); ++y){
3685 p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
3686 q = (unsigned int *)dest.scanLine(y);
3687 // blur this row of pixels.
3688 *q++=(*(p+src.width()));
3689 for(x=1; x < src.width()-1; ++x){
3690 // compute weighted average of target pixel color components.
3691 total_red=0.0;
3692 total_green=0.0;
3693 total_blue=0.0;
3694 total_opacity=0.0;
3695 s=p;
3696 Blur(1); Blur(2); Blur(1);
3697 s=p+src.width();
3698 Blur(2); Blur(weight); Blur(2);
3699 s=p+2*src.width();
3700 Blur(1); Blur(2); Blur(1);
3701 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
3702 (unsigned char)((total_green+(quantum/2))/quantum),
3703 (unsigned char)((total_blue+(quantum/2))/quantum),
3704 (unsigned char)((total_opacity+(quantum/2))/quantum));
3705 p++;
3706 q++;
3707 }
3708 p++;
3709 *q++=(*p);
3710 }
3711 }
3712 else{ // PsudeoClass source image
3713 unsigned char *p, *p2, *p3, *s;
3714 unsigned int *cTable = src.colorTable();
3715 int scanLineIdx;
3716 for(y=0; y < src.height(); ++y){
3717 scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
3718 p = (unsigned char *)src.scanLine(scanLineIdx);
3719 p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
3720 p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
3721 q = (unsigned int *)dest.scanLine(y);
3722 // blur this row of pixels.
3723 *q++=(*(cTable+(*p2)));
3724 for(x=1; x < src.width()-1; ++x){
3725 // compute weighted average of target pixel color components.
3726 total_red=0.0;
3727 total_green=0.0;
3728 total_blue=0.0;
3729 total_opacity=0.0;
3730 s=p;
3731 Blur256(1); Blur256(2); Blur256(1);
3732 s=p2;
3733 Blur256(2); Blur256(weight); Blur256(2);
3734 s=p3;
3735 Blur256(1); Blur256(2); Blur256(1);
3736 *q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
3737 (unsigned char)((total_green+(quantum/2))/quantum),
3738 (unsigned char)((total_blue+(quantum/2))/quantum),
3739 (unsigned char)((total_opacity+(quantum/2))/quantum));
3740 p++;
3741 p2++;
3742 p3++;
3743 q++;
3744 }
3745 p++;
3746 *q++=(*(cTable+(*p)));
3747 }
3748 }
3749 return(dest);
3750}
3751
3752// High quality, expensive HSV contrast. You can do a faster one by just
3753// taking a grayscale threshold (ie: 128) and incrementing RGB color
3754// channels above it and decrementing those below it, but this gives much
3755// better results. (mosfet 12/28/01)
3756void OImageEffect::contrastHSV(QImage &img, bool sharpen)
3757{
3758 int i, sign;
3759 unsigned int *data;
3760 int count;
3761 double brightness, scale, theta;
3762 QColor c;
3763 int h, s, v;
3764
3765 sign = sharpen ? 1 : -1;
3766 scale=0.5000000000000001;
3767 if(img.depth() > 8){
3768 count = img.width()*img.height();
3769 data = (unsigned int *)img.bits();
3770 }
3771 else{
3772 count = img.numColors();
3773 data = (unsigned int *)img.colorTable();
3774 }
3775 for(i=0; i < count; ++i){
3776 c.setRgb(data[i]);
3777 c.hsv(&h, &s, &v);
3778 brightness = v/255.0;
3779 theta=(brightness-0.5)*M_PI;
3780 brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
3781 if (brightness > 1.0)
3782 brightness=1.0;
3783 else
3784 if (brightness < 0)
3785 brightness=0.0;
3786 v = (int)(brightness*255);
3787 c.setHsv(h, s, v);
3788 data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
3789 }
3790}
3791
3792
3793
3794
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 @@
1//FIXME: Revise for Opie - do we really need such fancy stuff on PDA's?
2//FIXME: Maybe not on SL5xxx, but surely on C700 :))
3
4/* This file is part of the KDE libraries
5 Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@interaccess.com>
6 (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
7 (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
8
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions
11are met:
12
131. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
152. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18
19THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30*/
31
32// $Id$
33
34#ifndef OIMAGEEFFECT_H
35#define OIMAGEEFFECT_H
36
37class QImage;
38class QSize;
39class QColor;
40
41/**
42 * This class includes various @ref QImage based graphical effects.
43 *
44 * Everything is
45 * static, so there is no need to create an instance of this class. You can
46 * just call the static methods. They are encapsulated here merely to provide
47 * a common namespace.
48 */
49
50class OImageEffect
51{
52public:
53 enum GradientType { VerticalGradient, HorizontalGradient,
54 DiagonalGradient, CrossDiagonalGradient,
55 PyramidGradient, RectangleGradient,
56 PipeCrossGradient, EllipticGradient };
57 enum RGBComponent { Red, Green, Blue, Gray, All };
58
59 enum Lighting {NorthLite, NWLite, WestLite, SWLite,
60 SouthLite, SELite, EastLite, NELite};
61
62 enum ModulationType { Intensity, Saturation, HueShift, Contrast };
63
64 enum NoiseType { UniformNoise=0, GaussianNoise, MultiplicativeGaussianNoise,
65 ImpulseNoise, LaplacianNoise, PoissonNoise};
66
67 enum RotateDirection{ Rotate90, Rotate180, Rotate270 };
68
69 /**
70 * Create a gradient from color a to color b of the specified type.
71 *
72 * @param size The desired size of the gradient.
73 * @param ca Color a
74 * @param cb Color b
75 * @param type The type of gradient.
76 * @param ncols The number of colors to use when not running on a
77 * truecolor display. The gradient will be dithered to this number of
78 * colors. Pass 0 to prevent dithering.
79 */
80 static QImage gradient(const QSize &size, const QColor &ca,
81 const QColor &cb, GradientType type, int ncols=3);
82
83 /**
84 * Create an unbalanced gradient.
85
86 * An unbalanced gradient is a gradient where the transition from
87 * color a to color b is not linear, but in this case, exponential.
88 *
89 * @param size The desired size of the gradient.
90 * @param ca Color a
91 * @param cb Color b
92 * @param type The type of gradient.
93 * @param xfactor The x decay length. Use a value between -200 and 200.
94 * @param yfactor The y decay length.
95 * @param ncols The number of colors. See OPixmapEffect:gradient.
96 */
97 static QImage unbalancedGradient(const QSize &size, const QColor &ca,
98 const QColor &cb, GradientType type, int xfactor = 100,
99 int yfactor = 100, int ncols = 3);
100
101 /**
102 * Blends a color into the destination image, using an opacity
103 * value for blending one into another. Very fast direct pixel
104 * manipulation is used.
105 *
106 * @author Karol Szwed (gallium@kde.org)
107 * @param clr source color to be blended into the destination image.
108 * @param dst destination image in which the source will be blended into.
109 * @param opacity opacity (in percent) which determines how much the source
110 * color will be blended into the destination image.
111 * @return The destination image (dst) containing the result.
112 */
113 static QImage& blend(const QColor& clr, QImage& dst, float opacity);
114
115 /**
116 * Blend the src image into the destination image, using an opacity
117 * value for blending one into another. Very fast direct pixel
118 * manipulation is used.
119 *
120 * @author Karol Szwed (gallium@kde.org)
121 * @param src source image to be blended into the destination image.
122 * @param dst destination image in which the source will be blended into.
123 * @param opacity opacity (in percent) which determines how much the source
124 * image will be blended into the destination image.
125 * @return The destination image (dst) containing the result.
126 */
127 static QImage& blend(QImage& src, QImage& dst, float opacity);
128
129 /**
130 * Blend the provided image into a background of the indicated color.
131 *
132 * @param initial_intensity this parameter takes values from -1 to 1:
133 * a) if positive: how much to fade the image in its
134 * less affected spot
135 * b) if negative: roughly indicates how much of the image
136 * remains unaffected
137 * @param bgnd indicates the color of the background to blend in
138 * @param eff lets you choose what kind of blending you like
139 * @param anti_dir blend in the opposite direction (makes no much sense
140 * with concentric blending effects)
141 * @param image must be 32bpp
142 */
143 static QImage& blend(QImage &image, float initial_intensity,
144 const QColor &bgnd, GradientType eff,
145 bool anti_dir=false);
146
147 /**
148 * Blend an image into another one, using a gradient type
149 * for blending from one to another.
150 *
151 * @param image1 source1 and result of blending
152 * @param image2 source2 of blending
153 * @param gt gradient type for blending between source1 and source2
154 * @param xf x decay length for unbalanced gradient tpye
155 * @param yf y decay length for unbalanced gradient tpye
156 */
157 static QImage& blend(QImage &image1,QImage &image2,
158 GradientType gt, int xf=100, int yf=100);
159
160 /**
161 * Blend an image into another one, using a color channel of a
162 * third image for the decision of blending from one to another.
163 *
164 * @param image1 Source 1 and result of blending
165 * @param image2 Source 2 of blending
166 * @param blendImage If the gray value of of pixel is 0, the result
167 * for this pixel is that of image1; for a gray value
168 * of 1, the pixel of image2 is used; for a value
169 * inbetween, a corresponding blending is used.
170 * @param channel The RBG channel to use for the blending decision.
171 */
172 static QImage& blend(QImage &image1, QImage &image2,
173 QImage &blendImage, RGBComponent channel);
174
175 /**
176 * Blend an image into another one, using alpha in the expected way.
177 * @author Rik Hemsley (rikkus) <rik@kde.org>
178 */
179 static bool blend(const QImage & upper, const QImage & lower, QImage & output);
180// Not yet... static bool blend(const QImage & image1, const QImage & image2, QImage & output, const QRect & destRect);
181
182 /**
183 * Blend an image into another one, using alpha in the expected way and
184 * over coordinates @p x and @p y with respect to the lower image.
185 * The output is a QImage which is the @p upper image already blended
186 * with the @p lower one, so its size will be (in general) the same than
187 * @p upper instead of the same size than @p lower like the method above.
188 * In fact, the size of @p output is like upper's one only when it can be
189 * painted on lower, if there has to be some clipping, output's size will
190 * be the clipped area and x and y will be set to the correct up-left corner
191 * where the clipped rectangle begins.
192 */
193 static bool blend(int &x, int &y, const QImage & upper, const QImage & lower, QImage & output);
194 /**
195 * Blend an image into another one, using alpha in the expected way and
196 * over coordinates @p x and @p y with respect to the lower image.
197 * The output is painted in the own @p lower image. This is an optimization
198 * of the blend method above provided by convenience.
199 */
200 static bool blendOnLower(int x, int y, const QImage & upper, const QImage & lower);
201
202 /**
203 * Modifies the intensity of a pixmap's RGB channel component.
204 *
205 * @author Daniel M. Duley (mosfet)
206 * @param image The QImage to process.
207 * @param percent Percent value. Use a negative value to dim.
208 * @param channel Which channel(s) should be modified
209 * @return The @p image, provided for convenience.
210 */
211 static QImage& channelIntensity(QImage &image, float percent,
212 RGBComponent channel);
213
214 /**
215 * Fade an image to a certain background color.
216 *
217 * The number of colors will not be changed.
218 *
219 * @param image The QImage to process.
220 * @param val The strength of the effect. 0 <= val <= 1.
221 * @param color The background color.
222 * @return Returns the @ref image(), provided for convenience.
223 */
224 static QImage& fade(QImage &img, float val, const QColor &color);
225
226
227 /**
228 * This recolors a pixmap. The most dark color will become color a,
229 * the most bright one color b, and in between.
230 *
231 * @param image A QImage to process.
232 * @param ca Color a
233 * @param cb Color b
234 */
235 static QImage& flatten(QImage &image, const QColor &ca,
236 const QColor &cb, int ncols=0);
237
238 /**
239 * Build a hash on any given @ref QImage
240 *
241 * @param image The QImage to process
242 * @param lite The hash faces the indicated lighting (cardinal poles).
243 * @param spacing How many unmodified pixels inbetween hashes.
244 * @return Returns the @ref image(), provided for convenience.
245 */
246 static QImage& hash(QImage &image, Lighting lite=NorthLite,
247 unsigned int spacing=0);
248
249 /**
250 * Either brighten or dim the image by a specified percent.
251 * For example, .50 will modify the colors by 50%.
252 *
253 * @author Daniel M. Duley (mosfet)
254 * @param image The QImage to process.
255 * @param percent The percent value. Use a negative value to dim.
256 * @return Returns The @ref image(), provided for convenience.
257 */
258 static QImage& intensity(QImage &image, float percent);
259
260 /**
261 * Modulate the image with a color channel of another image.
262 *
263 * @param image The QImage to modulate and result.
264 * @param modImage The QImage to use for modulation.
265 * @param reverse Invert the meaning of image/modImage; result is image!
266 * @param type The modulation Type to use.
267 * @param factor The modulation amplitude; with 0 no effect [-200;200].
268 * @param channel The RBG channel of image2 to use for modulation.
269 * @return Returns the @ref image(), provided for convenience.
270 */
271 static QImage& modulate(QImage &image, QImage &modImage, bool reverse,
272 ModulationType type, int factor, RGBComponent channel);
273
274 /**
275 * Convert an image to grayscale.
276 *
277 * @author Daniel M. Duley (mosfet)
278 * @param image The @ref QImage to process.
279 * @param fast Set to @p true in order to use a faster but non-photographic
280 * quality algorithm. Appropriate for things such as toolbar icons.
281 * @return Returns the @ref image(), provided for convenience.
282 */
283 static QImage& toGray(QImage &image, bool fast = false);
284
285 /**
286 * Desaturate an image evenly.
287 *
288 * @param image The QImage to process.
289 * @param desat A value between 0 and 1 setting the degree of desaturation
290 * @return Returns the @ref image(), provided for convenience.
291 */
292 static QImage& desaturate(QImage &image, float desat = 0.3);
293
294 /**
295 * Fast, but low quality contrast of an image. Also see contrastHSV.
296 *
297 * @author Daniel M. Duley (mosfet)
298 * @param image The QImage to process.
299 * @param c A contrast value between -255 to 255.
300 * @return The @ref image(), provided for convenience.
301 */
302 static QImage& contrast(QImage &image, int c);
303
304 /**
305 * Dither an image using Floyd-Steinberg dithering for low-color
306 * situations.
307 *
308 * @param image The QImage to process.
309 * @param palette The color palette to use
310 * @param size The size of the palette
311 * @return Returns the @ref image(), provided for convenience.
312 */
313 static QImage& dither(QImage &img, const QColor *palette, int size);
314
315 /**
316 * Calculate the image for a selected image, for instance a selected icon
317 * on the desktop.
318 * @param img the QImage to select
319 * @param col the selected color, usually from QColorGroup::highlight().
320 */
321 static QImage& selectedImage( QImage &img, const QColor &col );
322
323 /**
324 * High quality, expensive HSV contrast. You can do a faster one by just
325 * taking a intensity threshold (ie: 128) and incrementing RGB color
326 * channels above it and decrementing those below it, but this gives much
327 * better results.
328 *
329 * @author Daniel M. Duley (mosfet)
330 * @param img The QImage to process.
331 * @param sharpen If true sharpness is increase, (spiffed). Otherwise
332 * it is decreased, (dulled).
333 */
334 static void contrastHSV(QImage &img, bool sharpen=true);
335
336 /**
337 * Normalizes the pixel values to span the full range of color values.
338 * This is a contrast enhancement technique.
339 * @author Daniel M. Duley (mosfet)
340 */
341 static void normalize(QImage &img);
342
343 /**
344 * Performs histogram equalization on the reference
345 * image.
346 * @author Daniel M. Duley (mosfet)
347 */
348 static void equalize(QImage &img);
349
350 /**
351 * Thresholds the reference image. You can also threshold images by using
352 * ThresholdDither in the various QPixmap/QImage convert methods, but this
353 * lets you specify a threshold value.
354 *
355 * @author Daniel M. Duley (mosfet)
356 * @param img The QImage to process.
357 * @param value The threshold value.
358 */
359 static void threshold(QImage &img, unsigned int value=128);
360
361 /**
362 * Produces a 'solarization' effect seen when exposing a photographic
363 * film to light during the development process.
364 *
365 * @author Daniel M. Duley (mosfet)
366 * @param img The QImage to process.
367 * @param factor The extent of the solarization (0-99.9)
368 */
369 static void solarize(QImage &img, double factor=50.0);
370
371 /**
372 * Embosses the source image. This involves highlighting the edges
373 * and applying various other enhancements in order to get a metal
374 * effect.
375 *
376 * @author Daniel M. Duley (mosfet)
377 * @param src The QImage to process.
378 * @return The embossed image. The original is not changed.
379 */
380 static QImage emboss(QImage &src);
381
382 /**
383 * Minimizes speckle noise in the source image using the 8 hull
384 * algorithm.
385 *
386 * @author Daniel M. Duley (mosfet)
387 * @param src The QImage to process.
388 * @return The despeckled image. The original is not changed.
389 */
390 static QImage despeckle(QImage &src);
391
392 /**
393 * Produces a neat little "charcoal" effect.
394 *
395 * @author Daniel M. Duley (mosfet)
396 * @param src The QImage to process.
397 * @param factor The factor for detecting lines (0-99.0).
398 * @return The charcoal image. The original is not changed.
399 */
400 static QImage charcoal(QImage &src, double factor=50.0);
401
402 /**
403 * Rotates the image by the specified amount
404 *
405 * @author Daniel M. Duley (mosfet)
406 * @param src The QImage to process.
407 * @param r The rotate direction.
408 * @return The rotated image. The original is not changed.
409 */
410 static QImage rotate(QImage &src, RotateDirection r);
411
412 /**
413 * Scales an image using simple pixel sampling. This does not produce
414 * nearly as nice a result as QImage::smoothScale(), but has the
415 * advantage of being much faster - only a few milliseconds.
416 *
417 * @author Daniel M. Duley (mosfet)
418 * @param src The QImage to process.
419 * @param w The new width.
420 * @param h The new height.
421 * @return The scaled image. The original is not changed.
422 */
423 static QImage sample(QImage &src, int w, int h);
424
425 /**
426 * Adds noise to an image.
427 *
428 * @author Daniel M. Duley (mosfet)
429 * @param src The QImage to process.
430 * @param type The algorithm used to generate the noise.
431 * @return The image with noise added. The original is not changed.
432 */
433 static QImage addNoise(QImage &src, NoiseType type = GaussianNoise);
434
435 /**
436 * Blurs an image by convolving pixel neighborhoods.
437 *
438 * @author Daniel M. Duley (mosfet)
439 * @param src The QImage to process.
440 * @param factor The percent weight to give to the center pixel.
441 * @return The blurred image. The original is not changed.
442 */
443 static QImage blur(QImage &src, double factor=50.0);
444
445 /**
446 * Detects edges in an image using pixel neighborhoods and an edge
447 * detection mask.
448 *
449 * @author Daniel M. Duley (mosfet)
450 * @param src The QImage to process.
451 * @param factor The percent weight to give to the center pixel.
452 * @return The image with edges detected. The original is not changed.
453 */
454 static QImage edge(QImage &src, double factor=50.0);
455
456 /**
457 * Implodes an image by a specified percent.
458 *
459 * @author Daniel M. Duley (mosfet)
460 * @param src The QImage to process.
461 * @param factor The extent of the implosion.
462 * @param background An RGBA value to use for the background. After the
463 * effect some pixels may be "empty". This value is used for those pixels.
464 * @return The imploded image. The original is not changed.
465 */
466 static QImage implode(QImage &src, double factor=30.0,
467 unsigned int background = 0xFFFFFFFF);
468 /**
469 * Produces an oil painting effect.
470 *
471 * @author Daniel M. Duley (mosfet)
472 * @param src The QImage to process.
473 * @param radius The radius of the pixel neighborhood used in applying the
474 * effect.
475 * @return The new image. The original is not changed.
476 */
477 static QImage oilPaint(QImage &src, int radius=3);
478
479 /**
480 * Sharpens the pixels in the image using pixel neighborhoods.
481 *
482 * @author Daniel M. Duley (mosfet)
483 * @param src The QImage to process.
484 * @param factor The percent weight to give to the center pixel.
485 * @return The sharpened image. The original is not changed.
486 */
487 static QImage sharpen(QImage &src, double factor=30.0);
488
489 /**
490 * Randomly displaces pixels.
491 *
492 * @author Daniel M. Duley (mosfet)
493 * @param src The QImage to process.
494 * @param amount The vicinity for choosing a random pixel to swap.
495 * @return The image with pixels displaced. The original is not changed.
496 */
497 static QImage spread(QImage &src, unsigned int amount=3);
498
499 /**
500 * Shades the image using a distance light source.
501 *
502 * @author Daniel M. Duley (mosfet)
503 * @param src The QImage to process.
504 * @param color_shading If true do color shading, otherwise do grayscale.
505 * @param azimuth Determines the light source and direction.
506 * @param elevation Determines the light source and direction.
507 * @return The shaded image. The original is not changed.
508 */
509 static QImage shade(QImage &src, bool color_shading=true, double azimuth=30.0,
510 double elevation=30.0);
511 /**
512 * Swirls the image by a specified amount
513 *
514 * @author Daniel M. Duley (mosfet)
515 * @param src The QImage to process.
516 * @param degrees The tightness of the swirl.
517 * @param background An RGBA value to use for the background. After the
518 * effect some pixels may be "empty". This value is used for those pixels.
519 * @return The swirled image. The original is not changed.
520 */
521 static QImage swirl(QImage &src, double degrees=50.0, unsigned int background =
522 0xFFFFFFFF);
523
524 /**
525 * Modifies the pixels along a sine wave.
526 *
527 * @author Daniel M. Duley (mosfet)
528 * @param src The QImage to process.
529 * @param amplitude The amplitude of the sine wave.
530 * @param wavelength The frequency of the sine wave.
531 * @return The new image. The original is not changed.
532 */
533 static QImage wave(QImage &src, double amplitude=25.0, double frequency=150.0,
534 unsigned int background = 0xFFFFFFFF);
535
536private:
537
538 /**
539 * Helper function to fast calc some altered (lighten, shaded) colors
540 *
541 */
542 static unsigned int lHash(unsigned int c);
543 static unsigned int uHash(unsigned int c);
544
545 /**
546 * Helper function to find the nearest color to the RBG triplet
547 */
548 static int nearestColor( int r, int g, int b, const QColor *pal, int size );
549
550 static void hull(const int x_offset, const int y_offset, const int polarity,
551 const int width, const int height,
552 unsigned int *f, unsigned int *g);
553 static unsigned int generateNoise(unsigned int pixel, NoiseType type);
554 static unsigned int interpolateColor(QImage *image, double x, double y,
555 unsigned int background);
556};
557
558#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 @@
1/*
2                 This file is part of the Opie Project
3
4 =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28
29*/
30
31/* QT */
32
33#include <qcolor.h>
34#include <qheader.h>
35#include <qpainter.h>
36#include <qpixmap.h>
37
38/* OPIE */
39
40#include <opie2/olistview.h>
41
42/*======================================================================================
43 * OListView
44 *======================================================================================*/
45
46OListView::OListView( QWidget *parent, const char *name )
47 :QListView( parent, name )
48{
49 //FIXME: get from global settings and calculate ==> see oglobalsettings.*
50
51 m_alternateBackground = QColor( 238, 246, 255 );
52 m_columnSeparator = QPen( QColor( 150, 160, 170 ), 0, DotLine );
53 m_fullWidth = true;
54}
55
56OListView::~OListView()
57{
58}
59
60void OListView::setFullWidth( bool fullWidth )
61{
62 m_fullWidth = m_fullWidth;
63 #if QT_VERSION > 290
64 header()->setStretchEnabled( fullWidth, columns()-1 );
65 #endif
66}
67
68bool OListView::fullWidth() const
69{
70 return m_fullWidth;
71}
72
73int OListView::addColumn( const QString& label, int width )
74{
75 int result = QListView::addColumn( label, width );
76 #if QT_VERSION > 290
77 if (m_fullWidth) {
78 header()->setStretchEnabled( false, columns()-2 );
79 header()->setStretchEnabled( true, columns()-1 );
80 }
81 #endif
82 return result;
83}
84
85int OListView::addColumn( const QIconSet& iconset, const QString& label, int width )
86{
87 int result = QListView::addColumn( iconset, label, width );
88 #if QT_VERSION > 290
89 if (m_fullWidth) {
90 header()->setStretchEnabled( false, columns()-2 );
91 header()->setStretchEnabled( true, columns()-1 );
92 }
93 #endif
94 return result;
95}
96
97void OListView::removeColumn( int index )
98{
99 QListView::removeColumn(index);
100 #if QT_VERSION > 290
101 if ( m_fullWidth && index == columns() )
102 {
103 header()->setStretchEnabled( true, columns()-1 );
104 }
105 #endif
106}
107
108const QColor& OListView::alternateBackground() const
109{
110 return m_alternateBackground;
111}
112
113void OListView::setAlternateBackground( const QColor &c )
114{
115 m_alternateBackground = c;
116 repaint();
117}
118
119const QPen& OListView::columnSeparator() const
120{
121 return m_columnSeparator;
122}
123
124void OListView::setColumnSeparator( const QPen& p )
125{
126 m_columnSeparator = p;
127 repaint();
128}
129
130OListViewItem* OListView::childFactory()
131{
132 return new OListViewItem( this );
133}
134
135#ifndef QT_NO_DATASTREAM
136void OListView::serializeTo( QDataStream& s ) const
137{
138 #warning Caution... the binary format is still under construction...
139 qDebug( "storing OListView..." );
140
141 // store number of columns and the labels
142 s << columns();
143 for ( int i = 0; i < columns(); ++i )
144 s << columnText( i );
145
146 // calculate the number of top-level items to serialize
147 int items = 0;
148 QListViewItem* item = firstChild();
149 while ( item )
150 {
151 item = item->nextSibling();
152 items++;
153 }
154
155 // store number of items and the items itself
156 s << items;
157 item = firstChild();
158 for ( int i = 0; i < items; ++i )
159 {
160 s << *static_cast<OListViewItem*>( item );
161 item = item->nextSibling();
162 }
163
164 qDebug( "OListview stored." );
165}
166
167void OListView::serializeFrom( QDataStream& s )
168{
169 #warning Caution... the binary format is still under construction...
170 qDebug( "loading OListView..." );
171
172 int cols;
173 s >> cols;
174 qDebug( "read number of columns = %d", cols );
175
176 while ( columns() < cols ) addColumn( QString::null );
177
178 for ( int i = 0; i < cols; ++i )
179 {
180 QString coltext;
181 s >> coltext;
182 qDebug( "read text '%s' for column %d", (const char*) coltext, i );
183 setColumnText( i, coltext );
184 }
185
186 int items;
187 s >> items;
188 qDebug( "read number of items = %d", items );
189
190 for ( int i = 0; i < items; ++i )
191 {
192 OListViewItem* item = childFactory();
193 s >> *item;
194 }
195
196 qDebug( "OListView loaded." );
197
198}
199
200QDataStream& operator<<( QDataStream& s, const OListView& lv )
201{
202 lv.serializeTo( s );
203}
204
205QDataStream& operator>>( QDataStream& s, OListView& lv )
206{
207 lv.serializeFrom( s );
208}
209#endif // QT_NO_DATASTREAM
210
211/*======================================================================================
212 * OListViewItem
213 *======================================================================================*/
214
215OListViewItem::OListViewItem(QListView *parent)
216 : QListViewItem(parent)
217{
218 init();
219}
220
221OListViewItem::OListViewItem(QListViewItem *parent)
222 : QListViewItem(parent)
223{
224 init();
225}
226
227OListViewItem::OListViewItem(QListView *parent, QListViewItem *after)
228 : QListViewItem(parent, after)
229{
230 init();
231}
232
233OListViewItem::OListViewItem(QListViewItem *parent, QListViewItem *after)
234 : QListViewItem(parent, after)
235{
236 init();
237}
238
239OListViewItem::OListViewItem(QListView *parent,
240 QString label1, QString label2, QString label3, QString label4,
241 QString label5, QString label6, QString label7, QString label8)
242 : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8)
243{
244 init();
245}
246
247OListViewItem::OListViewItem(QListViewItem *parent,
248 QString label1, QString label2, QString label3, QString label4,
249 QString label5, QString label6, QString label7, QString label8)
250 : QListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8)
251{
252 init();
253}
254
255OListViewItem::OListViewItem(QListView *parent, QListViewItem *after,
256 QString label1, QString label2, QString label3, QString label4,
257 QString label5, QString label6, QString label7, QString label8)
258 : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8)
259{
260 init();
261}
262
263OListViewItem::OListViewItem(QListViewItem *parent, QListViewItem *after,
264 QString label1, QString label2, QString label3, QString label4,
265 QString label5, QString label6, QString label7, QString label8)
266 : QListViewItem(parent, after, label1, label2, label3, label4, label5, label6, label7, label8)
267{
268 init();
269}
270
271OListViewItem::~OListViewItem()
272{
273}
274
275void OListViewItem::init()
276{
277 m_known = false;
278}
279
280const QColor &OListViewItem::backgroundColor()
281{
282 return isAlternate() ? static_cast<OListView*>(listView())->alternateBackground() :
283 listView()->viewport()->colorGroup().base();
284}
285
286bool OListViewItem::isAlternate()
287{
288 OListView *lv = static_cast<OListView*>( listView() );
289
290 // check if the item above is an OListViewItem
291 OListViewItem *above = static_cast<OListViewItem*>( itemAbove() );
292 /*if (! itemAbove()->inherits( "OListViewItem" )) return false;*/
293
294 // check if we have a valid alternate background color
295 if (!(lv && lv->alternateBackground().isValid())) return false;
296
297 m_known = above ? above->m_known : true;
298 if (m_known)
299 {
300 m_odd = above ? !above->m_odd : false;
301 }
302 else
303 {
304 OListViewItem *item;
305 bool previous = true;
306 if (parent())
307 {
308 item = static_cast<OListViewItem *>(parent());
309 if ( item /*&& item->inherits( "OListViewItem" )*/ ) previous = item->m_odd;
310 item = static_cast<OListViewItem *>(parent()->firstChild());
311 /* if ( !item.inherits( "OListViewItem" ) item = 0; */
312 }
313 else
314 {
315 item = static_cast<OListViewItem *>(lv->firstChild());
316 }
317
318 while(item)
319 {
320 item->m_odd = previous = !previous;
321 item->m_known = true;
322 item = static_cast<OListViewItem *>(item->nextSibling());
323 /* if (!item.inherits( "OListViewItem" ) ) break; */
324 }
325 }
326 return m_odd;
327}
328
329void OListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
330{
331 QColorGroup _cg = cg;
332 const QPixmap *pm = listView()->viewport()->backgroundPixmap();
333 if (pm && !pm->isNull())
334 {
335 _cg.setBrush( QColorGroup::Base, QBrush(backgroundColor(), *pm) );
336 p->setBrushOrigin( -listView()->contentsX(), -listView()->contentsY() );
337 }
338 else if ( isAlternate() )
339 {
340 _cg.setColor( QColorGroup::Base, static_cast<OListView*>( listView() )->alternateBackground() );
341 }
342 QListViewItem::paintCell( p, _cg, column, width, alignment );
343
344 //FIXME: Use styling here!
345
346 const QPen& pen = static_cast<OListView*>( listView() )->columnSeparator();
347 p->setPen( pen );
348 p->drawLine( width-1, 0, width-1, height() );
349}
350
351OListViewItem* OListViewItem::childFactory()
352{
353 return new OListViewItem( this );
354}
355
356#ifndef QT_NO_DATASTREAM
357void OListViewItem::serializeTo( QDataStream& s ) const
358{
359 #warning Caution... the binary format is still under construction...
360 qDebug( "storing OListViewItem..." );
361
362 // store item text
363 for ( int i = 0; i < listView()->columns(); ++i )
364 {
365 s << text( i );
366 }
367
368 // calculate the number of children to serialize
369 int items = 0;
370 QListViewItem* item = firstChild();
371 while ( item )
372 {
373 item = item->nextSibling();
374 items++;
375 }
376
377 // store number of items and the items itself
378 s << items;
379 item = firstChild();
380 for ( int i = 0; i < items; ++i )
381 {
382 s << *static_cast<OListViewItem*>( item );
383 item = item->nextSibling();
384 }
385
386 qDebug( "OListviewItem stored." );
387}
388void OListViewItem::serializeFrom( QDataStream& s )
389{
390 #warning Caution... the binary format is still under construction...
391 qDebug( "loading OListViewItem..." );
392
393 for ( int i = 0; i < listView()->columns(); ++i )
394 {
395 QString coltext;
396 s >> coltext;
397 qDebug( "read text '%s' for column %d", (const char*) coltext, i );
398 setText( i, coltext );
399 }
400
401 int items;
402 s >> items;
403 qDebug( "read number of items = %d", items );
404
405 for ( int i = 0; i < items; ++i )
406 {
407 OListViewItem* item = childFactory();
408 s >> (*item);
409 }
410
411 qDebug( "OListViewItem loaded." );
412}
413
414QDataStream& operator<<( QDataStream& s, const OListViewItem& lvi )
415{
416 lvi.serializeTo( s );
417}
418
419QDataStream& operator>>( QDataStream& s, OListViewItem& lvi )
420{
421 lvi.serializeFrom( s );
422}
423#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 @@
1/*
2                 This file is part of the Opie Project
3
4 =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28
29*/
30
31#ifndef OLISTVIEW_H
32#define OLISTVIEW_H
33
34#include <qcolor.h>
35#include <qlistview.h>
36#include <qpen.h>
37#include <qdatastream.h>
38
39class OListViewItem;
40
41/**
42 * A @ref QListView variant featuring visual and functional enhancements
43 * like an alternate background for odd rows, an autostretch mode
44 * for the width of the widget ( >= Qt 3 only ) and persistence capabilities.
45 *
46 * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
47 * @short OListView list/tree widget.
48 */
49 class OListView: public QListView
50{
51 public:
52 /**
53 * Constructor.
54 *
55 * The parameters @p parent and @p name are handled by
56 * @ref QListView, as usual.
57 */
58 OListView ( QWidget *parent = 0, const char *name = 0 );
59
60 /**
61 * Destructor.
62 */
63 virtual ~OListView();
64
65 /**
66 * Let the last column fit exactly all the available width.
67 */
68 void setFullWidth( bool fullWidth );
69
70 /**
71 * Returns whether the last column is set to fit the available width.
72 */
73 bool fullWidth() const;
74
75 /**
76 * Reimplemented for full width support
77 */
78 virtual int addColumn( const QString& label, int width = -1 );
79
80 /**
81 * Reimplemented for full width support
82 */
83 virtual int addColumn( const QIconSet& iconset, const QString& label, int width = -1 );
84
85 /**
86 * Reimplemented for full width support
87 */
88 virtual void removeColumn(int index);
89
90 /**
91 * sets the alternate background background color.
92 * This only has an effect if the items are OListViewItems
93 *
94 * @param c the color to use for every other item. Set to an invalid
95 * color to disable alternate colors.
96 */
97 void setAlternateBackground( const QColor &c );
98
99 /**
100 * sets the column separator pen.
101 *
102 * @param p the pen used to draw the column separator.
103 */
104 void setColumnSeparator( const QPen &p );
105
106 /**
107 * @return the alternate background color
108 */
109 const QColor& alternateBackground() const;
110
111 /**
112 * @return the column separator pen
113 */
114 const QPen& columnSeparator() const;
115
116 /**
117 * create a list view item as child of this object
118 * @return the new object
119 */
120 virtual OListViewItem* childFactory();
121
122 #ifndef QT_NO_DATASTREAM
123 /**
124 * serialize this object to a @ref QDataStream
125 * @param s the stream used to serialize this object.
126 */
127 virtual void serializeTo( QDataStream& s ) const;
128
129 /**
130 * serialize this object from a @ref QDataStream
131 * @param s the stream used to serialize this object.
132 */
133 virtual void serializeFrom( QDataStream& s );
134 #endif
135
136 private:
137 QColor m_alternateBackground;
138 bool m_fullWidth;
139 QPen m_columnSeparator;
140};
141
142#ifndef QT_NO_DATASTREAM
143/**
144 * \relates QListView
145 * Writes a listview to the stream and returns a reference to the stream.
146 */
147QDataStream& operator<<( QDataStream& s, const OListView& lv );
148/**
149 * \relates QListView
150 * Reads a listview from the stream and returns a reference to the stream.
151 */
152QDataStream& operator>>( QDataStream& s, OListView& lv );
153#endif // QT_NO_DATASTREAM
154
155//****************************** OListViewItem ******************************************************************
156
157class OListViewItem: public QListViewItem
158{
159 public:
160 OListViewItem( QListView * parent );
161 OListViewItem( QListViewItem * parent );
162 OListViewItem( QListView * parent, QListViewItem * after );
163 OListViewItem( QListViewItem * parent, QListViewItem * after );
164
165 OListViewItem( QListView * parent,
166 QString, QString = QString::null,
167 QString = QString::null, QString = QString::null,
168 QString = QString::null, QString = QString::null,
169 QString = QString::null, QString = QString::null );
170
171 OListViewItem( QListViewItem * parent,
172 QString, QString = QString::null,
173 QString = QString::null, QString = QString::null,
174 QString = QString::null, QString = QString::null,
175 QString = QString::null, QString = QString::null );
176
177 OListViewItem( QListView * parent, QListViewItem * after,
178 QString, QString = QString::null,
179 QString = QString::null, QString = QString::null,
180 QString = QString::null, QString = QString::null,
181 QString = QString::null, QString = QString::null );
182
183 OListViewItem( QListViewItem * parent, QListViewItem * after,
184 QString, QString = QString::null,
185 QString = QString::null, QString = QString::null,
186 QString = QString::null, QString = QString::null,
187 QString = QString::null, QString = QString::null );
188
189 virtual ~OListViewItem();
190
191 const QColor& backgroundColor();
192 bool isAlternate();
193 void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int alignment );
194 void init();
195
196 /**
197 * create a list view item as child of this object
198 * @return the new object
199 */
200 virtual OListViewItem* childFactory();
201
202 #ifndef QT_NO_DATASTREAM
203 /**
204 * serialize this object to or from a @ref QDataStream
205 * @param s the stream used to serialize this object.
206 */
207 virtual void serializeTo( QDataStream& s ) const;
208
209 /**
210 * serialize this object to or from a @ref QDataStream
211 * @param s the stream used to serialize this object.
212 */
213 virtual void serializeFrom( QDataStream& s );
214 #endif
215
216 private:
217 bool m_known;
218 bool m_odd;
219};
220
221#ifndef QT_NO_DATASTREAM
222/**
223 * \relates QListViewItem
224 * Writes a listview item and all subitems recursively to the stream
225 * and returns a reference to the stream.
226 */
227QDataStream& operator<<( QDataStream &s, const OListViewItem& lvi );
228/**
229 * \relates QListViewItem
230 * Reads a listview item from the stream and returns a reference to the stream.
231 */
232QDataStream& operator>>( QDataStream &s, OListViewItem& lvi );
233#endif // QT_NO_DATASTREAM
234
235#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 @@
1TEMPLATE = lib
2CONFIG += qt warn_on debug
3DESTDIR = $(QTDIR)/lib
4HEADERS = ocompletionbox.h \
5 ocombobox.h \
6 oeditlistbox.h \
7 olineedit.h \
8 olistview.h \
9 oimageeffect.h \
10 opixmapeffect.h \
11 opopupmenu.h \
12 opixmapprovider.h \
13 oselector.h \
14 oversatileview.h \
15 oversatileviewitem.h \
16 #ojanuswidget.h \
17 odialog.h \
18 oseparator.h
19
20SOURCES = ocompletionbox.cpp \
21 ocombobox.cpp \
22 oeditlistbox.cpp \
23 olineedit.cpp \
24 olistview.cpp \
25 oimageeffect.cpp \
26 opixmapeffect.cpp \
27 opopupmenu.cpp \
28 opixmapprovider.cpp \
29 oselector.cpp \
30 oversatileview.cpp \
31 oversatileviewitem.cpp \
32 #ojanuswidget.cpp \
33 odialog.cpp \
34 oseparator.cpp
35
36INTERFACES =
37TARGET = opieui2
38VERSION = 1.8.1
39INCLUDEPATH += $(OPIEDIR)/include
40DEPENDPATH += $(OPIEDIR)/include
41LIBS += -lopiecore2
42MOC_DIR = moc
43OBJECTS_DIR = obj
44
45include ( $(OPIEDIR)/include.pro )
46
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 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
3 (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org>
4 (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
5
6*/
7
8// $Id$
9
10/* QT */
11
12#include <qimage.h>
13#include <qpainter.h>
14
15/* OPIE */
16
17#include <opie2/opixmapeffect.h>
18#include <opie2/oimageeffect.h>
19
20//======================================================================
21//
22// Gradient effects
23//
24//======================================================================
25
26
27OPixmap& OPixmapEffect::gradient(OPixmap &pixmap, const QColor &ca,
28 const QColor &cb, GradientType eff, int ncols)
29{
30 if(pixmap.depth() > 8 &&
31 (eff == VerticalGradient || eff == HorizontalGradient)) {
32
33 int rDiff, gDiff, bDiff;
34 int rca, gca, bca /*, rcb, gcb, bcb*/;
35
36 register int x, y;
37
38 rDiff = (/*rcb = */ cb.red()) - (rca = ca.red());
39 gDiff = (/*gcb = */ cb.green()) - (gca = ca.green());
40 bDiff = (/*bcb = */ cb.blue()) - (bca = ca.blue());
41
42 register int rl = rca << 16;
43 register int gl = gca << 16;
44 register int bl = bca << 16;
45
46 int rcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * rDiff;
47 int gcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * gDiff;
48 int bcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * bDiff;
49
50 QPainter p(&pixmap);
51
52 // these for-loops could be merged, but the if's in the inner loop
53 // would make it slow
54 switch(eff) {
55 case VerticalGradient:
56 for ( y = 0; y < pixmap.height(); y++ ) {
57 rl += rcdelta;
58 gl += gcdelta;
59 bl += bcdelta;
60
61 p.setPen(QColor(rl>>16, gl>>16, bl>>16));
62 p.drawLine(0, y, pixmap.width()-1, y);
63 }
64 break;
65 case HorizontalGradient:
66 for( x = 0; x < pixmap.width(); x++) {
67 rl += rcdelta;
68 gl += gcdelta;
69 bl += bcdelta;
70
71 p.setPen(QColor(rl>>16, gl>>16, bl>>16));
72 p.drawLine(x, 0, x, pixmap.height()-1);
73 }
74 break;
75 default:
76 ;
77 }
78 }
79 else {
80 QImage image = OImageEffect::gradient(pixmap.size(), ca, cb,
81 (OImageEffect::GradientType) eff, ncols);
82 pixmap.convertFromImage(image);
83 }
84
85 return pixmap;
86}
87
88
89// -----------------------------------------------------------------------------
90
91OPixmap& OPixmapEffect::unbalancedGradient(OPixmap &pixmap, const QColor &ca,
92 const QColor &cb, GradientType eff, int xfactor, int yfactor,
93 int ncols)
94{
95 QImage image = OImageEffect::unbalancedGradient(pixmap.size(), ca, cb,
96 (OImageEffect::GradientType) eff,
97 xfactor, yfactor, ncols);
98 pixmap.convertFromImage(image);
99
100 return pixmap;
101}
102
103
104//======================================================================
105//
106// Intensity effects
107//
108//======================================================================
109
110
111
112OPixmap& OPixmapEffect::intensity(OPixmap &pixmap, float percent)
113{
114 QImage image = pixmap.convertToImage();
115 OImageEffect::intensity(image, percent);
116 pixmap.convertFromImage(image);
117
118 return pixmap;
119}
120
121
122// -----------------------------------------------------------------------------
123
124OPixmap& OPixmapEffect::channelIntensity(OPixmap &pixmap, float percent,
125 RGBComponent channel)
126{
127 QImage image = pixmap.convertToImage();
128 OImageEffect::channelIntensity(image, percent,
129 (OImageEffect::RGBComponent) channel);
130 pixmap.convertFromImage(image);
131
132 return pixmap;
133}
134
135
136//======================================================================
137//
138// Blend effects
139//
140//======================================================================
141
142
143OPixmap& OPixmapEffect::blend(OPixmap &pixmap, float initial_intensity,
144 const QColor &bgnd, GradientType eff,
145 bool anti_dir, int ncols)
146{
147
148 QImage image = pixmap.convertToImage();
149 if (image.depth() <=8)
150 image = image.convertDepth(32); //Sloww..
151
152 OImageEffect::blend(image, initial_intensity, bgnd,
153 (OImageEffect::GradientType) eff, anti_dir);
154
155 unsigned int tmp;
156
157 if(pixmap.depth() <= 8 ) {
158 if ( ncols < 2 || ncols > 256 )
159 ncols = 3;
160 QColor *dPal = new QColor[ncols];
161 for (int i=0; i<ncols; i++) {
162 tmp = 0 + 255 * i / ( ncols - 1 );
163 dPal[i].setRgb ( tmp, tmp, tmp );
164 }
165 OImageEffect::dither(image, dPal, ncols);
166 pixmap.convertFromImage(image);
167 delete [] dPal;
168 }
169 else
170 pixmap.convertFromImage(image);
171
172 return pixmap;
173}
174
175
176//======================================================================
177//
178// Hash effects
179//
180//======================================================================
181
182OPixmap& OPixmapEffect::hash(OPixmap &pixmap, Lighting lite,
183 unsigned int spacing, int ncols)
184{
185 QImage image = pixmap.convertToImage();
186 OImageEffect::hash(image, (OImageEffect::Lighting) lite, spacing);
187
188 unsigned int tmp;
189
190 if(pixmap.depth() <= 8 ) {
191 if ( ncols < 2 || ncols > 256 )
192 ncols = 3;
193 QColor *dPal = new QColor[ncols];
194 for (int i=0; i<ncols; i++) {
195 tmp = 0 + 255 * i / ( ncols - 1 );
196 dPal[i].setRgb ( tmp, tmp, tmp );
197 }
198 OImageEffect::dither(image, dPal, ncols);
199 pixmap.convertFromImage(image);
200 delete [] dPal;
201 }
202 else
203 pixmap.convertFromImage(image);
204
205 return pixmap;
206}
207
208
209//======================================================================
210//
211// Pattern effects
212//
213//======================================================================
214
215#if 0
216void OPixmapEffect::pattern(OPixmap &pixmap, const QColor &ca,
217 const QColor &cb, unsigned pat[8])
218{
219 QImage img = pattern(pixmap.size(), ca, cb, pat);
220 pixmap.convertFromImage(img);
221}
222#endif
223
224// -----------------------------------------------------------------------------
225
226OPixmap OPixmapEffect::pattern(const OPixmap& pmtile, QSize size,
227 const QColor &ca, const QColor &cb, int ncols)
228{
229 if (pmtile.depth() > 8)
230 ncols = 0;
231
232 QImage img = pmtile.convertToImage();
233 OImageEffect::flatten(img, ca, cb, ncols);
234 OPixmap pixmap;
235 pixmap.convertFromImage(img);
236
237 return OPixmapEffect::createTiled(pixmap, size);
238}
239
240
241// -----------------------------------------------------------------------------
242
243OPixmap OPixmapEffect::createTiled(const OPixmap& pixmap, QSize size)
244{
245 OPixmap pix;
246
247 QPainter p(&pix);
248 p.drawTiledPixmap(0, 0, size.width(), size.height(), pixmap);
249
250 return pix;
251}
252
253
254//======================================================================
255//
256// Fade effects
257//
258//======================================================================
259
260OPixmap& OPixmapEffect::fade(OPixmap &pixmap, double val, const QColor &color)
261{
262 QImage img = pixmap.convertToImage();
263 OImageEffect::fade(img, val, color);
264 pixmap.convertFromImage(img);
265
266 return pixmap;
267}
268
269
270// -----------------------------------------------------------------------------
271OPixmap& OPixmapEffect::toGray(OPixmap &pixmap, bool fast)
272{
273 QImage img = pixmap.convertToImage();
274 OImageEffect::toGray(img, fast);
275 pixmap.convertFromImage(img);
276
277 return pixmap;
278}
279
280// -----------------------------------------------------------------------------
281OPixmap& OPixmapEffect::desaturate(OPixmap &pixmap, float desat)
282{
283 QImage img = pixmap.convertToImage();
284 OImageEffect::desaturate(img, desat);
285 pixmap.convertFromImage(img);
286
287 return pixmap;
288}
289// -----------------------------------------------------------------------------
290OPixmap& OPixmapEffect::contrast(OPixmap &pixmap, int c)
291{
292 QImage img = pixmap.convertToImage();
293 OImageEffect::contrast(img, c);
294 pixmap.convertFromImage(img);
295
296 return pixmap;
297}
298
299//======================================================================
300//
301// Dither effects
302//
303//======================================================================
304
305// -----------------------------------------------------------------------------
306OPixmap& OPixmapEffect::dither(OPixmap &pixmap, const QColor *palette, int size)
307{
308 QImage img = pixmap.convertToImage();
309 OImageEffect::dither(img, palette, size);
310 pixmap.convertFromImage(img);
311
312 return pixmap;
313}
314
315//======================================================================
316//
317// Other effects
318//
319//======================================================================
320
321OPixmap OPixmapEffect::selectedPixmap( const OPixmap &pix, const QColor &col )
322{
323 QImage img = pix.convertToImage();
324 OImageEffect::selectedImage(img, col);
325 OPixmap outPix;
326 outPix.convertFromImage(img);
327 return outPix;
328}
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 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
3 (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org>
4 (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
5
6*/
7
8// $Id$
9
10#ifndef __OPIXMAP_EFFECT_H
11#define __OPIXMAP_EFFECT_H
12
13
14#include <qsize.h>
15typedef QPixmap OPixmap;
16class QColor;
17
18/**
19 * This class includes various pixmap-based graphical effects.
20 *
21 * Everything is
22 * static, so there is no need to create an instance of this class. You can
23 * just call the static methods. They are encapsulated here merely to provide
24 * a common namespace.
25 */
26class OPixmapEffect
27{
28public:
29 enum GradientType { VerticalGradient, HorizontalGradient,
30 DiagonalGradient, CrossDiagonalGradient,
31 PyramidGradient, RectangleGradient,
32 PipeCrossGradient, EllipticGradient };
33 enum RGBComponent { Red, Green, Blue };
34
35 enum Lighting {NorthLite, NWLite, WestLite, SWLite,
36 SouthLite, SELite, EastLite, NELite};
37
38 /**
39 * Creates a gradient from color a to color b of the specified type.
40 *
41 * @param pixmap The pixmap to process.
42 * @param ca Color a.
43 * @param cb Color b.
44 * @param type The type of gradient.
45 * @param ncols The number of colors to use when not running on a
46 * truecolor display. The gradient will be dithered to this number of
47 * colors. Pass 0 to prevent dithering.
48 * @return Returns the generated pixmap, for convenience.
49 */
50 static OPixmap& gradient(OPixmap& pixmap, const QColor &ca, const QColor &cb,
51 GradientType type, int ncols=3);
52
53 /**
54 * Creates an unbalanced gradient.
55 *
56 * An unbalanced gradient is a gradient where the transition from
57 * color a to color b is not linear, but in this case, exponential.
58 *
59 * @param pixmap The pixmap that should be written.
60 * @param ca Color a.
61 * @param cb Color b.
62 * @param type The type of gradient.
63 * @param xfactor The x decay length. Use a value between -200 and 200.
64 * @param yfactor The y decay length.
65 * @param ncols The number of colors. See #gradient.
66 * @return The generated pixmap, for convencience.
67 */
68 static OPixmap& unbalancedGradient(OPixmap& pixmap, const QColor &ca,
69 const QColor &cb, GradientType type, int xfactor = 100,
70 int yfactor = 100, int ncols=3);
71
72 /**
73 * Creates a pixmap of a given size with the given pixmap.
74 *
75 * if the
76 * given size is bigger than the size of the pixmap, the pixmap is
77 * tiled.
78 *
79 * @param pixmap This is the source pixmap
80 * @param size The size the new pixmap should have.
81 * @return The generated, tiled pixmap.
82 */
83 static OPixmap createTiled(const OPixmap& pixmap, QSize size);
84
85 /**
86 * Either brightens or dims a pixmap by a specified ratio.
87 *
88 * @param pixmap The pixmap to process.
89 * @param ratio The ratio to use. Use negative value to dim.
90 * @return Returns The @ref pixmap(), provided for convenience.
91 */
92 static OPixmap& intensity(OPixmap& pixmap, float ratio);
93
94 /**
95 * Modifies the intensity of a pixmap's RGB channel component.
96 *
97 * @param pixmap The pixmap to process.
98 * @param ratio value. Use negative value to dim.
99 * @param channel Which channel(s) should be modified
100 * @return Returns the @ref pixmap(), provided for convenience.
101 */
102 static OPixmap& channelIntensity(OPixmap& pixmap, float ratio,
103 RGBComponent channel);
104
105 /**
106 * Blends the provided pixmap into a background of the indicated color.
107 *
108 * @param pixmap The pixmap to process.
109 * @param initial_intensity this parameter takes values from -1 to 1:
110 * @li If positive, it tells how much to fade the image in its
111 * less affected spot.
112 * @li If negative, it tells roughly indicates how much of the image
113 * remains unaffected
114 * @param bgnd Indicates the color of the background to blend in.
115 * @param eff Lets you choose what kind of blending you like.
116 * @param anti_dir Blend in the opposite direction (makes no much sense
117 * with concentric blending effects).
118 * @return Returns the @ref pixmap(), provided for convenience.
119 */
120 static OPixmap& blend(OPixmap& pixmap, float initial_intensity,
121 const QColor &bgnd, GradientType eff,
122 bool anti_dir=false, int ncols=3);
123
124 /**
125 * Builds a hash on any given pixmap.
126 *
127 * @param pixmap The pixmap to process.
128 * @param lite The hash faces the indicated lighting (cardinal poles)
129 * @param spacing How many unmodified pixels inbetween hashes.
130 * @return Returns The @ref pixmap(), provided for convenience.
131 */
132 static OPixmap& hash(OPixmap& pixmap, Lighting lite=NorthLite,
133 unsigned int spacing=0, int ncols=3);
134
135 /**
136 * Creates a pattern from a pixmap.
137 *
138 * The given pixmap is "flattened"
139 * between color a to color b.
140 *
141 * @param pixmap The pixmap to process.
142 * @param ca Color a.
143 * @param cb Color b.
144 * @param ncols The number of colors to use. The image will be
145 * dithered to this depth. Pass zero to prevent dithering.
146 * @return The @ref pixmap(), provided for convenience.
147 */
148 static OPixmap pattern(const OPixmap& pixmap, QSize size,
149 const QColor &ca, const QColor &cb, int ncols=8);
150
151 /**
152 * Recolors a pixmap.
153 *
154 * The most dark color will become color a,
155 * the most bright one color b, and in between.
156 *
157 * @param pixmap The pixmap to process.
158 * @param ca Color a.
159 * @param cb Color b.
160 * @param ncols The number of colors to use. Pass zero to prevent
161 * dithering.
162 * @return Returns the @ref pixmap(), provided for convenience.
163 */
164 static OPixmap& fade(OPixmap& pixmap, double val, const QColor &color);
165
166 /**
167 * Converts a pixmap to grayscale.
168 *
169 * @param pixmap The pixmap to process.
170 * @param fast Set to @p true in order to use a faster but non-photographic
171 * quality algorithm. Appropriate for things such as toolbar icons.
172 * @return Returns the @ref pixmap(), provided for convenience.
173 */
174 static OPixmap& toGray(OPixmap& pixmap, bool fast=false);
175
176 /**
177 * Desaturates a pixmap.
178 *
179 * @param pixmap The pixmap to process.
180 * @param desat A value between 0 and 1 setting the degree of desaturation
181 * @return Returns The @ref pixmap(), provided for convenience.
182 */
183 static OPixmap& desaturate(OPixmap& pixmap, float desat = 0.3);
184
185 /**
186 * Modifies the contrast of a pixmap.
187 *
188 * @param pixmap The pixmap to process.
189 * @param c A contrast value between -255 and 255.
190 * @return Returns the @ref pixmap(), provided for convenience.
191 */
192 static OPixmap& contrast(OPixmap& pixmap, int c);
193
194 /**
195 * Dithers a pixmap using Floyd-Steinberg dithering for low-color
196 * situations.
197 *
198 * @param pixmap The pixmap to process.
199 * @param palette The color palette to use.
200 * @param size The size of the palette.
201 * @return Returns the @ref pixmap(), provided for convenience.
202 */
203 static OPixmap& dither(OPixmap &pixmap, const QColor *palette, int size);
204
205 /**
206 * Calculate a 'selected' pixmap, for instance a selected icon
207 * on the desktop.
208 * @param pixmap the pixmap to select
209 * @param col the selected color, usually from QColorGroup::highlight().
210 */
211 static OPixmap selectedPixmap( const OPixmap &pixmap, const QColor &col );
212};
213
214
215#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 @@
1/* This file is part of the KDE libraries
2
3 Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License (LGPL) as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#include <opie2/opixmapprovider.h>
22
23OPixmapProvider::~OPixmapProvider() {}
24
25void OPixmapProvider::virtual_hook( int , void* )
26{ /*BASE::virtual_hook( id, data );*/ }
27
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 @@
1/* This file is part of the KDE libraries
2
3 Copyright (c) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License (LGPL) as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21#ifndef OPIXMAPPROVIDER_H
22#define OPIXMAPPROVIDER_H
23
24#include <qpixmap.h>
25
26/**
27 * A tiny abstract class with just one method:
28 * @ref pixmapFor()
29 *
30 * It will be called whenever an icon is searched for @p text.
31 *
32 * Used e.g. by @ref KHistoryCombo
33 *
34 * @author Carsten Pfeiffer <pfeiffer@kde.org>
35 * @short an abstract interface for looking up icons
36 */
37class OPixmapProvider
38{
39public:
40 virtual ~OPixmapProvider();
41 /**
42 * You may subclass this and return a pixmap of size @p size for @p text.
43 * @param text the text that is associated with the pixmap
44 * @param size the size of the icon in pixels, 0 for defaylt size.
45 * See @ref KIcon::StdSize.
46 * @return the pixmap for the arguments, or null if there is none
47 */
48 virtual QPixmap pixmapFor( const QString& text, int size = 0 ) = 0;
49protected:
50 virtual void virtual_hook( int id, void* data );
51};
52
53
54#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 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
3 Copyright (C) 2002 Hamish Rodda <meddie@yoyo.its.monash.edu.au>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19
20/* QT */
21
22#include <qapplication.h>
23#include <qcursor.h>
24#include <qpainter.h>
25#include <qdrawutil.h>
26#include <qtimer.h>
27#include <qfont.h>
28#include <qfontmetrics.h>
29#include <qregexp.h>
30#include <qstyle.h>
31
32/* OPIE */
33
34#include <opie2/opopupmenu.h>
35#include <opie2/oconfig.h>
36
37OPopupTitle::OPopupTitle(QWidget *parent, const char *name)
38 : QWidget(parent, name)
39{
40 setMinimumSize(16, fontMetrics().height()+8);
41}
42
43OPopupTitle::OPopupTitle(OPixmapEffect::GradientType /* gradient */,
44 const QColor &/* color */, const QColor &/* textColor */,
45 QWidget *parent, const char *name)
46 : QWidget(parent, name)
47{
48 setMinimumSize(16, fontMetrics().height()+8);
49}
50
51OPopupTitle::OPopupTitle(const OPixmap & /* background */, const QColor &/* color */,
52 const QColor &/* textColor */, QWidget *parent,
53 const char *name)
54 : QWidget(parent, name)
55{
56 setMinimumSize(16, fontMetrics().height()+8);
57}
58
59void OPopupTitle::setTitle(const QString &text, const QPixmap *icon)
60{
61 titleStr = text;
62 if (icon)
63 miniicon = *icon;
64 else
65 miniicon.resize(0, 0);
66
67 int w = miniicon.width()+fontMetrics().width(titleStr);
68 int h = QMAX( fontMetrics().height(), miniicon.height() );
69 setMinimumSize( w+16, h+8 );
70}
71
72void OPopupTitle::setText( const QString &text )
73{
74 titleStr = text;
75 int w = miniicon.width()+fontMetrics().width(titleStr);
76 int h = QMAX( fontMetrics().height(), miniicon.height() );
77 setMinimumSize( w+16, h+8 );
78}
79
80void OPopupTitle::setIcon( const QPixmap &pix )
81{
82 miniicon = pix;
83 int w = miniicon.width()+fontMetrics().width(titleStr);
84 int h = QMAX( fontMetrics().height(), miniicon.height() );
85 setMinimumSize( w+16, h+8 );
86}
87
88void OPopupTitle::paintEvent(QPaintEvent *)
89{
90 QRect r(rect());
91 QPainter p(this);
92 #if QT_VERSION > 290
93 qApp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active());
94 #else
95 #warning OPopupMenu is not fully functional on Qt2
96 #endif
97
98 if (!miniicon.isNull())
99 p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon);
100
101 if (!titleStr.isNull())
102 {
103 p.setPen(palette().active().text());
104 QFont f = p.font();
105 f.setBold(true);
106 p.setFont(f);
107 if(!miniicon.isNull())
108 {
109 p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8),
110 height(), AlignLeft | AlignVCenter | SingleLine,
111 titleStr);
112 }
113 else
114 {
115 p.drawText(0, 0, width(), height(),
116 AlignCenter | SingleLine, titleStr);
117 }
118 }
119
120 p.setPen(palette().active().highlight());
121 p.drawLine(0, 0, r.right(), 0);
122}
123
124QSize OPopupTitle::sizeHint() const
125{
126 return(minimumSize());
127}
128
129class OPopupMenu::OPopupMenuPrivate
130{
131public:
132 OPopupMenuPrivate ()
133 : noMatches(false)
134 , shortcuts(false)
135 , autoExec(false)
136 , lastHitIndex(-1)
137 , m_ctxMenu(0)
138 {}
139
140 ~OPopupMenuPrivate ()
141 {
142 delete m_ctxMenu;
143 }
144
145 QString m_lastTitle;
146
147 // variables for keyboard navigation
148 QTimer clearTimer;
149
150 bool noMatches : 1;
151 bool shortcuts : 1;
152 bool autoExec : 1;
153
154 QString keySeq;
155 QString originalText;
156
157 int lastHitIndex;
158
159 // support for RMB menus on menus
160 QPopupMenu* m_ctxMenu;
161 static bool s_continueCtxMenuShow;
162 static int s_highlightedItem;
163 static OPopupMenu* s_contextedMenu;
164};
165
166int OPopupMenu::OPopupMenuPrivate::s_highlightedItem(-1);
167OPopupMenu* OPopupMenu::OPopupMenuPrivate::s_contextedMenu(0);
168bool OPopupMenu::OPopupMenuPrivate::s_continueCtxMenuShow(true);
169
170OPopupMenu::OPopupMenu(QWidget *parent, const char *name)
171 : QPopupMenu(parent, name)
172{
173 d = new OPopupMenuPrivate;
174 resetKeyboardVars();
175 connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars()));
176}
177
178OPopupMenu::~OPopupMenu()
179{
180 if (OPopupMenuPrivate::s_contextedMenu == this)
181 {
182 OPopupMenuPrivate::s_contextedMenu = 0;
183 OPopupMenuPrivate::s_highlightedItem = -1;
184 }
185
186 delete d;
187}
188
189int OPopupMenu::insertTitle(const QString &text, int id, int index)
190{
191 OPopupTitle *titleItem = new OPopupTitle();
192 titleItem->setTitle(text);
193 int ret = insertItem(titleItem, id, index);
194 setItemEnabled(id, false);
195 return ret;
196}
197
198int OPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id,
199 int index)
200{
201 OPopupTitle *titleItem = new OPopupTitle();
202 titleItem->setTitle(text, &icon);
203 int ret = insertItem(titleItem, id, index);
204 setItemEnabled(id, false);
205 return ret;
206}
207
208void OPopupMenu::changeTitle(int id, const QString &text)
209{
210 QMenuItem *item = findItem(id);
211 if(item){
212 if(item->widget())
213 ((OPopupTitle *)item->widget())->setTitle(text);
214#ifndef NDEBUG
215 else
216 qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id );
217#endif
218 }
219#ifndef NDEBUG
220 else
221 qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id );
222#endif
223}
224
225void OPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text)
226{
227 QMenuItem *item = findItem(id);
228 if(item){
229 if(item->widget())
230 ((OPopupTitle *)item->widget())->setTitle(text, &icon);
231#ifndef NDEBUG
232 else
233 qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id );
234#endif
235 }
236#ifndef NDEBUG
237 else
238 qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id );
239#endif
240}
241
242QString OPopupMenu::title(int id) const
243{
244 if(id == -1) // obsolete
245 return(d->m_lastTitle);
246 QMenuItem *item = findItem(id);
247 if(item){
248 if(item->widget())
249 return(((OPopupTitle *)item->widget())->title());
250 else
251 qWarning("OPopupMenu: title() called with non-title id %d.", id);
252 }
253 else
254 qWarning("OPopupMenu: title() called with invalid id %d.", id);
255 return(QString::null);
256}
257
258QPixmap OPopupMenu::titlePixmap(int id) const
259{
260 QMenuItem *item = findItem(id);
261 if(item){
262 if(item->widget())
263 return(((OPopupTitle *)item->widget())->icon());
264 else
265 qWarning("KPopupMenu: titlePixmap() called with non-title id %d.", id);
266 }
267 else
268 qWarning("KPopupMenu: titlePixmap() called with invalid id %d.", id);
269 QPixmap tmp;
270 return(tmp);
271}
272
273/**
274 * This is re-implemented for keyboard navigation.
275 */
276void OPopupMenu::closeEvent(QCloseEvent*e)
277{
278 if (d->shortcuts)
279 resetKeyboardVars();
280 QPopupMenu::closeEvent(e);
281}
282
283void OPopupMenu::keyPressEvent(QKeyEvent* e)
284{
285 if (!d->shortcuts) {
286 // continue event processing by Qpopup
287 //e->ignore();
288 QPopupMenu::keyPressEvent(e);
289 return;
290 }
291
292 int i = 0;
293 bool firstpass = true;
294 QString keyString = e->text();
295
296 // check for common commands dealt with by QPopup
297 int key = e->key();
298 if (key == Key_Escape || key == Key_Return || key == Key_Enter
299 || key == Key_Up || key == Key_Down || key == Key_Left
300 || key == Key_Right || key == Key_F1) {
301
302 resetKeyboardVars();
303 // continue event processing by Qpopup
304 //e->ignore();
305 QPopupMenu::keyPressEvent(e);
306 return;
307 }
308
309 // check to see if the user wants to remove a key from the sequence (backspace)
310 // or clear the sequence (delete)
311 if (!d->keySeq.isNull()) {
312
313 if (key == Key_Backspace) {
314
315 if (d->keySeq.length() == 1) {
316 resetKeyboardVars();
317 return;
318 }
319
320 // keep the last sequence in keyString
321 keyString = d->keySeq.left(d->keySeq.length() - 1);
322
323 // allow sequence matching to be tried again
324 resetKeyboardVars();
325
326 } else if (key == Key_Delete) {
327 resetKeyboardVars();
328
329 // clear active item
330 setActiveItem(0);
331 return;
332
333 } else if (d->noMatches) {
334 // clear if there are no matches
335 resetKeyboardVars();
336
337 // clear active item
338 setActiveItem(0);
339
340 } else {
341 // the key sequence is not a null string
342 // therefore the lastHitIndex is valid
343 i = d->lastHitIndex;
344 }
345 } else if (key == Key_Backspace && parentMenu) {
346 // backspace with no chars in the buffer... go back a menu.
347 hide();
348 resetKeyboardVars();
349 return;
350 }
351
352 d->keySeq += keyString;
353 int seqLen = d->keySeq.length();
354
355 for (; i < (int)count(); i++) {
356 // compare typed text with text of this entry
357 int j = idAt(i);
358
359 // don't search disabled entries
360 if (!isItemEnabled(j))
361 continue;
362
363 QString thisText;
364
365 // retrieve the right text
366 // (the last selected item one may have additional ampersands)
367 if (i == d->lastHitIndex)
368 thisText = d->originalText;
369 else
370 thisText = text(j);
371
372 // if there is an accelerator present, remove it
373 if ((int)accel(j) != 0)
374 thisText = thisText.replace(QRegExp("&"), "");
375
376 // chop text to the search length
377 thisText = thisText.left(seqLen);
378
379 // do the search
380 if (thisText.find(d->keySeq, 0, false) == 0) {
381
382 if (firstpass) {
383 // match
384 setActiveItem(i);
385
386 // check to see if we're underlining a different item
387 if (d->lastHitIndex != i)
388 // yes; revert the underlining
389 changeItem(idAt(d->lastHitIndex), d->originalText);
390
391 // set the original text if it's a different item
392 if (d->lastHitIndex != i || d->lastHitIndex == -1)
393 d->originalText = text(j);
394
395 // underline the currently selected item
396 changeItem(j, underlineText(d->originalText, d->keySeq.length()));
397
398 // remeber what's going on
399 d->lastHitIndex = i;
400
401 // start/restart the clear timer
402 d->clearTimer.start(5000, true);
403
404 // go around for another try, to see if we can execute
405 firstpass = false;
406 } else {
407 // don't allow execution
408 return;
409 }
410 }
411
412 // fall through to allow execution
413 }
414
415 if (!firstpass) {
416 if (d->autoExec) {
417 // activate anything
418 activateItemAt(d->lastHitIndex);
419 resetKeyboardVars();
420
421 } else if (findItem(idAt(d->lastHitIndex)) &&
422 findItem(idAt(d->lastHitIndex))->popup()) {
423 // only activate sub-menus
424 activateItemAt(d->lastHitIndex);
425 resetKeyboardVars();
426 }
427
428 return;
429 }
430
431 // no matches whatsoever, clean up
432 resetKeyboardVars(true);
433 //e->ignore();
434 QPopupMenu::keyPressEvent(e);
435}
436
437QString OPopupMenu::underlineText(const QString& text, uint length)
438{
439 QString ret = text;
440 for (uint i = 0; i < length; i++) {
441 if (ret[2*i] != '&')
442 ret.insert(2*i, "&");
443 }
444 return ret;
445}
446
447void OPopupMenu::resetKeyboardVars(bool noMatches /* = false */)
448{
449 // Clean up keyboard variables
450 if (d->lastHitIndex != -1) {
451 changeItem(idAt(d->lastHitIndex), d->originalText);
452 d->lastHitIndex = -1;
453 }
454
455 if (!noMatches) {
456 d->keySeq = QString::null;
457 }
458
459 d->noMatches = noMatches;
460}
461
462void OPopupMenu::setKeyboardShortcutsEnabled(bool enable)
463{
464 d->shortcuts = enable;
465}
466
467void OPopupMenu::setKeyboardShortcutsExecute(bool enable)
468{
469 d->autoExec = enable;
470}
471/**
472 * End keyboard navigation.
473 */
474
475/**
476 * RMB menus on menus
477 */
478QPopupMenu* OPopupMenu::contextMenu()
479{
480 if (!d->m_ctxMenu)
481 {
482 d->m_ctxMenu = new QPopupMenu(this);
483 installEventFilter(this);
484 connect(d->m_ctxMenu, SIGNAL(aboutToHide()), this, SLOT(ctxMenuHiding()));
485 }
486
487 return d->m_ctxMenu;
488}
489
490void OPopupMenu::cancelContextMenuShow()
491{
492 OPopupMenuPrivate::s_continueCtxMenuShow = false;
493}
494
495int OPopupMenu::contextMenuFocusItem()
496{
497 return OPopupMenuPrivate::s_highlightedItem;
498}
499
500OPopupMenu* OPopupMenu::contextMenuFocus()
501{
502 return OPopupMenuPrivate::s_contextedMenu;
503}
504
505void OPopupMenu::itemHighlighted(int /* whichItem */)
506{
507 if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible())
508 {
509 return;
510 }
511
512 d->m_ctxMenu->hide();
513 showCtxMenu(mapFromGlobal(QCursor::pos()));
514}
515
516void OPopupMenu::showCtxMenu(QPoint pos)
517{
518 OPopupMenuPrivate::s_highlightedItem = idAt(pos);
519
520 if (OPopupMenuPrivate::s_highlightedItem == -1)
521 {
522 OPopupMenuPrivate::s_contextedMenu = 0;
523 return;
524 }
525
526 emit aboutToShowContextMenu(this, OPopupMenuPrivate::s_highlightedItem, d->m_ctxMenu);
527
528 if (!OPopupMenuPrivate::s_continueCtxMenuShow)
529 {
530 OPopupMenuPrivate::s_continueCtxMenuShow = true;
531 return;
532 }
533
534 OPopupMenuPrivate::s_contextedMenu = this;
535 d->m_ctxMenu->popup(this->mapToGlobal(pos));
536 connect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int)));
537}
538
539void OPopupMenu::ctxMenuHiding()
540{
541 disconnect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int)));
542 OPopupMenuPrivate::s_continueCtxMenuShow = true;
543}
544
545bool OPopupMenu::eventFilter(QObject* obj, QEvent* event)
546{
547 if (d->m_ctxMenu && obj == this)
548 {
549 if (event->type() == QEvent::MouseButtonRelease)
550 {
551 if (d->m_ctxMenu->isVisible())
552 {
553 return true;
554 }
555 }
556 #if QT_VERSION > 290
557 else if (event->type() == QEvent::ContextMenu)
558 #else
559 else if ( (event->type() == QEvent::MouseButtonPress) &&
560 ( (QMouseEvent*) event )->button() == QMouseEvent::RightButton )
561 #endif
562 {
563 showCtxMenu(mapFromGlobal(QCursor::pos()));
564 return true;
565 }
566 }
567
568 return QWidget::eventFilter(obj, event);
569}
570
571void OPopupMenu::hideEvent(QHideEvent*)
572{
573 if (d->m_ctxMenu)
574 {
575 d->m_ctxMenu->hide();
576 }
577}
578/**
579 * end of RMB menus on menus support
580 */
581
582// Obsolete
583OPopupMenu::OPopupMenu(const QString& title, QWidget *parent, const char *name)
584 : QPopupMenu(parent, name)
585{
586 d = new OPopupMenuPrivate;
587 setTitle(title);
588}
589
590// Obsolete
591void OPopupMenu::setTitle(const QString &title)
592{
593 OPopupTitle *titleItem = new OPopupTitle();
594 titleItem->setTitle(title);
595 insertItem(titleItem);
596 d->m_lastTitle = title;
597}
598
599void OPopupTitle::virtual_hook( int, void* )
600{ /*BASE::virtual_hook( id, data );*/ }
601
602void OPopupMenu::virtual_hook( int, void* )
603{ /*BASE::virtual_hook( id, data );*/ }
604
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 @@
1/* This file is part of the ODE libraries
2 Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 Boston, MA 02111-1307, USA.
17*/
18#ifndef _OPOPUP_H
19#define _OPOPUP_H
20
21#define INCLUDE_MENUITEM_DEF
22
23/* QT */
24
25#include <qpopupmenu.h>
26
27/* OPIE */
28
29#include <opie2/opixmapeffect.h>
30
31/**
32 * Title widget for use in @ref OPopupMenu.
33 *
34 * You usually don't have to create this manually since
35 * @ref OPopupMenu::insertTitle will do it for you, but it is allowed if
36 * you wish to customize it's look.
37 *
38 * @author Daniel M. Duley <mosfet@kde.org>
39 * @short OPopupMenu title widget.
40 */
41class OPopupTitle : public QWidget
42{
43 Q_OBJECT
44
45public:
46 /**
47 * Constructs a title widget with the user specified gradient, pixmap,
48 * and colors.
49 */
50 OPopupTitle(QWidget *parent=0, const char *name=0);
51 /**
52 * @deprecated
53 * Constructs a title widget with the specified gradient and colors.
54 */
55 OPopupTitle(OPixmapEffect::GradientType gradient, const QColor &color,
56 const QColor &textColor, QWidget *parent=0,
57 const char *name=0);
58 /**
59 * @deprecated
60 * Constructs a title widget with the specified pixmap and colors.
61 */
62 OPopupTitle(const OPixmap &background, const QColor &color,
63 const QColor &textColor, QWidget *parent=0,
64 const char *name=0);
65 /**
66 * Sets the title string and optional icon for the title widget.
67 *
68 * You will want to call this before inserting into a menu.
69 */
70 void setTitle(const QString &text, const QPixmap *icon=NULL);
71 /**
72 * Returns the current title.
73 */
74 QString title() const { return(titleStr); }
75 /**
76 * Returns the current icon.
77 */
78 QPixmap icon() const { return(miniicon); }
79
80 QSize sizeHint() const;
81
82public slots:
83 /// @since 3.1
84 void setText( const QString &text );
85 /// @since 3.1
86 void setIcon( const QPixmap &pix );
87
88protected:
89 void paintEvent(QPaintEvent *ev);
90
91 QString titleStr;
92 QPixmap miniicon;
93
94 // Remove in KDE4
95 OPixmapEffect::GradientType grType;
96 QPixmap fill;
97 QColor fgColor, bgColor, grHigh, grLow;
98 bool useGradient;
99
100protected:
101 virtual void virtual_hook( int id, void* data );
102private:
103 class OPopupTitlePrivate;
104 OPopupTitlePrivate *d;
105};
106
107/**
108 * OPopupMenu is a class for menus with standard title items and keyboard
109 * accessibility for popups with many options and/or varying options. It acts
110 * identically to QPopupMenu, with the addition of insertTitle(),
111 * changeTitle(), setKeyboardShortcutsEnabled() and
112 * setKeyboardShortcutsExecute() methods.
113 *
114 * The titles support a text string, an icon, plus user defined gradients,
115 * colors, and background pixmaps.
116 *
117 * The keyboard search algorithm is incremental with additional underlining
118 * for user feedback.
119 *
120 * @short A menu with title items.
121 * @author Daniel M. Duley <mosfet@kde.org>
122 * @author Hamish Rodda <meddie@yoyo.its.monash.edu.au>
123 */
124class OPopupMenu : public QPopupMenu {
125 Q_OBJECT
126public:
127 /**
128 * Constructs a OPopupMenu.
129 */
130 OPopupMenu(QWidget *parent=0, const char *name=0);
131
132 /**
133 * Destructs the object
134 */
135 ~OPopupMenu();
136
137 /**
138 * Inserts a title item with no icon.
139 */
140 int insertTitle(const QString &text, int id=-1, int index=-1);
141 /**
142 * Inserts a title item with the given icon and title.
143 */
144 int insertTitle(const QPixmap &icon, const QString &text, int id=-1,
145 int index=-1);
146 /**
147 * Changes the title of the item at the specified id. If a icon was
148 * previously set it is cleared.
149 */
150 void changeTitle(int id, const QString &text);
151 /**
152 * Changes the title and icon of the title item at the specified id.
153 */
154 void changeTitle(int id, const QPixmap &icon, const QString &text);
155 /**
156 * Returns the title of the title item at the specified id. The default
157 * id of -1 is for backwards compatibility only, you should always specify
158 * the id.
159 */
160 QString title(int id=-1) const;
161 /**
162 * Returns the icon of the title item at the specified id.
163 */
164 QPixmap titlePixmap(int id) const;
165
166 /**
167 * Enables keyboard navigation by searching for the entered key sequence.
168 * Also underlines the currently selected item, providing feedback on the search.
169 *
170 * Defaults to off.
171 *
172 * WARNING: calls to text() of currently keyboard-selected items will
173 * contain additional ampersand characters.
174 *
175 * WARNING: though pre-existing keyboard shortcuts will not interfere with the
176 * operation of this feature, they may be confusing to the user as the existing
177 * shortcuts will not work.
178 * @since 3.1
179 */
180 void setKeyboardShortcutsEnabled(bool enable);
181
182 /**
183 * Enables execution of the menu item once it is uniquely specified.
184 * Defaults to off.
185 * @since 3.1
186 */
187 void setKeyboardShortcutsExecute(bool enable);
188
189 /**
190 * Obsolete method provided for backwards compatibility only. Use the
191 * normal constructor and insertTitle instead.
192 */
193 OPopupMenu(const QString &title, QWidget *parent=0, const char *name=0);
194 /**
195 * Obsolete method provided for backwards compatibility only. Use
196 * insertTitle and changeTitle instead.
197 */
198 void setTitle(const QString &title);
199
200 /**
201 * Returns the context menu associated with this menu
202 * @since 3.2
203 */
204 QPopupMenu* contextMenu();
205
206 /**
207 * Hides the context menu if shown
208 * @since 3.2
209 */
210 void cancelContextMenuShow();
211
212 /**
213 * Returns the OPopupMenu associated with the current context menu
214 * @since 3.2
215 */
216 static OPopupMenu* contextMenuFocus();
217
218 /**
219 * returns the ID of the menuitem associated with the current context menu
220 * @since 3.2
221 */
222 static int contextMenuFocusItem();
223
224signals:
225 /**
226 * connect to this signal to be notified when a context menu is about to be shown
227 * @param menu The menu that the context menu is about to be shown for
228 * @param menuItem The menu item that the context menu is currently on
229 * @param ctxMenu The context menu itself
230 * @since 3.2
231 */
232 void aboutToShowContextMenu(OPopupMenu* menu, int menuItem, QPopupMenu* ctxMenu);
233
234protected:
235 virtual void closeEvent(QCloseEvent *);
236 virtual void keyPressEvent(QKeyEvent* e);
237 virtual bool eventFilter(QObject* obj, QEvent* event);
238 virtual void hideEvent(QHideEvent*);
239
240 virtual void virtual_hook( int id, void* data );
241
242protected slots:
243 /// @since 3.1
244 QString underlineText(const QString& text, uint length);
245 /// @since 3.1
246 void resetKeyboardVars(bool noMatches = false);
247 void itemHighlighted(int whichItem);
248 void showCtxMenu(QPoint pos);
249 void ctxMenuHiding();
250
251private:
252 class OPopupMenuPrivate;
253 OPopupMenuPrivate *d;
254};
255
256#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 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Martin Jones (mjones@kde.org)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19
20/* QT */
21
22#include <qimage.h>
23#include <qpainter.h>
24#include <qdrawutil.h>
25
26/* OPIE */
27
28#include <opie2/oimageeffect.h>
29#include <opie2/oselector.h>
30
31#define STORE_W 8
32#define STORE_W2 STORE_W * 2
33
34//-----------------------------------------------------------------------------
35/*
36 * 2D value selector.
37 * The contents of the selector are drawn by derived class.
38 */
39
40OXYSelector::OXYSelector( QWidget *parent, const char *name )
41 : QWidget( parent, name )
42{
43 xPos = 0;
44 yPos = 0;
45 minX = 0;
46 minY = 0;
47 maxX = 100;
48 maxY = 100;
49 store.setOptimization( QPixmap::BestOptim );
50 store.resize( STORE_W2, STORE_W2 );
51}
52
53
54OXYSelector::~OXYSelector()
55{}
56
57
58void OXYSelector::setRange( int _minX, int _minY, int _maxX, int _maxY )
59{
60 px = 2;
61 py = 2;
62 minX = _minX;
63 minY = _minY;
64 maxX = _maxX;
65 maxY = _maxY;
66}
67
68void OXYSelector::setValues( int _xPos, int _yPos )
69{
70 xPos = _xPos;
71 yPos = _yPos;
72
73 if ( xPos > maxX )
74 xPos = maxX;
75 else if ( xPos < minX )
76 xPos = minX;
77
78 if ( yPos > maxY )
79 yPos = maxY;
80 else if ( yPos < minY )
81 yPos = minY;
82
83 int xp = 2 + (width() - 4) * xPos / (maxX - minX);
84 int yp = height() - 2 - (height() - 4) * yPos / (maxY - minY);
85
86 setPosition( xp, yp );
87}
88
89QRect OXYSelector::contentsRect() const
90{
91 return QRect( 2, 2, width()-4, height()-4 );
92}
93
94void OXYSelector::paintEvent( QPaintEvent *ev )
95{
96 QRect cursorRect( px - STORE_W, py - STORE_W, STORE_W2, STORE_W2);
97 QRect paintRect = ev->rect();
98
99 QPainter painter;
100 painter.begin( this );
101
102 QBrush brush;
103 qDrawShadePanel( &painter, 0, 0, width(), height(), colorGroup(),
104 TRUE, 2, &brush );
105
106 drawContents( &painter );
107 if (paintRect.contains(cursorRect))
108 {
109 bitBlt( &store, 0, 0, this, px - STORE_W, py - STORE_W,
110 STORE_W2, STORE_W2, CopyROP );
111 drawCursor( &painter, px, py );
112 }
113 else if (paintRect.intersects(cursorRect))
114 {
115 repaint( cursorRect, false);
116 }
117
118 painter.end();
119}
120
121void OXYSelector::mousePressEvent( QMouseEvent *e )
122{
123 int xVal, yVal;
124 valuesFromPosition( e->pos().x() - 2, e->pos().y() - 2, xVal, yVal );
125 setValues( xVal, yVal );
126
127 emit valueChanged( xPos, yPos );
128}
129
130void OXYSelector::mouseMoveEvent( QMouseEvent *e )
131{
132 int xVal, yVal;
133 valuesFromPosition( e->pos().x() - 2, e->pos().y() - 2, xVal, yVal );
134 setValues( xVal, yVal );
135
136 emit valueChanged( xPos, yPos );
137}
138
139void OXYSelector::wheelEvent( QWheelEvent *e )
140{
141 #if QT_VERSION > 290
142 if ( e->orientation() == Qt::Horizontal )
143 setValues( xValue() + e->delta()/120, yValue() );
144 else
145 setValues( xValue(), yValue() + e->delta()/120 );
146
147 emit valueChanged( xPos, yPos );
148 #endif
149}
150
151void OXYSelector::valuesFromPosition( int x, int y, int &xVal, int &yVal ) const
152{
153 xVal = ( (maxX-minX) * (x-2) ) / ( width()-4 );
154 yVal = maxY - ( ( (maxY-minY) * (y-2) ) / ( height()-4 ) );
155
156 if ( xVal > maxX )
157 xVal = maxX;
158 else if ( xVal < minX )
159 xVal = minX;
160
161 if ( yVal > maxY )
162 yVal = maxY;
163 else if ( yVal < minY )
164 yVal = minY;
165}
166
167void OXYSelector::setPosition( int xp, int yp )
168{
169 if ( xp < 2 )
170 xp = 2;
171 else if ( xp > width() - 2 )
172 xp = width() - 2;
173
174 if ( yp < 2 )
175 yp = 2;
176 else if ( yp > height() - 2 )
177 yp = height() - 2;
178
179 QPainter painter;
180 painter.begin( this );
181
182 bitBlt( this, px - STORE_W, py - STORE_W, &store, 0, 0,
183 STORE_W2, STORE_W2, CopyROP );
184 bitBlt( &store, 0, 0, this, xp - STORE_W, yp - STORE_W,
185 STORE_W2, STORE_W2, CopyROP );
186 drawCursor( &painter, xp, yp );
187 px = xp;
188 py = yp;
189
190 painter.end();
191}
192
193void OXYSelector::drawContents( QPainter * )
194{}
195
196
197void OXYSelector::drawCursor( QPainter *p, int xp, int yp )
198{
199 p->setPen( QPen( white ) );
200
201 p->drawLine( xp - 6, yp - 6, xp - 2, yp - 2 );
202 p->drawLine( xp - 6, yp + 6, xp - 2, yp + 2 );
203 p->drawLine( xp + 6, yp - 6, xp + 2, yp - 2 );
204 p->drawLine( xp + 6, yp + 6, xp + 2, yp + 2 );
205}
206
207//-----------------------------------------------------------------------------
208/*
209 * 1D value selector with contents drawn by derived class.
210 * See OColorDialog for example.
211 */
212
213
214OSelector::OSelector( QWidget *parent, const char *name )
215 : QWidget( parent, name ), QRangeControl()
216{
217 _orientation = Horizontal;
218 _indent = TRUE;
219}
220
221OSelector::OSelector( Orientation o, QWidget *parent, const char *name )
222 : QWidget( parent, name ), QRangeControl()
223{
224 _orientation = o;
225 _indent = TRUE;
226}
227
228
229OSelector::~OSelector()
230{}
231
232
233QRect OSelector::contentsRect() const
234{
235 if ( orientation() == Vertical )
236 return QRect( 2, 5, width()-9, height()-10 );
237 else
238 return QRect( 5, 2, width()-10, height()-9 );
239}
240
241void OSelector::paintEvent( QPaintEvent * )
242{
243 QPainter painter;
244
245 painter.begin( this );
246
247 drawContents( &painter );
248
249 QBrush brush;
250
251 if ( indent() )
252 {
253 if ( orientation() == Vertical )
254 qDrawShadePanel( &painter, 0, 3, width()-5, height()-6,
255 colorGroup(), TRUE, 2, &brush );
256 else
257 qDrawShadePanel( &painter, 3, 0, width()-6, height()-5,
258 colorGroup(), TRUE, 2, &brush );
259 }
260
261 QPoint pos = calcArrowPos( value() );
262 drawArrow( &painter, TRUE, pos );
263
264 painter.end();
265}
266
267void OSelector::mousePressEvent( QMouseEvent *e )
268{
269 moveArrow( e->pos() );
270}
271
272void OSelector::mouseMoveEvent( QMouseEvent *e )
273{
274 moveArrow( e->pos() );
275}
276
277void OSelector::wheelEvent( QWheelEvent *e )
278{
279 int val = value() + e->delta()/120;
280 emit valueChanged( val );
281 setValue( val );
282}
283
284void OSelector::valueChange()
285{
286 QPainter painter;
287 QPoint pos;
288
289 painter.begin( this );
290
291 pos = calcArrowPos( prevValue() );
292 drawArrow( &painter, FALSE, pos );
293
294 pos = calcArrowPos( value() );
295 drawArrow( &painter, TRUE, pos );
296
297 painter.end();
298}
299
300void OSelector::moveArrow( const QPoint &pos )
301{
302 int val;
303
304 if ( orientation() == Vertical )
305 val = ( maxValue() - minValue() ) * (height()-pos.y()-3)
306 / (height()-10) + minValue();
307 else
308 val = ( maxValue() - minValue() ) * (width()-pos.x()-3)
309 / (width()-10) + minValue();
310
311 if ( val > maxValue() )
312 val = maxValue();
313 if ( val < minValue() )
314 val = minValue();
315
316 emit valueChanged( val );
317 setValue( val );
318}
319
320QPoint OSelector::calcArrowPos( int val )
321{
322 QPoint p;
323
324 if ( orientation() == Vertical )
325 {
326 p.setY( height() - ( (height()-10) * val
327 / ( maxValue() - minValue() ) + 5 ) );
328 p.setX( width() - 5 );
329 }
330 else
331 {
332 p.setX( width() - ( (width()-10) * val
333 / ( maxValue() - minValue() ) + 5 ) );
334 p.setY( height() - 5 );
335 }
336
337 return p;
338}
339
340void OSelector::drawContents( QPainter * )
341{}
342
343void OSelector::drawArrow( QPainter *painter, bool show, const QPoint &pos )
344{
345 if ( show )
346 {
347 QPointArray array(3);
348
349 painter->setPen( QPen() );
350 painter->setBrush( QBrush( colorGroup().buttonText() ) );
351 if ( orientation() == Vertical )
352 {
353 array.setPoint( 0, pos.x()+0, pos.y()+0 );
354 array.setPoint( 1, pos.x()+5, pos.y()+5 );
355 array.setPoint( 2, pos.x()+5, pos.y()-5 );
356 }
357 else
358 {
359 array.setPoint( 0, pos.x()+0, pos.y()+0 );
360 array.setPoint( 1, pos.x()+5, pos.y()+5 );
361 array.setPoint( 2, pos.x()-5, pos.y()+5 );
362 }
363
364 painter->drawPolygon( array );
365 }
366 else
367 {
368 if ( orientation() == Vertical )
369 {
370 repaint(pos.x(), pos.y()-5, 6, 11, true);
371 }
372 else
373 {
374 repaint(pos.x()-5, pos.y(), 11, 6, true);
375 }
376 }
377}
378
379//----------------------------------------------------------------------------
380
381OGradientSelector::OGradientSelector( QWidget *parent, const char *name )
382 : OSelector( parent, name )
383{
384 init();
385}
386
387
388OGradientSelector::OGradientSelector( Orientation o, QWidget *parent,
389 const char *name )
390 : OSelector( o, parent, name )
391{
392 init();
393}
394
395
396OGradientSelector::~OGradientSelector()
397{}
398
399
400void OGradientSelector::init()
401{
402 color1.setRgb( 0, 0, 0 );
403 color2.setRgb( 255, 255, 255 );
404
405 text1 = text2 = "";
406}
407
408
409void OGradientSelector::drawContents( QPainter *painter )
410{
411 QImage image( contentsRect().width(), contentsRect().height(), 32 );
412
413 QColor col;
414 float scale;
415
416 int redDiff = color2.red() - color1.red();
417 int greenDiff = color2.green() - color1.green();
418 int blueDiff = color2.blue() - color1.blue();
419
420 if ( orientation() == Vertical )
421 {
422 for ( int y = 0; y < image.height(); y++ )
423 {
424 scale = 1.0 * y / image.height();
425 col.setRgb( color1.red() + int(redDiff*scale),
426 color1.green() + int(greenDiff*scale),
427 color1.blue() + int(blueDiff*scale) );
428
429 unsigned int *p = (uint *) image.scanLine( y );
430 for ( int x = 0; x < image.width(); x++ )
431 *p++ = col.rgb();
432 }
433 }
434 else
435 {
436 unsigned int *p = (uint *) image.scanLine( 0 );
437
438 for ( int x = 0; x < image.width(); x++ )
439 {
440 scale = 1.0 * x / image.width();
441 col.setRgb( color1.red() + int(redDiff*scale),
442 color1.green() + int(greenDiff*scale),
443 color1.blue() + int(blueDiff*scale) );
444 *p++ = col.rgb();
445 }
446
447 for ( int y = 1; y < image.height(); y++ )
448 memcpy( image.scanLine( y ), image.scanLine( y - 1),
449 sizeof( unsigned int ) * image.width() );
450 }
451
452 QColor ditherPalette[8];
453
454 for ( int s = 0; s < 8; s++ )
455 ditherPalette[s].setRgb( color1.red() + redDiff * s / 8,
456 color1.green() + greenDiff * s / 8,
457 color1.blue() + blueDiff * s / 8 );
458
459 OImageEffect::dither( image, ditherPalette, 8 );
460
461 QPixmap p;
462 p.convertFromImage( image );
463
464 painter->drawPixmap( contentsRect().x(), contentsRect().y(), p );
465
466 if ( orientation() == Vertical )
467 {
468 int yPos = contentsRect().top() + painter->fontMetrics().ascent() + 2;
469 int xPos = contentsRect().left() + (contentsRect().width() -
470 painter->fontMetrics().width( text2 )) / 2;
471 QPen pen( color2 );
472 painter->setPen( pen );
473 painter->drawText( xPos, yPos, text2 );
474
475 yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2;
476 xPos = contentsRect().left() + (contentsRect().width() -
477 painter->fontMetrics().width( text1 )) / 2;
478 pen.setColor( color1 );
479 painter->setPen( pen );
480 painter->drawText( xPos, yPos, text1 );
481 }
482 else
483 {
484 int yPos = contentsRect().bottom()-painter->fontMetrics().descent()-2;
485
486 QPen pen( color2 );
487 painter->setPen( pen );
488 painter->drawText( contentsRect().left() + 2, yPos, text1 );
489
490 pen.setColor( color1 );
491 painter->setPen( pen );
492 painter->drawText( contentsRect().right() -
493 painter->fontMetrics().width( text2 ) - 2, yPos, text2 );
494 }
495}
496
497//-----------------------------------------------------------------------------
498
499static QColor *standardPalette = 0;
500
501#define STANDARD_PAL_SIZE 17
502
503OColor::OColor()
504: QColor()
505{
506 r = 0; g = 0; b = 0; h = 0; s = 0; v = 0;
507};
508
509OColor::OColor( const OColor &col)
510: QColor( col )
511{
512 h = col.h; s = col.s; v = col.v;
513 r = col.r; g = col.g; b = col.b;
514};
515
516OColor::OColor( const QColor &col)
517: QColor( col )
518{
519 QColor::rgb(&r, &g, &b);
520 QColor::hsv(&h, &s, &v);
521};
522
523bool OColor::operator==(const OColor& col) const
524{
525 return (h == col.h) && (s == col.s) && (v == col.v) &&
526 (r == col.r) && (g == col.g) && (b == col.b);
527}
528
529OColor& OColor::operator=(const OColor& col)
530{
531 *(QColor *)this = col;
532 h = col.h; s = col.s; v = col.v;
533 r = col.r; g = col.g; b = col.b;
534 return *this;
535}
536
537void
538OColor::setHsv(int _h, int _s, int _v)
539{
540 h = _h; s = _s; v = _v;
541 QColor::setHsv(h, s, v);
542 QColor::rgb(&r, &g, &b);
543};
544
545void
546OColor::setRgb(int _r, int _g, int _b)
547{
548 r = _r; g = _g; b = _b;
549 QColor::setRgb(r, g, b);
550 QColor::hsv(&h, &s, &v);
551}
552
553void
554OColor::rgb(int *_r, int *_g, int *_b) const
555{
556 *_r = r; *_g = g; *_b = b;
557}
558
559void
560OColor::hsv(int *_h, int *_s, int *_v) const
561{
562 *_h = h; *_s = s; *_v = v;
563}
564
565static void createStandardPalette()
566{
567 if ( standardPalette )
568 return;
569
570 standardPalette = new QColor[STANDARD_PAL_SIZE];
571
572 int i = 0;
573
574 standardPalette[i++] = Qt::red;
575 standardPalette[i++] = Qt::green;
576 standardPalette[i++] = Qt::blue;
577 standardPalette[i++] = Qt::cyan;
578 standardPalette[i++] = Qt::magenta;
579 standardPalette[i++] = Qt::yellow;
580 standardPalette[i++] = Qt::darkRed;
581 standardPalette[i++] = Qt::darkGreen;
582 standardPalette[i++] = Qt::darkBlue;
583 standardPalette[i++] = Qt::darkCyan;
584 standardPalette[i++] = Qt::darkMagenta;
585 standardPalette[i++] = Qt::darkYellow;
586 standardPalette[i++] = Qt::white;
587 standardPalette[i++] = Qt::lightGray;
588 standardPalette[i++] = Qt::gray;
589 standardPalette[i++] = Qt::darkGray;
590 standardPalette[i++] = Qt::black;
591}
592
593
594OHSSelector::OHSSelector( QWidget *parent, const char *name )
595 : OXYSelector( parent, name )
596{
597 setRange( 0, 0, 359, 255 );
598}
599
600void OHSSelector::updateContents()
601{
602 drawPalette(&pixmap);
603}
604
605void OHSSelector::resizeEvent( QResizeEvent * )
606{
607 updateContents();
608}
609
610void OHSSelector::drawContents( QPainter *painter )
611{
612 painter->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap );
613}
614
615void OHSSelector::drawPalette( QPixmap *pixmap )
616{
617 int xSize = contentsRect().width(), ySize = contentsRect().height();
618 QImage image( xSize, ySize, 32 );
619 QColor col;
620 int h, s;
621 uint *p;
622
623 for ( s = ySize-1; s >= 0; s-- )
624 {
625 p = (uint *) image.scanLine( ySize - s - 1 );
626 for( h = 0; h < xSize; h++ )
627 {
628 col.setHsv( 359*h/(xSize-1), 255*s/(ySize-1), 192 );
629 *p = col.rgb();
630 p++;
631 }
632 }
633
634 if ( QColor::numBitPlanes() <= 8 )
635 {
636 createStandardPalette();
637 OImageEffect::dither( image, standardPalette, STANDARD_PAL_SIZE );
638 }
639 pixmap->convertFromImage( image );
640}
641
642
643//-----------------------------------------------------------------------------
644
645OValueSelector::OValueSelector( QWidget *parent, const char *name )
646 : OSelector( OSelector::Vertical, parent, name ), _hue(0), _sat(0)
647{
648 setRange( 0, 255 );
649 pixmap.setOptimization( QPixmap::BestOptim );
650}
651
652OValueSelector::OValueSelector(Orientation o, QWidget *parent, const char *name
653 )
654 : OSelector( o, parent, name), _hue(0), _sat(0)
655{
656 setRange( 0, 255 );
657 pixmap.setOptimization( QPixmap::BestOptim );
658}
659
660void OValueSelector::updateContents()
661{
662 drawPalette(&pixmap);
663}
664
665void OValueSelector::resizeEvent( QResizeEvent * )
666{
667 updateContents();
668}
669
670void OValueSelector::drawContents( QPainter *painter )
671{
672 painter->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap );
673}
674
675void OValueSelector::drawPalette( QPixmap *pixmap )
676{
677 int xSize = contentsRect().width(), ySize = contentsRect().height();
678 QImage image( xSize, ySize, 32 );
679 QColor col;
680 uint *p;
681 QRgb rgb;
682
683 if ( orientation() == OSelector::Horizontal )
684 {
685 for ( int v = 0; v < ySize; v++ )
686 {
687 p = (uint *) image.scanLine( ySize - v - 1 );
688
689 for( int x = 0; x < xSize; x++ )
690 {
691 col.setHsv( _hue, _sat, 255*x/(xSize-1) );
692 rgb = col.rgb();
693 *p++ = rgb;
694 }
695 }
696 }
697
698 if( orientation() == OSelector::Vertical )
699 {
700 for ( int v = 0; v < ySize; v++ )
701 {
702 p = (uint *) image.scanLine( ySize - v - 1 );
703 col.setHsv( _hue, _sat, 255*v/(ySize-1) );
704 rgb = col.rgb();
705 for ( int i = 0; i < xSize; i++ )
706 *p++ = rgb;
707 }
708 }
709
710 if ( QColor::numBitPlanes() <= 8 )
711 {
712 createStandardPalette();
713 OImageEffect::dither( image, standardPalette, STANDARD_PAL_SIZE );
714 }
715 pixmap->convertFromImage( image );
716}
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 @@
1/* This file is part of the KDE libraries
2 Copyright (C) 1997 Martin Jones (mjones@kde.org)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18*/
19//-----------------------------------------------------------------------------
20// Selector widgets for KDE Color Selector, but probably useful for other
21// stuff also.
22
23#ifndef __OSELECT_H__
24#define __OSELECT_H__
25
26#include <qwidget.h>
27#include <qrangecontrol.h>
28#include <qpixmap.h>
29
30/**
31 * OXYSelector is the base class for other widgets which
32 * provides the ability to choose from a two-dimensional
33 * range of values. The currently chosen value is indicated
34 * by a cross. An example is the @ref OHSSelector which
35 * allows to choose from a range of colors, and which is
36 * used in OColorDialog.
37 *
38 * A custom drawing routine for the widget surface has
39 * to be provided by the subclass.
40 */
41class OXYSelector : public QWidget
42{
43 Q_OBJECT
44
45public:
46 /**
47 * Constructs a two-dimensional selector widget which
48 * has a value range of [0..100] in both directions.
49 */
50 OXYSelector( QWidget *parent=0, const char *name=0 );
51 /**
52 * Destructs the widget.
53 */
54 ~OXYSelector();
55
56 /**
57 * Sets the current values in horizontal and
58 * vertical direction.
59 */
60 void setValues( int xPos, int yPos );
61 /**
62 * Sets the range of possible values.
63 */
64 void setRange( int minX, int minY, int maxX, int maxY );
65
66 /**
67 * @return the current value in horizontal direction.
68 */
69 int xValue() const {return xPos; }
70 /**
71 * @return the current value in vertical direction.
72 */
73 int yValue() const {return yPos; }
74
75 /**
76 * @return the rectangle on which subclasses should draw.
77 */
78 QRect contentsRect() const;
79
80signals:
81 /**
82 * This signal is emitted whenever the user chooses a value,
83 * e.g. by clicking with the mouse on the widget.
84 */
85 void valueChanged( int x, int y );
86
87protected:
88 /**
89 * Override this function to draw the contents of the widget.
90 * The default implementation does nothing.
91 *
92 * Draw within @ref contentsRect() only.
93 */
94 virtual void drawContents( QPainter * );
95 /**
96 * Override this function to draw the cursor which
97 * indicates the currently selected value pair.
98 */
99 virtual void drawCursor( QPainter *p, int xp, int yp );
100 /**
101 * @reimplemented
102 */
103 virtual void paintEvent( QPaintEvent *e );
104 /**
105 * @reimplemented
106 */
107 virtual void mousePressEvent( QMouseEvent *e );
108 /**
109 * @reimplemented
110 */
111 virtual void mouseMoveEvent( QMouseEvent *e );
112 /**
113 * @reimplemented
114 */
115 virtual void wheelEvent( QWheelEvent * );
116 /**
117 * Converts a pixel position to its corresponding values.
118 */
119 void valuesFromPosition( int x, int y, int& xVal, int& yVal ) const;
120
121private:
122 void setPosition( int xp, int yp );
123 int px;
124 int py;
125 int xPos;
126 int yPos;
127 int minX;
128 int maxX;
129 int minY;
130 int maxY;
131 QPixmap store;
132
133private:
134 class OXYSelectorPrivate;
135 OXYSelectorPrivate *d;
136};
137
138
139/**
140 * OSelector is the base class for other widgets which
141 * provides the ability to choose from a one-dimensional
142 * range of values. An example is the @ref OGradientSelector
143 * which allows to choose from a range of colors.
144 *
145 * A custom drawing routine for the widget surface has
146 * to be provided by the subclass.
147 */
148class OSelector : public QWidget, public QRangeControl
149{
150 Q_OBJECT
151 Q_PROPERTY( int value READ value WRITE setValue )
152 Q_PROPERTY( int minValue READ minValue WRITE setMinValue )
153 Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue )
154public:
155
156 /**
157 * Constructs a horizontal one-dimensional selection widget.
158 */
159 OSelector( QWidget *parent=0, const char *name=0 );
160 /**
161 * Constructs a one-dimensional selection widget with
162 * a given orientation.
163 */
164 OSelector( Orientation o, QWidget *parent = 0L, const char *name = 0L );
165 /*
166 * Destructs the widget.
167 */
168 ~OSelector();
169
170 /**
171 * @return the orientation of the widget.
172 */
173 Orientation orientation() const
174 {return _orientation; }
175
176 /**
177 * @return the rectangle on which subclasses should draw.
178 */
179 QRect contentsRect() const;
180
181 /**
182 * Sets the indent option of the widget to i.
183 * This determines whether a shaded frame is drawn.
184 */
185 void setIndent( bool i )
186 {_indent = i; }
187 /**
188 * @return whether the indent option is set.
189 */
190 bool indent() const
191 {return _indent; }
192
193 /**
194 * Sets the value.
195 */
196 void setValue(int value)
197 { QRangeControl::setValue(value); }
198
199 /**
200 * @returns the value.
201 */
202 int value() const
203 { return QRangeControl::value(); }
204
205 /**
206 * Sets the min value.
207 */
208 #if ( QT_VERSION > 290 )
209 void setMinValue(int value) { QRangeControl::setMinValue(value); }
210 #else
211 void setMinValue(int value) { QRangeControl::setRange(value,QRangeControl::maxValue()); }
212 #endif
213
214 /**
215 * @return the min value.
216 */
217 int minValue() const
218 { return QRangeControl::minValue(); }
219
220 /**
221 * Sets the max value.
222 */
223 #if ( QT_VERSION > 290 )
224 void setMaxValue(int value) { QRangeControl::setMaxValue(value); }
225 #else
226 void setMaxValue(int value) { QRangeControl::setRange(QRangeControl::minValue(),value); }
227 #endif
228
229 /**
230 * @return the max value.
231 */
232 int maxValue() const
233 { return QRangeControl::maxValue(); }
234
235signals:
236 /**
237 * This signal is emitted whenever the user chooses a value,
238 * e.g. by clicking with the mouse on the widget.
239 */
240 void valueChanged( int value );
241
242protected:
243 /**
244 * Override this function to draw the contents of the control.
245 * The default implementation does nothing.
246 *
247 * Draw only within contentsRect().
248 */
249 virtual void drawContents( QPainter * );
250 /**
251 * Override this function to draw the cursor which
252 * indicates the current value. This function is
253 * always called twice, once with argument show=false
254 * to clear the old cursor, once with argument show=true
255 * to draw the new one.
256 */
257 virtual void drawArrow( QPainter *painter, bool show, const QPoint &pos );
258
259 /**
260 * @reimplemented
261 */
262 virtual void valueChange();
263 /**
264 * @reimplemented
265 */
266 virtual void paintEvent( QPaintEvent * );
267 /**
268 * @reimplemented
269 */
270 virtual void mousePressEvent( QMouseEvent *e );
271 /**
272 * @reimplemented
273 */
274 virtual void mouseMoveEvent( QMouseEvent *e );
275 /**
276 * @reimplemented
277 */
278 virtual void wheelEvent( QWheelEvent * );
279
280private:
281 QPoint calcArrowPos( int val );
282 void moveArrow( const QPoint &pos );
283
284 Orientation _orientation;
285 bool _indent;
286
287private:
288 class OSelectorPrivate;
289 OSelectorPrivate *d;
290};
291
292
293/**
294 * The OGradientSelector widget allows the user to choose
295 * from a one-dimensional range of colors which is given as a
296 * gradient between two colors provided by the programmer.
297 */
298class OGradientSelector : public OSelector
299{
300 Q_OBJECT
301
302 Q_PROPERTY( QColor firstColor READ firstColor WRITE setFirstColor )
303 Q_PROPERTY( QColor secondColor READ secondColor WRITE setSecondColor )
304 Q_PROPERTY( QString firstText READ firstText WRITE setFirstText )
305 Q_PROPERTY( QString secondText READ secondText WRITE setSecondText )
306
307public:
308 /**
309 * Constructs a horizontal color selector which
310 * contains a gradient between white and black.
311 */
312 OGradientSelector( QWidget *parent=0, const char *name=0 );
313 /**
314 * Constructs a colors selector with orientation o which
315 * contains a gradient between white and black.
316 */
317 OGradientSelector( Orientation o, QWidget *parent=0, const char *name=0 );
318 /**
319 * Destructs the widget.
320 */
321 ~OGradientSelector();
322 /**
323 * Sets the two colors which span the gradient.
324 */
325 void setColors( const QColor &col1, const QColor &col2 )
326 {color1 = col1; color2 = col2; update();}
327 void setText( const QString &t1, const QString &t2 )
328 {text1 = t1; text2 = t2; update(); }
329
330 /**
331 * Set each color on its own.
332 */
333 void setFirstColor( const QColor &col )
334 { color1 = col; update(); }
335 void setSecondColor( const QColor &col )
336 { color2 = col; update(); }
337
338 /**
339 * Set each description on its own
340 */
341 void setFirstText( const QString &t )
342 { text1 = t; update(); }
343 void setSecondText( const QString &t )
344 { text2 = t; update(); }
345
346 const QColor firstColor() const
347 { return color1; }
348 const QColor secondColor() const
349 { return color2; }
350
351 const QString firstText() const
352 { return text1; }
353 const QString secondText() const
354 { return text2; }
355
356protected:
357 /**
358 * @reimplemented
359 */
360 virtual void drawContents( QPainter * );
361
362 /**
363 * @reimplemented
364 */
365 virtual QSize minimumSize() const
366 { return sizeHint(); }
367
368private:
369 void init();
370 QColor color1;
371 QColor color2;
372 QString text1;
373 QString text2;
374
375private:
376 class OGradientSelectorPrivate;
377 OGradientSelectorPrivate *d;
378};
379
380/**
381 * Widget for Hue/Saturation selection.
382 * The actual values can be fetched using the inherited xValue and yValue
383 * methods.
384 *
385 * @see OXYSelector, OValueSelector, OColorDialog
386 * @author Martin Jones (mjones@kde.org)
387 * @version $Id$
388*/
389class OHSSelector : public OXYSelector
390{
391 Q_OBJECT
392
393public:
394 /**
395 * Constructs a hue/saturation selection widget.
396 */
397 OHSSelector( QWidget *parent=0, const char *name=0 );
398
399protected:
400 /**
401 * Draws the contents of the widget on a pixmap,
402 * which is used for buffering.
403 */
404 virtual void drawPalette( QPixmap *pixmap );
405 /**
406 * @reimplemented
407 */
408 virtual void resizeEvent( QResizeEvent * );
409 /**
410 * Reimplemented from OXYSelector. This drawing is
411 * buffered in a pixmap here. As real drawing
412 * routine, drawPalette() is used.
413 */
414 virtual void drawContents( QPainter *painter );
415
416private:
417 void updateContents();
418 QPixmap pixmap;
419
420private:
421 class OHSSelectorPrivate;
422 OHSSelectorPrivate *d;
423};
424
425
426class OValueSelectorPrivate;
427/**
428 * Widget for color value selection.
429 *
430 * @see OHSSelector, OColorDialog
431 * @author Martin Jones (mjones@kde.org)
432 * @version $Id$
433 */
434class OValueSelector : public OSelector
435{
436 Q_OBJECT
437
438public:
439 /**
440 * Constructs a widget for color selection.
441 */
442 OValueSelector( QWidget *parent=0, const char *name=0 );
443 /**
444 * Constructs a widget for color selection with a given orientation
445 */
446 OValueSelector( Orientation o, QWidget *parent = 0, const char *name = 0 );
447
448 int hue() const
449 { return _hue; }
450 void setHue( int h )
451 { _hue = h; }
452 int saturation() const
453 { return _sat; }
454 void setSaturation( int s )
455 { _sat = s; }
456
457 void updateContents();
458protected:
459 /**
460 * Draws the contents of the widget on a pixmap,
461 * which is used for buffering.
462 */
463 virtual void drawPalette( QPixmap *pixmap );
464 /**
465 * @reimplemented
466 */
467 virtual void resizeEvent( QResizeEvent * );
468 /**
469 * Reimplemented from OSelector. The drawing is
470 * buffered in a pixmap here. As real drawing
471 * routine, drawPalette() is used.
472 */
473 virtual void drawContents( QPainter *painter );
474
475private:
476 int _hue;
477 int _sat;
478 QPixmap pixmap;
479
480private:
481 class OValueSelectorPrivate;
482 OValueSelectorPrivate *d;
483};
484
485
486class OColor : public QColor
487{
488public:
489 OColor();
490 OColor( const OColor &col);
491 OColor( const QColor &col);
492
493 OColor& operator=( const OColor& col);
494
495 bool operator==( const OColor& col) const;
496
497 void setHsv(int _h, int _s, int _v);
498 void setRgb(int _r, int _g, int _b);
499
500 void rgb(int *_r, int *_g, int *_b) const;
501 void hsv(int *_h, int *_s, int *_v) const;
502protected:
503 int h;
504 int s;
505 int v;
506 int r;
507 int g;
508 int b;
509
510private:
511 class OColorPrivate;
512 OColorPrivate *d;
513};
514
515
516
517 #endif // __OSELECT_H__
518
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 @@
1/*
2                 This file is part of the Opie Project
3
4              Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 Copyright (C) 1997 Michael Roth <mroth@wirlweb.de>
6 =.
7 .=l.
8           .>+-=
9 _;:,     .>    :=|. This program is free software; you can
10.> <`_,   >  .   <= redistribute it and/or modify it under
11:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
12.="- .-=="i,     .._ License as published by the Free Software
13 - .   .-<_>     .<> Foundation; either version 2 of the License,
14     ._= =}       : or (at your option) any later version.
15    .%`+i>       _;_.
16    .i_,=:_.      -<s. This program is distributed in the hope that
17     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
18    : ..    .:,     . . . without even the implied warranty of
19    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
20  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
21..}^=.=       =       ; Library General Public License for more
22++=   -.     .`     .: details.
23 :     =  ...= . :.=-
24 -.   .:....=;==+<; You should have received a copy of the GNU
25  -_. . .   )=.  = Library General Public License along with
26    --        :-=` this library; see the file COPYING.LIB.
27 If not, write to the Free Software Foundation,
28 Inc., 59 Temple Place - Suite 330,
29 Boston, MA 02111-1307, USA.
30
31*/
32
33/* QT */
34
35#include <qstyle.h>
36
37/* OPIE */
38
39#include <opie2/oseparator.h>
40
41OSeparator::OSeparator(QWidget* parent, const char* name, WFlags f)
42 : QFrame(parent, name, f)
43{
44 setLineWidth(1);
45 setMidLineWidth(0);
46 setOrientation( HLine );
47}
48
49
50
51OSeparator::OSeparator(int orientation, QWidget* parent, const char* name, WFlags f)
52 : QFrame(parent, name, f)
53{
54 setLineWidth(1);
55 setMidLineWidth(0);
56 setOrientation( orientation );
57}
58
59
60
61void OSeparator::setOrientation(int orientation)
62{
63 switch(orientation)
64 {
65 case Vertical:
66 case VLine:
67 setFrameStyle( QFrame::VLine | QFrame::Sunken );
68 setMinimumSize(2, 0);
69 break;
70
71 default:
72 qWarning( "OSeparator::setOrientation(): invalid orientation, using default orientation HLine" );
73
74 case Horizontal:
75 case HLine:
76 setFrameStyle( QFrame::HLine | QFrame::Sunken );
77 setMinimumSize(0, 2);
78 break;
79 }
80}
81
82
83
84int OSeparator::orientation() const
85{
86 if ( frameStyle() & VLine )
87 return VLine;
88
89 if ( frameStyle() & HLine )
90 return HLine;
91
92 return 0;
93}
94
95void OSeparator::drawFrame(QPainter *p)
96{
97 QPointp1, p2;
98 QRectr = frameRect();
99 const QColorGroup & g = colorGroup();
100
101 if ( frameStyle() & HLine ) {
102 p1 = QPoint( r.x(), r.height()/2 );
103 p2 = QPoint( r.x()+r.width(), p1.y() );
104 }
105 else {
106 p1 = QPoint( r.x()+r.width()/2, 0 );
107 p2 = QPoint( p1.x(), r.height() );
108 }
109
110#if QT_VERSION < 300
111 style().drawSeparator( p, p1.x(), p1.y(), p2.x(), p2.y(), g, true, 1, midLineWidth() );
112#else
113 QStyleOption opt( lineWidth(), midLineWidth() );
114 style().drawPrimitive( QStyle::PE_Separator, p, QRect( p1, p2 ), g, QStyle::Style_Sunken, opt );
115#endif
116}
117
118
119QSize OSeparator::sizeHint() const
120{
121 if ( frameStyle() & VLine )
122 return QSize(2, 0);
123
124 if ( frameStyle() & HLine )
125 return QSize(0, 2);
126
127 return QSize(-1, -1);
128}
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 @@
1/*
2                 This file is part of the Opie Project
3
4              Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 Copyright (C) 1997 Michael Roth <mroth@wirlweb.de>
6 =.
7 .=l.
8           .>+-=
9 _;:,     .>    :=|. This program is free software; you can
10.> <`_,   >  .   <= redistribute it and/or modify it under
11:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
12.="- .-=="i,     .._ License as published by the Free Software
13 - .   .-<_>     .<> Foundation; either version 2 of the License,
14     ._= =}       : or (at your option) any later version.
15    .%`+i>       _;_.
16    .i_,=:_.      -<s. This program is distributed in the hope that
17     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
18    : ..    .:,     . . . without even the implied warranty of
19    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
20  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
21..}^=.=       =       ; Library General Public License for more
22++=   -.     .`     .: details.
23 :     =  ...= . :.=-
24 -.   .:....=;==+<; You should have received a copy of the GNU
25  -_. . .   )=.  = Library General Public License along with
26    --        :-=` this library; see the file COPYING.LIB.
27 If not, write to the Free Software Foundation,
28 Inc., 59 Temple Place - Suite 330,
29 Boston, MA 02111-1307, USA.
30
31*/
32
33#ifndef OSEPARATOR_H
34#define OSEPARATOR_H
35
36#include <qframe.h>
37
38/**
39 * Standard horizontal or vertical separator.
40 *
41 * @author Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
42 * @author Michael Roth <mroth@wirlweb.de>
43 * @version $Id$
44*/
45class OSeparator : public QFrame
46{
47 Q_OBJECT
48 Q_PROPERTY( int orientation READ orientation WRITE setOrientation )
49 public:
50 /**
51 * Constructor.
52 **/
53 OSeparator(QWidget* parent=0, const char* name=0, WFlags f=0);
54 /**
55 * Constructor.
56 *
57 * @param orientation Set the orientation of the separator.
58 * Possible values are HLine or Horizontal and VLine or Vertical.
59 **/
60 OSeparator(int orientation, QWidget* parent=0, const char* name=0,
61 WFlags f=0);
62
63 /**
64 * Returns the orientation of the separator.
65 *
66 * Possible values are VLine and HLine.
67 **/
68 int orientation() const;
69
70 /**
71 * Set the orientation of the separator to @p orient
72 *
73 * Possible values are VLine and HLine.
74 */
75 void setOrientation(int orient);
76
77 /**
78 * The recommended height (width) for a horizontal (vertical) separator.
79 **/
80 virtual QSize sizeHint() const;
81
82protected:
83 virtual void drawFrame( QPainter * );
84
85private:
86 class OSeparatorPrivate* d;
87};
88
89
90#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 @@
1/*
2                 This file is part of the Opie Project
3
4 =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28
29*/
30
31/* QT */
32
33#include <qaction.h>
34#include <qbrush.h>
35#include <qfont.h>
36#include <qiconset.h>
37#include <qiconview.h>
38#include <qlistview.h>
39#include <qpalette.h>
40#include <qpoint.h>
41#include <qpopupmenu.h>
42#include <qrect.h>
43#include <qsize.h>
44#include <qstring.h>
45#include <qwidgetstack.h>
46
47/* OPIE */
48
49#include <opie2/oversatileview.h>
50#include <opie2/oversatileviewitem.h>
51#include <opie2/olistview.h>
52
53/* XPM */
54static const char * view_icon_xpm[] = {
55"16 16 16 1",
56 " c None",
57 ".c #87BD88",
58 "+c #8BBE8B",
59 "@c #81BA81",
60 "#c #6DAF6D",
61 "$c #87BD87",
62 "%c #FCFDFC",
63 "&c #AED0AE",
64 "*c #4E9C4C",
65 "=c #91BD91",
66 "-c #72B172",
67 ";c #448643",
68 ">c #519F50",
69 ",c #499247",
70 "'c #356A35",
71 ")c #686868",
72" ",
73" .+@# .+@# ",
74" $%&* $%&* ",
75" @=-; @=-; ",
76" #>,' #>,' ",
77" ",
78" )))))) )))))) ",
79" ",
80" ",
81" .+@# .+@# ",
82" $%&* $%&* ",
83" @=-; @=-; ",
84" #>,' #>,' ",
85" ",
86" )))))) )))))) ",
87" "};
88
89/* XPM */
90static const char * view_tree_xpm[] = {
91"16 16 17 1",
92 " c None",
93 ".c #3A3A3A",
94 "+c #87BD88",
95 "@c #8BBE8B",
96 "#c #81BA81",
97 "$c #6DAF6D",
98 "%c #87BD87",
99 "&c #FCFDFC",
100 "*c #AED0AE",
101 "=c #4E9C4C",
102 "-c #91BD91",
103 ";c #72B172",
104 ">c #448643",
105 ",c #686868",
106 "'c #519F50",
107 ")c #499247",
108 "!c #356A35",
109" . ",
110" . ",
111" . +@#$ ",
112" . %&*= ",
113" .. #-;> ,, ,,,",
114" . $')! ",
115" . ",
116" . ",
117" . ",
118" . +@#$ ",
119" . %&*= ",
120" .. #-;> ,, ,,,",
121" $')! ",
122" ",
123" ",
124" "};
125
126OVersatileView::OVersatileView( QWidget* parent, const char* name, int mode )
127 :QWidgetStack( parent, name ),
128 _viewmode( mode ), _warningpolicy( None ),
129 _treeleaf(), _treeopened(), _treeclosed(),
130 _iconleaf(), _iconopened(), _iconclosed()
131{
132 //
133 // Create child widgets and set some reasonable default styles
134 //
135
136 _listview = new OListView( this, "oversatileview embedded listview" );
137 _iconview = new QIconView( this, "oversatileview embedded iconview" );
138
139 _listview->setAllColumnsShowFocus( true );
140 _listview->setRootIsDecorated( true );
141 _listview->setShowSortIndicator( true );
142 _iconview->setGridX( 90 );
143 _iconview->setGridY( 42 );
144 _iconview->setAutoArrange( true );
145
146 #ifdef QWS // TODO: Let this depend on current geometry (rotation)
147 _iconview->setArrangement( QIconView::TopToBottom );
148 #else
149 _iconview->setArrangement( QIconView::LeftToRight );
150 #endif
151
152 _iconview->setResizeMode( QIconView::Adjust );
153
154 // qt-embedded: map stylus right on hold to right button press
155
156 #ifdef QWS
157 ( (QPEApplication*) qApp)->setStylusOperation( _iconview->viewport(), QPEApplication::RightOnHold );
158 ( (QPEApplication*) qApp)->setStylusOperation( _listview->viewport(), QPEApplication::RightOnHold );
159 #endif
160
161 setViewMode( mode ); // TODO: Read last style from config
162 // setSynchronization( true ); // TODO: Implement this
163
164 // create context menu allowing to switch between the views
165
166 _contextmenu = new QPopupMenu( 0, "oversatileview contextmenu" );
167 _contextmenu->setCaption( "Style" );
168 _contextmenu->setCheckable( true );
169 QActionGroup* ag = new QActionGroup( _contextmenu, "style option group" );
170 QAction* a1 = new QAction( "View Items in Icon Style", QIconSet( QPixmap( view_icon_xpm ) ),
171 "View Icons", 0, ag, "viewicon action", true );
172 QAction* a2 = new QAction( "View Items in Tree Style", QIconSet( QPixmap( view_tree_xpm ) ),
173 "View Tree", 0, ag, "viewtree action", true );
174 ag->addTo( _contextmenu );
175 if ( mode == Icons )
176 a1->setOn( true );
177 else if ( mode == Tree )
178 a2->setOn( true );
179 connect( a1, SIGNAL( activated() ), this, SLOT( setIconViewMode() ) );
180 connect( a2, SIGNAL( activated() ), this, SLOT( setTreeViewMode() ) );
181
182 #if (QT_VERSION >= 0x030000)
183 connect( _listview, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint&, int ) ), this, SLOT( contextMenuRequested( QListViewItem*, const QPoint&, int ) ) );
184 connect( _iconview, SIGNAL( contextMenuRequested( QIconViewItem*, const QPoint& ) ), this, SLOT( contextMenuRequested( QIconViewItem*, const QPoint& ) ) );
185 #else
186 connect( _listview, SIGNAL( rightButtonPressed( QListViewItem*, const QPoint&, int ) ), this, SLOT( contextMenuRequested( QListViewItem*, const QPoint&, int ) ) );
187 connect( _iconview, SIGNAL( rightButtonPressed( QIconViewItem*, const QPoint& ) ), this, SLOT( contextMenuRequested( QIconViewItem*, const QPoint& ) ) );
188 #endif
189
190 //
191 // signal forwarders
192 //
193 // unfortunately we can't short-circuit all the QListView and QIconView signals
194 // to OVersatileView signals, because the signal/slot mechanism doesn't allow
195 // type-conversion :-(
196
197 // common signals for listview
198
199 connect( _listview, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) );
200 connect( _listview, SIGNAL( selectionChanged( QListViewItem * ) ), this, SLOT( selectionChanged( QListViewItem * ) ) );
201 connect( _listview, SIGNAL( currentChanged( QListViewItem * ) ), this, SLOT( currentChanged( QListViewItem * ) ) );
202 connect( _listview, SIGNAL( clicked( QListViewItem * ) ), this, SLOT( clicked( QListViewItem * ) ) );
203 connect( _listview, SIGNAL( pressed( QListViewItem * ) ), this, SLOT( pressed( QListViewItem * ) ) );
204
205 connect( _listview, SIGNAL( doubleClicked( QListViewItem * ) ), this, SLOT( doubleClicked( QListViewItem * ) ) );
206 connect( _listview, SIGNAL( returnPressed( QListViewItem * ) ), this, SLOT( returnPressed( QListViewItem * ) ) );
207
208 connect( _listview, SIGNAL( onItem( QListViewItem * ) ), this, SLOT( onItem( QListViewItem * ) ) );
209 connect( _listview, SIGNAL( onViewport() ), this, SIGNAL( onViewport() ) );
210
211 // common signals for iconview
212
213 connect( _iconview, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) );
214 connect( _iconview, SIGNAL( selectionChanged( QIconViewItem * ) ), this, SLOT( selectionChanged( QIconViewItem * ) ) );
215 connect( _iconview, SIGNAL( currentChanged( QIconViewItem * ) ), this, SLOT( currentChanged( QIconViewItem * ) ) );
216 connect( _iconview, SIGNAL( clicked( QIconViewItem * ) ), this, SLOT( clicked( QIconViewItem * ) ) );
217 connect( _iconview, SIGNAL( pressed( QIconViewItem * ) ), this, SLOT( pressed( QIconViewItem * ) ) );
218
219 connect( _iconview, SIGNAL( doubleClicked( QIconViewItem * ) ), this, SLOT( doubleClicked( QIconViewItem * ) ) );
220 connect( _iconview, SIGNAL( returnPressed( QIconViewItem * ) ), this, SLOT( returnPressed( QIconViewItem * ) ) );
221
222 connect( _iconview, SIGNAL( onItem( QIconViewItem * ) ), this, SLOT( onItem( QIconViewItem * ) ) );
223 connect( _iconview, SIGNAL( onViewport() ), this, SIGNAL( onViewport() ) );
224
225 // listview only signals
226
227 connect( _listview, SIGNAL( expanded( QListViewItem * ) ), this, SLOT( expanded( QListViewItem * ) ) );
228 connect( _listview, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( collapsed( QListViewItem * ) ) );
229
230 // iconview only signals
231
232 connect( _iconview, SIGNAL( moved() ), this, SIGNAL( moved() ) );
233}
234
235OVersatileView::~OVersatileView()
236{
237}
238
239QPopupMenu* OVersatileView::contextMenu() const
240{
241 return _contextmenu;
242}
243
244void OVersatileView::contextMenuRequested( QListViewItem* item, const QPoint& pos, int col )
245{
246 // can't use QObject::inherits here, because ListViewItems, beit Q, O or K,
247 // do not inherit from QObject - assuming here the programmer is
248 // disciplined enough to only add OVersatileViewItems to an OVersatileView
249 popupContextMenu( static_cast<OVersatileViewItem*>( item ), pos, col );
250}
251
252void OVersatileView::contextMenuRequested( QIconViewItem* item, const QPoint& pos )
253{
254 // see above
255 popupContextMenu( static_cast<OVersatileViewItem*>( item ), pos, -1 );
256}
257
258void OVersatileView::popupContextMenu( OVersatileViewItem* item, const QPoint& pos, int col )
259{
260 if ( not item )
261 _contextmenu->exec( pos );
262 else
263 emit( contextMenuRequested( item, pos, col ) );
264}
265
266void OVersatileView::setSynchronization( bool sync )
267{
268 _synchronization = sync;
269}
270
271bool OVersatileView::synchronization()
272{
273 return _synchronization;
274}
275
276void OVersatileView::setDefaultPixmaps( int mode, QPixmap& leaf, QPixmap& opened, QPixmap& closed )
277{
278 if ( mode == Tree )
279 {
280 _treeleaf = leaf;
281 _treeopened = opened;
282 _treeclosed = closed;
283 }
284 else if ( mode == Icons )
285 {
286 _iconleaf = leaf;
287 _iconopened = opened;
288 _iconclosed = closed;
289 }
290 else
291 {
292 qDebug( "OVersatileView::setDefaultPixmaps(): invalid mode" );
293 }
294}
295
296QIconView* OVersatileView::iconView() const
297{
298 return _iconview;
299}
300
301OListView* OVersatileView::listView() const
302{
303 return _listview;
304}
305
306void OVersatileView::setViewMode( int mode )
307{
308 if ( mode == Tree )
309 {
310 _viewmode = mode;
311 raiseWidget( _listview );
312 }
313 else if ( mode == Icons )
314 {
315 _viewmode = mode;
316 raiseWidget( _iconview );
317 }
318 else
319 {
320 qDebug( "OVersatileView::setViewMode(): invalid mode" );
321 }
322}
323
324void OVersatileView::setIconViewMode()
325{
326 setViewMode( Icons );
327}
328
329void OVersatileView::setTreeViewMode()
330{
331 setViewMode( Tree );
332}
333
334bool OVersatileView::isValidViewMode( int mode ) const
335{
336 switch ( _warningpolicy )
337 {
338 case OVersatileView::None:
339 {
340 return true;
341 }
342 case OVersatileView::Warn:
343 {
344 if ( _viewmode != mode )
345 {
346 qDebug( "OVersatileView::isValidViewMode(): Requested operation not valid in current mode." );
347 return true;
348 }
349 }
350 case OVersatileView::WarnReturn:
351 {
352 if ( _viewmode != mode )
353 {
354 qDebug( "OVersatileView::isValidViewMode(): Requested operation not valid in current mode." );
355 return false;
356 }
357 }
358 default:
359 {
360 qWarning( "OVersatileView::isValidViewMode(): Inconsistent object state!" );
361 return true;
362 }
363 }
364}
365void OVersatileView::setWarningPolicy( int policy ) const
366{
367 _warningpolicy = policy;
368}
369bool OVersatileView::warningPolicy() const
370{
371 return _warningpolicy;
372}
373//==============================================================================================//
374// Stupid Signal forwarders...
375// Folks, this is why I like python with its dynamic typing:
376// I can code the following dozens of lines C++ in four Python lines...
377//==============================================================================================//
378
379void OVersatileView::selectionChanged( QListViewItem * item )
380{
381 emit( selectionChanged( static_cast<OVersatileViewItem*>( item ) ) );
382}
383
384void OVersatileView::selectionChanged( QIconViewItem * item )
385{
386 emit( selectionChanged( static_cast<OVersatileViewItem*>( item ) ) );
387}
388
389void OVersatileView::currentChanged( QListViewItem * item )
390{
391 emit( currentChanged( static_cast<OVersatileViewItem*>( item ) ) );
392}
393
394void OVersatileView::currentChanged( QIconViewItem * item )
395{
396 emit( currentChanged( static_cast<OVersatileViewItem*>( item ) ) );
397}
398
399void OVersatileView::clicked( QListViewItem * item )
400{
401 emit( clicked( static_cast<OVersatileViewItem*>( item ) ) );
402}
403
404void OVersatileView::clicked( QIconViewItem * item )
405{
406 emit( clicked( static_cast<OVersatileViewItem*>( item ) ) );
407}
408
409void OVersatileView::pressed( QListViewItem * item )
410{
411 emit( pressed( static_cast<OVersatileViewItem*>( item ) ) );
412}
413
414void OVersatileView::pressed( QIconViewItem * item )
415{
416 emit( pressed( static_cast<OVersatileViewItem*>( item ) ) );
417}
418
419void OVersatileView::doubleClicked( QListViewItem * item )
420{
421 emit( doubleClicked( static_cast<OVersatileViewItem*>( item ) ) );
422}
423
424void OVersatileView::doubleClicked( QIconViewItem * item )
425{
426 emit( doubleClicked( static_cast<OVersatileViewItem*>( item ) ) );
427}
428
429void OVersatileView::returnPressed( QListViewItem * item )
430{
431 emit( returnPressed( static_cast<OVersatileViewItem*>( item ) ) );
432}
433
434void OVersatileView::returnPressed( QIconViewItem * item )
435{
436 emit( returnPressed( static_cast<OVersatileViewItem*>( item ) ) );
437}
438
439void OVersatileView::onItem( QListViewItem * item )
440{
441 emit( onItem( static_cast<OVersatileViewItem*>( item ) ) );
442}
443
444void OVersatileView::onItem( QIconViewItem * item )
445{
446 emit( onItem( static_cast<OVersatileViewItem*>( item ) ) );
447}
448
449void OVersatileView::expanded( QListViewItem *item ) // QListView
450{
451 //qDebug( "OVersatileView::expanded(): opening tree..." );
452 if ( not _treeopened.isNull() )
453 item->setPixmap( 0, _treeopened );
454 emit( expanded( static_cast<OVersatileViewItem*>( item ) ) );
455}
456void OVersatileView::collapsed( QListViewItem *item ) // QListView
457{
458 if ( not _treeclosed.isNull() )
459 item->setPixmap( 0, _treeclosed );
460 emit( collapsed( static_cast<OVersatileViewItem*>( item ) ) );
461}
462
463//=============================================================================================//
464// OVersatileView Case I - API only existing in QListView or QIconView but not in both!
465//==============================================================================================//
466
467int OVersatileView::treeStepSize() const // QListView
468{
469 if ( not isValidViewMode( Tree ) )
470 {
471 return -1;
472 }
473 return _listview->treeStepSize();
474}
475 void OVersatileView::setTreeStepSize( int size ) // QListView
476{
477 if ( not isValidViewMode( Tree ) )
478 {
479 return;
480 }
481 _listview->setTreeStepSize( size );
482}
483
484QHeader * OVersatileView::header() const // QListView
485{
486 if ( not isValidViewMode( Tree ) )
487 {
488 return 0;
489 }
490 return _listview->header();
491}
492
493 int OVersatileView::addColumn( const QString &label, int size ) // QListView
494{
495 if ( not isValidViewMode( Tree ) )
496 {
497 return -1;
498 }
499 return _listview->addColumn( label, size );
500}
501
502 int OVersatileView::addColumn( const QIconSet& iconset, const QString &label, int size ) // QListView
503{
504 if ( not isValidViewMode( Tree ) )
505 {
506 return -1;
507 }
508 return _listview->addColumn( iconset, label, size );
509}
510
511void OVersatileView::removeColumn( int index ) // QListView
512{
513 if ( not isValidViewMode( Tree ) )
514 {
515 return;
516 }
517 _listview->removeColumn( index );
518}
519 void OVersatileView::setColumnText( int column, const QString &label ) // QListView
520{
521 if ( not isValidViewMode( Tree ) )
522 {
523 return;
524 }
525 _listview->setColumnText( column, label );
526}
527 void OVersatileView::setColumnText( int column, const QIconSet& iconset, const QString &label ) // QListView
528{
529 if ( not isValidViewMode( Tree ) )
530 {
531 return;
532 }
533 _listview->setColumnText( column, iconset, label );
534}
535QString OVersatileView::columnText( int column ) const // QListView
536{
537 if ( not isValidViewMode( Tree ) )
538 {
539 return QString::null;
540 }
541 return _listview->columnText( column );
542}
543 void OVersatileView::setColumnWidth( int column, int width ) // QListView
544{
545 if ( not isValidViewMode( Tree ) )
546 {
547 return;
548 }
549 _listview->setColumnWidth( column, width );
550}
551int OVersatileView::columnWidth( int column ) const // QListView
552{
553 if ( not isValidViewMode( Tree ) )
554 {
555 return -1;
556 }
557 return _listview->columnWidth( column );
558}
559 void OVersatileView::setColumnWidthMode( int column, WidthMode mode ) // QListView
560{
561 if ( not isValidViewMode( Tree ) )
562 {
563 return;
564 }
565 _listview->setColumnWidth( column, mode );
566}
567int OVersatileView::columns() const // QListView
568{
569 if ( not isValidViewMode( Tree ) )
570 {
571 return -1;
572 }
573 return _listview->columns();
574}
575
576 void OVersatileView::setColumnAlignment( int column, int align ) // QListView
577{
578 if ( not isValidViewMode( Tree ) )
579 {
580 return;
581 }
582 _listview->setColumnAlignment( column, align );
583}
584int OVersatileView::columnAlignment( int column ) const // QListView
585{
586 if ( not isValidViewMode( Tree ) )
587 {
588 return -1;
589 }
590 return _listview->columnAlignment( column );
591}
592
593OVersatileViewItem * OVersatileView::itemAt( const QPoint & screenPos ) const // QListView
594{
595 if ( not isValidViewMode( Tree ) )
596 {
597 return 0;
598 }
599 return static_cast<OVersatileViewItem*>( _listview->itemAt( screenPos ) );
600}
601QRect OVersatileView::itemRect( const OVersatileViewItem * item ) const // QListView
602{
603 if ( not isValidViewMode( Tree ) )
604 {
605 return QRect( -1, -1, -1, -1 );
606 }
607 return _listview->itemRect( item );
608}
609int OVersatileView::itemPos( const OVersatileViewItem * item ) // QListView
610{
611 if ( not isValidViewMode( Tree ) )
612 {
613 return -1;
614 }
615 return _listview->itemPos( item );
616}
617
618bool OVersatileView::isSelected( const OVersatileViewItem * item ) const // QListView // also in QIconViewItem but !in QIconView *shrug*
619{
620 if ( not isValidViewMode( Tree ) )
621 {
622 return false;
623 }
624 return _listview->isSelected( item );
625}
626
627 void OVersatileView::setMultiSelection( bool enable )
628{
629 _listview->setMultiSelection( enable );
630}
631bool OVersatileView::isMultiSelection() const
632{
633 return _listview->isMultiSelection();
634}
635
636OVersatileViewItem * OVersatileView::selectedItem() const // QListView
637{
638 if ( not isValidViewMode( Tree ) )
639 {
640 return 0;
641 }
642 return static_cast<OVersatileViewItem*>( _listview->selectedItem() );
643}
644 void OVersatileView::setOpen( OVersatileViewItem * item, bool open ) // QListView
645{
646 if ( not isValidViewMode( Tree ) )
647 {
648 return;
649 }
650 _listview->setOpen( item, open );
651}
652bool OVersatileView::isOpen( const OVersatileViewItem * item ) const // QListView
653{
654 if ( not isValidViewMode( Tree ) )
655 {
656 return false;
657 }
658 return _listview->isOpen( item );
659}
660
661OVersatileViewItem * OVersatileView::firstChild() const // QListView
662{
663 if ( not isValidViewMode( Tree ) )
664 {
665 return 0;
666 }
667 return static_cast<OVersatileViewItem*>( _listview->firstChild() );
668}
669int OVersatileView::childCount() const // QListView
670{
671 if ( not isValidViewMode( Tree ) )
672 {
673 return -1;
674 }
675 return _listview->childCount();
676}
677
678 void OVersatileView::setAllColumnsShowFocus( bool focus ) // QListView
679{
680 if ( not isValidViewMode( Tree ) )
681 {
682 return;
683 }
684 _listview->setAllColumnsShowFocus( focus );
685}
686bool OVersatileView::allColumnsShowFocus() const // QListView
687{
688 if ( not isValidViewMode( Tree ) )
689 {
690 return false;
691 }
692 return _listview->allColumnsShowFocus();
693}
694
695 void OVersatileView::setItemMargin( int margin ) // QListView
696{
697 if ( not isValidViewMode( Tree ) )
698 {
699 return;
700 }
701 _listview->setItemMargin( margin );
702}
703int OVersatileView::itemMargin() const // QListView
704{
705 if ( not isValidViewMode( Tree ) )
706 {
707 return -1;
708 }
709 return _listview->itemMargin();
710}
711
712 void OVersatileView::setRootIsDecorated( bool decorate ) // QListView
713{
714 if ( not isValidViewMode( Tree ) )
715 {
716 return;
717 }
718 _listview->setRootIsDecorated( decorate );
719}
720bool OVersatileView::rootIsDecorated() const // QListView
721{
722 if ( not isValidViewMode( Tree ) )
723 {
724 return false;
725 }
726 return _listview->rootIsDecorated();
727}
728
729void OVersatileView::setShowSortIndicator( bool show ) // QListView
730{
731 if ( not isValidViewMode( Tree ) )
732 {
733 return;
734 }
735 _listview->setShowSortIndicator( show );
736}
737bool OVersatileView::showSortIndicator() const // QListView
738{
739 if ( not isValidViewMode( Tree ) )
740 {
741 return false;
742 }
743 return _listview->showSortIndicator();
744}
745
746void OVersatileView::triggerUpdate() // QListView
747{
748 if ( not isValidViewMode( Tree ) )
749 {
750 return;
751 }
752 _listview->triggerUpdate();
753}
754
755//
756// only in QIconView
757//
758
759uint OVersatileView::count() const // QIconView
760{
761 if ( not isValidViewMode( Icons ) )
762 {
763 return 0;
764 }
765 return _iconview->count();
766}
767
768int OVersatileView::index( const OVersatileViewItem *item ) const // QIconView
769{
770 if ( not isValidViewMode( Icons ) )
771 {
772 return -1;
773 }
774 return _iconview->index( item );
775}
776
777OVersatileViewItem* OVersatileView::firstItem() const // QIconView
778{
779 if ( not isValidViewMode( Icons ) )
780 {
781 return 0;
782 }
783 return static_cast<OVersatileViewItem*>( _iconview->firstItem() );
784}
785OVersatileViewItem* OVersatileView::lastItem() const // QIconView
786{
787 if ( not isValidViewMode( Icons ) )
788 {
789 return 0;
790 }
791 return static_cast<OVersatileViewItem*>( _iconview->lastItem() );
792}
793
794OVersatileViewItem* OVersatileView::findItem( const QPoint &pos ) const // QIconView
795{
796 if ( not isValidViewMode( Icons ) )
797 {
798 return 0;
799 }
800 return static_cast<OVersatileViewItem*>( _iconview->findItem( pos ) );
801}
802OVersatileViewItem* OVersatileView::findItem( const QString &text ) const // QIconView
803{
804 if ( not isValidViewMode( Icons ) )
805 {
806 return 0;
807 }
808 return static_cast<OVersatileViewItem*>( _iconview->findItem( text ) );
809}
810
811OVersatileViewItem* OVersatileView::findFirstVisibleItem( const QRect &r ) const // QIconView
812{
813 if ( not isValidViewMode( Icons ) )
814 {
815 return 0;
816 }
817 return static_cast<OVersatileViewItem*>( _iconview->findFirstVisibleItem( r ) );
818}
819OVersatileViewItem* OVersatileView::findLastVisibleItem( const QRect &r ) const // QIconView
820{
821 if ( not isValidViewMode( Icons ) )
822 {
823 return 0;
824 }
825 return static_cast<OVersatileViewItem*>( _iconview->findLastVisibleItem( r ) );
826}
827
828 void OVersatileView::setGridX( int rx ) // QIconView
829{
830 if ( not isValidViewMode( Icons ) )
831 {
832 return;
833 }
834 _iconview->setGridX( rx );
835}
836 void OVersatileView::setGridY( int ry ) // QIconView
837{
838 if ( not isValidViewMode( Icons ) )
839 {
840 return;
841 }
842 _iconview->setGridY( ry );
843}
844int OVersatileView::gridX() const // QIconView
845{
846 if ( not isValidViewMode( Icons ) )
847 {
848 return -1;
849 }
850 return _iconview->gridX();
851}
852int OVersatileView::gridY() const // QIconView
853{
854 if ( not isValidViewMode( Icons ) )
855 {
856 return -1;
857 }
858 return _iconview->gridY();
859}
860 void OVersatileView::setSpacing( int sp ) // QIconView
861{
862 if ( not isValidViewMode( Icons ) )
863 {
864 return;
865 }
866 _iconview->setSpacing( sp );
867}
868int OVersatileView::spacing() const // QIconView
869{
870 if ( not isValidViewMode( Icons ) )
871 {
872 return -1;
873 }
874 return _iconview->spacing();
875}
876 void OVersatileView::setItemTextPos( QIconView::ItemTextPos pos ) // QIconView
877{
878 if ( not isValidViewMode( Icons ) )
879 {
880 return;
881 }
882 _iconview->setItemTextPos( pos );
883}
884QIconView::ItemTextPos OVersatileView::itemTextPos() const // QIconView
885{
886 if ( not isValidViewMode( Icons ) )
887 {
888 return (QIconView::ItemTextPos) -1;
889 }
890 return _iconview->itemTextPos();
891}
892 void OVersatileView::setItemTextBackground( const QBrush &b ) // QIconView
893{
894 if ( not isValidViewMode( Icons ) )
895 {
896 return;
897 }
898 _iconview->setItemTextBackground( b );
899}
900QBrush OVersatileView::itemTextBackground() const // QIconView
901{
902 if ( not isValidViewMode( Icons ) )
903 {
904 return QBrush();
905 }
906 return _iconview->itemTextBackground();
907}
908 void OVersatileView::setArrangement( QIconView::Arrangement am ) // QIconView
909{
910 if ( not isValidViewMode( Icons ) )
911 {
912 return;
913 }
914 _iconview->setArrangement( am );
915}
916QIconView::Arrangement OVersatileView::arrangement() const // QIconView
917{
918 if ( not isValidViewMode( Icons ) )
919 {
920 return (QIconView::Arrangement) -1;
921 }
922 return _iconview->arrangement();
923}
924 void OVersatileView::setResizeMode( QIconView::ResizeMode am ) // QIconView
925{
926 if ( not isValidViewMode( Icons ) )
927 {
928 return;
929 }
930 _iconview->setResizeMode( am );
931}
932QIconView::ResizeMode OVersatileView::resizeMode() const // QIconView
933{
934 if ( not isValidViewMode( Icons ) )
935 {
936 return (QIconView::ResizeMode) -1;
937 }
938 return _iconview->resizeMode();
939}
940 void OVersatileView::setMaxItemWidth( int w ) // QIconView
941{
942 if ( not isValidViewMode( Icons ) )
943 {
944 return;
945 }
946 _iconview->setMaxItemWidth( w );
947}
948int OVersatileView::maxItemWidth() const // QIconView
949{
950 if ( not isValidViewMode( Icons ) )
951 {
952 return -1;
953 }
954 return _iconview->maxItemWidth();
955}
956 void OVersatileView::setMaxItemTextLength( int w ) // QIconView
957{
958 if ( not isValidViewMode( Icons ) )
959 {
960 return;
961 }
962 _iconview->setMaxItemTextLength( w );
963}
964int OVersatileView::maxItemTextLength() const // QIconView
965{
966 if ( not isValidViewMode( Icons ) )
967 {
968 return -1;
969 }
970 return _iconview->maxItemTextLength();
971}
972 void OVersatileView::setAutoArrange( bool b ) // QIconView
973{
974 if ( not isValidViewMode( Icons ) )
975 {
976 return;
977 }
978 _iconview->setAutoArrange( b );
979}
980bool OVersatileView::autoArrange() const // QIconView
981{
982 if ( not isValidViewMode( Icons ) )
983 {
984 return false;
985 }
986 return _iconview->autoArrange();
987}
988 void OVersatileView::setShowToolTips( bool b ) // QIconView
989{
990 if ( not isValidViewMode( Icons ) )
991 {
992 return;
993 }
994 _iconview->setShowToolTips( b );
995}
996bool OVersatileView::showToolTips() const // QIconView
997{
998 if ( not isValidViewMode( Icons ) )
999 {
1000 return false;
1001 }
1002 return _iconview->showToolTips();
1003}
1004
1005bool OVersatileView::sorting() const // QIconView
1006{
1007 if ( not isValidViewMode( Icons ) )
1008 {
1009 return false;
1010 }
1011 return _iconview->sorting();
1012}
1013bool OVersatileView::sortDirection() const // QIconView
1014{
1015 if ( not isValidViewMode( Icons ) )
1016 {
1017 return false;
1018 }
1019 return _iconview->sortDirection();
1020}
1021
1022 void OVersatileView::setItemsMovable( bool b ) // QIconView
1023{
1024 if ( not isValidViewMode( Icons ) )
1025 {
1026 return;
1027 }
1028 _iconview->setItemsMovable( b );
1029}
1030bool OVersatileView::itemsMovable() const // QIconView
1031{
1032 if ( not isValidViewMode( Icons ) )
1033 {
1034 return false;
1035 }
1036 return _iconview->itemsMovable();
1037}
1038void OVersatileView::setWordWrapIconText( bool b ) // QIconView
1039{
1040 if ( not isValidViewMode( Icons ) )
1041 {
1042 return;
1043 }
1044 _iconview->setWordWrapIconText( b );
1045}
1046bool OVersatileView::wordWrapIconText() const // QIconView
1047{
1048 if ( not isValidViewMode( Icons ) )
1049 {
1050 return false;
1051 }
1052 return _iconview->wordWrapIconText();
1053}
1054
1055void OVersatileView::arrangeItemsInGrid( const QSize &grid, bool update ) // QIconView
1056{
1057 if ( not isValidViewMode( Icons ) )
1058 {
1059 return;
1060 }
1061 _iconview->arrangeItemsInGrid( grid, update );
1062}
1063void OVersatileView::arrangeItemsInGrid( bool update ) // QIconView
1064{
1065 if ( not isValidViewMode( Icons ) )
1066 {
1067 return;
1068 }
1069 _iconview->arrangeItemsInGrid( update );
1070}
1071void OVersatileView::updateContents() // QIconView
1072{
1073 if ( not isValidViewMode( Icons ) )
1074 {
1075 return;
1076 }
1077 _iconview->updateContents();
1078}
1079
1080//==============================================================================================//
1081// OVersatileView Case II - QListView / QIconView common API
1082//==============================================================================================//
1083
1084void OVersatileView::clear()
1085{
1086 _iconview->clear();
1087 _listview->clear();
1088}
1089
1090void OVersatileView::setFont( const QFont & font )
1091{
1092 _iconview->setFont( font );
1093 _listview->setFont( font );
1094}
1095void OVersatileView::setPalette( const QPalette & palette )
1096{
1097 _iconview->setPalette( palette );
1098 _listview->setPalette( palette );
1099}
1100
1101void OVersatileView::takeItem( OVersatileViewItem * item )
1102{
1103 _iconview->takeItem( item );
1104 _listview->takeItem( item );
1105}
1106
1107void OVersatileView::setSelectionMode( SelectionMode mode )
1108{
1109 _iconview->setSelectionMode( (QIconView::SelectionMode) mode );
1110 _listview->setSelectionMode( (QListView::SelectionMode) mode );
1111}
1112OVersatileView::SelectionMode OVersatileView::selectionMode() const
1113{
1114 return (OVersatileView::SelectionMode) _iconview->selectionMode();
1115}
1116
1117void OVersatileView::selectAll( bool select )
1118{
1119 _iconview->selectAll( select );
1120}
1121void OVersatileView::clearSelection()
1122{
1123 _iconview->clearSelection();
1124 _listview->clearSelection();
1125}
1126void OVersatileView::invertSelection()
1127{
1128 _iconview->invertSelection();
1129 _listview->invertSelection();
1130}
1131
1132void OVersatileView::ensureItemVisible( const OVersatileViewItem * item )
1133{
1134 _iconview->ensureItemVisible( const_cast<OVersatileViewItem*>( item ) );
1135 _listview->ensureItemVisible( item );
1136}
1137void OVersatileView::repaintItem( const OVersatileViewItem * item ) const
1138{
1139 _iconview->repaintItem( const_cast<OVersatileViewItem*>( item ) );
1140 _listview->repaintItem( item );
1141}
1142
1143void OVersatileView::setCurrentItem( OVersatileViewItem * item )
1144{
1145 _iconview->setCurrentItem( item );
1146 _listview->setCurrentItem( item );
1147}
1148OVersatileViewItem * OVersatileView::currentItem() const
1149{
1150 return static_cast<OVersatileViewItem*>( _listview->currentItem() );
1151}
1152
1153// bool eventFilter( QObject * o, QEvent * ) // use QWidgetStack implementation
1154
1155// QSize minimumSizeHint() const // use QWidgetStack implementation
1156// QSizePolicy sizePolicy() const // use QWidgetStack implementation
1157// QSize sizeHint() const // use QWidgetStack implementation
1158
1159//==============================================================================================//
1160// OVersatileView Case III - APIs which differ slightly
1161//==============================================================================================//
1162
1163/*
1164
1165 void OVersatileView::insertItem( OVersatileViewItem * ) // QListView
1166 void OVersatileView::insertItem( OVersatileViewItem *item, OVersatileViewItem *after = 0L ) // QIconView
1167
1168 void OVersatileView::setSelected( OVersatileViewItem *, bool ) // QListView
1169 void OVersatileView::setSelected( OVersatileViewItem *item, bool s, bool cb = FALSE ) // QIconView
1170
1171 void OVersatileView::setSorting( int column, bool increasing = TRUE ) // QListView
1172void OVersatileView::setSorting( bool sort, bool ascending = TRUE ) // QIconView
1173
1174void OVersatileView::sort() // #### make in next major release // QListView
1175 void OVersatileView::sort( bool ascending = TRUE ) // QIconView
1176
1177*/
1178
1179
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 @@
1/*
2                 This file is part of the Opie Project
3
4 =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28
29*/
30
31#ifndef OVERSATILEVIEW_H
32#define OVERSATILEVIEW_H
33
34/* QT */
35
36#include <qwidgetstack.h>
37#include <qiconview.h>
38
39/* OPIE */
40
41#include <qpe/qpeapplication.h>
42
43/* FORWARDS */
44
45class QHeader;
46class QIconSet;
47class QIconViewItem;
48class OListView;
49class QListViewItem;
50class QPopupMenu;
51class QString;
52
53#ifndef QT_NO_DRAGANDDROP
54class QIconDragItem;
55#endif
56
57class OVersatileView : public QWidgetStack
58{
59 Q_OBJECT
60
61 friend class OVersatileViewItem;
62
63 //==============================================================================================//
64 // OVersatileView High Level API
65 //==============================================================================================//
66
67 public:
68 OVersatileView( QWidget* parent = 0, const char* name = 0, int mode = 0 );
69 ~OVersatileView();
70
71 QPopupMenu* contextMenu() const;
72
73 void setSynchronization( bool sync );
74 bool synchronization();
75
76 enum ViewMode { Tree = 0, Icons };
77 int viewMode();
78
79 QIconView* iconView() const;
80 OListView* listView() const;
81
82 enum WarningPolicy { None = 0, Warn, WarnReturn };
83
84 void setWarningPolicy( int ) const; // warn, if calling a method which doesn't apply to the current viewmode
85 bool warningPolicy() const;
86
87 void setDefaultPixmaps( int mode, QPixmap& leaf, QPixmap& opened, QPixmap& closed );
88
89 public slots:
90 void setViewMode( int mode );
91 void setIconViewMode();
92 void setTreeViewMode();
93
94 protected:
95 virtual bool isValidViewMode( int mode ) const;
96 virtual void popupContextMenu( OVersatileViewItem* item, const QPoint& pos, int col = 0 );
97
98 private:
99 int _viewmode;
100 bool _synchronization;
101 mutable int _warningpolicy;
102
103 OListView* _listview;
104 QIconView* _iconview;
105
106 QPixmap _treeleaf;
107 QPixmap _treeopened;
108 QPixmap _treeclosed;
109
110 QPixmap _iconleaf;
111 QPixmap _iconopened;
112 QPixmap _iconclosed;
113
114 QPopupMenu* _contextmenu;
115
116 int _iconstyle;
117 int _treestyle;
118
119 private slots:
120
121 void contextMenuRequested( QListViewItem*, const QPoint&, int );
122 void contextMenuRequested( QIconViewItem*, const QPoint& );
123
124 // type converting signal forwarders
125
126 void selectionChanged( QListViewItem * );
127 void currentChanged( QListViewItem * );
128 void clicked( QListViewItem * );
129 void pressed( QListViewItem * );
130 void doubleClicked( QListViewItem * );
131 void returnPressed( QListViewItem * );
132 void onItem( QListViewItem * );
133
134 void selectionChanged( QIconViewItem * );
135 void currentChanged( QIconViewItem * );
136 void clicked( QIconViewItem * );
137 void pressed( QIconViewItem * );
138 void doubleClicked( QIconViewItem * );
139 void returnPressed( QIconViewItem * );
140 void onItem( QIconViewItem * );
141
142 void expanded( QListViewItem * item ); // QListView
143 void collapsed( QListViewItem * item ); // QListView
144
145 signals:
146
147 void contextMenuRequested( OVersatileViewItem * item, const QPoint& pos, int col );
148
149 /*#ifndef QT_NO_DRAGANDDROP
150 void dropped( QDropEvent *e, const QValueList<QIconDragItem> &lst ); // QIconView
151 #endif
152 void itemRenamed( OVersatileViewItem *item, const QString & ); // QIconView
153 void itemRenamed( OVersatileViewItem *item ); // QIconView
154 */
155
156 //==============================================================================================//
157 // "Derived" API - Case 1: Methods existing either only in QListView or only in QIconView
158 //==============================================================================================//
159
160public:
161
162 /*
163 enum Arrangement { // QIconView
164 LeftToRight = 0,
165 TopToBottom
166 };
167 enum ResizeMode { // QIconView
168 Fixed = 0,
169 Adjust
170 };
171 enum ItemTextPos { // QIconView
172 Bottom = 0,
173 Right
174 };
175 */
176
177 //
178 // only in QListView
179 //
180
181 int treeStepSize() const; // QListView
182 virtual void setTreeStepSize( int ); // QListView
183
184 QHeader * header() const; // QListView
185
186 virtual int addColumn( const QString &label, int size = -1); // QListView
187 virtual int addColumn( const QIconSet& iconset, const QString &label, int size = -1); // QListView
188 void removeColumn( int index ); // #### make virtual in next major release! // QListView
189 virtual void setColumnText( int column, const QString &label ); // QListView
190 virtual void setColumnText( int column, const QIconSet& iconset, const QString &label ); // QListView
191 QString columnText( int column ) const; // QListView
192 virtual void setColumnWidth( int column, int width ); // QListView
193 int columnWidth( int column ) const; // QListView
194 enum WidthMode { Manual, Maximum }; // QListView
195 virtual void setColumnWidthMode( int column, WidthMode ); // QListView
196 WidthMode columnWidthMode( int column ) const; // QListView
197 int columns() const; // QListView
198
199 virtual void setColumnAlignment( int, int ); // QListView
200 int columnAlignment( int ) const; // QListView
201
202 OVersatileViewItem * itemAt( const QPoint & screenPos ) const; // QListView
203 QRect itemRect( const OVersatileViewItem * ) const; // QListView
204 int itemPos( const OVersatileViewItem * ); // QListView
205
206 bool isSelected( const OVersatileViewItem * ) const; // QListView // also in QIconViewItem but not in QIconView *shrug*
207
208 virtual void setMultiSelection( bool enable ); // QListView
209 bool isMultiSelection() const; // QListView
210
211 OVersatileViewItem * selectedItem() const; // QListView
212 virtual void setOpen( OVersatileViewItem *, bool ); // QListView
213 bool isOpen( const OVersatileViewItem * ) const; // QListView
214
215 OVersatileViewItem * firstChild() const; // QListView
216 int childCount() const; // QListView
217
218 virtual void setAllColumnsShowFocus( bool ); // QListView
219 bool allColumnsShowFocus() const; // QListView
220
221 virtual void setItemMargin( int ); // QListView
222 int itemMargin() const; // QListView
223
224 virtual void setRootIsDecorated( bool ); // QListView
225 bool rootIsDecorated() const; // QListView
226
227 void setShowSortIndicator( bool show ); // QListView
228 bool showSortIndicator() const; // QListView
229
230 int index( const OVersatileViewItem *item ) const; // QIconView
231
232 public slots:
233 void triggerUpdate(); // QListView
234
235 signals:
236 void expanded( OVersatileViewItem *item ); // QListView
237 void collapsed( OVersatileViewItem *item ); // QListView
238
239 //
240 // only in QIconView
241 //
242
243 public:
244 uint count() const; // QIconView
245
246 OVersatileViewItem *firstItem() const; // QIconView
247 OVersatileViewItem *lastItem() const; // QIconView
248
249 OVersatileViewItem *findItem( const QPoint &pos ) const; // QIconView
250 OVersatileViewItem *findItem( const QString &text ) const; // QIconView
251
252 OVersatileViewItem* findFirstVisibleItem( const QRect &r ) const; // QIconView
253 OVersatileViewItem* findLastVisibleItem( const QRect &r ) const; // QIconView
254
255 virtual void setGridX( int rx ); // QIconView
256 virtual void setGridY( int ry ); // QIconView
257 int gridX() const; // QIconView
258 int gridY() const; // QIconView
259 virtual void setSpacing( int sp ); // QIconView
260 int spacing() const; // QIconView
261 virtual void setItemTextPos( QIconView::ItemTextPos pos ); // QIconView
262 QIconView::ItemTextPos itemTextPos() const; // QIconView
263 virtual void setItemTextBackground( const QBrush &b ); // QIconView
264 QBrush itemTextBackground() const; // QIconView
265 virtual void setArrangement( QIconView::Arrangement am ); // QIconView
266 QIconView::Arrangement arrangement() const; // QIconView
267 virtual void setResizeMode( QIconView::ResizeMode am ); // QIconView
268 QIconView::ResizeMode resizeMode() const; // QIconView
269 virtual void setMaxItemWidth( int w ); // QIconView
270 int maxItemWidth() const; // QIconView
271 virtual void setMaxItemTextLength( int w ); // QIconView
272 int maxItemTextLength() const; // QIconView
273 virtual void setAutoArrange( bool b ); // QIconView
274 bool autoArrange() const; // QIconView
275 virtual void setShowToolTips( bool b ); // QIconView
276 bool showToolTips() const; // QIconView
277
278 bool sorting() const; // QIconView
279 bool sortDirection() const; // QIconView
280
281 virtual void setItemsMovable( bool b ); // QIconView
282 bool itemsMovable() const; // QIconView
283 virtual void setWordWrapIconText( bool b ); // QIconView
284 bool wordWrapIconText() const; // QIconView
285
286 public slots:
287 virtual void arrangeItemsInGrid( const QSize &grid, bool update = TRUE ); // QIconView
288 virtual void arrangeItemsInGrid( bool update = TRUE ); // QIconView
289 virtual void updateContents(); // QIconView
290
291 signals:
292 /*#ifndef QT_NO_DRAGANDDROP
293 void dropped( QDropEvent *e, const QValueList<QIconDragItem> &lst ); // QIconView
294 #endif
295 */
296 void moved(); // QIconView
297 void itemRenamed( OVersatileViewItem *item, const QString & ); // QIconView
298 void itemRenamed( OVersatileViewItem *item ); // QIconView
299
300 //==============================================================================================//
301 // "Derived" API - Case 2: Methods existing in QListView and QIconView with the same signatures
302 //==============================================================================================//
303
304 public:
305 enum SelectionMode {
306 Single = 0,
307 Multi,
308 Extended,
309 NoSelection
310 };
311
312 virtual void clear();
313
314 virtual void setFont( const QFont & );
315 virtual void setPalette( const QPalette & );
316
317 virtual void takeItem( OVersatileViewItem * );
318
319 void setSelectionMode( SelectionMode mode );
320 SelectionMode selectionMode() const;
321
322 virtual void selectAll( bool select );
323 virtual void clearSelection();
324 virtual void invertSelection();
325
326 void ensureItemVisible( const OVersatileViewItem * );
327 virtual void repaintItem( const OVersatileViewItem * ) const;
328
329 virtual void setCurrentItem( OVersatileViewItem * );
330 OVersatileViewItem * currentItem() const;
331
332 // bool eventFilter( QObject * o, QEvent * ); // use QWidgetStack implementation
333
334 // QSize minimumSizeHint() const; // use QWidgetStack implementation
335 // QSizePolicy sizePolicy() const; // use QWidgetStack implementation
336 // QSize sizeHint() const; // use QWidgetStack implementation
337
338 signals:
339 void selectionChanged();
340 void selectionChanged( OVersatileViewItem * );
341 void currentChanged( OVersatileViewItem * );
342 void clicked( OVersatileViewItem * );
343 void pressed( OVersatileViewItem * );
344
345 void doubleClicked( OVersatileViewItem * );
346 void returnPressed( OVersatileViewItem * );
347
348 void onItem( OVersatileViewItem * );
349 void onViewport();
350
351 //==============================================================================================//
352 // "Derived" API - Case 2: Methods existing in QListView and QIconView with differing signatures
353 //==============================================================================================//
354
355 /*
356
357 public:
358 virtual void insertItem( OVersatileViewItem * ); // QListView
359 virtual void insertItem( OVersatileViewItem *item, OVersatileViewItem *after = 0L ); // QIconView
360
361 virtual void setSelected( OVersatileViewItem *, bool ); // QListView
362 virtual void setSelected( OVersatileViewItem *item, bool s, bool cb = FALSE ); // QIconView
363
364 virtual void setSorting( int column, bool increasing = TRUE ); // QListView
365 void setSorting( bool sort, bool ascending = TRUE ); // QIconView
366
367 void sort(); // #### make virtual in next major release // QListView
368 virtual void sort( bool ascending = TRUE ); // QIconView
369
370 */
371
372 signals:
373 void clicked( OVersatileViewItem *, const QPoint &, int ); // QListView
374 void clicked( OVersatileViewItem *, const QPoint & ); // QIconView
375
376 void pressed( OVersatileViewItem *, const QPoint &, int ); // QListView
377 void pressed( OVersatileViewItem *, const QPoint & ); // QIconView
378
379 void rightButtonClicked( OVersatileViewItem* item, const QPoint& pos ); // QIconView
380 void rightButtonClicked( OVersatileViewItem *, const QPoint&, int ); // QListView
381
382 void rightButtonPressed( OVersatileViewItem* item, const QPoint& pos ); // QIconView
383 void rightButtonPressed( OVersatileViewItem *, const QPoint&, int ); // QListView
384
385 void mouseButtonPressed( int, OVersatileViewItem *, const QPoint& , int ); // QListView
386 void mouseButtonPressed( int button, OVersatileViewItem* item, const QPoint& pos ); // QIconView
387
388 void mouseButtonClicked( int, OVersatileViewItem *, const QPoint&, int ); // QListView
389 void mouseButtonClicked( int button, OVersatileViewItem* item, const QPoint& pos ); // QIconView
390
391};
392
393#endif
394
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 @@
1/*
2                 This file is part of the Opie Project
3
4 =. (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 .=l.
6           .>+-=
7 _;:,     .>    :=|. This program is free software; you can
8.> <`_,   >  .   <= redistribute it and/or modify it under
9:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
10.="- .-=="i,     .._ License as published by the Free Software
11 - .   .-<_>     .<> Foundation; either version 2 of the License,
12     ._= =}       : or (at your option) any later version.
13    .%`+i>       _;_.
14    .i_,=:_.      -<s. This program is distributed in the hope that
15     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
16    : ..    .:,     . . . without even the implied warranty of
17    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
18  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
19..}^=.=       =       ; Library General Public License for more
20++=   -.     .`     .: details.
21 :     =  ...= . :.=-
22 -.   .:....=;==+<; You should have received a copy of the GNU
23  -_. . .   )=.  = Library General Public License along with
24    --        :-=` this library; see the file COPYING.LIB.
25 If not, write to the Free Software Foundation,
26 Inc., 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, USA.
28
29*/
30
31#include <opie2/oversatileviewitem.h>
32#include <opie2/oversatileview.h>
33
34OVersatileViewItem::OVersatileViewItem( OVersatileView * parent )
35 :OListViewItem( parent->_listview ), QIconViewItem( parent->_iconview ),
36 _versatileview( parent )
37{
38 init();
39}
40
41OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after )
42 :OListViewItem( parent->_listview, after ), QIconViewItem( parent->_iconview, after ),
43 _versatileview( parent )
44{
45 init();
46}
47
48OVersatileViewItem::OVersatileViewItem( OVersatileView * parent,
49 QString a, QString b, QString c, QString d,
50 QString e, QString f, QString g, QString h )
51 :OListViewItem( parent->_listview, a, b, c, d, e, f, g, h ),
52 QIconViewItem( parent->_iconview, a ),
53 _versatileview( parent )
54{
55 init();
56}
57
58OVersatileViewItem::OVersatileViewItem( OVersatileView * parent, OVersatileViewItem* after,
59 QString a, QString b, QString c, QString d,
60 QString e, QString f, QString g, QString h )
61 :OListViewItem( parent->_listview, after, a, b, c, d, e, f, g, h ),
62 QIconViewItem( parent->_iconview, after, a ),
63 _versatileview( parent )
64{
65 init();
66}
67
68OVersatileViewItem::OVersatileViewItem( OVersatileViewItem * parent,
69 QString a, QString b, QString c, QString d,
70 QString e, QString f, QString g, QString h )
71 :OListViewItem( parent, a, b, c, d, e, f, g, h ),
72 QIconViewItem( parent->_versatileview->_iconview, a ),
73 _versatileview( parent->_versatileview )
74{
75 init();
76}
77
78OVersatileViewItem::OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem* after,
79 QString a, QString b, QString c, QString d,
80 QString e, QString f, QString g, QString h )
81 :OListViewItem( parent, after, a, b, c, d, e, f, g, h ),
82 QIconViewItem( parent->_versatileview->_iconview, after, a ),
83 _versatileview( parent->_versatileview )
84{
85 init();
86}
87
88OVersatileViewItem::~OVersatileViewItem()
89{
90}
91
92OVersatileView* OVersatileViewItem::versatileView() const
93{
94 return _versatileview;
95}
96
97void OVersatileViewItem::init()
98{
99 if ( not firstChild() )
100 {
101 // I'm a sweet yellow and browne autumn leaf
102
103 OListViewItem::setPixmap( 0, _versatileview->_treeleaf );
104 QIconViewItem::setPixmap( _versatileview->_iconleaf );
105 }
106 else
107 {
108 // I'm a node and I have a little baby child
109
110 if ( isOpen() )
111 {
112 OListViewItem::setPixmap( 0, _versatileview->_treeopened );
113 QIconViewItem::setPixmap( _versatileview->_iconopened );
114 }
115 else
116 {
117 OListViewItem::setPixmap( 0, _versatileview->_treeclosed );
118 QIconViewItem::setPixmap( _versatileview->_iconclosed );
119 }
120 }
121
122}
123
124void OVersatileViewItem::setRenameEnabled( bool allow )
125{
126 #if (QT_VERSION >= 0x030000)
127 OListViewItem::setRenameEnabled( 0, allow ); // TODO: Backport to Qt-Embedded 2.x?
128 #endif
129 QIconViewItem::setRenameEnabled( allow );
130}
131
132
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 @@
1/*
2                 This file is part of the Opie Project
3
4              Copyright (C) 2003 Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>
5 =.
6 .=l.
7           .>+-=
8 _;:,     .>    :=|. This program is free software; you can
9.> <`_,   >  .   <= redistribute it and/or modify it under
10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
11.="- .-=="i,     .._ License as published by the Free Software
12 - .   .-<_>     .<> Foundation; either version 2 of the License,
13     ._= =}       : or (at your option) any later version.
14    .%`+i>       _;_.
15    .i_,=:_.      -<s. This program is distributed in the hope that
16     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
17    : ..    .:,     . . . without even the implied warranty of
18    =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
19  _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
20..}^=.=       =       ; Library General Public License for more
21++=   -.     .`     .: details.
22 :     =  ...= . :.=-
23 -.   .:....=;==+<; You should have received a copy of the GNU
24  -_. . .   )=.  = Library General Public License along with
25    --        :-=` this library; see the file COPYING.LIB.
26 If not, write to the Free Software Foundation,
27 Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA.
29
30*/
31
32#ifndef OVERSATILEVIEWITEM_H
33#define OVERSATILEVIEWITEM_H
34
35/* QT */
36
37#include <qiconview.h>
38
39/* OPIE */
40
41#include <opie2/olistview.h>
42
43class OVersatileView;
44
45class OVersatileViewItem : public OListViewItem, public QIconViewItem
46{
47 public:
48 OVersatileViewItem( OVersatileView * parent );
49
50 OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after );
51
52 OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem * after );
53
54 OVersatileViewItem( OVersatileView * parent, QString,
55 QString = QString::null, QString = QString::null,
56 QString = QString::null, QString = QString::null,
57 QString = QString::null, QString = QString::null,
58 QString = QString::null );
59
60 OVersatileViewItem( OVersatileViewItem * parent, QString,
61 QString = QString::null, QString = QString::null,
62 QString = QString::null, QString = QString::null,
63 QString = QString::null, QString = QString::null,
64 QString = QString::null );
65
66 OVersatileViewItem( OVersatileView * parent, OVersatileViewItem * after, QString,
67 QString = QString::null, QString = QString::null,
68 QString = QString::null, QString = QString::null,
69 QString = QString::null, QString = QString::null,
70 QString = QString::null );
71
72 OVersatileViewItem( OVersatileViewItem * parent, OVersatileViewItem * after, QString,
73 QString = QString::null, QString = QString::null,
74 QString = QString::null, QString = QString::null,
75 QString = QString::null, QString = QString::null,
76 QString = QString::null );
77
78 virtual ~OVersatileViewItem();
79
80 OVersatileView* versatileView() const;
81
82 // TODO: Implement the remaining constructors from QIconView
83
84 /* OIconViewItem( QIconView *parent, const QString &text, const QPixmap &icon );
85 OIconViewItem( QIconView *parent, QIconViewItem *after, const QString &text, const QPixmap &icon );
86 */
87
88 virtual void setRenameEnabled( bool );
89
90 // TODO: Implement the remaining method multiplexers
91
92 private:
93 OVersatileView* _versatileview;
94
95 private:
96 void init();
97
98};
99
100#endif