summaryrefslogtreecommitdiffstats
path: root/kstyles/keramik/pixmaploader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kstyles/keramik/pixmaploader.cpp')
-rw-r--r--kstyles/keramik/pixmaploader.cpp629
1 files changed, 629 insertions, 0 deletions
diff --git a/kstyles/keramik/pixmaploader.cpp b/kstyles/keramik/pixmaploader.cpp
new file mode 100644
index 000000000..b3c4a8c47
--- /dev/null
+++ b/kstyles/keramik/pixmaploader.cpp
@@ -0,0 +1,629 @@
+/*
+ Copyright (c) 2002 Malte Starostik <malte@kde.org>
+ (c) 2002,2003 Maksim Orlovich <maksim@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qglobal.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpixmapcache.h>
+
+#include "pixmaploader.h"
+
+
+#include "pixmaps.keramik"
+
+using namespace Keramik;
+
+PixmapLoader* PixmapLoader::s_instance = 0;
+
+PixmapLoader::PixmapLoader(): m_pixmapCache(327680, 2017)
+
+{
+ m_pixmapCache.setAutoDelete(true);
+
+ for (int c=0; c<256; c++)
+ clamp[c]=static_cast<unsigned char>(c);
+
+ for (int c=256; c<540; c++)
+ clamp[c] = 255;
+
+}
+
+void PixmapLoader::clear()
+{
+ //m_cache.clear();
+}
+
+QImage* PixmapLoader::getDisabled(int name, const QColor& color, const QColor& back, bool blend)
+{
+ KeramikEmbedImage* edata = KeramikGetDbImage(name);
+ if (!edata)
+ return 0;
+
+ //Like getColored, but desaturate a bit, and lower gamma..
+
+ //Create a real image...
+ QImage* img = new QImage(edata->width, edata->height, 32);
+
+
+
+ //OK, now, fill it in, using the color..
+ Q_UINT32 r, g,b;
+ Q_UINT32 i = qGray(color.rgb());
+ r = (3*color.red()+i)>>2;
+ g = (3*color.green()+i)>>2;
+ b = (3*color.blue()+i)>>2;
+
+ Q_UINT32 br = back.red(), bg = back.green(), bb = back.blue();
+
+
+ if (edata->haveAlpha)
+ {
+ if (blend)
+ {
+ img->setAlphaBuffer(false);
+ Q_UINT32* write = reinterpret_cast< Q_UINT32* >(img->bits() );
+ int size = img->width()*img->height() * 3;
+
+ for (int pos = 0; pos < size; pos+=3)
+ {
+ Q_UINT32 scale = edata->data[pos];
+ Q_UINT32 add = (edata->data[pos+1]*i+127)>>8;
+ Q_UINT32 alpha = edata->data[pos+2];
+ Q_UINT32 destAlpha = 256 - alpha;
+
+ Q_UINT32 rr = clamp[((r*scale+127)>>8) + add];
+ Q_UINT32 rg = clamp[((g*scale+127)>>8) + add];
+ Q_UINT32 rb = clamp[((b*scale+127)>>8) + add];
+
+ *write =qRgb(((rr*alpha+127)>>8) + ((br*destAlpha+127)>>8),
+ ((rg*alpha+127)>>8) + ((bg*destAlpha+127)>>8),
+ ((rb*alpha+127)>>8) + ((bb*destAlpha+127)>>8));
+
+ write++;
+ }
+ }
+ else
+ {
+ img->setAlphaBuffer(true);
+ Q_UINT32* write = reinterpret_cast< Q_UINT32* >(img->bits() );
+ int size = img->width()*img->height() * 3;
+
+ for (int pos = 0; pos < size; pos+=3)
+ {
+ Q_UINT32 scale = edata->data[pos];
+ Q_UINT32 add = (edata->data[pos+1]*i+127)>>8;
+ Q_UINT32 alpha = edata->data[pos+2];
+
+ Q_UINT32 rr = clamp[((r*scale+127)>>8) + add];
+ Q_UINT32 rg = clamp[((g*scale+127)>>8) + add];
+ Q_UINT32 rb = clamp[((b*scale+127)>>8) + add];
+
+ *write =qRgba(rr, rg, rb, alpha);
+
+ write++;
+ }
+
+ }
+ }
+ else
+ {
+ img->setAlphaBuffer(false);
+ Q_UINT32* write = reinterpret_cast< Q_UINT32* >(img->bits() );
+ int size = img->width()*img->height() * 2;
+
+ for (int pos = 0; pos < size; pos+=2)
+ {
+ Q_UINT32 scale = edata->data[pos];
+ Q_UINT32 add = (edata->data[pos+1]*i+127)>>8;
+ Q_UINT32 rr = clamp[((r*scale+127)>>8) + add];
+ Q_UINT32 rg = clamp[((g*scale+127)>>8) + add];
+ Q_UINT32 rb = clamp[((b*scale+127)>>8) + add];
+ *write =qRgb(rr, rg, rb);
+ write++;
+ }
+ }
+
+ return img;
+}
+
+QImage* PixmapLoader::getColored(int name, const QColor& color, const QColor& back, bool blend)
+{
+ KeramikEmbedImage* edata = KeramikGetDbImage(name);
+ if (!edata)
+ return 0;
+
+ //Create a real image...
+ QImage* img = new QImage(edata->width, edata->height, 32);
+
+ //OK, now, fill it in, using the color..
+ Q_UINT32 r, g,b;
+ r = color.red() + 2;
+ g = color.green() + 2;
+ b = color.blue() + 2;
+
+// int i = qGray(color.rgb());
+
+ Q_UINT32 br = back.red(), bg = back.green(), bb = back.blue();
+
+ if (edata->haveAlpha)
+ {
+ if (blend)
+ {
+ img->setAlphaBuffer(false);
+
+ Q_UINT32* write = reinterpret_cast< Q_UINT32* >(img->bits() );
+ int size = img->width()*img->height() * 3;
+ for (int pos = 0; pos < size; pos+=3)
+ {
+ Q_UINT32 scale = edata->data[pos];
+ Q_UINT32 add = edata->data[pos+1];
+ Q_UINT32 alpha = edata->data[pos+2];
+ Q_UINT32 destAlpha = 256 - alpha;
+
+ if (scale != 0)
+ add = add*5/4;
+
+ Q_UINT32 rr = clamp[((r*scale+127)>>8) + add];
+ Q_UINT32 rg = clamp[((g*scale+127)>>8) + add];
+ Q_UINT32 rb = clamp[((b*scale+127)>>8) + add];
+
+ *write =qRgb(((rr*alpha+127)>>8) + ((br*destAlpha+127)>>8),
+ ((rg*alpha+127)>>8) + ((bg*destAlpha+127)>>8),
+ ((rb*alpha+127)>>8) + ((bb*destAlpha+127)>>8));
+
+ write++;
+ }
+ }
+ else
+ {
+ img->setAlphaBuffer(true);
+
+ Q_UINT32* write = reinterpret_cast< Q_UINT32* >(img->bits() );
+ int size = img->width()*img->height() * 3;
+
+ for (int pos = 0; pos < size; pos+=3)
+ {
+ Q_UINT32 scale = edata->data[pos];
+ Q_UINT32 add = edata->data[pos+1];
+ Q_UINT32 alpha = edata->data[pos+2];
+ if (scale != 0)
+ add = add*5/4;
+
+ Q_UINT32 rr = clamp[((r*scale+127)>>8) + add];
+ Q_UINT32 rg = clamp[((g*scale+127)>>8) + add];
+ Q_UINT32 rb = clamp[((b*scale+127)>>8) + add];
+
+ *write =qRgba(rr, rg, rb, alpha);
+ write++;
+ }
+ }
+ }
+ else
+ {
+ img->setAlphaBuffer(false);
+
+ Q_UINT32* write = reinterpret_cast< Q_UINT32* >(img->bits() );
+ int size = img->width()*img->height() * 2;
+
+ for (int pos = 0; pos < size; pos+=2)
+ {
+ Q_UINT32 scale = edata->data[pos];
+ Q_UINT32 add = edata->data[pos+1];
+ if (scale != 0)
+ add = add*5/4;
+
+ Q_UINT32 rr = clamp[((r*scale+127)>>8) + add];
+ Q_UINT32 rg = clamp[((g*scale+127)>>8) + add];
+ Q_UINT32 rb = clamp[((b*scale+127)>>8) + add];
+
+
+ *write =qRgb(rr, rg, rb);
+ write++;
+ }
+ }
+
+ return img;
+}
+
+QPixmap PixmapLoader::pixmap( int name, const QColor& color, const QColor& bg, bool disabled, bool blend )
+{
+ return scale(name, 0, 0, color, bg, disabled, blend);
+}
+
+
+QPixmap PixmapLoader::scale( int name, int width, int height, const QColor& color, const QColor& bg, bool disabled, bool blend )
+{
+ KeramikCacheEntry entry(name, color, bg, disabled, blend, width, height);
+ KeramikCacheEntry* cacheEntry;
+
+ int key = entry.key();
+
+ if ((cacheEntry = m_pixmapCache.find(key, true)))
+ {
+ if (entry == *cacheEntry) //True match!
+ return *cacheEntry->m_pixmap;
+ else //Remove old entry in case of a conflict!
+ m_pixmapCache.remove(key);
+ }
+
+
+ QImage* img = 0;
+ QPixmap* result = 0;
+
+ if (disabled)
+ img = getDisabled(name, color, bg, blend);
+ else
+ img = getColored(name, color, bg, blend);
+
+ if (!img)
+ {
+ KeramikCacheEntry* toAdd = new KeramikCacheEntry(entry);
+ toAdd->m_pixmap = new QPixmap();
+ m_pixmapCache.insert(key, toAdd, 16);
+ return QPixmap();
+ }
+
+ if (width == 0 && height == 0)
+ result = new QPixmap(*img);
+ else
+ result = new QPixmap(img->smoothScale( width ? width : img->width(),
+ height ? height: img->height()));
+ delete img;
+
+ KeramikCacheEntry* toAdd = new KeramikCacheEntry(entry);
+ toAdd->m_pixmap = result;
+
+ if (!m_pixmapCache.insert(key, toAdd, result->width()*result->height()*result->depth()/8)) {
+ QPixmap toRet = *result;
+ delete toAdd;
+ return toRet;
+ }
+
+ return *result;
+}
+
+QSize PixmapLoader::size( int id )
+{
+ KeramikEmbedImage* edata = KeramikGetDbImage(id);
+ if (!edata)
+ return QSize(0,0);
+ return QSize(edata->width, edata->height);
+}
+
+void TilePainter::draw( QPainter *p, int x, int y, int width, int height, const QColor& color, const QColor& bg, bool disabled, PaintMode mode )
+{
+ if (mode == PaintTrivialMask)
+ {
+ p->fillRect(x, y, width, height, Qt::color1);
+ return;
+ }
+
+ bool swBlend = (mode != PaintFullBlend);
+ unsigned int scaledColumns = 0, scaledRows = 0, lastScaledColumn = 0, lastScaledRow = 0;
+ int scaleWidth = width, scaleHeight = height;
+
+ //scaleWidth, scaleHeight are calculated to contain the area available
+ //for all tiled and stretched columns/rows respectively.
+ //This is need to redistribute the area remaining after painting
+ //the "fixed" elements. We also keep track of the last col and row
+ //being scaled so rounding errors don't cause us to be short a pixel or so.
+ for ( unsigned int col = 0; col < columns(); ++col )
+ if ( columnMode( col ) != Fixed )
+ {
+ scaledColumns++;
+ lastScaledColumn = col;
+ }
+ else scaleWidth -= PixmapLoader::the().size (absTileName( col, 0 ) ).width();
+
+ for ( unsigned int row = 0; row < rows(); ++row )
+ if ( rowMode( row ) != Fixed )
+ {
+ scaledRows++;
+ lastScaledRow = row;
+ }
+ else scaleHeight -= PixmapLoader::the().size (absTileName( 0, row ) ).height();
+
+
+ if ( scaleWidth < 0 ) scaleWidth = 0;
+ if ( scaleHeight < 0 ) scaleHeight = 0;
+
+
+ int ypos = y;
+
+ //Center vertically if everything is fixed but there is extra room remaining
+ if ( scaleHeight && !scaledRows )
+ ypos += scaleHeight / 2;
+
+ for ( unsigned int row = 0; row < rows(); ++row )
+ {
+ int xpos = x;
+
+ //Center horizontally if extra space and no where to redistribute it to...
+ if ( scaleWidth && !scaledColumns )
+ xpos += scaleWidth / 2;
+
+ //If not fixed vertically, calculate our share of space available
+ //for scalable rows.
+ int h = rowMode( row ) == Fixed ? 0 : scaleHeight / scaledRows;
+
+ //Redistribute any "extra" pixels to the last scaleable row.
+ if ( scaledRows && row == lastScaledRow )
+ {
+ int allocatedEvenly = scaleHeight / scaledRows * scaledRows;
+ h += scaleHeight - allocatedEvenly;
+ }
+
+
+ //If we're fixed, get the height from the pixmap itself.
+ int realH = h ? h : PixmapLoader::the().size (absTileName( 0, row ) ).height();
+
+ //Skip non-fitting stretched/tiled rows, too.
+ if (rowMode( row ) != Fixed && h == 0)
+ continue;
+
+
+ //Set h to 0 to denote that we aren't scaling
+ if ( rowMode( row ) == Tiled )
+ h = 0;
+
+ for ( unsigned int col = 0; col < columns(); ++col )
+ {
+ //Calculate width for rows that aren't fixed.
+ int w = columnMode( col ) == Fixed ? 0 : scaleWidth / scaledColumns;
+
+ //Get the width of the pixmap..
+ int tileW = PixmapLoader::the().size (absTileName( col, row ) ).width();
+
+ //Redistribute any extra pixels..
+ if ( scaledColumns && col == lastScaledColumn ) w += scaleWidth - scaleWidth / scaledColumns * scaledColumns;
+
+ //The width to use...
+ int realW = w ? w : tileW;
+
+ //Skip any non-fitting stretched/tiled columns
+ if (columnMode( col ) != Fixed && w == 0)
+ continue;
+
+ //Set w to 0 to denote that we aren't scaling
+ if ( columnMode( col ) == Tiled )
+ w = 0;
+
+ //If we do indeed have a pixmap..
+ if ( tileW )
+ {
+ //If scaling in either direction.
+ if ( w || h )
+ {
+ if (mode != PaintMask)
+ {
+ p->drawTiledPixmap( xpos, ypos, realW, realH, scale( col, row, w, h, color, bg, disabled, swBlend ) );
+ }
+ else
+ {
+ const QBitmap* mask = scale( col, row, w, h, color, bg, disabled, false ).mask();
+ if (mask)
+ {
+ p->setBackgroundColor(Qt::color0);
+ p->setPen(Qt::color1);
+ p->drawTiledPixmap( xpos, ypos, realW, realH, *mask);
+ }
+ else
+ p->fillRect ( xpos, ypos, realW, realH, Qt::color1);
+ }
+ }
+ else
+ {
+ //Tiling (or fixed, the same really)
+ if (mode != PaintMask)
+ {
+ p->drawTiledPixmap( xpos, ypos, realW, realH, tile( col, row, color, bg, disabled, swBlend ) );
+ }
+ else
+ {
+ const QBitmap* mask = tile( col, row, color, bg, disabled, false ).mask();
+ if (mask)
+ {
+ p->setBackgroundColor(Qt::color0);
+ p->setPen(Qt::color1);
+ p->drawTiledPixmap( xpos, ypos, realW, realH, *mask);
+ }
+ else
+ p->fillRect ( xpos, ypos, realW, realH, Qt::color1);
+
+ }
+ }
+ }
+
+ //Advance horizontal position
+ xpos += realW;
+ }
+
+ //Advance vertical position
+ ypos += realH;
+ }
+}
+
+RectTilePainter::RectTilePainter( int name,
+ bool scaleH, bool scaleV,
+ unsigned int columns, unsigned int rows )
+ : TilePainter( name ),
+ m_scaleH( scaleH ),
+ m_scaleV( scaleV )
+{
+ m_columns = columns;
+ m_rows = rows;
+
+ TileMode mh = m_scaleH ? Scaled : Tiled;
+ TileMode mv = m_scaleV ? Scaled : Tiled;
+ for (int c=0; c<4; c++)
+ {
+ if (c != 1)
+ colMde[c] = Fixed;
+ else
+ colMde[c] = mh;
+ }
+
+ for (int c=0; c<4; c++)
+ {
+ if (c != 1)
+ rowMde[c] = Fixed;
+ else
+ rowMde[c] = mv;
+ }
+
+}
+
+int RectTilePainter::tileName( unsigned int column, unsigned int row ) const
+{
+ return row *3 + column;
+}
+
+ActiveTabPainter::ActiveTabPainter( bool bottom )
+ : RectTilePainter( bottom? keramik_tab_bottom_active: keramik_tab_top_active, false),
+ m_bottom( bottom )
+{
+ m_rows = 2;
+ if (m_bottom)
+ {
+ rowMde[0] = rowMde[2] = rowMde[3] = Scaled;
+ rowMde[1] = Fixed;
+ }
+ else
+ {
+ rowMde[0] = rowMde[2] = rowMde[3] = Fixed;
+ rowMde[1] = Scaled;
+ }
+}
+
+int ActiveTabPainter::tileName( unsigned int column, unsigned int row ) const
+{
+ if ( m_bottom )
+ return RectTilePainter::tileName( column, row + 1 );
+ return RectTilePainter::tileName( column, row );
+}
+
+InactiveTabPainter::InactiveTabPainter( Mode mode, bool bottom )
+ : RectTilePainter( bottom? keramik_tab_bottom_inactive: keramik_tab_top_inactive, false),
+ m_mode( mode ), m_bottom( bottom )
+{
+ m_rows = 2;
+ if (m_bottom)
+ {
+ rowMde[0] = Scaled;
+ rowMde[1] = Fixed;
+ }
+ else
+ {
+ rowMde[0] = Fixed;
+ rowMde[1] = Scaled;
+ }
+
+ /**
+ Most fully, inactive tabs look like this:
+ L C R
+ / --- \
+ | === |
+
+ 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.
+
+ We want the left-most tab to look like this:
+
+ L C
+ / --
+ | ==
+
+ "Middle" tabs look like this:
+
+ L C
+ | --
+ | ==
+
+ And the right most tab looks like this:
+
+ L C R
+ | -- \
+ | == |
+
+ So we have to vary the number of columns, and for everything but left-most tab, the L tab gets the special separator
+ tile.
+ */
+
+ Mode rightMost = QApplication::reverseLayout() ? First : Last;
+ m_columns = (m_mode == rightMost ? 3 : 2);
+}
+
+int InactiveTabPainter::tileName( unsigned int column, unsigned int row ) const
+{
+ Mode leftMost = QApplication::reverseLayout() ? Last : First;
+ if ( column == 0 && m_mode != leftMost )
+ return KeramikTileSeparator;
+ if ( m_bottom )
+ return RectTilePainter::tileName( column, row + 1 );
+ return RectTilePainter::tileName( column, row );
+}
+
+ScrollBarPainter::ScrollBarPainter( int type, int count, bool horizontal )
+ : TilePainter( name( horizontal ) ),
+ m_type( type ),
+ m_count( count ),
+ m_horizontal( horizontal )
+{
+ for (int c=0; c<5; c++)
+ {
+ if ( !m_horizontal || !( c % 2 ) ) colMde[c] = Fixed;
+ else colMde[c] = Tiled;
+
+ if ( m_horizontal || !( c % 2 ) ) rowMde[c] = Fixed;
+ else rowMde[c] = Tiled;
+ }
+
+ m_columns = m_horizontal ? m_count : 1;
+ m_rows = m_horizontal ? 1 : m_count;
+
+}
+
+int ScrollBarPainter::name( bool horizontal )
+{
+ return horizontal? keramik_scrollbar_hbar: keramik_scrollbar_vbar;
+}
+
+int ScrollBarPainter::tileName( unsigned int column, unsigned int row ) const
+{
+ unsigned int num = ( column ? column : row ) + 1;
+ if ( m_count == 5 )
+ if ( num == 3 ) num = 4;
+ else if ( num == 4 ) num = 2;
+ else if ( num == 5 ) num = 3;
+
+ return m_type + (num-1)*16;
+}
+
+int SpinBoxPainter::tileName( unsigned int column, unsigned int ) const
+{
+ return column + 1;
+}
+
+// vim: ts=4 sw=4 noet
+// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;