-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | apps/Settings/Theme.desktop | 7 | ||||
-rw-r--r-- | noncore/styles/theme/ogfxeffect.cpp | 324 | ||||
-rw-r--r-- | noncore/styles/theme/ogfxeffect.h | 78 | ||||
-rw-r--r-- | noncore/styles/theme/opie-theme.control | 11 | ||||
-rw-r--r-- | noncore/styles/theme/othemebase.cpp | 1212 | ||||
-rw-r--r-- | noncore/styles/theme/othemebase.h | 739 | ||||
-rw-r--r-- | noncore/styles/theme/othemestyle.cpp | 1532 | ||||
-rw-r--r-- | noncore/styles/theme/othemestyle.h | 365 | ||||
-rw-r--r-- | noncore/styles/theme/plugin.cpp | 19 | ||||
-rw-r--r-- | noncore/styles/theme/settings/main.cpp | 34 | ||||
-rw-r--r-- | noncore/styles/theme/settings/settings.pro | 24 | ||||
-rw-r--r-- | noncore/styles/theme/settings/themeset.cpp | 124 | ||||
-rw-r--r-- | noncore/styles/theme/settings/themeset.h | 20 | ||||
-rw-r--r-- | noncore/styles/theme/theme.pro | 32 | ||||
-rw-r--r-- | pics/theme/Theme.png | bin | 0 -> 2771 bytes |
16 files changed, 4522 insertions, 1 deletions
@@ -3,49 +3,49 @@ indefault: dynamic all: default docs LIBS=library libopie INPUTCOMPONENTS= inputmethods/keyboard inputmethods/pickboard \ inputmethods/handwriting inputmethods/unikeyboard \ inputmethods/jumpx inputmethods/kjumpx \ inputmethods/dvorak APPLETS= core/applets/batteryapplet core/applets/batteryapplet-ipaq \ core/applets/irdaapplet core/applets/volumeapplet \ core/applets/clockapplet core/applets/netmonapplet \ core/applets/screenshotapplet core/applets/clipboardapplet \ core/applets/cardmon core/applets/obex \ core/applets/vmemo noncore/net/netsetup/dialup \ noncore/net/netsetup/lan MAIL= noncore/mail/libmail noncore/mail/bend PLAYER = core/multimedia/opieplayer/libmpeg3 \ core/multimedia/opieplayer/libmad \ core/multimedia/opieplayer/wavplugin -COMPONENTS=$(LOCALCOMPONENTS) $(INPUTCOMPONENTS) $(APPLETS) $(MAIL) $(PLAYER) +COMPONENTS=$(LOCALCOMPONENTS) $(INPUTCOMPONENTS) $(APPLETS) $(MAIL) # $(PLAYER) PIMAPPS = core/pim/addressbook core/pim/datebook \ core/pim/today core/pim/todo COREAPPS = core/apps/filebrowser core/apps/helpbrowser \ core/apps/textedit core/apps/embeddedkonsole \ core/launcher core/apps/sysinfo \ core/apps/oipkg core/apps/qcop COREMULTIMEDIA = core/multimedia/opieplayer CORESETTINGS = core/settings/light-and-power core/settings/security \ core/settings/systemtime core/settings/citytime \ core/settings/wlansetup NONCORESETTINGS =noncore/settings/language noncore/settings/rotation \ noncore/settings/appearance noncore/settings/sound \ noncore/settings/mediummount \ noncore/settings/tabmanager noncore/settings/appskey \ noncore/settings/netsystemtime NONCORETOOLS = noncore/tools/calculator noncore/tools/clock \ noncore/tools/remote noncore/tools/opie-sh noncore/apps/advancedfm diff --git a/apps/Settings/Theme.desktop b/apps/Settings/Theme.desktop new file mode 100644 index 0000000..197184f --- a/dev/null +++ b/apps/Settings/Theme.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Exec=theme-settings +Icon=theme/Theme +Name=Theme-Settings +Name[de]=Thema-Einstellungen + diff --git a/noncore/styles/theme/ogfxeffect.cpp b/noncore/styles/theme/ogfxeffect.cpp new file mode 100644 index 0000000..a991728 --- a/dev/null +++ b/noncore/styles/theme/ogfxeffect.cpp @@ -0,0 +1,324 @@ +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + +*/ + +// $Id$ + +#include <qimage.h> +#include <qpainter.h> + +#include "ogfxeffect.h" + + +//====================================================================== +// +// Gradient effects +// +//====================================================================== + + +QPixmap& OGfxEffect::gradient(QPixmap &pixmap, const QColor &ca, + const QColor &cb, GradientType eff, int ncols) +{ + if(pixmap.depth() > 8 && + (eff == VerticalGradient || eff == HorizontalGradient)) { + + int rDiff, gDiff, bDiff; + int rca, gca, bca /*, rcb, gcb, bcb*/; + + register int x, y; + + rDiff = (/*rcb = */ cb.red()) - (rca = ca.red()); + gDiff = (/*gcb = */ cb.green()) - (gca = ca.green()); + bDiff = (/*bcb = */ cb.blue()) - (bca = ca.blue()); + + register int rl = rca << 16; + register int gl = gca << 16; + register int bl = bca << 16; + + int rcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * rDiff; + int gcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * gDiff; + int bcdelta = ((1<<16) / (eff == VerticalGradient ? pixmap.height() : pixmap.width())) * bDiff; + + QPainter p(&pixmap); + + // these for-loops could be merged, but the if's in the inner loop + // would make it slow + switch(eff) { + case VerticalGradient: + for ( y = 0; y < pixmap.height(); y++ ) { + rl += rcdelta; + gl += gcdelta; + bl += bcdelta; + + p.setPen(QColor(rl>>16, gl>>16, bl>>16)); + p.drawLine(0, y, pixmap.width()-1, y); + } + break; + case HorizontalGradient: + for( x = 0; x < pixmap.width(); x++) { + rl += rcdelta; + gl += gcdelta; + bl += bcdelta; + + p.setPen(QColor(rl>>16, gl>>16, bl>>16)); + p.drawLine(x, 0, x, pixmap.height()-1); + } + break; + default: + ; + } + } + else { +// QImage image = OGfxEffect::gradient(pixmap.size(), ca, cb, +// (OGfxEffect::GradientType) eff, ncols); +// pixmap.convertFromImage(image); + } + + return pixmap; +} + + +//====================================================================== +// +// Blend effects +// +//====================================================================== + + +QPixmap& OGfxEffect::blend(QPixmap &pixmap, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir, int ncols) +{ + QImage image = pixmap.convertToImage(); + OGfxEffect::blend(image, initial_intensity, bgnd, eff, anti_dir); + + unsigned int tmp; + + if ( pixmap. depth ( ) <= 8 ) + image. convertDepth ( pixmap. depth ( )); + + pixmap.convertFromImage(image); + + return pixmap; +} + + +QImage& OGfxEffect::blend(QImage &image, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir) +{ + if (image.width() == 0 || image.height() == 0) { + qDebug ( "Invalid image\n" ); + return image; + } + + int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue(); + int r, g, b; + int ind; + + unsigned int xi, xf, yi, yf; + unsigned int a; + + // check the boundaries of the initial intesity param + float unaffected = 1; + if (initial_intensity > 1) initial_intensity = 1; + if (initial_intensity < -1) initial_intensity = -1; + if (initial_intensity < 0) { + unaffected = 1. + initial_intensity; + initial_intensity = 0; + } + + + float intensity = initial_intensity; + float var = 1. - initial_intensity; + + if (anti_dir) { + initial_intensity = intensity = 1.; + var = -var; + } + + register int x, y; + + unsigned int *data = (unsigned int *)image.bits(); + + if( eff == VerticalGradient || eff == HorizontalGradient ) { + + // set the image domain to apply the effect to + xi = 0, xf = image.width(); + yi = 0, yf = image.height(); + if (eff == VerticalGradient) { + if (anti_dir) yf = (int)(image.height() * unaffected); + else yi = (int)(image.height() * (1 - unaffected)); + } + else { + if (anti_dir) xf = (int)(image.width() * unaffected); + else xi = (int)(image.height() * (1 - unaffected)); + } + + var /= (eff == VerticalGradient?yf-yi:xf-xi); + + for (y = yi; y < (int)yf; y++) { + intensity = eff == VerticalGradient? intensity + var : + initial_intensity; + for (x = xi; x < (int)xf ; x++) { + if (eff == HorizontalGradient) intensity += var; + ind = x + image.width() * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + } + else if (eff == DiagonalGradient || eff == CrossDiagonalGradient) { + float xvar = var / 2 / image.width(); // / unaffected; + float yvar = var / 2 / image.height(); // / unaffected; + float tmp; + + for (x = 0; x < image.width() ; x++) { + tmp = xvar * (eff == DiagonalGradient? x : image.width()-x-1); + for (y = 0; y < image.height() ; y++) { + intensity = initial_intensity + tmp + yvar * y; + ind = x + image.width() * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + } + + else if (eff == RectangleGradient || eff == EllipticGradient) { + float xvar; + float yvar; + + for (x = 0; x < image.width() / 2 + image.width() % 2; x++) { + xvar = var / image.width() * (image.width() - x*2/unaffected-1); + for (y = 0; y < image.height() / 2 + image.height() % 2; y++) { + yvar = var / image.height() * (image.height() - y*2/unaffected -1); + + if (eff == RectangleGradient) + intensity = initial_intensity + QMAX(xvar, yvar); + else + intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); + if (intensity > 1) intensity = 1; + if (intensity < 0) intensity = 0; + + //NW + ind = x + image.width() * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + //NE + ind = image.width() - x - 1 + image.width() * y ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + + //CT loop is doubled because of stupid central row/column issue. + // other solution? + for (x = 0; x < image.width() / 2; x++) { + xvar = var / image.width() * (image.width() - x*2/unaffected-1); + for (y = 0; y < image.height() / 2; y++) { + yvar = var / image.height() * (image.height() - y*2/unaffected -1); + + if (eff == RectangleGradient) + intensity = initial_intensity + QMAX(xvar, yvar); + else + intensity = initial_intensity + sqrt(xvar * xvar + yvar * yvar); + if (intensity > 1) intensity = 1; + if (intensity < 0) intensity = 0; + + //SW + ind = x + image.width() * (image.height() - y -1) ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + + //SE + ind = image.width()-x-1 + image.width() * (image.height() - y - 1) ; + r = qRed (data[ind]) + (int)(intensity * + (r_bgnd - qRed (data[ind]))); + g = qGreen(data[ind]) + (int)(intensity * + (g_bgnd - qGreen(data[ind]))); + b = qBlue (data[ind]) + (int)(intensity * + (b_bgnd - qBlue (data[ind]))); + if (r > 255) r = 255; if (r < 0 ) r = 0; + if (g > 255) g = 255; if (g < 0 ) g = 0; + if (b > 255) b = 255; if (b < 0 ) b = 0; + a = qAlpha(data[ind]); + data[ind] = qRgba(r, g, b, a); + } + } + } + + else + qDebug ( "not implemented\n" ); + + return image; +} + +#if 0 +// Not very efficient as we create a third big image... +// +QImage& KQGfxEffect::blend(QImage &image1, QImage &image2, + GradientType gt, int xf, int yf) +{ + if (image1.width() == 0 || image1.height() == 0 || + image2.width() == 0 || image2.height() == 0) + return image1; + + QImage image3; + + image3 = KQGfxEffect::unbalancedGradient(image1.size(), + QColor(0,0,0), QColor(255,255,255), + gt, xf, yf, 0); + + return blend(image1,image2,image3, Red); // Channel to use is arbitrary +} +#endif diff --git a/noncore/styles/theme/ogfxeffect.h b/noncore/styles/theme/ogfxeffect.h new file mode 100644 index 0000000..45a8482 --- a/dev/null +++ b/noncore/styles/theme/ogfxeffect.h @@ -0,0 +1,78 @@ +/* This file is part of the KDE libraries + Copyright (C) 1998, 1999 Christian Tibirna <ctibirna@total.net> + (C) 1998, 1999 Daniel M. Duley <mosfet@kde.org> + (C) 1998, 1999 Dirk A. Mueller <mueller@kde.org> + +*/ + +// $Id$ + +#ifndef __OGFX_EFFECT_H +#define __OGFX_EFFECT_H + +#include <qpixmap.h> +#include <qimage.h> + +/** + * This class includes various pixmap-based graphical effects. + * + * Everything is + * static, so there is no need to create an instance of this class. You can + * just call the static methods. They are encapsulated here merely to provide + * a common namespace. + */ +class OGfxEffect +{ +public: + enum GradientType { VerticalGradient, HorizontalGradient, + DiagonalGradient, CrossDiagonalGradient, + PyramidGradient, RectangleGradient, + PipeCrossGradient, EllipticGradient }; + enum RGBComponent { Red, Green, Blue }; + + enum Lighting {NorthLite, NWLite, WestLite, SWLite, + SouthLite, SELite, EastLite, NELite}; + + /** + * Create a gradient from color a to color b of the specified type. + * + * @param pixmap The pixmap to process. + * @param ca Color a. + * @param cb Color b. + * @param type The type of gradient. + * @param ncols The number of colors to use when not running on a + * truecolor display. The gradient will be dithered to this number of + * colors. Pass 0 to prevent dithering. + * @return Returns the generated pixmap, for convenience. + */ + static QPixmap& gradient(QPixmap& pixmap, const QColor &ca, const QColor &cb, + GradientType type, int ncols=3); + + + /** + * Blend the provided pixmap into a background of the indicated color + * + * @param pixmap The pixmap to process. + * @param initial_intensity this parameter takes values from -1 to 1: + * @li If positive, it tells how much to fade the image in its + * less affected spot. + * @li If negative, it tells roughly indicates how much of the image + * remains unaffected + * @param bgnd Indicates the color of the background to blend in. + * @param eff Lets you choose what kind of blending you like. + * @param anti_dir Blend in the opposite direction (makes no much sense + * with concentric blending effects). + * @return Returns the @ref pixmap(), provided for convenience. + */ + static QPixmap& blend(QPixmap& pixmap, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir=false, int ncols=3); + + + static QImage& blend(QImage &image, float initial_intensity, + const QColor &bgnd, GradientType eff, + bool anti_dir); +}; + + +#endif diff --git a/noncore/styles/theme/opie-theme.control b/noncore/styles/theme/opie-theme.control new file mode 100644 index 0000000..02739fb --- a/dev/null +++ b/noncore/styles/theme/opie-theme.control @@ -0,0 +1,11 @@ +Files: plugins/styles/libtheme.so* bin/theme-settings apps/Settings/Theme.desktop pics/theme/Theme.png +Priority: optional +Section: opie/system +Maintainer: Robert Griebl <sandman@handhelds.org> +Architecture: arm +Version: $QPE_VERSION-$SUB_VERSION.1 +Depends: opie-base ($QPE_VERSION) +Description: Themed style. + This style accepts all themes written +for KDE 2.2 + diff --git a/noncore/styles/theme/othemebase.cpp b/noncore/styles/theme/othemebase.cpp new file mode 100644 index 0000000..00cea03 --- a/dev/null +++ b/noncore/styles/theme/othemebase.cpp @@ -0,0 +1,1212 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Daniel M. Duley <mosfet@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 version 2 as published by the Free Software Foundation. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#include "othemebase.h" +#include "ogfxeffect.h" +#include <qpe/qpeapplication.h> +//#include <kdebug.h> +//#include <klocale.h> +#include <qpe/config.h> +//#include <kglobal.h> +//#include <kglobalsettings.h> +//#include <kstddirs.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qdir.h> +#include <qpainter.h> +#include <qbitmap.h> +#include <stdlib.h> +#include <qstringlist.h> + +#include <stdio.h> + +template class QIntCache<OThemePixmap> +; + +static const char *widgetEntries[] = + { // unsunken widgets (see header) + "PushButton", "ComboBox", "HSBarSlider", "VSBarSlider", "Bevel", "ToolButton", + "ScrollButton", "HScrollDeco", "VScrollDeco", "ComboDeco", "MenuItem", "Tab", + "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", + // sunken widgets + "PushButtonDown", "ComboBoxDown", "HSBarSliderDown", "VSBarSliderDown", + "BevelDown", "ToolButtonDown", "ScrollButtonDown", "HScrollDecoDown", + "VScrollDecoDown", "ComboDecoDown", "MenuItemDown", "TabDown", "SunkenArrowUp", + "SunkenArrowDown", "SunkenArrowLeft", "SunkenArrowRight", + // everything else + "HScrollGroove", "VScrollGroove", "Slider", "SliderGroove", "CheckBoxDown", + "CheckBox", "RadioDown", "Radio", "HBarHandle", "VBarHandle", + "ToolBar", "Splitter", "CheckMark", "MenuBar", "DisableArrowUp", + "DisableArrowDown", "DisableArrowLeft", "DisableArrowRight", "ProgressBar", + "ProgressBackground", "MenuBarItem", "Background" + }; + +#define INHERIT_ITEMS 16 + + +// This is used to encode the keys. I used to use masks but I think this +// bitfield is nicer :) I don't know why C++ coders don't use these more.. +// (mosfet) +struct kthemeKeyData +{ +unsigned int id : + 6; +unsigned int width : + 12; +unsigned int height : + 12; +unsigned int border : + 1; +unsigned int mask : + 1; +}; + +union kthemeKey{ + kthemeKeyData data; + unsigned int cacheKey; +}; + +class MyConfig : public Config +{ +public: + MyConfig ( const QString &f, Domain d ) : Config ( f, d ) + { } + + bool hasGroup ( const QString &gname ) const + { + QMap< QString, ConfigGroup>::ConstIterator it = groups. find ( gname ); + return ( it != groups.end() ); + } +}; + +void OThemeBase::generateBorderPix( int i ) +{ + // separate pixmap into separate components + if ( pbPixmaps[ i ] ) { + // evidently I have to do masks manually... + const QBitmap * srcMask = pbPixmaps[ i ] ->mask(); + QBitmap destMask( pbWidth[ i ], pbWidth[ i ] ); + QPixmap tmp( pbWidth[ i ], pbWidth[ i ] ); + + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], 0, 0, pbWidth[ i ], pbWidth[ i ], + Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, 0, 0, pbWidth[ i ], pbWidth[ i ], + Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + pbPixmaps[ i ] ->setBorder( OThemePixmap::TopLeft, tmp ); + + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], pbPixmaps[ i ] ->width() - pbWidth[ i ], 0, + pbWidth[ i ], pbWidth[ i ], Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, pbPixmaps[ i ] ->width() - pbWidth[ i ], + 0, pbWidth[ i ], pbWidth[ i ], Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + pbPixmaps[ i ] ->setBorder( OThemePixmap::TopRight, tmp ); + + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], 0, pbPixmaps[ i ] ->height() - pbWidth[ i ], + pbWidth[ i ], pbWidth[ i ], Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, 0, pbPixmaps[ i ] ->height() - pbWidth[ i ], + pbWidth[ i ], pbWidth[ i ], Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + pbPixmaps[ i ] ->setBorder( OThemePixmap::BottomLeft, tmp ); + + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], pbPixmaps[ i ] ->width() - pbWidth[ i ], + pbPixmaps[ i ] ->height() - pbWidth[ i ], pbWidth[ i ], pbWidth[ i ], + Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, pbPixmaps[ i ] ->width() - pbWidth[ i ], + pbPixmaps[ i ] ->height() - pbWidth[ i ], pbWidth[ i ], pbWidth[ i ], + Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + pbPixmaps[ i ] ->setBorder( OThemePixmap::BottomRight, tmp ); + + tmp.resize( pbPixmaps[ i ] ->width() - pbWidth[ i ] * 2, pbWidth[ i ] ); + destMask.resize( pbPixmaps[ i ] ->width() - pbWidth[ i ] * 2, pbWidth[ i ] ); + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], pbWidth[ i ], 0, + pbPixmaps[ i ] ->width() - pbWidth[ i ] * 2, pbWidth[ i ], Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, pbWidth[ i ], 0, + pbPixmaps[ i ] ->width() - pbWidth[ i ] * 2, pbWidth[ i ], + Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + pbPixmaps[ i ] ->setBorder( OThemePixmap::Top, tmp ); + + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], pbWidth[ i ], + pbPixmaps[ i ] ->height() - pbWidth[ i ], + pbPixmaps[ i ] ->width() - pbWidth[ i ] * 2, pbWidth[ i ], Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, pbWidth[ i ], + pbPixmaps[ i ] ->height() - pbWidth[ i ], + pbPixmaps[ i ] ->width() - pbWidth[ i ] * 2, pbWidth[ i ], Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + pbPixmaps[ i ] ->setBorder( OThemePixmap::Bottom, tmp ); + + tmp.resize( pbWidth[ i ], pbPixmaps[ i ] ->height() - pbWidth[ i ] * 2 ); + destMask.resize( pbWidth[ i ], pbPixmaps[ i ] ->height() - pbWidth[ i ] * 2 ); + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], 0, pbWidth[ i ], pbWidth[ i ], + pbPixmaps[ i ] ->height() - pbWidth[ i ] * 2, Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, 0, pbWidth[ i ], pbWidth[ i ], + pbPixmaps[ i ] ->height() - pbWidth[ i ] * 2, Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + + pbPixmaps[ i ] ->setBorder( OThemePixmap::Left, tmp ); + + bitBlt( &tmp, 0, 0, pbPixmaps[ i ], pbPixmaps[ i ] ->width() - pbWidth[ i ], + pbWidth[ i ], pbWidth[ i ], pbPixmaps[ i ] ->height() - pbWidth[ i ] * 2, + Qt::CopyROP, false ); + if ( srcMask ) { + bitBlt( &destMask, 0, 0, srcMask, pbPixmaps[ i ] ->width() - pbWidth[ i ], + pbWidth[ i ], pbWidth[ i ], pbPixmaps[ i ] ->height() - pbWidth[ i ] * 2, + Qt::CopyROP, false ); + tmp.setMask( destMask ); + } + pbPixmaps[ i ] ->setBorder( OThemePixmap::Right, tmp ); + } + else + qDebug ( "OThemeBase: Tried making border from empty pixmap" ); +} + + +void OThemeBase::copyWidgetConfig( int sourceID, int destID, QString *pixnames, + QString *brdnames ) +{ + scaleHints[ destID ] = scaleHints[ sourceID ]; + gradients[ destID ] = gradients[ sourceID ]; + blends[ destID ] = blends[ sourceID ]; + bContrasts[ destID ] = bContrasts[ sourceID ]; + borders[ destID ] = borders[ sourceID ]; + highlights[ destID ] = highlights[ sourceID ]; + + if ( grLowColors[ sourceID ] ) + grLowColors[ destID ] = new QColor( *grLowColors[ sourceID ] ); + else + grLowColors[ destID ] = NULL; + + if ( grHighColors[ sourceID ] ) + grHighColors[ destID ] = new QColor( *grHighColors[ sourceID ] ); + else + grHighColors[ destID ] = NULL; + + if ( colors[ sourceID ] ) + colors[ destID ] = new QColorGroup( *colors[ sourceID ] ); + else + colors[ destID ] = NULL; + + // pixmap + pixnames[ destID ] = pixnames[ sourceID ]; + duplicate[ destID ] = false; + pixmaps[ destID ] = NULL; + images[ destID ] = NULL; + if ( !pixnames[ destID ].isEmpty() ) { + if ( scaleHints[ sourceID ] == TileScale && blends[ sourceID ] == 0.0 ) { + pixmaps[ destID ] = pixmaps[ sourceID ]; + duplicate[ destID ] = true; + } + if ( !duplicate[ destID ] ) { + pixmaps[ destID ] = loadPixmap( pixnames[ destID ] ); + if ( scaleHints[ destID ] == TileScale && blends[ destID ] == 0.0 ) + images[ destID ] = NULL; + else + images[ destID ] = loadImage( pixnames[ destID ] ); + } + } + + // border pixmap + pbDuplicate[ destID ] = false; + pbPixmaps[ destID ] = NULL; + pbWidth[ destID ] = pbWidth[ sourceID ]; + brdnames[ destID ] = brdnames[ sourceID ]; + if ( !brdnames[ destID ].isEmpty() ) { + pbPixmaps[ destID ] = pbPixmaps[ sourceID ]; + pbDuplicate[ destID ] = true; + } + + if ( sourceID == ActiveTab && destID == InactiveTab ) + aTabLine = iTabLine; + else if ( sourceID == InactiveTab && destID == ActiveTab ) + iTabLine = aTabLine; +} + +void OThemeBase::readConfig( Qt::GUIStyle /*style*/ ) +{ +#define PREBLEND_ITEMS 12 + static WidgetType preBlend[] = {Slider, IndicatorOn, IndicatorOff, + ExIndicatorOn, ExIndicatorOff, HScrollDeco, VScrollDeco, HScrollDecoDown, + VScrollDecoDown, ComboDeco, ComboDecoDown, CheckMark}; + + int i; + QString tmpStr; + QString copyfrom[ WIDGETS ]; + QString pixnames[ WIDGETS ]; // used for duplicate check + QString brdnames[ WIDGETS ]; + bool loaded[ WIDGETS ]; // used for preloading for CopyWidget + + if ( configFileName.isEmpty() ) { + Config cfg ( "qpe" ); + cfg. setGroup ( "Appearance" ); + + configFileName = cfg. readEntry ( "Theme", "default" ); + } + MyConfig config( configFilePath + "/themes/" + configFileName + ".themerc" , Config::File ); + + printf ( "Opened config file: %s\n", ( configFilePath + "/themes/" + configFileName + ".themerc" ). ascii()); + + // Are we initalized? + for ( i = 0; i < INHERIT_ITEMS; ++i ) { + applyResourceGroup( &config, i, copyfrom, pixnames, brdnames ); + printf ( "%d [%s]: copy=%s, pix=%s, brd=%s\n", i, widgetEntries [i], copyfrom [i].latin1(), pixnames[i].latin1(),brdnames[i].latin1() ); + } + for ( ; i < INHERIT_ITEMS*2; ++i ) { + if ( config.hasGroup( QString( widgetEntries[ i ] ) ) ) { + applyResourceGroup( &config, i, copyfrom, pixnames, brdnames ); + printf ( "%d [%s]: copy=%s, pix=%s, brd=%s\n", i, widgetEntries [i], copyfrom [i].latin1(), pixnames[i].latin1(),brdnames[i].latin1() ); + } + else { + copyfrom [ i ] = widgetEntries[ i - INHERIT_ITEMS ]; + printf ( "%d [%s]: copy=%s\n", i, widgetEntries [i], copyfrom [i].latin1()); + } + } + for ( ; i < WIDGETS; ++i ) { + applyResourceGroup( &config, i, copyfrom, pixnames, brdnames ); + printf ( "%d [%s]: copy=%s, pix=%s, brd=%s\n", i, widgetEntries [i], copyfrom [i].latin1(), pixnames[i].latin1(),brdnames[i].latin1() ); + } + applyMiscResourceGroup( &config ); + + // initalize defaults that may not be read + for ( i = 0; i < WIDGETS; ++i ) + loaded[ i ] = false; + btnXShift = btnYShift = focus3DOffset = 0; + aTabLine = iTabLine = true; + roundedButton = roundedCombo = roundedSlider = focus3D = false; + splitterWidth = 10; + + for ( i = 0; i < WIDGETS; ++i ) { + readResourceGroup( i, copyfrom, pixnames, brdnames, loaded ); + printf ( "%d [%s]: copy=%s, pix=%s, brd=%s, colors=%s\n", i, widgetEntries [i], copyfrom [i].latin1(), pixnames[i].latin1(),brdnames[i].latin1(), (colors[i]?colors[i]->background().name().latin1():"<none)" )); + } + + // misc items + readMiscResourceGroup(); + + // Handle preblend items + for ( i = 0; i < PREBLEND_ITEMS; ++i ) { + if ( pixmaps[ preBlend[ i ] ] != NULL && blends[ preBlend[ i ] ] != 0.0 ) + blend( preBlend[ i ] ); + } +} + +OThemeBase::OThemeBase( const QString & configFile ) + : QWindowsStyle() +{ + configFilePath = QPEApplication::qpeDir ( ) + "/plugins/styles/"; + configFileName = configFile; + + readConfig( Qt::WindowsStyle ); + cache = new OThemeCache( cacheSize ); +} + +void OThemeBase::applyConfigFile( const QString &/*file*/ ) +{ +#if 0 + // handle std color scheme + Config inConfig( file, Config::File ); + Config globalConfig ( "qpe" ); + + globalConfig. setGroup ( "Apperance" ); + inConfig. setGroup( "General" ); + + if ( inConfig.hasKey( "foreground" ) ) + globalConfig.writeEntry( "Text", inConfig.readEntry( "foreground", " " ) ); + if ( inConfig.hasKey( "background" ) ) + globalConfig.writeEntry( "Background", inConfig.readEntry( "background", " " ) ); + if ( inConfig.hasKey( "selectForeground" ) ) + globalConfig.writeEntry( "HighlightedText", inConfig.readEntry( "selectForeground", " " ) ); + if ( inConfig.hasKey( "selectBackground" ) ) + globalConfig.writeEntry( "Highlight", inConfig.readEntry( "selectBackground", " " ) ); + if ( inConfig.hasKey( "windowForeground" ) ) + globalConfig.writeEntry( "Text", inConfig.readEntry( "windowForeground", " " ) ); + if ( inConfig.hasKey( "windowBackground" ) ) + globalConfig.writeEntry( "Base", inConfig.readEntry( "windowBackground", " " ) ); + + // Keep track of the current theme so that we can select the right one + // in the KControl module. + globalConfig.writeEntry ( "CurrentTheme", file ); + + globalConfig.write(); +#endif +} + +OThemeBase::~OThemeBase() +{ + int i; + for ( i = 0; i < WIDGETS; ++i ) { + if ( !duplicate[ i ] ) { + if ( images[ i ] ) + delete images[ i ]; + if ( pixmaps[ i ] ) + delete pixmaps[ i ]; + } + if ( !pbDuplicate[ i ] && pbPixmaps[ i ] ) + delete pbPixmaps[ i ]; + if ( colors[ i ] ) + delete( colors[ i ] ); + if ( grLowColors[ i ] ) + delete( grLowColors[ i ] ); + if ( grHighColors[ i ] ) + delete( grHighColors[ i ] ); + } + delete cache; +} + +QImage* OThemeBase::loadImage( QString &name ) +{ + QImage * image = new QImage; + QString path = configFilePath + "/pixmaps/" + name; + image->load( path ); + if ( !image->isNull() ) + return ( image ); + qDebug ( "OThemeBase: Unable to load image %s\n", name.ascii ( ) ); + delete image; + return ( NULL ); +} + +OThemePixmap* OThemeBase::loadPixmap( QString &name ) +{ + OThemePixmap * pixmap = new OThemePixmap( false ); + QString path = configFilePath + "/pixmaps/" + name; + pixmap->load( path ); + if ( !pixmap->isNull() ) + return pixmap; + qDebug ( "OThemeBase: Unable to load pixmap %s\n", name.ascii() ); + delete pixmap; + return ( NULL ); +} + +OThemePixmap* OThemeBase::scale( int w, int h, WidgetType widget ) +{ + if ( scaleHints[ widget ] == FullScale ) { + if ( !pixmaps[ widget ] || pixmaps[ widget ] ->width() != w || + pixmaps[ widget ] ->height() != h ) { + OThemePixmap * cachePix = cache->pixmap( w, h, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, + widget ); + else + qDebug( "We would have inserted a null pixmap!\n" ); + pixmaps[ widget ] = cachePix; + } + else { + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, widget ); + QImage tmpImg = images[ widget ] ->smoothScale( w, h ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->convertFromImage( tmpImg ); + if ( blends[ widget ] != 0.0 ) + blend( widget ); + } + } + } + else if ( scaleHints[ widget ] == HorizontalScale ) { + if ( pixmaps[ widget ] ->width() != w ) { + OThemePixmap * cachePix = cache->horizontalPixmap( w, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::HorizontalScale, widget ); + else + qDebug ( "We would have inserted a null pixmap!\n" ); + pixmaps[ widget ] = cachePix; + } + else { + cache->insert( pixmaps[ widget ], OThemeCache::HorizontalScale, widget ); + QImage tmpImg = images[ widget ] -> + smoothScale( w, images[ widget ] ->height() ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->convertFromImage( tmpImg ); + if ( blends[ widget ] != 0.0 ) + blend( widget ); + } + } + } + else if ( scaleHints[ widget ] == VerticalScale ) { + if ( pixmaps[ widget ] ->height() != h ) { + OThemePixmap * cachePix = cache->verticalPixmap( w, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::VerticalScale, widget ); + else + qDebug ( "We would have inserted a null pixmap!\n" ); + pixmaps[ widget ] = cachePix; + } + else { + cache->insert( pixmaps[ widget ], OThemeCache::VerticalScale, widget ); + QImage tmpImg = + images[ widget ] ->smoothScale( images[ widget ] ->width(), h ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->convertFromImage( tmpImg ); + if ( blends[ widget ] != 0.0 ) + blend( widget ); + } + } + } + // If blended tile here so the blend is scaled properly + else if ( scaleHints[ widget ] == TileScale && blends[ widget ] != 0.0 ) { + if ( !pixmaps[ widget ] || pixmaps[ widget ] ->width() != w || + pixmaps[ widget ] ->height() != h ) { + OThemePixmap * cachePix = cache->pixmap( w, h, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, widget ); + pixmaps[ widget ] = cachePix; + } + else { + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, widget ); + QPixmap tile; + tile.convertFromImage( *images[ widget ] ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->resize( w, h ); + QPainter p( pixmaps[ widget ] ); + p.drawTiledPixmap( 0, 0, w, h, tile ); + if ( blends[ widget ] != 0.0 ) + blend( widget ); + } + } + } + return ( pixmaps[ widget ] ); +} + +OThemePixmap* OThemeBase::scaleBorder( int w, int h, WidgetType widget ) +{ + OThemePixmap * pixmap = NULL; + if ( !pbPixmaps[ widget ] && !pbWidth[ widget ] ) + return ( NULL ); + pixmap = cache->pixmap( w, h, widget, true ); + if ( pixmap ) { + pixmap = new OThemePixmap( *pixmap ); + } + else { + pixmap = new OThemePixmap(); + pixmap->resize( w, h ); + QBitmap mask; + mask.resize( w, h ); + mask.fill( color0 ); + QPainter mPainter; + mPainter.begin( &mask ); + + QPixmap *tmp = borderPixmap( widget ) ->border( OThemePixmap::TopLeft ); + const QBitmap *srcMask = tmp->mask(); + int bdWidth = tmp->width(); + + bitBlt( pixmap, 0, 0, tmp, 0, 0, bdWidth, bdWidth, + Qt::CopyROP, false ); + if ( srcMask ) + bitBlt( &mask, 0, 0, srcMask, 0, 0, bdWidth, bdWidth, + Qt::CopyROP, false ); + else + mPainter.fillRect( 0, 0, bdWidth, bdWidth, color1 ); + + + tmp = borderPixmap( widget ) ->border( OThemePixmap::TopRight ); + srcMask = tmp->mask(); + bitBlt( pixmap, w - bdWidth, 0, tmp, 0, 0, bdWidth, + bdWidth, Qt::CopyROP, false ); + if ( srcMask ) + bitBlt( &mask, w - bdWidth, 0, srcMask, 0, 0, bdWidth, + bdWidth, Qt::CopyROP, false ); + else + mPainter.fillRect( w - bdWidth, 0, bdWidth, bdWidth, color1 ); + + tmp = borderPixmap( widget ) ->border( OThemePixmap::BottomLeft ); + srcMask = tmp->mask(); + bitBlt( pixmap, 0, h - bdWidth, tmp, 0, 0, bdWidth, + bdWidth, Qt::CopyROP, false ); + if ( srcMask ) + bitBlt( &mask, 0, h - bdWidth, srcMask, 0, 0, bdWidth, + bdWidth, Qt::CopyROP, false ); + else + mPainter.fillRect( 0, h - bdWidth, bdWidth, bdWidth, color1 ); + + tmp = borderPixmap( widget ) ->border( OThemePixmap::BottomRight ); + srcMask = tmp->mask(); + bitBlt( pixmap, w - bdWidth, h - bdWidth, tmp, 0, 0, + bdWidth, bdWidth, Qt::CopyROP, false ); + if ( srcMask ) + bitBlt( &mask, w - bdWidth, h - bdWidth, srcMask, 0, 0, + bdWidth, bdWidth, Qt::CopyROP, false ); + else + mPainter.fillRect( w - bdWidth, h - bdWidth, bdWidth, bdWidth, color1 ); + + QPainter p; + p.begin( pixmap ); + if ( w - bdWidth * 2 > 0 ) { + tmp = borderPixmap( widget ) ->border( OThemePixmap::Top ); + srcMask = tmp->mask(); + p.drawTiledPixmap( bdWidth, 0, w - bdWidth * 2, bdWidth, *tmp ); + if ( srcMask ) + mPainter.drawTiledPixmap( bdWidth, 0, w - bdWidth * 2, bdWidth, *srcMask ); + else + mPainter.fillRect( bdWidth, 0, w - bdWidth * 2, bdWidth, color1 ); + + tmp = borderPixmap( widget ) ->border( OThemePixmap::Bottom ); + srcMask = tmp->mask(); + p.drawTiledPixmap( bdWidth, h - bdWidth, w - bdWidth * 2, bdWidth, + *tmp ); + if ( srcMask ) + mPainter.drawTiledPixmap( bdWidth, h - bdWidth, w - bdWidth * 2, bdWidth, *srcMask ); + else + mPainter.fillRect( bdWidth, h - bdWidth, w - bdWidth * 2, bdWidth, + color1 ); + } + if ( h - bdWidth * 2 > 0 ) { + tmp = borderPixmap( widget ) ->border( OThemePixmap::Left ); + srcMask = tmp->mask(); + p.drawTiledPixmap( 0, bdWidth, bdWidth, h - bdWidth * 2, *tmp ); + if ( srcMask ) + mPainter.drawTiledPixmap( 0, bdWidth, bdWidth, h - bdWidth * 2, *srcMask ); + else + mPainter.fillRect( 0, bdWidth, bdWidth, h - bdWidth * 2, color1 ); + + tmp = borderPixmap( widget ) ->border( OThemePixmap::Right ); + srcMask = tmp->mask(); + p.drawTiledPixmap( w - bdWidth, bdWidth, bdWidth, h - bdWidth * 2, + *tmp ); + if ( srcMask ) + mPainter.drawTiledPixmap( w - bdWidth, bdWidth, bdWidth, h - bdWidth * 2, *srcMask ); + else + mPainter.fillRect( w - bdWidth, bdWidth, bdWidth, h - bdWidth * 2, color1 ); + } + p.end(); + mPainter.end(); + pixmap->setMask( mask ); + cache->insert( pixmap, OThemeCache::FullScale, widget, true ); + if ( !pixmap->mask() ) + qDebug ( "No mask for border pixmap!\n" ); + } + return ( pixmap ); +} + + +OThemePixmap* OThemeBase::blend( WidgetType widget ) +{ + OGfxEffect::GradientType g; + switch ( gradients[ widget ] ) { + case GrHorizontal: + g = OGfxEffect::HorizontalGradient; + break; + case GrVertical: + g = OGfxEffect::VerticalGradient; + break; + case GrPyramid: + g = OGfxEffect::PyramidGradient; + break; + case GrRectangle: + g = OGfxEffect::RectangleGradient; + break; + case GrElliptic: + g = OGfxEffect::EllipticGradient; + break; + default: + g = OGfxEffect::DiagonalGradient; + break; + } + OGfxEffect::blend( *pixmaps[ widget ], blends[ widget ], *grLowColors[ widget ], + g, false ); + return ( pixmaps[ widget ] ); +} + +OThemePixmap* OThemeBase::gradient( int w, int h, WidgetType widget ) +{ + if ( gradients[ widget ] == GrVertical ) { + if ( !pixmaps[ widget ] || pixmaps[ widget ] ->height() != h ) { + OThemePixmap * cachePix = cache->verticalPixmap( h, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::VerticalScale, + widget ); + pixmaps[ widget ] = cachePix; + } + else { + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::VerticalScale, + widget ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->resize( w, h ); + OGfxEffect::gradient( *pixmaps[ widget ], *grHighColors[ widget ], + *grLowColors[ widget ], + OGfxEffect::VerticalGradient ); + } + } + } + else if ( gradients[ widget ] == GrHorizontal ) { + if ( !pixmaps[ widget ] || pixmaps[ widget ] ->width() != w ) { + OThemePixmap * cachePix = cache->horizontalPixmap( w, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], + OThemeCache::HorizontalScale, widget ); + pixmaps[ widget ] = cachePix; + } + else { + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], + OThemeCache::HorizontalScale, widget ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->resize( w, h ); + OGfxEffect::gradient( *pixmaps[ widget ], *grHighColors[ widget ], + *grLowColors[ widget ], + OGfxEffect::HorizontalGradient ); + } + } + } + else if ( gradients[ widget ] == GrReverseBevel ) { + if ( !pixmaps[ widget ] || pixmaps[ widget ] ->width() != w || + pixmaps[ widget ] ->height() != h ) { + OThemePixmap * cachePix = cache->pixmap( w, h, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, + widget ); + pixmaps[ widget ] = cachePix; + } + else { + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, + widget ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->resize( w, h ); + + QPixmap s; + int offset = decoWidth( widget ); + s.resize( w - offset * 2, h - offset * 2 ); + QColor lc( *grLowColors[ widget ] ); + QColor hc( *grHighColors[ widget ] ); + if ( bevelContrast( widget ) ) { + int bc = bevelContrast( widget ); + // want single increments, not factors like light()/dark() + lc.setRgb( lc.red() - bc, lc.green() - bc, lc.blue() - bc ); + hc.setRgb( hc.red() + bc, hc.green() + bc, hc.blue() + bc ); + } + OGfxEffect::gradient( *pixmaps[ widget ], + lc, hc, + OGfxEffect::DiagonalGradient ); + OGfxEffect::gradient( s, *grHighColors[ widget ], + *grLowColors[ widget ], + OGfxEffect::DiagonalGradient ); + bitBlt( pixmaps[ widget ], offset, offset, &s, 0, 0, w - offset * 2, + h - offset * 2, Qt::CopyROP ); + } + } + } + else { + OGfxEffect::GradientType g; + switch ( gradients[ widget ] ) { + case GrPyramid: + g = OGfxEffect::PyramidGradient; + break; + case GrRectangle: + g = OGfxEffect::RectangleGradient; + break; + case GrElliptic: + g = OGfxEffect::EllipticGradient; + break; + default: + g = OGfxEffect::DiagonalGradient; + break; + } + if ( !pixmaps[ widget ] || pixmaps[ widget ] ->width() != w || + pixmaps[ widget ] ->height() != h ) { + OThemePixmap * cachePix = cache->pixmap( w, h, widget ); + if ( cachePix ) { + cachePix = new OThemePixmap( *cachePix ); + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, + widget ); + pixmaps[ widget ] = cachePix; + } + else { + if ( pixmaps[ widget ] ) + cache->insert( pixmaps[ widget ], OThemeCache::FullScale, + widget ); + pixmaps[ widget ] = new OThemePixmap; + pixmaps[ widget ] ->resize( w, h ); + OGfxEffect::gradient( *pixmaps[ widget ], *grHighColors[ widget ], + *grLowColors[ widget ], g ); + } + } + } + return ( pixmaps[ widget ] ); +} + +OThemePixmap* OThemeBase::scalePixmap( int w, int h, WidgetType widget ) +{ + + if ( gradients[ widget ] && blends[ widget ] == 0.0 ) + return ( gradient( w, h, widget ) ); + + return ( scale( w, h, widget ) ); +} + +QColorGroup* OThemeBase::makeColorGroup( QColor &fg, QColor &bg, + Qt::GUIStyle ) +{ + if ( shading == Motif ) { + int highlightVal, lowlightVal; + highlightVal = 100 + ( 2* /*KGlobalSettings::contrast()*/ 3 + 4 ) * 16 / 10; + lowlightVal = 100 + ( ( 2* /*KGlobalSettings::contrast()*/ 3 + 4 ) * 10 ); + return ( new QColorGroup( fg, bg, bg.light( highlightVal ), + bg.dark( lowlightVal ), bg.dark( 120 ), + fg, qApp->palette().normal().base() ) ); + } + else + return ( new QColorGroup( fg, bg, bg.light( 150 ), bg.dark(), + bg.dark( 120 ), fg, + qApp->palette().normal().base() ) ); +} + +static QColor strToColor ( const QString &str ) +{ + QString str2 = str. stripWhiteSpace ( ); + + if ( str2 [0] == '#' ) + return QColor ( str2 ); + else { + QStringList sl = QStringList::split ( ',', str2 ); + + if ( sl. count ( ) >= 3 ) + return QColor ( sl [0]. toInt ( ), sl [1]. toInt ( ), sl [2]. toInt ( )); + } + return QColor ( 0, 0, 0 ); +} + + + +void OThemeBase::applyMiscResourceGroup( Config *config ) +{ + config-> setGroup ( "Misc" ); + QString tmpStr; + + tmpStr = config->readEntry( "SButtonPosition" ); + if ( tmpStr == "BottomLeft" ) + sbPlacement = SBBottomLeft; + else if ( tmpStr == "BottomRight" ) + sbPlacement = SBBottomRight; + else { + if ( tmpStr != "Opposite" && !tmpStr.isEmpty() ) + qDebug ( "OThemeBase: Unrecognized sb button option %s, using Opposite.\n", tmpStr.ascii() ); + sbPlacement = SBOpposite; + } + tmpStr = config->readEntry( "ArrowType" ); + if ( tmpStr == "Small" ) + arrowStyle = SmallArrow; + else if ( tmpStr == "3D" ) + arrowStyle = MotifArrow; + else { + if ( tmpStr != "Normal" && !tmpStr.isEmpty() ) + qDebug ( "OThemeBase: Unrecognized arrow option %s, using Normal.\n", tmpStr.ascii() ); + arrowStyle = LargeArrow; + } + tmpStr = config->readEntry( "ShadeStyle" ); + if ( tmpStr == "Motif" ) + shading = Motif; + else if ( tmpStr == "Next" ) + shading = Next; + else if ( tmpStr == "KDE" ) + shading = KDE; + else + shading = Windows; + + defaultFrame = config->readNumEntry( "FrameWidth", 2 ); + cacheSize = config->readNumEntry( "Cache", 1024 ); + sbExtent = config->readNumEntry( "ScrollBarExtent", 16 ); + + config-> setGroup ( "General" ); + + if ( config-> hasKey ( "foreground" )) fgcolor = strToColor ( config-> readEntry ( "foreground" )); + if ( config-> hasKey ( "background" )) bgcolor = strToColor ( config-> readEntry ( "background" )); + if ( config-> hasKey ( "selectForeground" )) selfgcolor = strToColor ( config-> readEntry ( "selectForeground" )); + if ( config-> hasKey ( "selectBackground" )) selbgcolor = strToColor ( config-> readEntry ( "selectBackground" )); + if ( config-> hasKey ( "windowForeground" )) winfgcolor = strToColor ( config-> readEntry ( "windowForeground" )); + if ( config-> hasKey ( "windowBackground" )) winbgcolor = strToColor ( config-> readEntry ( "windowBackground" )); +} + +void OThemeBase::readMiscResourceGroup() +{} + +void OThemeBase::applyResourceGroup( Config *config, int i, QString *copyfrom, QString *pixnames, QString *brdnames ) +{ + QString tmpStr; + + config-> setGroup ( widgetEntries [ i ] ); + + tmpStr = config->readEntry( "CopyWidget", "" ); + copyfrom [ i ] = tmpStr; + if ( !tmpStr.isEmpty() ) + return ; + + // Scale hint + tmpStr = config->readEntry( "Scale" ); + if ( tmpStr == "Full" ) + scaleHints [ i ] = FullScale; + else if ( tmpStr == "Horizontal" ) + scaleHints [ i ] = HorizontalScale; + else if ( tmpStr == "Vertical" ) + scaleHints [ i ] = VerticalScale; + else { + if ( tmpStr != "Tile" && !tmpStr.isEmpty() ) + qDebug ( "OThemeBase: Unrecognized scale option %s, using Tile.\n", tmpStr.ascii() ); + scaleHints [ i ] = TileScale; + } + + + // Gradient type + tmpStr = config->readEntry( "Gradient" ); + if ( tmpStr == "Diagonal" ) + gradients [ i ] = GrDiagonal; + else if ( tmpStr == "Horizontal" ) + gradients [ i ] = GrHorizontal; + else if ( tmpStr == "Vertical" ) + gradients [ i ] = GrVertical; + else if ( tmpStr == "Pyramid" ) + gradients [ i ] = GrPyramid; + else if ( tmpStr == "Rectangle" ) + gradients [ i ] = GrRectangle; + else if ( tmpStr == "Elliptic" ) + gradients [ i ] = GrElliptic; + else if ( tmpStr == "ReverseBevel" ) + gradients [ i ] = GrReverseBevel; + else { + if ( tmpStr != "None" && !tmpStr.isEmpty() ) + qDebug ( "OThemeBase: Unrecognized gradient option %s, using None.\n", tmpStr.ascii() ); + gradients [ i ] = GrNone; + } + + // Blend intensity + blends[ i ] = config->readEntry( "BlendIntensity", "0.0" ).toDouble(); + + // Bevel contrast + bContrasts[ i ] = config->readNumEntry( "BevelContrast", 0 ); + + // Border width + borders [ i ] = config->readNumEntry( "Border", 1 ); + + // Highlight width + highlights [ i ] = config->readNumEntry( "Highlight", 1 ); + + // Gradient low color or blend background + if ( config->hasKey( "GradientLow" ) && ( gradients[ i ] != GrNone || blends[ i ] != 0.0 )) + grLowColors[ i ] = new QColor( strToColor ( config->readEntry( "GradientLow", qApp->palette().normal().background().name() ))); + else + grLowColors[ i ] = NULL; + + + // Gradient high color + if ( config->hasKey( "GradientHigh" ) && ( gradients[ i ] != GrNone )) + grHighColors[ i ] = new QColor( strToColor ( config->readEntry( "GradientHigh", qApp->palette().normal().background().name() ))); + else + grHighColors[ i ] = NULL; + + // Extended color attributes + if ( config->hasKey( "Foreground" ) || config->hasKey( "Background" ) ) { + QColor bg = strToColor( config->readEntry( "Background", qApp->palette().normal().background().name() )); + QColor fg = strToColor( config->readEntry( "Foreground", qApp->palette().normal().foreground().name() )); + + colors[ i ] = makeColorGroup( fg, bg, Qt::WindowsStyle ); + } + else + colors[ i ] = NULL; + + // Pixmap + tmpStr = config->readEntry( "Pixmap", "" ); + pixnames[ i ] = tmpStr; + duplicate[ i ] = false; + pixmaps[ i ] = NULL; + images[ i ] = NULL; + + + // Pixmap border + tmpStr = config->readEntry( "PixmapBorder", "" ); + brdnames[ i ] = tmpStr; + pbDuplicate[ i ] = false; + pbPixmaps[ i ] = NULL; + pbWidth[ i ] = 0; + if ( !tmpStr.isEmpty() ) { + pbWidth[ i ] = config->readNumEntry( "PixmapBWidth", 0 ); + if ( pbWidth[ i ] == 0 ) { + qDebug ( "OThemeBase: No border width specified for pixmapped border widget %s\n", widgetEntries[ i ] ); + qDebug ( "OThemeBase: Using default of 2.\n" ); + pbWidth[ i ] = 2; + } + } + + + // Various widget specific settings. This was more efficent when bunched + // together in the misc group, but this makes an easier to read config. + if ( i == SliderGroove ) + roundedSlider = config->readBoolEntry( "SmallGroove", false ); + else if ( i == ActiveTab || i == InactiveTab ) + aTabLine = iTabLine = config->readBoolEntry( "BottomLine", true ); + else if ( i == Splitter ) + splitterWidth = config->readNumEntry( "Width", 10 ); + else if ( i == ComboBox || i == ComboBoxDown ) { + roundedCombo = config->readBoolEntry( "Round", false ); + } + else if ( i == PushButton || i == PushButtonDown ) { + btnXShift = config->readNumEntry( "XShift", 0 ); + btnYShift = config->readNumEntry( "YShift", 0 ); + focus3D = config->readBoolEntry( "3DFocusRect", false ); + focus3DOffset = config->readBoolEntry( "3DFocusOffset", 0 ); + roundedButton = config->readBoolEntry( "Round", false ); + } +} + + +void OThemeBase::readResourceGroup( int i, QString *copyfrom, QString *pixnames, QString *brdnames, + bool *loadArray ) +{ + if ( loadArray[ i ] == true ) { + return ; // already been preloaded. + } + + int tmpVal; + QString tmpStr; + + tmpStr = copyfrom [ i ]; + if ( !tmpStr.isEmpty() ) { // Duplicate another widget's config + int sIndex; + loadArray[ i ] = true; + for ( sIndex = 0; sIndex < WIDGETS; ++sIndex ) { + if ( tmpStr == widgetEntries[ sIndex ] ) { + if ( !loadArray[ sIndex ] ) // hasn't been loaded yet + readResourceGroup( sIndex, copyfrom, pixnames, brdnames, + loadArray ); + break; + } + } + if ( loadArray[ sIndex ] ) { + copyWidgetConfig( sIndex, i, pixnames, brdnames ); + } + else + qDebug ( "OThemeBase: Unable to identify source widget for %s\n", widgetEntries[ i ] ); + return ; + } + // special inheritance for disabled arrows (these are tri-state unlike + // the rest of what we handle). + for ( tmpVal = DisArrowUp; tmpVal <= DisArrowRight; ++tmpVal ) { + if ( tmpVal == i ) { + tmpStr = pixnames [ i ]; + if ( tmpStr.isEmpty() ) { + copyWidgetConfig( ArrowUp + ( tmpVal - DisArrowUp ), i, pixnames, + brdnames ); + return ; + } + } + } + + // Pixmap + int existing; + // Scan for duplicate pixmaps(two identical pixmaps, tile scale, no blend, + // no pixmapped border) + if ( !pixnames [ i ].isEmpty() ) { + for ( existing = 0; existing < i; ++existing ) { + if ( pixnames[ i ] == pixnames[ existing ] && scaleHints[ i ] == TileScale && + scaleHints[ existing ] == TileScale && blends[ existing ] == 0.0 && + blends[ i ] == 0.0 ) { + pixmaps[ i ] = pixmaps[ existing ]; + duplicate[ i ] = true; + break; + } + } + } + // load + if ( !duplicate[ i ] && !pixnames[ i ].isEmpty() ) { + pixmaps[ i ] = loadPixmap( pixnames[ i ] ); + // load and save images for scaled/blended widgets for speed. + if ( scaleHints[ i ] == TileScale && blends[ i ] == 0.0 ) + images[ i ] = NULL; + else + images[ i ] = loadImage( pixnames[ i ] ); + } + + // Pixmap border + if ( !brdnames [ i ]. isEmpty () ) { + // duplicate check + for ( existing = 0; existing < i; ++existing ) { + if ( brdnames [i] == brdnames[ existing ] ) { + pbPixmaps[ i ] = pbPixmaps[ existing ]; + pbDuplicate[ i ] = true; + break; + } + } + } + // load + if ( !pbDuplicate[ i ] && !brdnames[ i ].isEmpty() ) + pbPixmaps[ i ] = loadPixmap( brdnames[ i ] ); + + if ( pbPixmaps[ i ] && !pbDuplicate[ i ] ) + generateBorderPix( i ); + + loadArray[ i ] = true; +} + + +OThemePixmap::OThemePixmap( bool timer ) + : QPixmap() +{ + if(timer){ + t = new QTime; + t->start(); + } + else + t = NULL; + int i; + for ( i = 0; i < 8; ++i ) + b[ i ] = NULL; +} + +OThemePixmap::OThemePixmap( const OThemePixmap &p ) + : QPixmap( p ) +{ + if(p.t){ + t = new QTime; + t->start(); + } + else + t = NULL; + int i; + for ( i = 0; i < 8; ++i ) + if ( p.b[ i ] ) + b[ i ] = new QPixmap( *p.b[ i ] ); + else + b[ i ] = NULL; +} + + + +OThemePixmap::~OThemePixmap() +{ + if(t) + delete t; + int i; + for ( i = 0; i < 8; ++i ) + if ( b[ i ] ) + delete b[ i ]; +} + +OThemeCache::OThemeCache( int maxSize, QObject *parent, const char *name ) + : QObject( parent, name ) +{ + cache.setMaxCost( maxSize * 1024 ); + cache.setAutoDelete( true ); + flushTimer.start(300000); // 5 minutes + connect(&flushTimer, SIGNAL(timeout()), SLOT(flushTimeout())); +} + +void OThemeCache::flushTimeout() +{ + QIntCacheIterator<OThemePixmap> it( cache ); + while ( it.current() ) { + if ( it.current() ->isOld() ) + cache.remove( it.currentKey() ); + else + ++it; + } +} + +OThemePixmap* OThemeCache::pixmap( int w, int h, int widgetID, bool border, + bool mask ) +{ + + kthemeKey key; + key.cacheKey = 0; // shut up, gcc + key.data.id = widgetID; + key.data.width = w; + key.data.height = h; + key.data.border = border; + key.data.mask = mask; + + OThemePixmap *pix = cache.find( ( unsigned long ) key.cacheKey ); + if ( pix ) + pix->updateAccessed(); + return ( pix ); +} + +OThemePixmap* OThemeCache::horizontalPixmap( int w, int widgetID ) +{ + kthemeKey key; + key.cacheKey = 0; // shut up, gcc + key.data.id = widgetID; + key.data.width = w; + key.data.height = 0; + key.data.border = false; + key.data.mask = false; + OThemePixmap *pix = cache.find( ( unsigned long ) key.cacheKey ); + if ( pix ) + pix->updateAccessed(); + return ( pix ); +} + +OThemePixmap* OThemeCache::verticalPixmap( int h, int widgetID ) +{ + kthemeKey key; + key.cacheKey = 0; // shut up, gcc + key.data.id = widgetID; + key.data.width = 0; + key.data.height = h; + key.data.border = false; + key.data.mask = false; + OThemePixmap *pix = cache.find( ( unsigned long ) key.cacheKey ); + if ( pix ) + pix->updateAccessed(); + return ( pix ); +} + +bool OThemeCache::insert( OThemePixmap *pixmap, ScaleHint scale, int widgetID, + bool border, bool mask ) +{ + kthemeKey key; + key.cacheKey = 0; // shut up, gcc + key.data.id = widgetID; + key.data.width = ( scale == FullScale || scale == HorizontalScale ) ? + pixmap->width() : 0; + key.data.height = ( scale == FullScale || scale == VerticalScale ) ? + pixmap->height() : 0; + key.data.border = border; + key.data.mask = mask; + + if ( cache.find( ( unsigned long ) key.cacheKey, true ) != NULL ) { + return ( true ); // a pixmap of this scale is already in there + } + return ( cache.insert( ( unsigned long ) key.cacheKey, pixmap, + pixmap->width() * pixmap->height() * pixmap->depth() / 8 ) ); +} + +//#include "kthemebase.moc" diff --git a/noncore/styles/theme/othemebase.h b/noncore/styles/theme/othemebase.h new file mode 100644 index 0000000..e691692 --- a/dev/null +++ b/noncore/styles/theme/othemebase.h @@ -0,0 +1,739 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Daniel M. Duley <mosfet@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 version 2 as published by the Free Software Foundation. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#ifndef __OTHEMEBASE_H +#define __OTHEMEBASE_H + +#include <qdatetime.h> +#include <qtimer.h> +#include <qwindowsstyle.h> +#include <qpixmap.h> +#include <qpe/config.h> +#include <qimage.h> +#include <qintcache.h> +#include <qstring.h> +#include <qpalette.h> + +#define WIDGETS 54 + +/** + * This class adds simple time management to QPixmap for use in flushing + * OThemeCache. + * + * @author Daniel M. Duley <mosfet@kde.org> + */ +class OThemePixmap : public QPixmap +{ +public: + enum BorderType{Top = 0, Bottom, Left, Right, TopLeft, TopRight, BottomLeft, + BottomRight}; + + OThemePixmap( bool timer = true ); + OThemePixmap( const OThemePixmap &p ); + ~OThemePixmap(); + QPixmap* border( BorderType type ); + void setBorder( BorderType type, const QPixmap &p ); + void updateAccessed(); + bool isOld(); +protected: + QTime *t; + QPixmap *b[ 8 ]; + +private: + class OThemePixmapPrivate; + OThemePixmapPrivate *d; +}; + +inline QPixmap* OThemePixmap::border( BorderType type ) +{ + return ( b[ type ] ); +} + +inline void OThemePixmap::setBorder( BorderType type, const QPixmap &p ) +{ + if ( b[ type ] ) { + qWarning( "OThemePixmap: Overwriting existing border!" ); + delete( b[ type ] ); + } + b[ type ] = new QPixmap( p ); +} + +inline void OThemePixmap::updateAccessed() +{ + if (t) + t->start(); +} + +inline bool OThemePixmap::isOld() +{ + return ( t ? t->elapsed() >= 300000 : false ); +} + +/** + * A very simple pixmap cache for theme plugins. QPixmapCache is not used + * since it uses QString keys which are not needed. All the information we + * need can be encoded in a numeric key. Using QIntCache instead allows us to + * skip the string operations. + * + * This class is mostly just inline methods that do bit operations on a key + * composed of the widget ID, width and/or height, and then calls + * QIntCache::find(). + * + * One other thing to note is that full, horizontal, and vertically scaled + * pixmaps are not used interchangeably. For example, if you insert a fully + * scaled pixmap that is 32x32 then request a horizontally scaled pixmap with + * a width of 32, they will not match. This is because a pixmap that has been + * inserted into the cache has already been scaled at some point and it is + * very likely the vertical height was not originally 32. Thus the pixmap + * will be wrong when drawn, even though the horizontal width matches. + * + * @author Daniel M. Duley <mosfet@kde.org> + * + */ +class OThemeCache : public QObject +{ + Q_OBJECT +public: + /** + * The scale hints supported by the cache. Note that Tiled is not here + * since tiled pixmaps are kept only once in OThemeBase. + */ + enum ScaleHint{FullScale, HorizontalScale, VerticalScale}; + /** + * The constructor. + * + * @param maxSize The maximum size of the cache in kilobytes. + */ + OThemeCache( int maxSize, QObject *parent = 0, const char *name = 0 ); + /** + * Inserts a new pixmap into the cache. + * + * @param pixmap The pixmap to insert. + * @param scale The scaling type of the pixmap. + * @param widgetID The widget ID of the pixmap, usually from OThemeBase's + * WidgetType enum. + * + * @return True if the insert was successful, false otherwise. + */ + bool insert( OThemePixmap *pixmap, ScaleHint scale, int widgetID, + bool border = false, bool mask = false ); + /** + * Returns a fully scaled pixmap. + * + * @param w The pixmap width to search for. + * @param h The pixmap height to search for. + * @param widgetID The widget ID to search for. + * + * @return True if a pixmap matching the width, height, and widget ID of + * the pixmap exists, NULL otherwise. + */ + OThemePixmap* pixmap( int w, int h, int widgetID, bool border = false, + bool mask = false ); + /** + * Returns a horizontally scaled pixmap. + * + * @param w The pixmap width to search for. + * @param widgetID The widget ID to search for. + * + * @return True if a pixmap matching the width and widget ID of + * the pixmap exists, NULL otherwise. + */ + OThemePixmap* horizontalPixmap( int w, int widgetID ); + /** + * Returns a vertically scaled pixmap. + * + * @param h The pixmap height to search for. + * @param widgetID The widget ID to search for. + * + * @return True if a pixmap matching the height and widget ID of + * the pixmap exists, NULL otherwise. + */ + OThemePixmap* verticalPixmap( int h, int widgetID ); +protected slots: + void flushTimeout(); +protected: + QIntCache<OThemePixmap> cache; + QTimer flushTimer; + +private: + class OThemeCachePrivate; + OThemeCachePrivate *d; +}; + + +/** + * This is a base class for KDE themed styles. It implements a cache, + * configuration file parsing, pixmap scaling, gradients, and a lot + * of inline methods for accessing user specified parameters. + * + * Note that this class *does not* actually implement any themes. It just + * provides the groundwork for doing so. The only reason to use this class + * directly is if you plan to reimplement all of the widgets. Otherwise, + * refer to OThemeStyle for a fully themed style you can derive from. + * + * @author Daniel M. Duley <mosfet@kde.org> + */ +class OThemeBase: public QWindowsStyle +{ + Q_OBJECT +public: + /** + * Constructs a new OThemeBase object. + */ + OThemeBase( const QString &configFile ); + ~OThemeBase(); + /** + * Describes if a pixmap should be scaled fully, horizontally, vertically, + * or not at all and tiled. + */ + enum ScaleHint{FullScale, HorizontalScale, VerticalScale, TileScale}; + /** + * The default arrow types. + */ + enum ArrowStyle{MotifArrow, LargeArrow, SmallArrow}; + /** + * The default frame shading styles. + */ + enum ShadeStyle{Motif, Windows, Next, KDE}; + /** + * The default scrollbar button layout. BottomLeft is like what Next + * uses, BottomRight is like Platinum, and Opposite it like Windows and + * Motif. + */ + enum SButton{SBBottomLeft, SBBottomRight, SBOpposite}; + /** + * The gradient types. Horizontal is left to right, Vertical is top to + * bottom, and diagonal is upper-left to bottom-right. + */ + enum Gradient{GrNone, GrHorizontal, GrVertical, GrDiagonal, GrPyramid, + GrRectangle, GrElliptic, GrReverseBevel}; + /** + * This provides a list of widget types that OThemeBase recognizes. + */ + /* Internal note: The order here is important. Some widgets inherit + * properties. This is usually for when you have two settings for the + * same widget, ie: on(sunken), and off. The on settings will inherit + * the properties of the off one when nothing is specified in the config. + * + * In order to be able to handle this while still having everything in + * one group that is easy to loop from we have the following order: + * unsunked(off) items, sunken(on)items, and then the ones that don't + * matter. INHERIT_ITEMS define the number of widgets that have inheritence + * so if 0 == PushButtonOff then INHERIT_ITEMS should == PushButtonOn + * and so on. WIDGETS define the total number of widgets. + */ + enum WidgetType{ + // Off (unsunken widgets) + PushButton = 0, ComboBox, HScrollBarSlider, VScrollBarSlider, Bevel, + ToolButton, ScrollButton, HScrollDeco, VScrollDeco, + ComboDeco, MenuItem, InactiveTab, ArrowUp, ArrowDown, ArrowLeft, + ArrowRight, + // On (sunken widgets) + PushButtonDown, ComboBoxDown, HScrollBarSliderDown, + VScrollBarSliderDown, BevelDown, ToolButtonDown, ScrollButtonDown, + HScrollDecoDown, VScrollDecoDown, ComboDecoDown, MenuItemDown, + ActiveTab, SunkenArrowUp, SunkenArrowDown, SunkenArrowLeft, + SunkenArrowRight, + // Everything else (indicators must have separate settings) + HScrollGroove, VScrollGroove, Slider, SliderGroove, IndicatorOn, + IndicatorOff, ExIndicatorOn, ExIndicatorOff, HBarHandle, VBarHandle, + ToolBar, Splitter, CheckMark, MenuBar, DisArrowUp, DisArrowDown, + DisArrowLeft, DisArrowRight, ProgressBar, ProgressBg, MenuBarItem, + Background}; + + /** + * The scaling type specified by the Config file. + * + * @param widget A Widgets enum value. + * + * @return A ScaleHint enum value. + */ + ScaleHint scaleHint( WidgetType widget ) const; + /** + * The gradient type specified by the KConfig file. + * + * @param widget A Widgets enum value. + * + * @return A Gradient enum value. + */ + Gradient gradientHint( WidgetType widget ) const; + /** + * The color group specified for a given widget. + * If a color group is set in the theme configuration + * that is used, otherwise defaultColor is returned. + * + * @param defaultColor The colorGroup to set if one is available. + * + * @param widget The widget whose color group to retrieve. + * + */ + const QColorGroup* colorGroup( const QColorGroup &defaultGroup, + WidgetType widget ) const; + + QBrush pixmapBrush( const QColorGroup &group, QColorGroup::ColorRole role, + int w, int h, WidgetType widget ); + /** + * True if the widget has a pixmap or gradient specified. + */ + bool isPixmap( WidgetType widget ) const; + /** + * True if the widget has a color group specified. + */ + bool isColor( WidgetType widget ) const; + /** + * True if the user specified a 3D focus rectangle + */ + bool is3DFocus() const; + /** + * If the user specified a 3D focus rectangle, they may also specify an + * offset from the default rectangle to use when drawing it. This returns + * the specified offset. + */ + int focusOffset() const; + /** + * The border width of the specified widget. + */ + int borderWidth( WidgetType widget ) const; + /** + * Pixmap border width of the specified widget. + */ + int pixBorderWidth( WidgetType widget ) const; + /** + * Returns the border pixmap if enabled for the specified widget. This + * will contain the originial pixmap, plus the edges separated in + * OThemePixmap::border() if valid. If invalid it will return NULL. + */ + OThemePixmap* borderPixmap( WidgetType widget ); + /** + * The highlight width of the specified widget. + */ + int highlightWidth( WidgetType widget ) const; + /** + * The border plus highlight width of the widget. + */ + int decoWidth( WidgetType widget ) const; + /** + * The extent (width for vertical, height for horizontal) requested + * for the scrollbars. + */ + int getSBExtent() const; + /** + * The scrollbar button layout. + */ + SButton scrollBarLayout() const; + /** + * The arrow type. + */ + ArrowStyle arrowType() const; + /** + * The shading type. + */ + ShadeStyle shade() const; + /** + * The frame width. + */ + int frameWidth() const; + /** + * The splitter width. + */ + int splitWidth() const; + /** + * The contrast for some bevel effects such as reverse gradient. + */ + int bevelContrast( WidgetType widget ) const; + /** + * The button text X shift. + */ + int buttonXShift() const; + /** + * The button text Y shift. + */ + int buttonYShift() const; + /** + * Returns either the slider length of the slider pixmap if available, + * otherwise the length specified in the config file. + */ + int sliderButtonLength() const; + /** + * True if rounded buttons are requested. + */ + bool roundButton() const; + /** + * True if rounded comboboxes are requested. + */ + bool roundComboBox() const; + /** + * True if rounded slider grooves are requested. + */ + bool roundSlider() const; + /** + * True if a line should be drawn on the bottom of active tabs. + */ + bool activeTabLine() const; + /** + * True if a line should be drawn on the bottom of inactive tabs. + */ + bool inactiveTabLine() const; + /** + * Returns the current uncached pixmap for the given widget. This will + * usually be either the last scaled or gradient pixmap if those have + * been specified in the config file, the original pixmap if not, or NULL + * if no pixmap has been specified. + */ + OThemePixmap* uncached( WidgetType widget ) const; + /** + * Returns the pixmap for the given widget at the specified width and + * height. This will return NULL if no pixmap or gradient is specified. + * It may also return a different sized pixmap if the scaling + * is set to Tiled. When using this method, you should call it using + * the needed width and height then use QPainter::drawTiledPixmap to + * paint it. Doing this, if the pixmap is scaled it will be the proper + * size, otherwise it will be tiled. + * + * @param w Requested width. + * @param h Requested height. + * @param widget Widget type. + * @return The pixmap or NULL if one is not specified. + */ + virtual OThemePixmap *scalePixmap( int w, int h, WidgetType widget ); + /** + * This method reads a configuration file and applies it to the user's + * kstylerc file. It does not signal applications to reload via the + * KDEChangeGeneral atom, if you want to do this you must do so yourself. + * See kcmdisplay's general.cpp for an example. + * + * @param file The configuration file to apply. + */ + static void applyConfigFile( const QString &file ); +protected: + /** + * Returns a QImage for the given widget if the widget is scaled, NULL + * otherwise. QImages of the original pixmap are stored for scaled + * widgets in order to facilitate fast and accurate smooth-scaling. This + * also saves us a conversion from a pixmap to an image then back again. + */ + QImage* image( WidgetType widget ) const; + /** + * Returns the gradient high color if one is specified, NULL otherwise. + */ + QColor* gradientHigh( WidgetType widget ) const; + /** + * Returns the gradient low color if one is specified, NULL otherwise. + */ + QColor* gradientLow( WidgetType widget ) const; + /** + * Reads in all the configuration file entries supported. + * + * @param colorStyle The style for the color groups. In KDE, colors were + * calculated a little differently for Motif vs Windows styles. This + * is obsolete. + */ + void readConfig( Qt::GUIStyle colorStyle = Qt::WindowsStyle ); + void readWidgetConfig( int i, Config *config, QString *pixnames, + QString *brdnames, bool *loadArray ); + void copyWidgetConfig( int sourceID, int destID, QString *pixnames, + QString *brdnames ); + /** + * Makes a full color group based on the given foreground and background + * colors. This is the same code used by KDE (kapp.cpp) in previous + * versions. + */ + QColorGroup* makeColorGroup( QColor &fg, QColor &bg, + Qt::GUIStyle style = Qt::WindowsStyle ); + OThemePixmap* scale( int w, int h, WidgetType widget ); + OThemePixmap* scaleBorder( int w, int h, WidgetType type ); + OThemePixmap* gradient( int w, int h, WidgetType widget ); + OThemePixmap* blend( WidgetType widget ); + void generateBorderPix( int i ); + void applyResourceGroup( Config *config, int i, QString *copyfrom, QString *pixnames, QString *brdnames ); + void applyMiscResourceGroup( Config *config ); + void readResourceGroup( int i, QString *copyfrom, QString *pixnames, QString *brdnames, + bool *loadArray ); + void readMiscResourceGroup(); + /** + * Attempts to load a pixmap from the default OThemeBase locations. + */ + OThemePixmap* loadPixmap( QString &name ); + /** + * Attempts to load a image from the default OThemeBase locations. + */ + QImage* loadImage( QString &name ); +private: + SButton sbPlacement; + ArrowStyle arrowStyle; + ShadeStyle shading; + int defaultFrame; + int btnXShift, btnYShift; + int sliderLen; + int splitterWidth; + int focus3DOffset; + int sbExtent; + bool smallGroove; + bool roundedButton, roundedCombo, roundedSlider; + bool aTabLine, iTabLine; + bool focus3D; + OThemeCache *cache; + int cacheSize; + QString configFileName; + QString configFilePath; + +protected: + QColor fgcolor, bgcolor, selfgcolor, selbgcolor, winfgcolor, winbgcolor; + +private: + /** + * The theme pixmaps. Many of these may be NULL if no pixmap is specified. + * There may also be duplicate pixmap pointers if more than one widget + * uses the same tiled pixmap. If a pixmap is tiled, it is kept here and + * this acts as a cache. Otherwise this will hold whatever the last scaled + * pixmap was. + */ + OThemePixmap *pixmaps[ WIDGETS ]; + /** + * The theme images. These are for scaled images and are kept in order + * to maintain fast smoothscaling. + */ + QImage *images[ WIDGETS ]; + /** + * The border widths + */ + unsigned char borders[ WIDGETS ]; + /** + * The highlight widths + */ + unsigned char highlights[ WIDGETS ]; + /** + * The scale hints for pixmaps and gradients. + */ + ScaleHint scaleHints[ WIDGETS ]; + /** + * All the color groups. + */ + QColorGroup *colors[ WIDGETS ]; + /** + * Gradient low colors (or blend background). + */ + QColor *grLowColors[ WIDGETS ]; + /** + * Gradient high colors. + */ + QColor *grHighColors[ WIDGETS ]; + /** + * Gradient types. + */ + Gradient gradients[ WIDGETS ]; + /** + * Blend intensity factors + */ + float blends[ WIDGETS ]; + /** + * Bevel contrasts + */ + unsigned char bContrasts[ WIDGETS ]; + /** + * Duplicate pixmap entries (used during destruction). + */ + bool duplicate[ WIDGETS ]; + /** + * Pixmapped border widths + */ + int pbWidth[ WIDGETS ]; + /** + * Pixmapped borders + */ + OThemePixmap *pbPixmaps[ WIDGETS ]; + /** + * Duplicate border pixmapped border entries + */ + bool pbDuplicate[ WIDGETS ]; + +private: + class OThemeBasePrivate; + OThemeBasePrivate *d; + +}; + +inline bool OThemeBase::isPixmap( WidgetType widget ) const +{ + return ( pixmaps[ widget ] != NULL || gradients[ widget ] != GrNone ); +} + +inline bool OThemeBase::isColor( WidgetType widget ) const +{ + return ( colors[ widget ] != NULL ); +} + +inline bool OThemeBase::is3DFocus() const +{ + return ( focus3D ); +} + +inline int OThemeBase::focusOffset() const +{ + return ( focus3DOffset ); +} + +inline int OThemeBase::bevelContrast( WidgetType widget ) const +{ + return ( bContrasts[ widget ] ); +} + +inline OThemeBase::ScaleHint OThemeBase::scaleHint( WidgetType widget ) const +{ + return ( ( widget < WIDGETS ) ? scaleHints[ widget ] : TileScale ); +} + +inline OThemeBase::Gradient OThemeBase::gradientHint( WidgetType widget ) const +{ + return ( ( widget < WIDGETS ) ? gradients[ widget ] : GrNone ); +} + +inline OThemePixmap* OThemeBase::uncached( WidgetType widget ) const +{ + return ( pixmaps[ widget ] ); +} + +inline QBrush OThemeBase::pixmapBrush( const QColorGroup &group, + QColorGroup::ColorRole role, + int w, int h, WidgetType widget ) +{ + if ( pixmaps[ widget ] || images[ widget ] ) + return ( QBrush( group.color( role ), *scalePixmap( w, h, widget ) ) ); + else + return ( group.color( role ) ); +} + +inline const QColorGroup* OThemeBase::colorGroup( const QColorGroup &defaultGroup, + WidgetType widget ) const +{ + return ( ( colors[ widget ] ) ? colors[ widget ] : &defaultGroup ); +} + +inline int OThemeBase::borderWidth( WidgetType widget ) const +{ + return ( pbWidth[ widget ] ? pbWidth[ widget ] : borders[ widget ] ); +} + +inline int OThemeBase::pixBorderWidth( WidgetType widget ) const +{ + return ( pbWidth[ widget ] ); +} + +inline int OThemeBase::highlightWidth( WidgetType widget ) const +{ + return ( pbWidth[ widget ] ? 0 : highlights[ widget ] ); +} + +inline int OThemeBase::decoWidth( WidgetType widget ) const +{ + return ( pbWidth[ widget ] ? pbWidth[ widget ] : borders[ widget ] + highlights[ widget ] ); +} + +inline QColor* OThemeBase::gradientHigh( WidgetType widget ) const +{ + return ( grHighColors[ widget ] ); +} + +inline QColor* OThemeBase::gradientLow( WidgetType widget ) const +{ + return ( grLowColors[ widget ] ); +} + +inline QImage* OThemeBase::image( WidgetType widget ) const +{ + return ( images[ widget ] ); +} + +inline OThemeBase::SButton OThemeBase::scrollBarLayout() const +{ + return ( sbPlacement ); +} + +inline OThemeBase::ArrowStyle OThemeBase::arrowType() const +{ + return ( arrowStyle ); +} + +inline OThemeBase::ShadeStyle OThemeBase::shade() const +{ + return ( shading ); +} + +inline int OThemeBase::frameWidth() const +{ + return ( defaultFrame ); +} + +inline int OThemeBase::buttonXShift() const +{ + return ( btnXShift ); +} + +inline int OThemeBase::splitWidth() const +{ + return ( splitterWidth ); +} + +inline int OThemeBase::buttonYShift() const +{ + return ( btnYShift ); +} + +inline int OThemeBase::sliderButtonLength() const +{ + if ( isPixmap( Slider ) ) + return ( uncached( Slider ) ->width() ); + else + return ( sliderLen ); +} + +inline bool OThemeBase::roundButton() const +{ + return ( roundedButton ); +} + +inline bool OThemeBase::roundComboBox() const +{ + return ( roundedCombo ); +} + +inline bool OThemeBase::roundSlider() const +{ + return ( roundedSlider ); +} + +inline bool OThemeBase::activeTabLine() const +{ + return ( aTabLine ); +} + +inline bool OThemeBase::inactiveTabLine() const +{ + return ( iTabLine ); +} + +inline int OThemeBase::getSBExtent() const +{ + return ( sbExtent ); +} + +inline OThemePixmap* OThemeBase::borderPixmap( WidgetType widget ) +{ + return ( pbPixmaps[ widget ] ); +} + +#endif diff --git a/noncore/styles/theme/othemestyle.cpp b/noncore/styles/theme/othemestyle.cpp new file mode 100644 index 0000000..61127b8 --- a/dev/null +++ b/noncore/styles/theme/othemestyle.cpp @@ -0,0 +1,1532 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Daniel M. Duley <mosfet@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 version 2 as published by the Free Software Foundation. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "othemestyle.h" +#include "othemebase.h" +#include <qpe/qpeapplication.h> +#include <qbitmap.h> +#define INCLUDE_MENUITEM_DEF +#include <qmenudata.h> +#include <qpopupmenu.h> +#include <qtabbar.h> +#include <qglobal.h> + +#include <limits.h> +#include <stdio.h> + +#define QCOORDARRLEN(x) sizeof(x)/(sizeof(QCOORD)*2) + +OThemeStyle::OThemeStyle( const QString &configFile ) + : OThemeBase( configFile ) +{ + setScrollBarExtent( getSBExtent(), getSBExtent() ); + setButtonDefaultIndicatorWidth( 0 ); // We REALLY should support one, see drawPushButton() below! +} + +OThemeStyle::~OThemeStyle() +{} + +void OThemeStyle::polish( QApplication * /*app*/ ) +{} + +void OThemeStyle::polish( QPalette &p ) +{ + oldPalette = p; + + QColor bg = oldPalette. color ( QPalette::Normal, QColorGroup::Background ); + + if ( bgcolor. isValid ( )) + bg = bgcolor; + + if ( isColor ( Background )) + bg = colorGroup ( oldPalette. active ( ), Background )-> background ( ); + + p = QPalette ( bg, bg ); + + if ( isPixmap( Background ) ) + p. setBrush ( QColorGroup::Background, QBrush ( bg, *uncached ( Background ))); + + if ( fgcolor. isValid ( )) { + p. setColor ( QColorGroup::Foreground, fgcolor ); + p. setColor ( QColorGroup::ButtonText, fgcolor ); + } + if ( selfgcolor. isValid ( )) + p. setColor ( QColorGroup::HighlightedText, selfgcolor ); + if ( selbgcolor. isValid ( )) + p. setColor ( QColorGroup::Highlight, selbgcolor ); + if ( winfgcolor. isValid ( )) + p. setColor ( QColorGroup::Text, winfgcolor ); + if ( winbgcolor. isValid ( )) + p. setColor ( QColorGroup::Base, winbgcolor ); + +} + + +void OThemeStyle::unPolish( QApplication *app ) +{ + app->setPalette( oldPalette, true ); +} + +void OThemeStyle::polish( QWidget *w ) +{ + if ( !w->isTopLevel() ) { + if ( w->inherits( "QGroupBox" ) + || w->inherits( "QTabWidget" ) ) { + w->setAutoMask( TRUE ); + return ; + } + if ( w->inherits( "QLabel" ) + || w->inherits( "QSlider" ) + || w->inherits( "QButton" ) + || w->inherits( "QProgressBar" ) + ) { + w->setBackgroundOrigin( QWidget::ParentOrigin ); + } + } + if ( w->inherits( "QPopupMenu" ) ) { + popupPalette = w->palette(); + if ( isColor( MenuItem ) || isColor( MenuItemDown ) ) { + QPalette newPal( w->palette() ); + w->setPalettePropagation( QWidget::SamePalette ); + if ( isColor( MenuItem ) ) { + newPal.setNormal( *colorGroup( newPal.normal(), MenuItem ) ); + newPal.setDisabled( *colorGroup( newPal.normal(), MenuItem ) ); + } + if ( isColor( MenuItemDown ) ) + newPal.setActive( *colorGroup( newPal.active(), MenuItemDown ) ); + w->setPalette( newPal ); + } + } + if ( w->inherits( "QCheckBox" ) ) { + if ( isColor( IndicatorOff ) || isColor( IndicatorOn ) ) { + QPalette newPal( w->palette() ); + w->setPalettePropagation( QWidget::SamePalette ); + if ( isColor( IndicatorOff ) ) { + newPal.setNormal( *colorGroup( newPal.normal(), IndicatorOff ) ); + newPal.setDisabled( *colorGroup( newPal.normal(), IndicatorOff ) ); + } + if ( isColor( IndicatorOn ) ) + newPal.setActive( *colorGroup( newPal.active(), IndicatorOn ) ); + w->setPalette( newPal ); + } + } + if ( w->inherits( "QRadioButton" ) ) { + if ( isColor( ExIndicatorOff ) || isColor( ExIndicatorOn ) ) { + QPalette newPal( w->palette() ); + w->setPalettePropagation( QWidget::SamePalette ); + if ( isColor( ExIndicatorOff ) ) { + newPal.setNormal( *colorGroup( newPal.normal(), ExIndicatorOff ) ); + newPal.setDisabled( *colorGroup( newPal.normal(), + ExIndicatorOff ) ); + } + if ( isColor( ExIndicatorOn ) ) + newPal.setActive( *colorGroup( newPal.active(), ExIndicatorOn ) ); + w->setPalette( newPal ); + } + } +} + +void OThemeStyle::unPolish( QWidget* w ) +{ + if ( !w->isTopLevel() ) { + if ( w->inherits( "QGroupBox" ) + || w->inherits( "QTabWidget" ) ) { + w->setAutoMask( FALSE ); + return ; + } + if ( w->inherits( "QLabel" ) + || w->inherits( "QSlider" ) + || w->inherits( "QButton" ) + || w->inherits( "QProgressBar" ) + ) { + w->setBackgroundOrigin( QWidget::WidgetOrigin ); + } + } + if ( w->inherits( "QPopupMenu" ) ) + w->unsetPalette(); + if ( w->inherits( "QCheckBox" ) ) + w->unsetPalette(); + if ( w->inherits( "QRadioButton" ) ) + w->unsetPalette(); +} + +void OThemeStyle::drawBaseButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken, bool + rounded, WidgetType type, const QBrush * ) +{ + int offset = borderPixmap( type ) ? 0 : decoWidth( type ); + QPen oldPen = p->pen(); + + // handle reverse bevel here since it uses decowidth differently + if ( gradientHint( type ) == GrReverseBevel ) { + int i; + bitBlt( p->device(), x, y, scalePixmap( w, h, type ), 0, 0, w, h, + Qt::CopyROP, true ); + p->setPen( g.text() ); + for ( i = 0; i < borderWidth( type ); ++i, ++x, ++y, w -= 2, h -= 2 ) + p->drawRect( x, y, w, h ); + } + // same with KDE style borders + else if ( !borderPixmap( type ) && shade() == KDE ) { + qDrawWinButton( p, x, y, w, h, g, sunken ); + if ( isPixmap( type ) ) + p->drawTiledPixmap( x + 4, y + 4, w - 6, h - 6, + *scalePixmap( w - 6, h - 6, + type ) ); + else + p->fillRect( x + 4, y + 4, w - 6, h - offset * 6, + g.brush( QColorGroup::Button ) ); + + } + else { + if ( ( w - offset * 2 ) > 0 && ( h - offset * 2 ) > 0 ) { + if ( isPixmap( type ) ) + if ( rounded ) + p->drawTiledPixmap( x, y, w, h, *scalePixmap( w, h, type ) ); + else + p->drawTiledPixmap( x + offset, y + offset, w - offset * 2, + h - offset * 2, + *scalePixmap( w - offset * 2, h - offset * 2, + type ) ); + else + p->fillRect( x + offset, y + offset, w - offset * 2, h - offset * 2, + g.brush( QColorGroup::Button ) ); + } + if ( borderPixmap( type ) ) + bitBlt( p->device(), x, y, scaleBorder( w, h, type ), 0, 0, w, h, + Qt::CopyROP, false ); + else + drawShade( p, x, y, w, h, g, sunken, rounded, + highlightWidth( type ), borderWidth( type ), shade() ); + } + p->setPen( oldPen ); +} + +void OThemeStyle::drawButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken, + const QBrush *fill ) +{ + drawBaseButton( p, x, y, w, h, g, sunken, roundButton(), sunken ? + PushButtonDown : PushButton, fill ); +} + +void OThemeStyle::drawPushButton( QPushButton* btn, QPainter *p ) +{ + bool sunken = btn->isOn() || btn->isDown(); + int diw = buttonDefaultIndicatorWidth(); + drawBaseButton( p, diw, diw, btn->width() - 2 * diw, btn->height() - 2 * diw, + *colorGroup( btn->colorGroup(), sunken ? PushButtonDown : + PushButton ), sunken, roundButton(), + sunken ? PushButtonDown : PushButton, NULL ); + // TODO if diw, draw fancy default button indicator +} + +void OThemeStyle::drawBaseMask( QPainter *p, int x, int y, int w, int h, + bool round ) +{ + // round edge fills + static const QCOORD btm_left_fill[] = { + 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, + 1, 2, 2, 2, 3, 2, 4, 2, 2, 3, 3, 3, 4, 3, 3, 4, 4, 4 + }; + + static const QCOORD btm_right_fill[] = { + 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 0, 1, 1, 1, 2, 1, 3, 1, 4, + 1, 0, 2, 1, 2, 2, 2, 3, 2, 0, 3, 1, 3, 2, 3, 0, 4, 1, 4 + }; + + static const QCOORD top_left_fill[] = { + 3, 0, 4, 0, 2, 1, 3, 1, 4, 1, 1, 2, 2, 2, 3, 2, 4, 2, 0, 3, + 1, 3, 2, 3, 3, 3, 4, 3, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4 + }; + + static const QCOORD top_right_fill[] = { + 0, 0, 1, 0, 0, 1, 1, 1, 2, 1, 0, 2, 1, 2, 2, 2, 3, 2, 0, + 3, 1, 3, 2, 3, 3, 3, 4, 3, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4 + }; + + QBrush fillBrush( color1, SolidPattern ); + p->setPen( color1 ); + if ( round && w > 19 && h > 19 ) { + int x2 = x + w - 1; + int y2 = y + h - 1; + QPointArray a( QCOORDARRLEN( top_left_fill ), top_left_fill ); + a.translate( 1, 1 ); + p->drawPoints( a ); + a.setPoints( QCOORDARRLEN( btm_left_fill ), btm_left_fill ); + a.translate( 1, h - 6 ); + p->drawPoints( a ); + a.setPoints( QCOORDARRLEN( top_right_fill ), top_right_fill ); + a.translate( w - 6, 1 ); + p->drawPoints( a ); + a.setPoints( QCOORDARRLEN( btm_right_fill ), btm_right_fill ); + a.translate( w - 6, h - 6 ); + p->drawPoints( a ); + + p->fillRect( x + 6, y, w - 12, h, fillBrush ); + p->fillRect( x, y + 6, x + 6, h - 12, fillBrush ); + p->fillRect( x2 - 6, y + 6, x2, h - 12, fillBrush ); + p->drawLine( x + 6, y, x2 - 6, y ); + p->drawLine( x + 6, y2, x2 - 6, y2 ); + p->drawLine( x, y + 6, x, y2 - 6 ); + p->drawLine( x2, y + 6, x2, y2 - 6 ); + + } + else + p->fillRect( x, y, w, h, fillBrush ); +} + +void OThemeStyle::drawButtonMask( QPainter *p, int x, int y, int w, int h ) +{ + drawBaseMask( p, x, y, w, h, roundButton() ); +} + +void OThemeStyle::drawComboButtonMask( QPainter *p, int x, int y, int w, int h ) +{ + drawBaseMask( p, x, y, w, h, roundComboBox() ); +} + +void OThemeStyle::drawBevelButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken, + const QBrush * ) +{ + WidgetType type = sunken ? BevelDown : Bevel; + drawBaseButton( p, x, y, w, h, *colorGroup( g, type ), sunken, false, type ); +} + +#if 0 +void OThemeStyle::drawKToolBarButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken, + bool raised, bool enabled, bool popup, + KToolButtonType type, const QString &btext, + const QPixmap *pixmap, QFont *font, + QWidget * ) +{ + QFont tmp_font( QString::fromLatin1( "Helvetica" ), 10 ); + if ( font ) + tmp_font = *font; + QFontMetrics fm( tmp_font ); + WidgetType widget = sunken ? ToolButtonDown : ToolButton; + + drawBaseButton( p, x, y, w, h, *colorGroup( g, widget ), sunken, false, + widget ); + int dx, dy; + if ( type == Icon ) { // icon only + if ( pixmap ) { + dx = ( w - pixmap->width() ) / 2; + dy = ( h - pixmap->height() ) / 2; + if ( sunken ) { + ++dx; + ++dy; + } + p->drawPixmap( x + dx, y + dy, *pixmap ); + } + } + else if ( type == IconTextRight ) { // icon and text (if any) + if ( pixmap ) { + dx = 4; + dy = ( h - pixmap->height() ) / 2; + if ( sunken ) { + ++dx; + ++dy; + } + p->drawPixmap( x + dx, y + dy, *pixmap ); + } + if ( !btext.isNull() ) { + int tf = AlignVCenter | AlignLeft; + if ( pixmap ) + dx = 4 + pixmap->width() + 2; + else + dx = 4; + dy = 0; + if ( sunken ) { + ++dx; + ++dy; + } + if ( font ) + p->setFont( *font ); + if ( raised ) + p->setPen( KGlobalSettings::toolBarHighlightColor() ); + p->drawText( x + dx, y + dy, w - dx, h, tf, btext ); + } + } + else if ( type == Text ) { // only text, even if there is a icon + if ( !btext.isNull() ) { + int tf = AlignTop | AlignLeft; + if ( !enabled ) + p->setPen( g.dark() ); + dx = ( w - fm.width( btext ) ) / 2; + dy = ( h - fm.lineSpacing() ) / 2; + if ( sunken ) { + ++dx; + ++dy; + } + if ( font ) + p->setFont( *font ); + if ( raised ) + p->setPen( KGlobalSettings::toolBarHighlightColor() ); + p->drawText( x + dx, y + dy, fm.width( btext ), fm.lineSpacing(), tf, btext ); + } + } + else if ( type == IconTextBottom ) { + if ( pixmap ) { + dx = ( w - pixmap->width() ) / 2; + dy = ( h - fm.lineSpacing() - pixmap->height() ) / 2; + if ( sunken ) { + ++dx; + ++dy; + } + p->drawPixmap( x + dx, y + dy, *pixmap ); + } + if ( !btext.isNull() ) { + int tf = AlignBottom | AlignHCenter; + dx = ( w - fm.width( btext ) ) / 2; + dy = h - fm.lineSpacing() - 4; + if ( sunken ) { + ++dx; + ++dy; + } + if ( font ) + p->setFont( *font ); + if ( raised ) + p->setPen( KGlobalSettings::toolBarHighlightColor() ); + p->drawText( x + dx, y + dy, fm.width( btext ), fm.lineSpacing(), tf, btext ); + } + } + if ( popup ) { + if ( enabled ) + qDrawArrow ( p, DownArrow, WindowsStyle, false, w - 5, h - 5, 0, 0, + g, true ); + else + qDrawArrow ( p, DownArrow, WindowsStyle, false, w - 5, h - 5, + 0, 0, g, false ); + } +} + +void OThemeStyle::drawKBarHandle( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, KToolBarPos, QBrush * ) +{ + if ( w > h ) + drawBaseButton( p, x, y, w, h, *colorGroup( g, HBarHandle ), false, false, + HBarHandle ); + else + drawBaseButton( p, x, y, w, h, *colorGroup( g, VBarHandle ), false, false, + VBarHandle ); +} + +void OThemeStyle::drawKToolBar( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, KToolBarPos, QBrush * ) +{ + drawBaseButton( p, x, y, w, h, *colorGroup( g, ToolBar ), false, false, + ToolBar ); +} +#endif + +QRect OThemeStyle::buttonRect( int x, int y, int w, int h ) +{ + int spacing = decoWidth( PushButton ) > decoWidth( PushButtonDown ) ? + decoWidth( PushButton ) : decoWidth( PushButtonDown ); + return ( QRect( x + spacing, y + spacing, w - ( spacing * 2 ), h - ( spacing * 2 ) ) ); +} + +void OThemeStyle::drawComboButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken, bool, + bool, const QBrush * ) +{ + WidgetType widget = sunken ? ComboBoxDown : ComboBox; + drawBaseButton( p, x, y, w, h, *colorGroup( g, widget ), sunken, + roundComboBox(), widget ); + if ( !sunken && isPixmap( ComboDeco ) ) + p->drawPixmap( w - uncached( ComboDeco ) ->width() - + decoWidth( ComboBox ) - 2, + y + ( h - uncached( ComboDeco ) -> + height() ) / 2, *uncached( ComboDeco ) ); + else if ( sunken && isPixmap( ComboDecoDown ) ) + p->drawPixmap( w - uncached( ComboDecoDown ) ->width() - + decoWidth( ComboBoxDown ) - 2, + y + ( h - uncached( ComboDecoDown ) -> + height() ) / 2, *uncached( ComboDecoDown ) ); + else { + qDrawArrow( p, Qt::DownArrow, Qt::MotifStyle, false, w - 15, y + 6, 10, + h - 15, *colorGroup( g, widget ), true ); + qDrawShadeRect( p, w - 14, y + 7 + ( h - 15 ), 10, 3, *colorGroup( g, widget ) ); + } +} + +void OThemeStyle::drawScrollBarControls( QPainter *p, const QScrollBar *sb, + int sliderStart, uint controls, + uint activeControl ) +{ + int sliderMin, sliderMax, sliderLength, buttonDim; + QRect add + , sub, addPage, subPage, slider; + int addX, addY, subX, subY; + bool horizontal = sb->orientation() == QScrollBar::Horizontal; + int len = ( horizontal ) ? sb->width() : sb->height(); + int extent = ( horizontal ) ? sb->height() : sb->width(); + int offset = decoWidth( horizontal ? HScrollGroove : VScrollGroove ); + QColorGroup g = sb->colorGroup(); + + scrollBarMetrics( sb, sliderMin, sliderMax, sliderLength, buttonDim ); + if ( sliderStart > sliderMax ) + sliderStart = sliderMax; + + int sliderEnd = sliderStart + sliderLength; + int sliderWidth = extent - offset * 2; + + // Scary button placement code >:-P Feel free to improve this if you + // want. I get a headache just looking at it... (mosfet) + if ( scrollBarLayout() == SBOpposite ) { + if ( horizontal ) { + subY = addY = ( extent - buttonDim ) / 2; + subX = offset; + addX = len - buttonDim - offset; + } + else { + subX = addX = ( extent - buttonDim ) / 2; + subY = offset; + addY = len - buttonDim - offset; + } + sub.setRect( subX, subY, buttonDim, buttonDim ); + add.setRect( addX, addY, buttonDim, buttonDim ); + if ( horizontal ) { + subPage.setRect( sub.right() + 1, offset, + sliderStart - sub.right() - 1 , sliderWidth ); + addPage.setRect( sliderEnd, offset, addX - sliderEnd, sliderWidth ); + slider.setRect( sliderStart, offset, sliderLength, sliderWidth ); + } + else { + subPage.setRect( offset, sub.bottom() + 1, sliderWidth, + sliderStart - sub.bottom() - 1 ); + addPage.setRect( offset, sliderEnd, sliderWidth, addY - sliderEnd ); + slider.setRect( offset, sliderStart, sliderWidth, sliderLength ); + } + } + else if ( horizontal ) { + subY = addY = ( extent - buttonDim ) / 2; + if ( scrollBarLayout() == SBBottomLeft ) { + subX = offset; + addX = buttonDim + offset; + subPage.setRect( buttonDim * 2, 0, sliderStart - 1, extent ); + addPage.setRect( sliderEnd, 0, len - sliderEnd, extent ); + slider.setRect( sliderStart, 0, sliderLength, extent ); + } + else { + subX = len - buttonDim - buttonDim - offset; + addX = len - buttonDim - offset; + subPage.setRect( offset + 1, offset, sliderStart - 1 , sliderWidth ); + addPage.setRect( sliderEnd, offset, subX - sliderEnd, sliderWidth ); + slider.setRect( sliderStart, offset, sliderLength, sliderWidth ); + } + sub.setRect( subX, subY, buttonDim, buttonDim ); + add.setRect( addX, addY, buttonDim, buttonDim ); + } + else { // BottomLeft and BottomRight vertical bars are the same. + subX = addX = ( extent - buttonDim ) / 2; + subY = len - buttonDim - buttonDim - offset; + addY = len - buttonDim - offset; + subPage.setRect( offset, offset + 1, sliderWidth, + sliderStart - offset - 1 ); + addPage.setRect( offset, sliderEnd, sliderWidth, subY - sliderEnd ); + slider.setRect( offset, sliderStart, sliderWidth, sliderLength ); + sub.setRect( subX, subY, buttonDim, buttonDim ); + add.setRect( addX, addY, buttonDim, buttonDim ); + } + // End of the button placement code + + bool active; + if ( ( controls & QStyle::SubPage ) ) { + drawScrollBarGroove( p, sb, horizontal, subPage, g ); + } + if ( ( controls & QStyle::AddPage ) ) { + drawScrollBarGroove( p, sb, horizontal, addPage, g ); + } + if ( controls & QStyle::AddLine ) { + active = activeControl == QStyle::AddLine; + drawBaseButton( p, add.x(), add.y(), add.width(), add.height(), + *colorGroup( g, active ? ScrollButtonDown : ScrollButton ), + active, false, active ? ScrollButtonDown : ScrollButton ); + drawArrow( p, ( horizontal ) ? RightArrow : DownArrow, active, add.x() + 3, + add.y() + 3, add.width() - 6, add.height() - 6, + *colorGroup( g, active ? ScrollButtonDown : ScrollButton ) ); + } + if ( controls & QStyle::SubLine ) { + active = activeControl == QStyle::SubLine; + p->setPen( g.dark() ); + p->drawRect( sub ); + drawBaseButton( p, sub.x(), sub.y(), sub.width(), sub.height(), + *colorGroup( g, active ? ScrollButtonDown : ScrollButton ), + active, false, active ? ScrollButtonDown : ScrollButton ); + drawArrow( p, ( horizontal ) ? LeftArrow : UpArrow, active, sub.x() + 3, + sub.y() + 3, sub.width() - 6, sub.height() - 6, + *colorGroup( g, active ? ScrollButtonDown : ScrollButton ) ); + } + if ( controls & QStyle::Slider ) { + active = activeControl == QStyle::Slider; + WidgetType widget = horizontal ? + active ? HScrollBarSliderDown : HScrollBarSlider : + active ? VScrollBarSliderDown : VScrollBarSlider; + + drawBaseButton( p, slider.x(), slider.y(), slider.width(), + slider.height(), *colorGroup( g, widget ), active, false, + widget ); + int spaceW = horizontal ? slider.width() - decoWidth( widget ) - 4 : + slider.width(); + int spaceH = horizontal ? slider.height() : + slider.height() - decoWidth( widget ) - 4; +widget = active ? horizontal ? HScrollDecoDown : VScrollDecoDown : + horizontal ? HScrollDeco : VScrollDeco; + if ( isPixmap( widget ) ) { + if ( spaceW >= uncached( widget ) ->width() && + spaceH >= uncached( widget ) ->height() ) { + p->drawPixmap( slider.x() + ( slider.width() - + uncached( widget ) ->width() ) / 2, + slider.y() + ( slider.height() - + uncached( widget ) ->height() ) / 2, + *uncached( widget ) ); + } + } + } +} + +void OThemeStyle::drawScrollBarGroove( QPainter *p, const QScrollBar *sb, + bool horizontal, QRect r, QColorGroup g ) + +{ + WidgetType widget = ( horizontal ) ? HScrollGroove : VScrollGroove; + if ( !isPixmap( widget ) ) { + p->fillRect( r, colorGroup( g, widget ) ->brush( QColorGroup::Background ) ); + } + else { + // If the groove is pixmapped we make a full-sized image (it gets + // cached) then bitBlt it to the appropriate rect. + QPixmap buffer( sb->size() ); + QPainter bPainter( &buffer ); + bPainter.drawTiledPixmap( 0, 0, buffer.width(), buffer.height(), + *scalePixmap( buffer.width(), buffer.height(), + widget ) ); + bitBlt( p->device(), r.x(), r.y(), &buffer, r.x(), r.y(), r.width(), + r.height(), Qt::CopyROP ); + } + // Do the borders and frame + drawShade( p, sb->rect().x(), sb->rect().y(), sb->rect().width(), + sb->rect().height(), *colorGroup( g, widget ), true, false, + highlightWidth( widget ), borderWidth( widget ), shade() ); +} + +void OThemeStyle::scrollBarMetrics( const QScrollBar *sb, int &sliderMin, + int &sliderMax, int &sliderLength, + int &buttonDim ) +{ + bool horizontal = sb->orientation() == QScrollBar::Horizontal; + int offset = decoWidth( horizontal ? HScrollGroove : VScrollGroove ); + int maxlen; + int len = horizontal ? sb->width() : sb->height(); + int extent = horizontal ? sb->height() : sb->width(); + + if ( len > ( extent - offset * 2 - 1 ) * 2 + offset * 2 ) + buttonDim = extent - offset * 2; + else + buttonDim = ( len - offset * 2 ) / 2 - 1; + maxlen = len - offset * 2 - buttonDim * 2 - 1; + + switch ( scrollBarLayout() ) { + case SBBottomLeft: + sliderMin = ( horizontal ) ? buttonDim * 2 + offset + 1 : offset + 1; + break; + case SBBottomRight: + sliderMin = offset + 1; + break; + case SBOpposite: + default: + sliderMin = offset + buttonDim; + break; + } + if ( sb->maxValue() == sb->minValue() ) + sliderLength = maxlen; + else + sliderLength = ( sb->pageStep() * maxlen ) / ( sb->maxValue() - + sb->minValue() + sb->pageStep() ); + if ( sliderLength < 12 || ( sb->maxValue() - sb->minValue() ) > INT_MAX / 2 ) + sliderLength = 12; + if ( sliderLength > maxlen ) + sliderLength = maxlen; + sliderMax = sliderMin + maxlen - sliderLength; +} + +QStyle::ScrollControl OThemeStyle::scrollBarPointOver( const QScrollBar *sb, + int sliderStart, + const QPoint &p ) +{ + if ( !sb->rect().contains( p ) ) + return ( QStyle::NoScroll ); + int sliderMin, sliderMax, sliderLength, buttonDim; + int pos = ( sb->orientation() == QScrollBar::Horizontal ) ? p.x() : p.y(); + scrollBarMetrics( sb, sliderMin, sliderMax, sliderLength, buttonDim ); + + if ( scrollBarLayout() == SBOpposite ) { + if ( pos < sliderMin ) + return QStyle::SubLine; + if ( pos < sliderStart ) + return SubPage; + if ( pos < sliderStart + sliderLength ) + return QStyle::Slider; + if ( pos < sliderMax + sliderLength ) + return QStyle::AddPage; + return QStyle::AddLine; + } + if ( scrollBarLayout() == SBBottomLeft && sb->orientation() == + QScrollBar::Horizontal ) { + if ( pos <= buttonDim ) + return ( QStyle::SubLine ); + else if ( pos <= buttonDim * 2 ) + return ( QStyle::AddLine ); + else if ( pos < sliderStart ) + return ( QStyle::SubPage ); + else if ( pos < sliderStart + sliderLength ) + return ( QStyle::Slider ); + return ( AddPage ); + } + else { + if ( pos < sliderStart ) + return QStyle::SubPage; + if ( pos < sliderStart + sliderLength ) + return QStyle::Slider; + if ( pos < sliderMax + sliderLength ) + return QStyle::AddPage; + if ( pos < sliderMax + sliderLength + buttonDim ) + return QStyle::SubLine; + return QStyle::AddLine; + } +} + +QSize OThemeStyle::exclusiveIndicatorSize() const +{ + if ( isPixmap( ExIndicatorOn ) ) + return ( uncached( ExIndicatorOn ) ->size() ); + else + return ( QWindowsStyle::exclusiveIndicatorSize() ); +} + +QSize OThemeStyle::indicatorSize() const +{ + if ( isPixmap( IndicatorOn ) ) + return ( uncached( IndicatorOn ) ->size() ); + else + return ( QWindowsStyle::indicatorSize() ); +} + +void OThemeStyle::drawExclusiveIndicator( QPainter* p, int x, int y, int w, + int h, const QColorGroup &g, bool on, + bool down, bool enabled ) +{ + if ( isPixmap( ( on || down ) ? ExIndicatorOn : ExIndicatorOff ) ) { + p->drawPixmap( x, y, *uncached( ( on || down ) ? ExIndicatorOn : + ExIndicatorOff ) ); + } + else { + QWindowsStyle::drawExclusiveIndicator( p, x, y, w, h, + *colorGroup( g, ExIndicatorOn ), + on, down, enabled ); + } + +} + +void OThemeStyle::drawIndicator( QPainter* p, int x, int y, int w, int h, + const QColorGroup &g, int state, bool down, + bool enabled ) +{ + if ( isPixmap( ( down || state != QButton::Off ) ? + IndicatorOn : IndicatorOff ) ) { + p->drawPixmap( x, y, *uncached( ( down || state != QButton::Off ) ? + IndicatorOn : IndicatorOff ) ); + } + else { + QWindowsStyle::drawIndicator( p, x, y, w, h, + *colorGroup( g, IndicatorOn ), state, + down, enabled ); + } +} + +void OThemeStyle::drawExclusiveIndicatorMask( QPainter *p, int x, int y, int w, + int h, bool on ) +{ + if ( isPixmap( ( on ) ? ExIndicatorOn : ExIndicatorOff ) ) { + const QBitmap * mask = uncached( ( on ) ? ExIndicatorOn : ExIndicatorOff ) -> + mask(); + if ( mask ) { + p->drawPixmap( x, y, *mask ); + } + else + p->fillRect( x, y, w, h, QBrush( color1, SolidPattern ) ); + } + else + QWindowsStyle::drawExclusiveIndicatorMask( p, x, y, w, h, on ); +} + +void OThemeStyle::drawIndicatorMask( QPainter *p, int x, int y, int w, int h, + int state ) +{ + if ( isPixmap( ( state != QButton::Off ) ? IndicatorOn : IndicatorOff ) ) { + const QBitmap * mask = uncached( ( state != QButton::Off ) ? IndicatorOn : + IndicatorOff ) ->mask(); + if ( mask ) + p->drawPixmap( x, y, *mask ); + else + p->fillRect( x, y, w, h, QBrush( color1, SolidPattern ) ); + } + else + QWindowsStyle::drawIndicatorMask( p, x, y, w, h, state ); +} + +void OThemeStyle::drawSliderGroove( QPainter *p, int x, int y, int w, int h, + const QColorGroup& g, QCOORD c, + Orientation orient ) +{ + if ( roundSlider() ) + QWindowsStyle::drawSliderGroove( p, x, y, w, h, + *colorGroup( g, SliderGroove ), + c, orient ); + else + drawBaseButton( p, x, y, w, h, *colorGroup( g, SliderGroove ), true, + false, SliderGroove ); +} + +void OThemeStyle::drawSlider( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, Orientation orient, + bool tickAbove, bool tickBelow ) +{ + if ( isPixmap( Slider ) ) { + if ( orient == Qt::Horizontal ) + p->drawPixmap( x, y + ( h - uncached( Slider ) ->height() ) / 2, + *uncached( Slider ) ); + else + p->drawPixmap( x + ( w - uncached( Slider ) ->width() ) / 2, + y, *uncached( Slider ) ); + } + else { + QWindowsStyle::drawSlider( p, x, y, w, h, *colorGroup( g, Slider ), + orient, tickAbove, tickBelow ); + } +} + +void OThemeStyle::drawSliderMask( QPainter *p, int x, int y, int w, int h, + Orientation orient, bool tickAbove, + bool tickBelow ) +{ + // This is odd. If we fill in the entire region it still masks the slider + // properly. I have no idea, this used to be different in Qt betas... + if ( isPixmap( Slider ) ) + p->fillRect( x, y, w, h, QBrush( color1, SolidPattern ) ); + else + QWindowsStyle::drawSliderMask( p, x, y, w, h, orient, tickAbove, + tickBelow ); +} + +int OThemeStyle::defaultFrameWidth() const +{ + return ( frameWidth() ); +} + +void OThemeStyle::getButtonShift( int &x, int &y ) +{ + x = buttonXShift(); + y = buttonYShift(); +} + +int OThemeStyle::sliderLength() const +{ + return ( sliderButtonLength() ); +} + +void OThemeStyle::drawArrow( QPainter *p, Qt::ArrowType type, bool down, int x, + int y, int w, int h, const QColorGroup &g, + bool enabled, const QBrush * ) +{ + // Handles pixmapped arrows. A little inefficent because you can specify + // some as pixmaps and some as default types. + WidgetType widget; + switch ( type ) { + case UpArrow: +widget = enabled ? down ? SunkenArrowUp : ArrowUp : DisArrowUp; + break; + case DownArrow: +widget = enabled ? down ? SunkenArrowDown : ArrowDown : DisArrowDown; + break; + case LeftArrow: +widget = enabled ? down ? SunkenArrowLeft : ArrowLeft : DisArrowLeft; + break; + case RightArrow: + default: +widget = enabled ? down ? SunkenArrowRight : ArrowRight : DisArrowRight; + break; + } + if ( isPixmap( widget ) ) { + p->drawPixmap( x + ( w - uncached( widget ) ->width() ) / 2, + y + ( h - uncached( widget ) ->height() ) / 2, + *uncached( widget ) ); + return ; + } + const QColorGroup *cg = colorGroup( g, widget ); + // Standard arrow types + if ( arrowType() == MotifArrow ) + qDrawArrow( p, type, Qt::MotifStyle, down, x, y, w, h, *cg, enabled ); + else if ( arrowType() == SmallArrow ) { + QColorGroup tmp( *cg ); + tmp.setBrush( QColorGroup::Button, QBrush( NoBrush ) ); + QWindowsStyle::drawArrow( p, type, false, x, y, w, h, + tmp, true ); + } + else { + QPointArray a; + int x2 = x + w - 1, y2 = y + h - 1; + switch ( type ) { + case Qt::UpArrow: + a.setPoints( 4, x, y2, x2, y2, x + w / 2, y, x, y2 ); + break; + case Qt::DownArrow: + a.setPoints( 4, x, y, x2, y, x + w / 2, y2, x, y ); + break; + case Qt::LeftArrow: + a.setPoints( 4, x2, y, x2, y2, x, y + h / 2, x2, y ); + break; + default: + a.setPoints( 4, x, y, x, y2, x2, y + h / 2, x, y ); + break; + } + QBrush oldBrush = p->brush(); + QPen oldPen = p->pen(); + p->setBrush( cg->brush( QColorGroup::Shadow ) ); + p->setPen( cg->shadow() ); + p->drawPolygon( a ); + p->setBrush( oldBrush ); + p->setPen( oldPen ); + } +} + +/* This is where we draw the borders and highlights. The new round button + * code is a pain in the arse. We don't want to be calculating arcs so + * use a whole lotta QPointArray's ;-) The code is made a lot more complex + * because you can have variable width border and highlights... + * I may want to cache this if round buttons are used, but am concerned + * about excessive cache misses. This is a memory/speed tradeoff that I + * have to test. + */ +void OThemeStyle::drawShade( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken, bool rounded, + int hWidth, int bWidth, ShadeStyle style ) +{ + int i, sc, bc, x2, y2; + QPen highPen, lowPen; + + if ( style == Motif ) { + highPen.setColor( sunken ? g.dark() : g.light() ); + lowPen.setColor( sunken ? g.light() : g.dark() ); + } + else { + highPen.setColor( sunken ? g.shadow() : g.light() ); + lowPen.setColor( sunken ? g.light() : g.shadow() ); + } + + // Advanced round buttons + if ( rounded && w > 19 && h > 19 ) { + x2 = x + w - 1, y2 = y + h - 1; + QPointArray bPntArray, hPntArray, lPntArray; + QPointArray bLineArray, hLineArray, lLineArray; + // borders + for ( i = 0, bc = 0; i < bWidth; ++i ) { + bPntArray.putPoints( bc, 24, x + 4, y + 1, x + 5, y + 1, x + 3, y + 2, x + 2, y + 3, + x + 1, y + 4, x + 1, y + 5, x + 1, y2 - 5, x + 1, y2 - 4, x + 2, y2 - 3, + x2 - 5, y + 1, x2 - 4, y + 1, x2 - 3, y + 2, x2 - 5, y2 - 1, + x2 - 4, y2 - 1, x2 - 3, y2 - 2, x2 - 2, y2 - 3, x2 - 1, y2 - 5, + x2 - 1, y2 - 4, x + 3, y2 - 2, x + 4, y2 - 1, x + 5, y2 - 1, + x2 - 2, y + 3, x2 - 1, y + 4, x2 - 1, y + 5 ); + bc += 24; + // ellispe edges don't match exactly, so fill in blanks + if ( i < bWidth - 1 || hWidth != 0 ) { + bPntArray.putPoints( bc, 20, x + 6, y + 1, x + 4, y + 2, x + 3, y + 3, + x + 2, y + 4, x + 1, y + 6, x2 - 6, y + 1, x2 - 4, y + 2, + x2 - 3, y + 3, x + 2, y2 - 4, x + 1, y2 - 6, x2 - 6, y2 - 1, + x2 - 4, y2 - 2, x2 - 3, y2 - 3, x2 - 2, y2 - 4, x2 - 1, y2 - 6, + x + 6, y2 - 1, x + 4, y2 - 2, x + 3, y2 - 3, x2 - 1, y + 6, + x2 - 2, y + 4 ); + bc += 20; + } + bLineArray.putPoints( i * 8, 8, x + 6, y, x2 - 6, y, x, y + 6, x, y2 - 6, + x + 6, y2, x2 - 6, y2, x2, y + 6, x2, y2 - 6 ); + ++x, ++y; + --x2, --y2; + } + // highlights + for ( i = 0, sc = 0; i < hWidth; ++i ) { + hPntArray.putPoints( sc, 12, x + 4, y + 1, x + 5, y + 1, // top left + x + 3, y + 2, x + 2, y + 3, x + 1, y + 4, x + 1, y + 5, + x + 1, y2 - 5, x + 1, y2 - 4, x + 2, y2 - 3, // half corners + x2 - 5, y + 1, x2 - 4, y + 1, x2 - 3, y + 2 ); + lPntArray.putPoints( sc, 12, x2 - 5, y2 - 1, x2 - 4, y2 - 1, // btm right + x2 - 3, y2 - 2, x2 - 2, y2 - 3, x2 - 1, y2 - 5, x2 - 1, y2 - 4, + x + 3, y2 - 2, x + 4, y2 - 1, x + 5, y2 - 1, //half corners + x2 - 2, y + 3, x2 - 1, y + 4, x2 - 1, y + 5 ); + sc += 12; + if ( i < hWidth - 1 ) { + hPntArray.putPoints( sc, 10, x + 6, y + 1, x + 4, y + 2, // top left + x + 3, y + 3, x + 2, y + 4, x + 1, y + 6, + x2 - 6, y + 1, x2 - 4, y + 2, // half corners + x2 - 3, y + 3, x + 2, y2 - 4, x + 1, y2 - 6 ); + lPntArray.putPoints( sc, 10, x2 - 6, y2 - 1, x2 - 4, y2 - 2, // btm right + x2 - 3, y2 - 3, x2 - 2, y2 - 4, x2 - 1, y2 - 6, + x + 6, y2 - 1, x + 4, y2 - 2, // half corners + x + 3, y2 - 3, x2 - 1, y + 6, x2 - 2, y + 4 ); + sc += 10; + } + hLineArray.putPoints( i * 4, 4, x + 6, y, x2 - 6, y, x, y + 6, x, y2 - 6 ); + lLineArray.putPoints( i * 4, 4, x + 6, y2, x2 - 6, y2, x2, y + 6, x2, y2 - 6 ); + ++x, ++y; + --x2, --y2; + } + p->setPen( Qt::black ); + p->drawPoints( bPntArray ); + p->drawLineSegments( bLineArray ); + p->setPen( highPen ); + p->drawPoints( hPntArray ); + p->drawLineSegments( hLineArray ); + p->setPen( lowPen ); + p->drawPoints( lPntArray ); + p->drawLineSegments( lLineArray ); + } + // Rectangular buttons + else { + QPointArray highShade( hWidth * 4 ); + QPointArray lowShade( hWidth * 4 ); + + p->setPen( g.shadow() ); + for ( i = 0; i < bWidth && w > 2 && h > 2; ++i, ++x, ++y, w -= 2, h -= 2 ) + p->drawRect( x, y , w, h ); + + if ( !hWidth ) + return ; + + x2 = x + w - 1, y2 = y + h - 1; + for ( i = 0; i < hWidth; ++i, ++x, ++y, --x2, --y2 ) { + highShade.putPoints( i * 4, 4, x, y, x2, y, x, y, x, y2 ); + lowShade.putPoints( i * 4, 4, x, y2, x2, y2, x2, y, x2, y2 ); + } + if ( style == Windows && hWidth > 1 ) { + p->setPen( highPen ); + p->drawLineSegments( highShade, 0, 2 ); + p->setPen( lowPen ); + p->drawLineSegments( lowShade, 0, 2 ); + + p->setPen( ( sunken ) ? g.dark() : g.mid() ); + p->drawLineSegments( highShade, 4 ); + p->setPen( ( sunken ) ? g.mid() : g.dark() ); + p->drawLineSegments( lowShade, 4 ); + } + else { + p->setPen( ( sunken ) ? g.dark() : g.light() ); + p->drawLineSegments( highShade ); + p->setPen( ( sunken ) ? g.light() : g.dark() ); + p->drawLineSegments( lowShade ); + } + } +} + +void OThemeStyle::drawPushButtonLabel( QPushButton *btn, QPainter *p ) +{ + WidgetType widget = btn->isDown() || btn->isOn() ? PushButtonDown : + PushButton; + const QColorGroup *cg = colorGroup( btn->colorGroup(), widget ); + int x, y, w, h; + + QRect r = btn->rect(); + r.rect( &x, &y, &w, &h ); + x += decoWidth( widget ); + y += decoWidth( widget ); + w -= decoWidth( widget ) * 2; + h -= decoWidth( widget ) * 2; + bool act = btn->isOn() || btn->isDown(); + + // If this is a button with an associated popup menu, draw an arrow first + if ( btn->popup() ) { + int dx = menuButtonIndicatorWidth( btn->height() ); + + QColorGroup g( btn->colorGroup() ); + int xx = x + w - dx - 4; + int yy = y - 3; + int hh = h + 6; + + if ( !act ) { + p->setPen( g.light() ); + p->drawLine( xx, yy + 3, xx, yy + hh - 4 ); + } + else { + p->setPen( g.button() ); + p->drawLine( xx, yy + 4, xx, yy + hh - 4 ); + } + drawArrow( p, DownArrow, FALSE, + x + w - dx - 2, y + 2, dx, h - 4, + btn->colorGroup(), + btn->isEnabled() ); + w -= dx; + } + + // Next, draw iconset, if any + if ( btn->iconSet() && !btn->iconSet() ->isNull() ) { + QIconSet::Mode mode = btn->isEnabled() + ? QIconSet::Normal : QIconSet::Disabled; + if ( mode == QIconSet::Normal && btn->hasFocus() ) + mode = QIconSet::Active; + QPixmap pixmap = btn->iconSet() ->pixmap( QIconSet::Small, mode ); + int pixw = pixmap.width(); + int pixh = pixmap.height(); + + p->drawPixmap( x + 6, y + h / 2 - pixh / 2, pixmap ); + x += pixw + 8; + w -= pixw + 8; + } + + if ( widget == PushButtonDown ) { + drawItem( p, x + buttonXShift(), y + buttonYShift(), + w, h, AlignCenter | ShowPrefix, *cg, btn->isEnabled(), + btn->pixmap(), btn->text(), -1, &cg->buttonText() ); + } + else { + drawItem( p, x, y, w, h, AlignCenter | ShowPrefix, *cg, + btn->isEnabled(), btn->pixmap(), btn->text(), -1, + &cg->buttonText() ); + } +} + +int OThemeStyle::splitterWidth() const +{ + return ( splitWidth() ); +} + +void OThemeStyle::drawSplitter( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, Orientation ) +{ + drawBaseButton( p, x, y, w, h, *colorGroup( g, Splitter ), false, false, + Splitter ); +} + +void OThemeStyle::drawCheckMark( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool act, bool dis ) +{ + if ( isPixmap( CheckMark ) ) { + if ( !dis ) + p->drawPixmap( x + ( w - uncached( CheckMark ) ->width() ) / 2, + y + ( h - uncached( CheckMark ) ->height() ) / 2, + *uncached( CheckMark ) ); + } + else + QWindowsStyle::drawCheckMark( p, x, y, w, h, *colorGroup( g, CheckMark ), + act, dis ); +} + +int OThemeStyle::popupMenuItemHeight( bool /*checkable*/, QMenuItem *mi, + const QFontMetrics &fm ) +{ + int h2, h = 0; + int offset = QMAX( decoWidth( MenuItemDown ), decoWidth( MenuItem ) ) + 4; + + if ( mi->isSeparator() ) + return ( 2 ); + if ( mi->isChecked() ) + h = isPixmap( CheckMark ) ? uncached( CheckMark ) ->height() + offset : + offset + 16; + if ( mi->pixmap() ) { + h2 = mi->pixmap() ->height() + offset; + h = h2 > h ? h2 : h; + } + if ( mi->iconSet() ) { + h2 = mi->iconSet() -> + pixmap( QIconSet::Small, QIconSet::Normal ).height() + offset; + h = h2 > h ? h2 : h; + } + h2 = fm.height() + offset; + h = h2 > h ? h2 : h; + return ( h ); +} + +void OThemeStyle::drawPopupMenuItem( QPainter* p, bool checkable, int maxpmw, + int tab, QMenuItem* mi, + const QPalette& pal, bool act, + bool enabled, int x, int y, int w, int h ) +{ + // I changed the following method to be based from Qt's instead of my own + // wacky code. Works much better now :P (mosfet) + static const int motifItemFrame = 2; // menu item frame width + static const int motifItemHMargin = 5; // menu item hor text margin + static const int motifItemVMargin = 4; // menu item ver text margin + + static const int motifArrowHMargin = 6; // arrow horizontal margin + static const int windowsRightBorder = 12; // right border on windowsstatic const int windowsCheckMarkWidth = 12; // checkmarks width on windows + bool dis = !enabled; + const QColorGroup &g = dis ? *colorGroup( pal.normal(), MenuItem ) : + *colorGroup( pal.normal(), MenuItemDown ); + + QColorGroup itemg = dis ? *colorGroup( pal.disabled(), MenuItem ) + : act ? *colorGroup( pal.active(), MenuItemDown ) + : *colorGroup( pal.normal(), MenuItem ); + + maxpmw = QMAX( maxpmw, 20 ); + int checkcol = maxpmw; + + if ( mi && mi->isSeparator() ) { + p->setPen( g.dark() ); + p->drawLine( x, y, x + w, y ); + p->setPen( g.light() ); + p->drawLine( x, y + 1, x + w, y + 1 ); + return ; + } + if ( act ) { + drawBaseButton( p, x, y, w, h, g, true, false, MenuItemDown ); + } + else { + drawShade( p, x, y, w, h, *colorGroup( g, MenuItem ), false, false, + highlightWidth( MenuItem ), borderWidth( MenuItem ), + shade() ); + int dw = decoWidth( MenuItem ); + if ( !isPixmap( MenuItem ) ) + p->fillRect( x + dw, y + dw, w - dw * 2, h - dw * 2, + colorGroup( g, MenuItem ) -> + brush( QColorGroup::Background ) ); + else { + // process inactive item pixmaps as one large item + p->drawTiledPixmap( x + dw, y + dw, w - dw * 2, h - dw * 2, *scalePixmap + // (w, p->window().height(), MenuItem), + ( w, p->clipRegion().boundingRect().height(), MenuItem ), + x, y ); + } + + if ( checkable && mi && mi->isChecked() ) { + // draw 'pressed' border around checkable items + // This is extremely important for items that have an iconset + // because the checkmark isn't drawn in that case + // An alternative would be superimposing the checkmark over + // the iconset instead or not drawing the iconset at all. + int mw = checkcol + motifItemFrame; + drawShade( p, x, y, mw, h, g, true, false, + highlightWidth( MenuItemDown ), + borderWidth( MenuItemDown ), shade() ); + } + } + if ( !mi ) + return ; + if ( mi->iconSet() ) { + QIconSet::Mode mode = dis ? QIconSet::Disabled : QIconSet::Normal; + if ( act && !dis ) + mode = QIconSet::Active; + QPixmap pixmap = mi->iconSet() ->pixmap( QIconSet::Small, mode ); + int pixw = pixmap.width(); + int pixh = pixmap.height(); + QRect cr( x, y, checkcol, h ); + QRect pmr( 0, 0, pixw, pixh ); + pmr.moveCenter( cr.center() ); + p->setPen( itemg.text() ); + p->drawPixmap( pmr.topLeft(), pixmap ); + + } + else if ( checkable ) { + int mw = checkcol + motifItemFrame; + int mh = h - 2 * motifItemFrame; + if ( mi->isChecked() ) { + drawCheckMark( p, x + motifItemFrame, + y + motifItemFrame, mw, mh, itemg, act, dis ); + } + } + + p->setPen( colorGroup( g, act ? MenuItemDown : MenuItem ) ->text() ); + + QColor discol; + if ( dis ) { + discol = itemg.text(); + p->setPen( discol ); + } + + int xm = motifItemFrame + checkcol + motifItemHMargin; + + QString s = mi->text(); + if ( !s.isNull() ) { + int t = s.find( '\t' ); + int m = motifItemVMargin; + const int text_flags = AlignVCenter | ShowPrefix | DontClip | SingleLine; + if ( t >= 0 ) { + if ( dis && !act ) { + p->setPen( g.light() ); + p->drawText( x + w - tab - windowsRightBorder - motifItemHMargin - motifItemFrame + 1, + y + m + 1, tab, h - 2 * m, text_flags, s.mid( t + 1 ) ); + p->setPen( discol ); + } + p->drawText( x + w - tab - windowsRightBorder - motifItemHMargin - motifItemFrame, + y + m, tab, h - 2 * m, text_flags, s.mid( t + 1 ) ); + } + if ( dis && !act ) { + p->setPen( g.light() ); + p->drawText( x + xm + 1, y + m + 1, w - xm + 1, h - 2 * m, text_flags, s, t ); + p->setPen( discol ); + } + p->drawText( x + xm, y + m, w - xm - tab + 1, h - 2 * m, text_flags, s, t ); + } + else if ( mi->pixmap() ) { + QPixmap * pixmap = mi->pixmap(); + if ( pixmap->depth() == 1 ) + p->setBackgroundMode( OpaqueMode ); + p->drawPixmap( x + xm, y + motifItemFrame, *pixmap ); + if ( pixmap->depth() == 1 ) + p->setBackgroundMode( TransparentMode ); + } + if ( mi->popup() ) { + int dim = ( h - 2 * motifItemFrame ) / 2; + if ( act ) { + if ( !dis ) + discol = colorGroup( g, MenuItemDown ) ->text(); + //discol = white; + QColorGroup g2( discol, g.highlight(), + white, white, + dis ? discol : white, + discol, white ); + drawArrow( p, RightArrow, true, + x + w - motifArrowHMargin - motifItemFrame - dim, y + h / 2 - dim / 2, + dim, dim, g2, TRUE ); + } + else { + drawArrow( p, RightArrow, + false, + x + w - motifArrowHMargin - motifItemFrame - dim, y + h / 2 - dim / 2, + dim, dim, g, mi->isEnabled() ); + } + } +} + +void OThemeStyle::drawFocusRect( QPainter *p, const QRect &r, + const QColorGroup &g, const QColor *c, + bool atBorder ) +{ + p->setPen( g.dark() ); + if ( !is3DFocus() ) + QWindowsStyle::drawFocusRect( p, r, g, c, atBorder ); + else { + int i = focusOffset(); + p->drawLine( r.x() + i, r.y() + 1 + i, r.x() + i, r.bottom() - 1 - i ); + p->drawLine( r.x() + 1 + i, r.y() + i, r.right() - 1 - i, r.y() + i ); + p->setPen( g.light() ); + p->drawLine( r.right() - i, r.y() + 1 + i, r.right() - i, r.bottom() - 1 - i ); + p->drawLine( r.x() + 1 + i, r.bottom() - i, r.right() - 1 - i, r.bottom() - i ); + } +} + +#if 0 +void OThemeStyle::drawKMenuBar( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool, QBrush * ) +{ + drawBaseButton( p, x, y, w, h, *colorGroup( g, MenuBar ), false, false, + MenuBar ); +} + +void OThemeStyle::drawKMenuItem( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool active, + QMenuItem *mi, QBrush * ) +{ + const QColorGroup * cg = colorGroup( g, active ? MenuBarItem : MenuBar ); + QColor btext = cg->buttonText(); + if ( active ) + drawBaseButton( p, x, y, w, h, *cg, false, false, MenuBarItem ); + //qDrawShadePanel(p, x, y, w, h, *cg, false, 1); + + drawItem( p, x, y, w, h, AlignCenter | ShowPrefix | DontClip | SingleLine, + *cg, mi->isEnabled(), mi->pixmap(), mi->text(), + -1, &btext ); + ; +} + +void OThemeStyle::drawKProgressBlock( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, QBrush * ) +{ + drawBaseButton( p, x, y, w, h, *colorGroup( g, ProgressBar ), false, false, + ProgressBar ); +} + +void OThemeStyle::getKProgressBackground( const QColorGroup &g, QBrush &bg ) +{ + const QColorGroup * cg = colorGroup( g, ProgressBg ); + bg.setColor( cg->color( QColorGroup::Background ) ); + if ( isPixmap( ProgressBg ) ) + bg.setPixmap( *uncached( ProgressBg ) ); +} +#endif + +void OThemeStyle::tabbarMetrics( const QTabBar* t, int& hframe, int& vframe, int& overlap ) +{ + QCommonStyle::tabbarMetrics( t, hframe, vframe, overlap ); +} + +void OThemeStyle::drawTab( QPainter* p, const QTabBar* tb, QTab* t , + bool selected ) +{ + WidgetType widget = selected ? ActiveTab : InactiveTab; + const QColorGroup *cg = colorGroup( tb->colorGroup(), widget ); + int i; + int x = t->r.x(), y = t->r.y(); + int x2 = t->r.right(), y2 = t->r.bottom(); + int bWidth = borderWidth( widget ); + int hWidth = highlightWidth( widget ); + if ( tb->shape() == QTabBar::RoundedAbove ) { + if ( !selected ) { + p->fillRect( x, y, x2 - x + 1, 2, + tb->palette().normal().brush( QColorGroup::Background ) ); + y += 2; + } + p->setPen( cg->text() ); + i = 0; + if ( i < bWidth ) { + p->drawLine( x, y + 1, x, y2 ); + p->drawLine( x2, y + 1, x2, y2 ); + p->drawLine( x + 1, y, x2 - 1, y ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y2, x2, y2 ); + --y2; + } + ++i, ++x, ++y, --x2; + } + for ( ; i < bWidth; ++i, ++x, ++y, --x2 ) { + p->drawLine( x, y, x, y2 ); + p->drawLine( x2, y, x2, y2 ); + p->drawLine( x, y, x2, y ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y2, x2, y2 ); + --y2; + } + } + i = 0; + if ( i < hWidth && bWidth == 0 ) { + p->setPen( cg->light() ); + p->drawLine( x, y + 1, x, y2 ); + p->drawLine( x + 1, y, x2 - 1, y ); + p->setPen( cg->dark() ); + p->drawLine( x2, y + 1, x2, y2 ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y2, x2, y2 ); + --y2; + } + ++i, ++x, ++y, --x2; + } + for ( ; i < hWidth; ++i, ++x, ++y, --x2 ) { + p->setPen( cg->light() ); + p->drawLine( x, y, x, y2 ); + p->drawLine( x, y, x2, y ); + p->setPen( cg->dark() ); + p->drawLine( x2, y + 1, x2, y2 ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y2, x2, y2 ); + --y2; + } + } + if ( isPixmap( widget ) ) + p->drawTiledPixmap( x, y, x2 - x + 1, y2 - y + 1, + *scalePixmap( x2 - x + 1, y2 - y + 1, widget ) ); + else + p->fillRect( x, y, x2 - x + 1, y2 - y + 1, cg->background() ); + } + else if ( tb->shape() == QTabBar::RoundedBelow ) { + if ( !selected ) { + p->fillRect( x, y2 - 2, x2 - x + 1, 2, + tb->palette().normal().brush( QColorGroup::Background ) ); + y2 -= 2; + } + p->setPen( cg->text() ); + i = 0; + if ( i < bWidth ) { + p->drawLine( x, y, x, y2 - 1 ); + p->drawLine( x2, y, x2, y2 - 1 ); + p->drawLine( x + 1, y2, x2 - 1, y2 ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y, x2, y ); + ++y; + } + } + for ( ; i < bWidth; ++i, ++x, --x2, --y2 ) { + p->drawLine( x, y, x, y2 ); + p->drawLine( x2, y, x2, y2 ); + p->drawLine( x, y2, x2, y2 ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y, x2, y ); + ++y; + } + } + i = 0; + if ( i < hWidth && bWidth == 0 ) { + p->setPen( cg->dark() ); + p->drawLine( x + 1, y2, x2 - 1, y2 ); + p->drawLine( x2, y, x2, y2 - 1 ); + p->setPen( cg->light() ); + p->drawLine( x, y, x, y2 - 1 ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y, x2, y ); + ++y; + } + ++i, ++x, --x2, --y2; + } + for ( ; i < hWidth; ++i, ++x, --x2, --y2 ) { + p->setPen( cg->dark() ); + p->drawLine( x, y2, x2, y2 ); + p->drawLine( x2, y, x2, y2 ); + p->setPen( cg->light() ); + p->drawLine( x, y, x, y2 ); + if ( selected ? activeTabLine() : inactiveTabLine() ) { + p->drawLine( x, y, x2, y ); + ++y; + } + } + if ( isPixmap( widget ) ) + p->drawTiledPixmap( x, y, x2 - x + 1, y2 - y + 1, + *scalePixmap( x2 - x + 1, y2 - y + 1, widget ) ); + else + p->fillRect( x, y, x2 - x + 1, y2 - y + 1, cg->background() ); + } + else + QCommonStyle::drawTab( p, tb, t, selected ); +} + +void OThemeStyle::drawTabMask( QPainter* p, const QTabBar* tb, QTab* t, + bool selected ) +{ + QRect r( t->r ); + + if ( tb->shape() == QTabBar::RoundedAbove ) { + if ( !selected ) + r.setTop( r.top() + 2 ); + p->drawLine( r.left() + 1, r.top(), r.right() - 1, r.top() ); + QBrush b( color1, SolidPattern ); + p->fillRect( r.left(), r.top() + 1, r.width(), r.height() - 1, b ); + } + else if ( tb->shape() == QTabBar::RoundedBelow ) { + if ( !selected ) + r.setBottom( r.bottom() - 2 ); + p->drawLine( r.left() + 1, r.bottom(), r.right() - 1, r.bottom() ); + QBrush b( color1, SolidPattern ); + p->fillRect( r.left(), r.top(), r.width(), r.height() - 1, b ); + } + else + QCommonStyle::drawTabMask( p, tb, t, selected ); + +} + + +//#include "kthemestyle.moc" + diff --git a/noncore/styles/theme/othemestyle.h b/noncore/styles/theme/othemestyle.h new file mode 100644 index 0000000..02bec78 --- a/dev/null +++ b/noncore/styles/theme/othemestyle.h @@ -0,0 +1,365 @@ +/* This file is part of the KDE libraries + Copyright (C) 1999 Daniel M. Duley <mosfet@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 version 2 as published by the Free Software Foundation. + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#ifndef __KTHEMESTYLE_H +#define __KTHEMESTYLE_H + +#include "othemebase.h" +#include <qwindowdefs.h> +#include <qobject.h> +#include <qbutton.h> +#include <qpushbutton.h> +#include <qscrollbar.h> +#include <qstring.h> + + +/** + * KDE themed styles. + * + * It provides methods for + * drawing most widgets with user-specified borders, highlights, pixmaps, + * etc. It also handles various other settings such as scrollbar types, + * rounded buttons, and shading types. For a full list of parameters this + * class handles refer to the KDE theme configuration documentation. + * + */ + +class OThemeStyle: public OThemeBase +{ + Q_OBJECT +public: + /** + * Construct a new @ref OThemeStyle object. + * + * @param configFile A KConfig file to use as the theme configuration. + * Defaults to ~/.kderc. + */ + OThemeStyle( const QString &configFile = QString::null ); + ~OThemeStyle(); + virtual void polish( QWidget* ); + virtual void unPolish( QWidget* ); + /** + * By default this just sets the background brushes to the pixmapped + * background. + */ + virtual void polish( QApplication *app ); + virtual void unPolish( QApplication* ); + + /// @internal + // to make it possible for derived classes to overload this function + virtual void polish( QPalette& pal ); + + /** + * This is a convenience method for drawing widgets with + * borders, highlights, pixmaps, colors, etc... + * You specify the widget type and it will draw it according to the + * config file settings. + * + * @param p The QPainter to draw on. + * @param g The color group to use. + * @param rounded @p true if the widget is rounded, @p false if rectangular. + * @param type The widget type to paint. + * @param fill An optional fill brush. Currently ignored (the config file + * is used instead). + */ + virtual void drawBaseButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken = FALSE, + bool rounded = FALSE, WidgetType type = Bevel, + const QBrush *fill = 0 ); + /** + * Draw a mask with for widgets that may be rounded. + * + *Currently used + * by pushbuttons and comboboxes. + * + * @param p The QPainter to draw on. + * @param rounded @p true if the widget is rounded, @p false if rectangular. + */ + virtual void drawBaseMask( QPainter *p, int x, int y, int w, int h, + bool rounded ); + /** + * Draw a pushbutton. + * + * This calls @ref drawBaseButton() with @p PushButton as the + * widget type. + */ + virtual void drawButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken = FALSE, + const QBrush *fill = 0 ); + /** + * Draw a bevel button. + * + * This calls @ref drawBaseButton() with Bevel as the + * widget type. + */ + virtual void drawBevelButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken = FALSE, + const QBrush *fill = 0 ); +#if 0 + /** + * Draw a toolbar button. + */ + virtual void drawKToolBarButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken = false, + bool raised = true, bool enabled = true, + bool popup = false, KToolButtonType type = Icon, + const QString &btext = QString::null, + const QPixmap *icon = NULL, + QFont *font = NULL, QWidget *btn = NULL ); + /** + * Draw the handle used in toolbars. + */ + void drawKBarHandle( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, + KToolBarPos type, QBrush *fill = NULL ); + + /** + * Draw a toolbar. + */ + void drawKToolBar( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, KToolBarPos type, + QBrush *fill = NULL ); +#endif + /** + * Return the space available in a pushbutton, taking configurable + * borders and highlights into account. + */ + virtual QRect buttonRect( int x, int y, int w, int h ); + /** + * Draw an arrow in the style specified by the config file. + */ + virtual void drawArrow( QPainter *p, Qt::ArrowType type, bool down, + int x, int y, int w, int h, const QColorGroup &g, + bool enabled = true, const QBrush *fill = 0 ); + /** + * Return the size of the exclusive indicator pixmap if one is specified + * in the config file, otherwise it uses the base style's size. + */ + virtual QSize exclusiveIndicatorSize() const; + /** + * Draw an exclusive indicator widget. + * + * If a pixmap is specified in the + * config file that is used, otherwise the base style's widget is drawn. + */ + virtual void drawExclusiveIndicator( QPainter* p, int x, int y, int w, + int h, const QColorGroup &g, bool on, + bool down = FALSE, + bool enabled = TRUE ); + /** + * Set the mask of an exclusive indicator widget. + * + * If a pixmap is specified + * it is masked according to it's transparent pixels, otherwise the + * base style's mask is used. + */ + virtual void drawExclusiveIndicatorMask( QPainter *p, int x, int y, int w, + int h, bool on ); + /** + * Set the mask of an indicator widget. + * + * If a pixmap is specified + * it is masked according to it's transparent pixels, otherwise the + * base style's mask is used. + */ + virtual void drawIndicatorMask( QPainter *p, int x, int y, int w, int h, + int state ); + /** + * Set the mask for pushbuttons. + */ + virtual void drawButtonMask( QPainter *p, int x, int y, int w, int h ); + /** + * Set the mask for combo boxes. + */ + virtual void drawComboButtonMask( QPainter *p, int x, int y, int w, int h ); + /** + * Return the size of the indicator pixmap if one is specified + * in the config file, otherwise it uses the base style's size. + */ + virtual QSize indicatorSize() const; + /** + * Draw an indicator widget. + * + * If a pixmap is specified in the + * config file that is used, otherwise the base style's widget is drawn. + */ + virtual void drawIndicator( QPainter* p, int x, int y, int w, int h, + const QColorGroup &g, int state, + bool down = FALSE, bool enabled = TRUE ); + /** + * Draw a combobox. + */ + virtual void drawComboButton( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken = FALSE, + bool editable = FALSE, bool enabled = TRUE, + const QBrush *fill = 0 ); + /** + * Draw a pushbutton. + */ + virtual void drawPushButton( QPushButton* btn, QPainter *p ); + /** + * Return the amount of button content displacement specified by the + * config file. + */ + virtual void getButtonShift( int &x, int &y ); + /** + * Return the frame width. + */ + virtual int defaultFrameWidth() const; + /** + * Calculate the metrics of the scrollbar controls according to the + * layout specified by the config file. + */ + virtual void scrollBarMetrics( const QScrollBar*, int&, int&, int&, int& ); + /** + * Draw a themed scrollbar. + */ + virtual void drawScrollBarControls( QPainter*, const QScrollBar*, + int sliderStart, uint controls, + uint activeControl ); + /** + * Return the control that the given point is over according to the + * layout in the config file. + */ + virtual ScrollControl scrollBarPointOver( const QScrollBar*, + int sliderStart, const QPoint& ); + /** + * Return the configurable default slider length. + */ + virtual int sliderLength() const; + /** + * Draw a slider control. + */ + virtual void drawSlider( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, Orientation, bool tickAbove, + bool tickBelow ); + /** + * Draw a slider groove. + */ + void drawSliderGroove( QPainter *p, int x, int y, int w, int h, + const QColorGroup& g, QCOORD c, + Orientation ); + /** + * Draw the mask for a slider (both the control and groove. + */ + virtual void drawSliderMask( QPainter *p, int x, int y, int w, int h, + Orientation, bool tickAbove, bool tickBelow ); + // void drawSliderGrooveMask(QPainter *p,int x, int y, int w, int h, + // QCOORD c, Orientation ); + /** + * Convience method for drawing themed scrollbar grooves. + * + * Since the + * grooves may be a scaled pixmap you cannot just bitblt the pixmap at + * any offset. This generates a cached pixmap at full size if needed and + * then copies the requested area. + * + * @param p The painter to draw on. + * @param sb The scrollbar (usually given by drawScrollBarControls). + * @param horizontal Is the scrollBar horizontal? + * @param r The rectangle to fill. + * @param g The color group to use. + */ + virtual void drawScrollBarGroove( QPainter *p, const QScrollBar *sb, + bool horizontal, QRect r, QColorGroup g ); + /** + * Draw a shaded rectangle using the given style. + * + * @param p The painter to draw on. + * @param g The color group to use. + * @param rounded Draws a rounded shape if true. Requires bWidth to be + * at least 1. + * @param hWidth The highlight width. + * @param bWidth The border width. + * @param style The shading style to use. + */ + virtual void drawShade( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool sunken, bool rounded, + int hWidth, int bWidth, ShadeStyle style ); + /** + * Draw the text for a pushbutton. + */ + virtual void drawPushButtonLabel( QPushButton *btn, QPainter *p ); + /** + * Draw a menubar. + */ +#if 0 + + void drawKMenuBar( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool macMode, + QBrush *fill = NULL ); +#endif + /** + * Draw a menubar item. + */ +#if 0 + + virtual void drawKMenuItem( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool active, + QMenuItem *item, QBrush *fill = NULL ); +#endif + /** + * Return the width of the splitter as specified in the config file. + */ + virtual int splitterWidth() const; + /** + * Draw a splitter widget. + */ + virtual void drawSplitter( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, Orientation ); + /** + * Draw a checkmark. + */ + virtual void drawCheckMark( QPainter *p, int x, int y, int w, int h, + const QColorGroup &g, bool act, bool dis ); + /** + * Draw a menu item. + * + * Note: This method manually handles applying + * inactive menu backgrounds to the entire widget. + */ + virtual void drawPopupMenuItem( QPainter *p, bool checkable, int maxpmw, + int tab, QMenuItem *mi, const QPalette &pal, + bool act, bool enabled, int x, int y, int w, + int h ); + int popupMenuItemHeight( bool checkable, QMenuItem *mi, + const QFontMetrics &fm ); + /** + * Draw the focus rectangle. + */ + void drawFocusRect( QPainter *p, const QRect &r, const QColorGroup &g, + const QColor *c = 0, bool atBorder = false ); + /** + * Draw a @ref KProgess bar. + */ + // virtual void drawKProgressBlock(QPainter *p, int x, int y, int w, int h, + // const QColorGroup &g, QBrush *fill); + /** + * Return the background for @ref KProgress. + */ + // virtual void getKProgressBackground(const QColorGroup &g, QBrush &bg); + virtual void tabbarMetrics( const QTabBar*, int&, int&, int& ); + virtual void drawTab( QPainter*, const QTabBar*, QTab*, bool selected ); + virtual void drawTabMask( QPainter*, const QTabBar*, QTab*, bool selected ); +protected: + QPalette oldPalette, popupPalette, indiPalette, exIndiPalette; + + class OThemeStylePrivate; + OThemeStylePrivate *d; +}; + +#endif diff --git a/noncore/styles/theme/plugin.cpp b/noncore/styles/theme/plugin.cpp new file mode 100644 index 0000000..b334357 --- a/dev/null +++ b/noncore/styles/theme/plugin.cpp @@ -0,0 +1,19 @@ +//#include <klocale.h> +#include "othemestyle.h" + +extern "C" +{ + QStyle * allocate() { + return new OThemeStyle ( "" ); + } + int minor_version() { + return 0; + } + int major_version() { + return 1; + } + const char * description() { + return ( "Theme Style" ); + } +} + diff --git a/noncore/styles/theme/settings/main.cpp b/noncore/styles/theme/settings/main.cpp new file mode 100644 index 0000000..94d40f3 --- a/dev/null +++ b/noncore/styles/theme/settings/main.cpp @@ -0,0 +1,34 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "themeset.h" + +#include <qpe/qpeapplication.h> + + +int main ( int argc, char** argv ) +{ + QPEApplication a ( argc, argv ); + + ThemeSet dlg; + a. showMainWidget ( &dlg ); + + return a. exec ( ); +} diff --git a/noncore/styles/theme/settings/settings.pro b/noncore/styles/theme/settings/settings.pro new file mode 100644 index 0000000..85d1f7a --- a/dev/null +++ b/noncore/styles/theme/settings/settings.pro @@ -0,0 +1,24 @@ +TEMPLATE = app +CONFIG += qt warn_on release +DESTDIR = $(OPIEDIR)/bin +HEADERS = themeset.h +SOURCES = themeset.cpp main.cpp +INCLUDEPATH += $(OPIEDIR)/include +DEPENDPATH += ../$(OPIEDIR)/include +LIBS += -lqpe +TARGET = theme-settings + +TRANSLATIONS = ../../../../i18n/de/theme-settings.ts \ + ../../../../i18n/en/theme-settings.ts \ + ../../../../i18n/es/theme-settings.ts \ + ../../../../i18n/fr/theme-settings.ts \ + ../../../../i18n/hu/theme-settings.ts \ + ../../../../i18n/ja/theme-settings.ts \ + ../../../../i18n/ko/theme-settings.ts \ + ../../../../i18n/no/theme-settings.ts \ + ../../../../i18n/pl/theme-settings.ts \ + ../../../../i18n/pt/theme-settings.ts \ + ../../../../i18n/pt_BR/theme-settings.ts \ + ../../../../i18n/sl/theme-settings.ts \ + ../../../../i18n/zh_CN/theme-settings.ts \ + ../../../../i18n/zh_TW/theme-settings.ts diff --git a/noncore/styles/theme/settings/themeset.cpp b/noncore/styles/theme/settings/themeset.cpp new file mode 100644 index 0000000..046618e --- a/dev/null +++ b/noncore/styles/theme/settings/themeset.cpp @@ -0,0 +1,124 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + + +#include "themeset.h" + +#include <qpe/qpeapplication.h> +#include <qpe/global.h> + +#include <qlabel.h> +#include <qlayout.h> +#include <qlistview.h> +#include <qdir.h> + +#include <qpe/config.h> + + +class MyConfig : public Config +{ +public: + MyConfig ( const QString &f, Domain d ) : Config ( f, d ) + { } + + bool hasGroup ( const QString &gname ) const + { + QMap< QString, ConfigGroup>::ConstIterator it = groups. find ( gname ); + return ( it != groups.end() ); + } +}; + +class MyItem : public QListViewItem +{ +public: + MyItem ( QListView *lv, const QString &name, const QString &comm, const QString &theme ) : QListViewItem ( lv, name, comm ) + { + m_theme = theme; + } + + + QString m_theme; +}; + + +ThemeSet::ThemeSet ( QWidget* parent, const char *name, WFlags fl ) + : QDialog ( parent, name, fl ) +{ + setCaption ( tr( "Theme Style" ) ); + + Config config ( "qpe" ); + config. setGroup ( "Appearance" ); + + QString active = config. readEntry ( "Theme", "default" ); + + QVBoxLayout *vbox = new QVBoxLayout ( this ); + vbox-> setSpacing ( 3 ); + vbox-> setMargin ( 6 ); + + vbox-> addWidget ( new QLabel ( tr( "Select the theme to be used" ), this )); + + m_list = new QListView ( this ); + m_list-> addColumn ( tr( "Name" )); + m_list-> addColumn ( tr( "Description" )); + m_list-> setSelectionMode ( QListView::Single ); + m_list-> setAllColumnsShowFocus ( true ); + vbox-> addWidget ( m_list, 10 ); + + QListViewItem *item = new MyItem ( m_list, tr( "[No theme]" ), "", "" ); + m_list-> setSelected ( item, true ); + + QString path = QPEApplication::qpeDir() + "/plugins/styles/themes"; + QStringList list = QDir ( path, "*.themerc" ). entryList ( ); + + for ( QStringList::Iterator it = list. begin(); it != list. end ( ); ++it ) { + MyConfig cfg ( path + "/" + *it, Config::File ); + + if ( cfg. hasGroup ( "Misc" )) { + cfg. setGroup ( "Misc" ); + + QString name = cfg. readEntry ( "Name" ); + QString comm = cfg. readEntry ( "Comment" ); + + if ( !name. isEmpty ( )) { + QString fname = (*it). left ((*it). length ( ) - 8 ); + + item = new MyItem ( m_list, name, comm, fname ); + if ( active == fname ) { + m_list-> setSelected ( item, true ); + } + } + } + } +} + +void ThemeSet::accept ( ) +{ + Config config ( "qpe" ); + config. setGroup ( "Appearance" ); + + MyItem *it = (MyItem *) m_list-> selectedItem ( ); + config. writeEntry ( "Theme", it ? it-> m_theme : QString ( "" )); + + Global::applyStyle ( ); + + QDialog::accept ( ); +} + diff --git a/noncore/styles/theme/settings/themeset.h b/noncore/styles/theme/settings/themeset.h new file mode 100644 index 0000000..24804ce --- a/dev/null +++ b/noncore/styles/theme/settings/themeset.h @@ -0,0 +1,20 @@ +#ifndef __OPIE_THEME_SET_H__ +#define __OPIE_THEME_SET_H__ + +#include <qdialog.h> + +class QListView; + +class ThemeSet : public QDialog { + Q_OBJECT + +public: + ThemeSet ( QWidget *parent = 0, const char *name = 0, WFlags fl = 0 ); + +protected: + virtual void accept ( ); + +private: + QListView *m_list; +}; +#endif diff --git a/noncore/styles/theme/theme.pro b/noncore/styles/theme/theme.pro new file mode 100644 index 0000000..fdcd20e --- a/dev/null +++ b/noncore/styles/theme/theme.pro @@ -0,0 +1,32 @@ +TEMPLATE = lib +CONFIG = qt embedded debug warn_on +SOURCES = ogfxeffect.cpp \ + othemestyle.cpp \ + othemebase.cpp \ + plugin.cpp + +HEADERS = ogfxeffect.h \ + othemebase.h \ + othemestyle.h + + +LIBS += -lqpe +INCLUDEPATH += $(OPIEDIR)/include +DESTDIR = $(OPIEDIR)/plugins/styles +TARGET = theme +VERSION = 1.0.0 + +TRANSLATIONS = ../../../i18n/de/libtheme.ts \ + ../../../i18n/en/libtheme.ts \ + ../../../i18n/es/libtheme.ts \ + ../../../i18n/fr/libtheme.ts \ + ../../../i18n/hu/libtheme.ts \ + ../../../i18n/ja/libtheme.ts \ + ../../../i18n/ko/libtheme.ts \ + ../../../i18n/no/libtheme.ts \ + ../../../i18n/pl/libtheme.ts \ + ../../../i18n/pt/libtheme.ts \ + ../../../i18n/pt_BR/libtheme.ts \ + ../../../i18n/sl/libtheme.ts \ + ../../../i18n/zh_CN/libtheme.ts \ + ../../../i18n/zh_TW/libtheme.ts diff --git a/pics/theme/Theme.png b/pics/theme/Theme.png Binary files differnew file mode 100644 index 0000000..67647d0 --- a/dev/null +++ b/pics/theme/Theme.png |