Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / runtime / kstyles / keramik / pixmaploader.cpp
blobb9802ca3d7b45ff5096ba13e652c011d881ece01
1 /*
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++)
47 clamp[c] = 255;
51 void PixmapLoader::clear()
53 //m_cache.clear();
56 QImage* PixmapLoader::getDisabled(int name, const QColor& color, const QColor& back, bool blend)
58 const KeramikEmbedImage* edata = KeramikGetDbImage(name);
59 if (!edata)
60 return 0;
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..
71 quint32 r, g,b;
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();
80 if (edata->haveAlpha)
82 if (blend)
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));
102 write++;
105 else
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);
122 write++;
127 else
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);
140 write++;
144 return img;
147 QImage* PixmapLoader::getColored(int name, const QColor& color, const QColor& back, bool blend)
149 const KeramikEmbedImage* edata = KeramikGetDbImage(name);
150 if (!edata)
151 return 0;
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..
158 quint32 r, g,b;
159 r = color.red() + 2;
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)
169 if (blend)
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;
180 if (scale != 0)
181 add = add*5/4;
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));
191 write++;
194 else
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];
204 if (scale != 0)
205 add = add*5/4;
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);
212 write++;
216 else
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];
225 if (scale != 0)
226 add = add*5/4;
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);
234 write++;
238 return img;
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;
261 QImage* img = 0;
262 QPixmap* result = 0;
264 if (disabled)
265 img = getDisabled(name, color, bg, blend);
266 else
267 img = getColored(name, color, bg, blend);
269 if (!img)
271 KeramikCacheEntry* toAdd = new KeramikCacheEntry(entry);
272 toAdd->m_pixmap = new QPixmap();
273 m_pixmapCache.insert(key, toAdd, 16);
274 return QPixmap();
277 if (width == 0 && height == 0)
278 result = new QPixmap(QPixmap::fromImage(*img));
279 else
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;
287 delete img;
289 if (!m_pixmapCache.insert(key, toAdd, result->width()*result->height()*result->depth()/8)) {
291 QPixmap toRet = *result;
292 delete toAdd;
293 return toRet;
296 return *result;
299 QSize PixmapLoader::size( int id )
301 const KeramikEmbedImage* edata = KeramikGetDbImage(id);
302 if (!edata)
303 return QSize(0,0);
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);
312 return;
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 )
327 scaledColumns++;
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 )
335 scaledRows++;
336 lastScaledRow = row;
338 else scaleHeight -= PixmapLoader::the().size (absTileName( 0, row ) ).height();
341 if ( scaleWidth < 0 ) scaleWidth = 0;
342 if ( scaleHeight < 0 ) scaleHeight = 0;
345 int ypos = y;
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 )
353 int xpos = x;
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
360 //for scalable rows.
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)
376 continue;
379 //Set h to 0 to denote that we aren't scaling
380 if ( rowMode( row ) == Tiled )
381 h = 0;
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)
399 continue;
401 //Set w to 0 to denote that we aren't scaling
402 if ( columnMode( col ) == Tiled )
403 w = 0;
405 //If we do indeed have a pixmap..
406 if ( tileW )
408 //If scaling in either direction.
409 if ( w || h )
411 if (mode != PaintMask)
413 p->drawTiledPixmap( xpos, ypos, realW, realH, scale( col, row, w, h, color, bg, disabled, swBlend ) );
415 /* else
417 const QBitmap* mask = scale( col, row, w, h, color, bg, disabled, false ).mask();
418 if (mask)
420 //### ?p->setBackgroundColor(Qt::color0);
421 p->setPen(Qt::color1);
422 p->drawTiledPixmap( xpos, ypos, realW, realH, *mask);
424 else
425 p->fillRect ( xpos, ypos, realW, realH, Qt::color1);
428 else
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 ) );
435 /* else
437 const QBitmap* mask = tile( col, row, color, bg, disabled, false ).mask();
438 if (mask)
440 // ### ? p->setBackgroundColor(Qt::color0);
441 p->setPen(Qt::color1);
442 p->drawTiledPixmap( xpos, ypos, realW, realH, *mask);
444 else
445 p->fillRect ( xpos, ypos, realW, realH, Qt::color1);
451 //Advance horizontal position
452 xpos += realW;
455 //Advance vertical position
456 ypos += realH;
460 RectTilePainter::RectTilePainter( int name,
461 bool scaleH, bool scaleV,
462 unsigned int columns, unsigned int rows )
463 : TilePainter( name ),
464 m_scaleH( scaleH ),
465 m_scaleV( scaleV )
467 m_columns = columns;
468 m_rows = rows;
470 TileMode mh = m_scaleH ? Scaled : Tiled;
471 TileMode mv = m_scaleV ? Scaled : Tiled;
472 for (int c=0; c<4; c++)
474 if (c != 1)
475 colMde[c] = Fixed;
476 else
477 colMde[c] = mh;
480 for (int c=0; c<4; c++)
482 if (c != 1)
483 rowMde[c] = Fixed;
484 else
485 rowMde[c] = mv;
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),
497 m_bottom( bottom )
499 m_rows = 2;
500 if (m_bottom)
502 rowMde[0] = rowMde[2] = rowMde[3] = Scaled;
503 rowMde[1] = Fixed;
505 else
507 rowMde[0] = rowMde[2] = rowMde[3] = Fixed;
508 rowMde[1] = Scaled;
512 int ActiveTabPainter::tileName( unsigned int column, unsigned int row ) const
514 if ( m_bottom )
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 )
524 m_rows = 2;
525 if (m_bottom)
527 rowMde[0] = Scaled;
528 rowMde[1] = Fixed;
530 else
532 rowMde[0] = Fixed;
533 rowMde[1] = Scaled;
537 Most fully, inactive tabs look like this:
538 L C R
539 / --- \
540 | === |
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:
547 / --
548 | ==
550 "Middle" tabs look like this:
553 | --
554 | ==
556 And the right most tab looks like this:
558 L C R
559 | -- \
560 | == |
562 So we have to vary the number of columns, and for everything but left-most tab, the L tab gets the special separator
563 tile.
566 //Mode rightMost = QApplication::isRightToLeft() ? First : Last;
567 //### RTL?
568 m_columns = (m_mode == QStyleOptionTab::End ? 3 : 2);
573 int InactiveTabPainter::tileName( unsigned int column, unsigned int row ) const
575 //### RTL?
576 //Mode leftMost = QApplication::isRightToLeft() ? Last : First;
577 if ( column == 0 && m_mode != QStyleOptionTab::Beginning)
578 return KeramikTileSeparator;
579 if ( m_bottom )
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 ) ),
587 m_type( type ),
588 m_count( count ),
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;
615 if ( m_count == 5 )
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
625 return column + 1;
628 // vim: ts=4 sw=4 noet
629 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;