2 Copyright (c) 2002 Malte Starostik <malte@kde.org>
3 (c) 2002,2003 Maksim Orlovich <maksim@kde.org>
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 as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "pixmaploader.h"
23 #include <QtGui/QApplication>
24 #include <QtGui/QBitmap>
25 #include <QtCore/QBool>
26 #include <QtGui/QImage>
27 #include <QtGui/QPainter>
28 #include <QtGui/QPixmap>
29 #include <QtGui/QPixmapCache>
32 #include "pixmaps.keramik"
34 using namespace Keramik
;
36 PixmapLoader
* PixmapLoader::s_instance
= 0;
38 PixmapLoader::PixmapLoader()
41 m_pixmapCache
.setMaxCost(327680);
42 //size of 100? m_pixmapCache.
43 for (int c
=0; c
<256; c
++)
44 clamp
[c
]=static_cast<unsigned char>(c
);
46 for (int c
=256; c
<540; c
++)
51 void PixmapLoader::clear()
56 QImage
* PixmapLoader::getDisabled(int name
, const QColor
& color
, const QColor
& back
, bool blend
)
58 const KeramikEmbedImage
* edata
= KeramikGetDbImage(name
);
62 //Like getColored, but desaturate a bit, and lower gamma..
64 //Create a real image...
65 QImage::Format format
= ( edata
->haveAlpha
&& !blend
? QImage::Format_ARGB32
: QImage::Format_RGB32
);
66 QImage
* img
= new QImage(edata
->width
, edata
->height
, format
);
70 //OK, now, fill it in, using the color..
72 quint32 i
= qGray(color
.rgb());
73 r
= (3*color
.red()+i
)>>2;
74 g
= (3*color
.green()+i
)>>2;
75 b
= (3*color
.blue()+i
)>>2;
77 quint32 br
= back
.red(), bg
= back
.green(), bb
= back
.blue();
84 quint32
* write
= reinterpret_cast< quint32
* >(img
->bits() );
85 int size
= img
->width()*img
->height() * 3;
87 for (int pos
= 0; pos
< size
; pos
+=3)
89 quint32 scale
= edata
->data
[pos
];
90 quint32 add
= (edata
->data
[pos
+1]*i
+127)>>8;
91 quint32 alpha
= edata
->data
[pos
+2];
92 quint32 destAlpha
= 256 - alpha
;
94 quint32 rr
= clamp
[((r
*scale
+127)>>8) + add
];
95 quint32 rg
= clamp
[((g
*scale
+127)>>8) + add
];
96 quint32 rb
= clamp
[((b
*scale
+127)>>8) + add
];
98 *write
=qRgb(((rr
*alpha
+127)>>8) + ((br
*destAlpha
+127)>>8),
99 ((rg
*alpha
+127)>>8) + ((bg
*destAlpha
+127)>>8),
100 ((rb
*alpha
+127)>>8) + ((bb
*destAlpha
+127)>>8));
107 quint32
* write
= reinterpret_cast< quint32
* >(img
->bits() );
108 int size
= img
->width()*img
->height() * 3;
110 for (int pos
= 0; pos
< size
; pos
+=3)
112 quint32 scale
= edata
->data
[pos
];
113 quint32 add
= (edata
->data
[pos
+1]*i
+127)>>8;
114 quint32 alpha
= edata
->data
[pos
+2];
116 quint32 rr
= clamp
[((r
*scale
+127)>>8) + add
];
117 quint32 rg
= clamp
[((g
*scale
+127)>>8) + add
];
118 quint32 rb
= clamp
[((b
*scale
+127)>>8) + add
];
120 *write
=qRgba(rr
, rg
, rb
, alpha
);
129 quint32
* write
= reinterpret_cast< quint32
* >(img
->bits() );
130 int size
= img
->width()*img
->height() * 2;
132 for (int pos
= 0; pos
< size
; pos
+=2)
134 quint32 scale
= edata
->data
[pos
];
135 quint32 add
= (edata
->data
[pos
+1]*i
+127)>>8;
136 quint32 rr
= clamp
[((r
*scale
+127)>>8) + add
];
137 quint32 rg
= clamp
[((g
*scale
+127)>>8) + add
];
138 quint32 rb
= clamp
[((b
*scale
+127)>>8) + add
];
139 *write
=qRgb(rr
, rg
, rb
);
147 QImage
* PixmapLoader::getColored(int name
, const QColor
& color
, const QColor
& back
, bool blend
)
149 const KeramikEmbedImage
* edata
= KeramikGetDbImage(name
);
153 //Create a real image...
154 QImage::Format format
= ( edata
->haveAlpha
&& !blend
? QImage::Format_ARGB32
: QImage::Format_RGB32
);
155 QImage
* img
= new QImage(edata
->width
, edata
->height
, format
);
157 //OK, now, fill it in, using the color..
160 g
= color
.green() + 2;
161 b
= color
.blue() + 2;
163 // int i = qGray(color.rgb());
165 quint32 br
= back
.red(), bg
= back
.green(), bb
= back
.blue();
167 if (edata
->haveAlpha
)
171 quint32
* write
= reinterpret_cast< quint32
* >(img
->bits() );
172 int size
= img
->width()*img
->height() * 3;
173 for (int pos
= 0; pos
< size
; pos
+=3)
175 quint32 scale
= edata
->data
[pos
];
176 quint32 add
= edata
->data
[pos
+1];
177 quint32 alpha
= edata
->data
[pos
+2];
178 quint32 destAlpha
= 256 - alpha
;
183 quint32 rr
= clamp
[((r
*scale
+127)>>8) + add
];
184 quint32 rg
= clamp
[((g
*scale
+127)>>8) + add
];
185 quint32 rb
= clamp
[((b
*scale
+127)>>8) + add
];
187 *write
=qRgb(((rr
*alpha
+127)>>8) + ((br
*destAlpha
+127)>>8),
188 ((rg
*alpha
+127)>>8) + ((bg
*destAlpha
+127)>>8),
189 ((rb
*alpha
+127)>>8) + ((bb
*destAlpha
+127)>>8));
196 quint32
* write
= reinterpret_cast< quint32
* >(img
->bits() );
197 int size
= img
->width()*img
->height() * 3;
199 for (int pos
= 0; pos
< size
; pos
+=3)
201 quint32 scale
= edata
->data
[pos
];
202 quint32 add
= edata
->data
[pos
+1];
203 quint32 alpha
= edata
->data
[pos
+2];
207 quint32 rr
= clamp
[((r
*scale
+127)>>8) + add
];
208 quint32 rg
= clamp
[((g
*scale
+127)>>8) + add
];
209 quint32 rb
= clamp
[((b
*scale
+127)>>8) + add
];
211 *write
=qRgba(rr
, rg
, rb
, alpha
);
218 quint32
* write
= reinterpret_cast< quint32
* >(img
->bits() );
219 int size
= img
->width()*img
->height() * 2;
221 for (int pos
= 0; pos
< size
; pos
+=2)
223 quint32 scale
= edata
->data
[pos
];
224 quint32 add
= edata
->data
[pos
+1];
228 quint32 rr
= clamp
[((r
*scale
+127)>>8) + add
];
229 quint32 rg
= clamp
[((g
*scale
+127)>>8) + add
];
230 quint32 rb
= clamp
[((b
*scale
+127)>>8) + add
];
233 *write
= qRgb(rr
, rg
, rb
);
241 QPixmap
PixmapLoader::pixmap( int name
, const QColor
& color
, const QColor
& bg
, bool disabled
, bool blend
)
243 return scale(name
, 0, 0, color
, bg
, disabled
, blend
);
247 QPixmap
PixmapLoader::scale( int name
, int width
, int height
, const QColor
& color
, const QColor
& bg
, bool disabled
, bool blend
)
249 KeramikCacheEntry
entry(name
, color
, bg
, disabled
, blend
, width
, height
);
250 KeramikCacheEntry
* cacheEntry
;
252 int key
= entry
.key();
254 if ((cacheEntry
= m_pixmapCache
.take(key
)))
256 if (entry
== *cacheEntry
) //True match!
257 return *cacheEntry
->m_pixmap
;
265 img
= getDisabled(name
, color
, bg
, blend
);
267 img
= getColored(name
, color
, bg
, blend
);
271 KeramikCacheEntry
* toAdd
= new KeramikCacheEntry(entry
);
272 toAdd
->m_pixmap
= new QPixmap();
273 m_pixmapCache
.insert(key
, toAdd
, 16);
277 if (width
== 0 && height
== 0)
278 result
= new QPixmap(QPixmap::fromImage(*img
));
280 result
= new QPixmap(QPixmap::fromImage(img
->scaled(width
? width
: img
->width(),
281 height
? height
: img
->height())));//,
282 //Qt::IgnoreAspectRatio,
283 //Qt::SmoothTransformation));
285 KeramikCacheEntry
* toAdd
= new KeramikCacheEntry(entry
);
286 toAdd
->m_pixmap
= result
;
289 if (!m_pixmapCache
.insert(key
, toAdd
, result
->width()*result
->height()*result
->depth()/8)) {
291 QPixmap toRet
= *result
;
299 QSize
PixmapLoader::size( int id
)
301 const KeramikEmbedImage
* edata
= KeramikGetDbImage(id
);
304 return QSize(edata
->width
, edata
->height
);
307 void TilePainter::draw( QPainter
*p
, int x
, int y
, int width
, int height
, const QColor
& color
, const QColor
& bg
, bool disabled
, PaintMode mode
)
309 if (mode
== PaintTrivialMask
)
311 p
->fillRect(x
, y
, width
, height
, Qt::color1
);
315 bool swBlend
= (mode
!= PaintFullBlend
);
316 unsigned int scaledColumns
= 0, scaledRows
= 0, lastScaledColumn
= 0, lastScaledRow
= 0;
317 int scaleWidth
= width
, scaleHeight
= height
;
319 //scaleWidth, scaleHeight are calculated to contain the area available
320 //for all tiled and stretched columns/rows respectively.
321 //This is need to redistribute the area remaining after painting
322 //the "fixed" elements. We also keep track of the last col and row
323 //being scaled so rounding errors don't cause us to be short a pixel or so.
324 for ( unsigned int col
= 0; col
< columns(); ++col
)
325 if ( columnMode( col
) != Fixed
)
328 lastScaledColumn
= col
;
330 else scaleWidth
-= PixmapLoader::the().size (absTileName( col
, 0 ) ).width();
332 for ( unsigned int row
= 0; row
< rows(); ++row
)
333 if ( rowMode( row
) != Fixed
)
338 else scaleHeight
-= PixmapLoader::the().size (absTileName( 0, row
) ).height();
341 if ( scaleWidth
< 0 ) scaleWidth
= 0;
342 if ( scaleHeight
< 0 ) scaleHeight
= 0;
347 //Center vertically if everything is fixed but there is extra room remaining
348 if ( scaleHeight
&& !scaledRows
)
349 ypos
+= scaleHeight
/ 2;
351 for ( unsigned int row
= 0; row
< rows(); ++row
)
355 //Center horizontally if extra space and no where to redistribute it to...
356 if ( scaleWidth
&& !scaledColumns
)
357 xpos
+= scaleWidth
/ 2;
359 //If not fixed vertically, calculate our share of space available
361 int h
= rowMode( row
) == Fixed
? 0 : scaleHeight
/ scaledRows
;
363 //Redistribute any "extra" pixels to the last scaleable row.
364 if ( scaledRows
&& row
== lastScaledRow
)
366 int allocatedEvenly
= scaleHeight
/ scaledRows
* scaledRows
;
367 h
+= scaleHeight
- allocatedEvenly
;
371 //If we're fixed, get the height from the pixmap itself.
372 int realH
= h
? h
: PixmapLoader::the().size (absTileName( 0, row
) ).height();
374 //Skip non-fitting stretched/tiled rows, too.
375 if (rowMode( row
) != Fixed
&& h
== 0)
379 //Set h to 0 to denote that we aren't scaling
380 if ( rowMode( row
) == Tiled
)
383 for ( unsigned int col
= 0; col
< columns(); ++col
)
385 //Calculate width for rows that aren't fixed.
386 int w
= columnMode( col
) == Fixed
? 0 : scaleWidth
/ scaledColumns
;
388 //Get the width of the pixmap..
389 int tileW
= PixmapLoader::the().size (absTileName( col
, row
) ).width();
391 //Redistribute any extra pixels..
392 if ( scaledColumns
&& col
== lastScaledColumn
) w
+= scaleWidth
- scaleWidth
/ scaledColumns
* scaledColumns
;
394 //The width to use...
395 int realW
= w
? w
: tileW
;
397 //Skip any non-fitting stretched/tiled columns
398 if (columnMode( col
) != Fixed
&& w
== 0)
401 //Set w to 0 to denote that we aren't scaling
402 if ( columnMode( col
) == Tiled
)
405 //If we do indeed have a pixmap..
408 //If scaling in either direction.
411 if (mode
!= PaintMask
)
413 p
->drawTiledPixmap( xpos
, ypos
, realW
, realH
, scale( col
, row
, w
, h
, color
, bg
, disabled
, swBlend
) );
417 const QBitmap* mask = scale( col, row, w, h, color, bg, disabled, false ).mask();
420 //### ?p->setBackgroundColor(Qt::color0);
421 p->setPen(Qt::color1);
422 p->drawTiledPixmap( xpos, ypos, realW, realH, *mask);
425 p->fillRect ( xpos, ypos, realW, realH, Qt::color1);
430 //Tiling (or fixed, the same really)
431 if (mode
!= PaintMask
)
433 p
->drawTiledPixmap( xpos
, ypos
, realW
, realH
, tile( col
, row
, color
, bg
, disabled
, swBlend
) );
437 const QBitmap* mask = tile( col, row, color, bg, disabled, false ).mask();
440 // ### ? p->setBackgroundColor(Qt::color0);
441 p->setPen(Qt::color1);
442 p->drawTiledPixmap( xpos, ypos, realW, realH, *mask);
445 p->fillRect ( xpos, ypos, realW, realH, Qt::color1);
451 //Advance horizontal position
455 //Advance vertical position
460 RectTilePainter::RectTilePainter( int name
,
461 bool scaleH
, bool scaleV
,
462 unsigned int columns
, unsigned int rows
)
463 : TilePainter( name
),
470 TileMode mh
= m_scaleH
? Scaled
: Tiled
;
471 TileMode mv
= m_scaleV
? Scaled
: Tiled
;
472 for (int c
=0; c
<4; c
++)
480 for (int c
=0; c
<4; c
++)
490 int RectTilePainter::tileName( unsigned int column
, unsigned int row
) const
492 return row
*3 + column
;
495 ActiveTabPainter::ActiveTabPainter( bool bottom
)
496 : RectTilePainter( bottom
? keramik_tab_bottom_active
: keramik_tab_top_active
, false),
502 rowMde
[0] = rowMde
[2] = rowMde
[3] = Scaled
;
507 rowMde
[0] = rowMde
[2] = rowMde
[3] = Fixed
;
512 int ActiveTabPainter::tileName( unsigned int column
, unsigned int row
) const
515 return RectTilePainter::tileName( column
, row
+ 1 );
516 return RectTilePainter::tileName( column
, row
);
520 InactiveTabPainter::InactiveTabPainter( QStyleOptionTab::TabPosition mode
, bool bottom
)
521 : RectTilePainter( bottom
? keramik_tab_bottom_inactive
: keramik_tab_top_inactive
, false),
522 m_mode( mode
), m_bottom( bottom
)
537 Most fully, inactive tabs look like this:
542 Where L,C, and R denote the tile positions. Of course, we don't want to draw all of the rounding for all the tabs.
544 We want the left-most tab to look like this:
550 "Middle" tabs look like this:
556 And the right most tab looks like this:
562 So we have to vary the number of columns, and for everything but left-most tab, the L tab gets the special separator
566 //Mode rightMost = QApplication::isRightToLeft() ? First : Last;
568 m_columns
= (m_mode
== QStyleOptionTab::End
? 3 : 2);
573 int InactiveTabPainter::tileName( unsigned int column
, unsigned int row
) const
576 //Mode leftMost = QApplication::isRightToLeft() ? Last : First;
577 if ( column
== 0 && m_mode
!= QStyleOptionTab::Beginning
)
578 return KeramikTileSeparator
;
580 return RectTilePainter::tileName( column
, row
+ 1 );
581 return RectTilePainter::tileName( column
, row
);
585 ScrollBarPainter::ScrollBarPainter( int type
, int count
, bool horizontal
)
586 : TilePainter( name( horizontal
) ),
589 m_horizontal( horizontal
)
591 for (int c
=0; c
<5; c
++)
593 if ( !m_horizontal
|| !( c
% 2 ) ) colMde
[c
] = Fixed
;
594 else colMde
[c
] = Tiled
;
596 if ( m_horizontal
|| !( c
% 2 ) ) rowMde
[c
] = Fixed
;
597 else rowMde
[c
] = Tiled
;
600 m_columns
= m_horizontal
? m_count
: 1;
601 m_rows
= m_horizontal
? 1 : m_count
;
607 int ScrollBarPainter::name( bool horizontal
)
609 return horizontal
? keramik_scrollbar_hbar
: keramik_scrollbar_vbar
;
612 int ScrollBarPainter::tileName( unsigned int column
, unsigned int row
) const
614 unsigned int num
= ( column
? column
: row
) + 1;
616 if ( num
== 3 ) num
= 4;
617 else if ( num
== 4 ) num
= 2;
618 else if ( num
== 5 ) num
= 3;
620 return m_type
+ (num
-1)*16;
623 int SpinBoxPainter::tileName( unsigned int column
, unsigned int ) const
628 // vim: ts=4 sw=4 noet
629 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;