You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/libs/themeengine/texture.cpp

496 lines
11 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2004-07-26
* Description : texture pixmap methods
*
* Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
*
* Adapted from fluxbox: Texture/TextureRender
*
* Texture.cc for Fluxbox Window Manager
* Copyright (c) 2002-2003 Henrik Kinnunen <fluxbox@users.sourceforge.net>
*
* from Image.cc for Blackbox - an X11 Window manager
* Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
*
* ============================================================ */
// C++ includes.
#include <cstring>
#include <cstdio>
// TQt includes.
#include <tqpainter.h>
#include <tqimage.h>
#include <tqpixmap.h>
// Local includes.
#include "theme.h"
#include "texture.h"
namespace Digikam
{
class TexturePriv
{
public:
TexturePriv()
{
red = 0;
green = 0;
blue = 0;
}
bool border;
unsigned char *red;
unsigned char *green;
unsigned char *blue;
int width;
int height;
TQPixmap pixmap;
TQColor color0;
TQColor color1;
TQColor borderColor;
Theme::Bevel bevel;
Theme::Gradient gradient;
};
Texture::Texture(int w, int h, const TQColor& from, const TQColor& to,
Theme::Bevel bevel, Theme::Gradient gradient,
bool border, const TQColor& borderColor)
{
d = new TexturePriv;
d->bevel = bevel;
d->gradient = gradient;
d->border = border;
d->borderColor = borderColor;
if (!border)
{
d->width = w;
d->height = h;
}
else
{
d->width = w-2;
d->height = h-2;
}
if (d->width <= 0 || d->height <= 0)
return;
if (bevel & Theme::SUNKEN)
{
d->color0 = to;
d->color1 = from;
}
else
{
d->color0 = from;
d->color1 = to;
}
if (gradient == Theme::SOLID)
{
doSolid();
}
else
{
d->red = new unsigned char[w*h];
d->green = new unsigned char[w*h];
d->blue = new unsigned char[w*h];
if (gradient == Theme::HORIZONTAL)
doHgradient();
else if (gradient == Theme::VERTICAL)
doVgradient();
else if (gradient == Theme::DIAGONAL)
doDgradient();
if (bevel & Theme::RAISED || bevel & Theme::SUNKEN)
doBevel();
buildImage();
}
}
Texture::~Texture()
{
if (d->red)
delete [] d->red;
if (d->green)
delete [] d->green;
if (d->blue)
delete [] d->blue;
delete d;
}
TQPixmap Texture::renderPixmap() const
{
if (d->width <= 0 || d->height <= 0)
return TQPixmap();
if (!d->border)
return d->pixmap;
TQPixmap pix(d->width+2, d->height+2);
bitBlt(&pix, 1, 1, &d->pixmap, 0, 0);
TQPainter p(&pix);
p.setPen(d->borderColor);
p.drawRect(0, 0, d->width+2, d->height+2);
p.end();
return pix;
}
void Texture::doSolid()
{
d->pixmap.resize(d->width, d->height);
TQPainter p(&d->pixmap);
p.fillRect(0, 0, d->width, d->height, d->color0);
if (d->bevel == Theme::RAISED)
{
p.setPen(d->color0.light(120));
p.drawLine(0, 0, d->width-1, 0); // top
p.drawLine(0, 0, 0, d->height-1); // left
p.setPen(d->color0.dark(120));
p.drawLine(0, d->height-1, d->width-1, d->height-1); // bottom
p.drawLine(d->width-1, 0, d->width-1, d->height-1); // right
}
else if (d->bevel == Theme::SUNKEN)
{
p.setPen(d->color0.dark(120));
p.drawLine(0, 0, d->width-1, 0); // top
p.drawLine(0, 0, 0, d->height-1); // left
p.setPen(d->color0.light(120));
p.drawLine(0, d->height-1, d->width-1, d->height-1); // bottom
p.drawLine(d->width-1, 0, d->width-1, d->height-1); // right
}
p.end();
}
void Texture::doHgradient()
{
float drx, dgx, dbx,
xr = (float) d->color0.red(),
xg = (float) d->color0.green(),
xb = (float) d->color0.blue();
unsigned char *pr = d->red, *pg = d->green, *pb = d->blue;
int x, y;
drx = (float) (d->color1.red() - d->color0.red());
dgx = (float) (d->color1.green() - d->color0.green());
dbx = (float) (d->color1.blue() - d->color0.blue());
drx /= d->width;
dgx /= d->width;
dbx /= d->width;
for (x = 0; x < d->width; x++)
{
*(pr++) = (unsigned char) (xr);
*(pg++) = (unsigned char) (xg);
*(pb++) = (unsigned char) (xb);
xr += drx;
xg += dgx;
xb += dbx;
}
for (y = 1; y < d->height; y++, pr += d->width, pg += d->width, pb += d->width)
{
memcpy(pr, d->red, d->width);
memcpy(pg, d->green, d->width);
memcpy(pb, d->blue, d->width);
}
}
void Texture::doVgradient()
{
float dry, dgy, dby,
yr = (float) d->color0.red(),
yg = (float) d->color0.green(),
yb = (float) d->color0.blue();
dry = (float) (d->color1.red() - d->color0.red());
dgy = (float) (d->color1.green() - d->color0.green());
dby = (float) (d->color1.blue() - d->color0.blue());
dry /= d->height;
dgy /= d->height;
dby /= d->height;
unsigned char *pr = d->red, *pg = d->green, *pb = d->blue;
int y;
for (y = 0; y < d->height; y++, pr += d->width, pg += d->width, pb += d->width) {
memset(pr, (unsigned char) yr, d->width);
memset(pg, (unsigned char) yg, d->width);
memset(pb, (unsigned char) yb, d->width);
yr += dry;
yg += dgy;
yb += dby;
}
}
void Texture::doDgradient()
{
unsigned int* xtable = new unsigned int[d->width*3];
unsigned int* ytable = new unsigned int[d->height*3];
float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
xr = (float) d->color0.red(),
xg = (float) d->color0.green(),
xb = (float) d->color0.blue();
unsigned char *pr = d->red, *pg = d->green, *pb = d->blue;
unsigned int w = d->width * 2, h = d->height * 2;
unsigned int *xt = xtable;
unsigned int *yt = ytable;
int x, y;
dry = drx = (float) (d->color1.red() - d->color0.red());
dgy = dgx = (float) (d->color1.green() - d->color0.green());
dby = dbx = (float) (d->color1.blue() - d->color0.blue());
// Create X table
drx /= w;
dgx /= w;
dbx /= w;
for (x = 0; x < d->width; x++)
{
*(xt++) = (unsigned char) (xr);
*(xt++) = (unsigned char) (xg);
*(xt++) = (unsigned char) (xb);
xr += drx;
xg += dgx;
xb += dbx;
}
// Create Y table
dry /= h;
dgy /= h;
dby /= h;
for (y = 0; y < d->height; y++)
{
*(yt++) = ((unsigned char) yr);
*(yt++) = ((unsigned char) yg);
*(yt++) = ((unsigned char) yb);
yr += dry;
yg += dgy;
yb += dby;
}
// Combine tables to create gradient
for (yt = ytable, y = 0; y < d->height; y++, yt += 3)
{
for (xt = xtable, x = 0; x < d->width; x++)
{
*(pr++) = *(xt++) + *(yt);
*(pg++) = *(xt++) + *(yt + 1);
*(pb++) = *(xt++) + *(yt + 2);
}
}
delete [] xtable;
delete [] ytable;
}
void Texture::doBevel()
{
unsigned char *pr = d->red, *pg = d->green, *pb = d->blue;
unsigned char r, g, b, rr ,gg ,bb;
unsigned int w = d->width, h = d->height - 1, wh = w * h;
while (--w)
{
r = *pr;
rr = r + (r >> 1);
if (rr < r) rr = ~0;
g = *pg;
gg = g + (g >> 1);
if (gg < g) gg = ~0;
b = *pb;
bb = b + (b >> 1);
if (bb < b) bb = ~0;
*pr = rr;
*pg = gg;
*pb = bb;
r = *(pr + wh);
rr = (r >> 2) + (r >> 1);
if (rr > r) rr = 0;
g = *(pg + wh);
gg = (g >> 2) + (g >> 1);
if (gg > g) gg = 0;
b = *(pb + wh);
bb = (b >> 2) + (b >> 1);
if (bb > b) bb = 0;
*((pr++) + wh) = rr;
*((pg++) + wh) = gg;
*((pb++) + wh) = bb;
}
r = *pr;
rr = r + (r >> 1);
if (rr < r) rr = ~0;
g = *pg;
gg = g + (g >> 1);
if (gg < g) gg = ~0;
b = *pb;
bb = b + (b >> 1);
if (bb < b) bb = ~0;
*pr = rr;
*pg = gg;
*pb = bb;
r = *(pr + wh);
rr = (r >> 2) + (r >> 1);
if (rr > r) rr = 0;
g = *(pg + wh);
gg = (g >> 2) + (g >> 1);
if (gg > g) gg = 0;
b = *(pb + wh);
bb = (b >> 2) + (b >> 1);
if (bb > b) bb = 0;
*(pr + wh) = rr;
*(pg + wh) = gg;
*(pb + wh) = bb;
pr = d->red + d->width;
pg = d->green + d->width;
pb = d->blue + d->width;
while (--h)
{
r = *pr;
rr = r + (r >> 1);
if (rr < r) rr = ~0;
g = *pg;
gg = g + (g >> 1);
if (gg < g) gg = ~0;
b = *pb;
bb = b + (b >> 1);
if (bb < b) bb = ~0;
*pr = rr;
*pg = gg;
*pb = bb;
pr += d->width - 1;
pg += d->width - 1;
pb += d->width - 1;
r = *pr;
rr = (r >> 2) + (r >> 1);
if (rr > r) rr = 0;
g = *pg;
gg = (g >> 2) + (g >> 1);
if (gg > g) gg = 0;
b = *pb;
bb = (b >> 2) + (b >> 1);
if (bb > b) bb = 0;
*(pr++) = rr;
*(pg++) = gg;
*(pb++) = bb;
}
r = *pr;
rr = r + (r >> 1);
if (rr < r) rr = ~0;
g = *pg;
gg = g + (g >> 1);
if (gg < g) gg = ~0;
b = *pb;
bb = b + (b >> 1);
if (bb < b) bb = ~0;
*pr = rr;
*pg = gg;
*pb = bb;
pr += d->width - 1;
pg += d->width - 1;
pb += d->width - 1;
r = *pr;
rr = (r >> 2) + (r >> 1);
if (rr > r) rr = 0;
g = *pg;
gg = (g >> 2) + (g >> 1);
if (gg > g) gg = 0;
b = *pb;
bb = (b >> 2) + (b >> 1);
if (bb > b) bb = 0;
*pr = rr;
*pg = gg;
*pb = bb;
}
void Texture::buildImage()
{
unsigned char *pr = d->red, *pg = d->green, *pb = d->blue;
TQImage image(d->width, d->height, 32);
unsigned int* bits = (unsigned int*) image.bits();
int p;
for (p =0; p < d->width*d->height; p++)
{
*bits = 0xff << 24 | *pr << 16 | *pg << 8 | *pb;
bits++;
pr++;
pg++;
pb++;
}
d->pixmap = TQPixmap(image);
}
} // NameSpace Digikam