kdefx Library API Documentation

kstyle.cpp

00001 /*
00002  * $Id: kstyle.cpp,v 1.30 2002/11/20 12:04:08 gallium Exp $
00003  *
00004  * KStyle
00005  * Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org>
00006  *
00007  * QWindowsStyle CC_ListView and style images were kindly donated by TrollTech,
00008  * Copyright (C) 1998-2000 TrollTech AS.
00009  *
00010  * Many thanks to Bradley T. Hughes for the 3 button scrollbar code.
00011  *
00012  * This library is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Library General Public
00014  * License version 2 as published by the Free Software Foundation.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Library General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Library General Public License
00022  * along with this library; see the file COPYING.LIB.  If not, write to
00023  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00024  * Boston, MA 02111-1307, USA.
00025  */
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include "config.h"
00029 #endif
00030 
00031 #include <qapplication.h>
00032 #include <qbitmap.h>
00033 #include <qcleanuphandler.h>
00034 #include <qmap.h>
00035 #include <qimage.h>
00036 #include <qlistview.h>
00037 #include <qmenubar.h>
00038 #include <qpainter.h>
00039 #include <qpixmap.h>
00040 #include <qpopupmenu.h>
00041 #include <qprogressbar.h>
00042 #include <qscrollbar.h>
00043 #include <qsettings.h>
00044 #include <qslider.h>
00045 #include <qstylefactory.h>
00046 #include <qtabbar.h>
00047 #include <qtoolbar.h>
00048 
00049 #include <kpixmap.h>
00050 #include <kpixmapeffect.h>
00051 #include <kimageeffect.h>
00052 #include "kstyle.h"
00053 
00054 #include <X11/Xlib.h>
00055 #ifdef HAVE_XRENDER
00056 #include <X11/extensions/Xrender.h>
00057 extern bool qt_use_xrender;
00058 #endif
00059 
00060 #include <limits.h>
00061 
00062 namespace
00063 {
00064     // INTERNAL
00065     enum TransparencyEngine {
00066         Disabled = 0,
00067         SoftwareTint,
00068         SoftwareBlend,
00069         XRender
00070     };
00071 
00072     // Drop Shadow
00073     struct ShadowElements {
00074         QWidget* w1;
00075         QWidget* w2;
00076     };
00077     typedef QMap<const QPopupMenu*,ShadowElements> ShadowMap;
00078         static ShadowMap *_shadowMap = 0;
00079         QSingleCleanupHandler<ShadowMap> cleanupShadowMap;
00080         ShadowMap &shadowMap() {
00081         if ( !_shadowMap ) {
00082         _shadowMap = new ShadowMap;
00083         cleanupShadowMap.set( &_shadowMap );
00084         }
00085         return *_shadowMap;
00086     }
00087 
00088 
00089     // DO NOT ASK ME HOW I MADE THESE TABLES!
00090     // (I probably won't remember anyway ;)
00091     const double top_right_corner[16] =
00092         { 0.949, 0.965, 0.980, 0.992,
00093           0.851, 0.890, 0.945, 0.980,
00094           0.706, 0.780, 0.890, 0.960,
00095           0.608, 0.706, 0.851, 0.949 };
00096 
00097     const double bottom_right_corner[16] =
00098         { 0.608, 0.706, 0.851, 0.949,
00099           0.706, 0.780, 0.890, 0.960,
00100           0.851, 0.890, 0.945, 0.980,
00101           0.949, 0.965, 0.980, 0.992 };
00102 
00103     const double bottom_left_corner[16] =
00104         { 0.949, 0.851, 0.706, 0.608,
00105           0.965, 0.890, 0.780, 0.706,
00106           0.980, 0.945, 0.890, 0.851,
00107           0.992, 0.980, 0.960, 0.949 };
00108 
00109     const double shadow_strip[4] =
00110         { 0.565, 0.675, 0.835, 0.945 };
00111 };
00112 
00113 
00114 struct KStylePrivate
00115 {
00116     bool  highcolor                : 1;
00117     bool  useFilledFrameWorkaround : 1;
00118     bool  etchDisabledText         : 1;
00119     bool  scrollablePopupmenus     : 1;
00120     bool  menuAltKeyNavigation     : 1;
00121     bool  menuDropShadow           : 1;
00122     int   popupMenuDelay;
00123     float menuOpacity;
00124 
00125     TransparencyEngine   transparencyEngine;
00126     KStyle::KStyleScrollBarType  scrollbarType;
00127     TransparencyHandler* menuHandler;
00128     KStyle::KStyleFlags flags;
00129 };
00130 
00131 
00132 class TransparencyHandler : public QObject
00133 {
00134     public:
00135         TransparencyHandler(KStyle* style, TransparencyEngine tEngine,
00136                             float menuOpacity, bool useDropShadow);
00137         ~TransparencyHandler();
00138         bool eventFilter(QObject* object, QEvent* event);
00139 
00140     protected:
00141         void blendToColor(const QColor &col);
00142         void blendToPixmap(const QColorGroup &cg, const QPopupMenu* p);
00143 #ifdef HAVE_XRENDER
00144         void XRenderBlendToPixmap(const QPopupMenu* p);
00145 #endif
00146         void createShadowWindows(const QPopupMenu* p);
00147         void removeShadowWindows(const QPopupMenu* p);
00148         void rightShadow(QImage& dst);
00149         void bottomShadow(QImage& dst);
00150     private:
00151         bool    dropShadow;
00152         float   opacity;
00153         QPixmap pix;
00154         KStyle* kstyle;
00155         TransparencyEngine te;
00156 };
00157 
00158 
00159 // -----------------------------------------------------------------------------
00160 
00161 
00162 KStyle::KStyle( KStyleFlags flags, KStyleScrollBarType sbtype )
00163     : QCommonStyle(), d(new KStylePrivate)
00164 {
00165     d->flags = flags;
00166     bool useMenuTransparency    = (flags & AllowMenuTransparency);
00167     d->useFilledFrameWorkaround = (flags & FilledFrameWorkaround);
00168     d->scrollbarType = sbtype;
00169     d->highcolor = QPixmap::defaultDepth() > 8;
00170 
00171     // Read style settings
00172     QSettings settings;
00173     d->popupMenuDelay       = settings.readNumEntry ("/KStyle/Settings/PopupMenuDelay", 256);
00174     d->etchDisabledText     = settings.readBoolEntry("/KStyle/Settings/EtchDisabledText", true);
00175     d->menuAltKeyNavigation = settings.readBoolEntry("/KStyle/Settings/MenuAltKeyNavigation", true);
00176     d->scrollablePopupmenus = settings.readBoolEntry("/KStyle/Settings/ScrollablePopupMenus", false);
00177     d->menuDropShadow       = settings.readBoolEntry("/KStyle/Settings/MenuDropShadow", false);
00178     d->menuHandler = NULL;
00179 
00180     if (useMenuTransparency) {
00181         QString effectEngine = settings.readEntry("/KStyle/Settings/MenuTransparencyEngine", "Disabled");
00182 
00183 #ifdef HAVE_XRENDER
00184         if (effectEngine == "XRender")
00185             d->transparencyEngine = XRender;
00186 #else
00187         if (effectEngine == "XRender")
00188             d->transparencyEngine = SoftwareBlend;
00189 #endif
00190         else if (effectEngine == "SoftwareBlend")
00191             d->transparencyEngine = SoftwareBlend;
00192         else if (effectEngine == "SoftwareTint")
00193             d->transparencyEngine = SoftwareTint;
00194         else
00195             d->transparencyEngine = Disabled;
00196 
00197         if (d->transparencyEngine != Disabled) {
00198             // Create an instance of the menu transparency handler
00199             d->menuOpacity = settings.readDoubleEntry("/KStyle/Settings/MenuOpacity", 0.90);
00200             d->menuHandler = new TransparencyHandler(this, d->transparencyEngine,
00201                                                      d->menuOpacity, d->menuDropShadow);
00202         }
00203     }
00204 
00205     // Create a transparency handler if only drop shadows are enabled.
00206     if (!d->menuHandler && d->menuDropShadow)
00207         d->menuHandler = new TransparencyHandler(this, Disabled, 1.0, d->menuDropShadow);
00208 }
00209 
00210 
00211 KStyle::~KStyle()
00212 {
00213     if (d->menuHandler)
00214         delete d->menuHandler;
00215 
00216     d->menuHandler = NULL;
00217     delete d;
00218 }
00219 
00220 
00221 QString KStyle::defaultStyle()
00222 {
00223     if (QPixmap::defaultDepth() > 8)
00224        return QString("Bluecurve");
00225     else
00226        return QString("light, 3rd revision");
00227 }
00228 
00229 
00230 void KStyle::polish( QWidget* widget )
00231 {
00232     if ( d->useFilledFrameWorkaround )
00233     {
00234         if (widget->inherits("QToolBar"))
00235             widget->installEventFilter(this);
00236         if (widget->inherits("QMenuBar"))
00237             widget->installEventFilter(this);
00238     }
00239 }
00240 
00241 
00242 void KStyle::unPolish( QWidget* widget )
00243 {
00244     if ( d->useFilledFrameWorkaround )
00245     {
00246         if (widget->inherits("QMenuBar"))
00247             widget->removeEventFilter(this);
00248         if (widget->inherits("QToolBar"))
00249             widget->removeEventFilter(this);
00250     }
00251 }
00252 
00253 
00254 // Style changes (should) always re-polish popups.
00255 void KStyle::polishPopupMenu( QPopupMenu* p )
00256 {
00257     if (!p->testWState( WState_Polished ))
00258         p->setCheckable(true);
00259 
00260     // Install transparency handler if the effect is enabled.
00261     if ( d->menuHandler &&
00262         (strcmp(p->name(), "tear off menu") != 0))
00263             p->installEventFilter(d->menuHandler);
00264 }
00265 
00266 
00267 // -----------------------------------------------------------------------------
00268 // KStyle extensions
00269 // -----------------------------------------------------------------------------
00270 
00271 void KStyle::setScrollBarType(KStyleScrollBarType sbtype)
00272 {
00273     d->scrollbarType = sbtype;
00274 }
00275 
00276 KStyle::KStyleFlags KStyle::styleFlags() const
00277 {
00278     return d->flags;
00279 }
00280 
00281 void KStyle::renderMenuBlendPixmap( KPixmap &pix, const QColorGroup &cg,
00282     const QPopupMenu* /* popup */ ) const
00283 {
00284     pix.fill(cg.button());  // Just tint as the default behaviour
00285 }
00286 
00287 
00288 void KStyle::drawKStylePrimitive( KStylePrimitive kpe,
00289                                   QPainter* p,
00290                                   const QWidget* widget,
00291                                   const QRect &r,
00292                                   const QColorGroup &cg,
00293                                   SFlags flags,
00294                                   const QStyleOption& /* opt */ ) const
00295 {
00296     switch( kpe )
00297     {
00298         // Dock / Toolbar / General handles.
00299         // ---------------------------------
00300 
00301         case KPE_DockWindowHandle: {
00302 
00303             // Draws a nice DockWindow handle including the dock title.
00304             QWidget* wid = const_cast<QWidget*>(widget);
00305             bool horizontal = flags & Style_Horizontal;
00306             int x,y,w,h,x2,y2;
00307 
00308             if ((wid->width() <= 2) || (wid->height() <= 2)) {
00309                 p->fillRect(r, cg.highlight());
00310                 return;
00311             }
00312 
00313             r.rect( &x, &y, &w, &h );
00314             x2 = x + w - 1;
00315             y2 = y + h - 1;
00316 
00317             QFont fnt;
00318             fnt = QApplication::font(wid);
00319             fnt.setPointSize( fnt.pointSize()-2 );
00320 
00321             // Draw the item on an off-screen pixmap
00322             // to preserve Xft antialiasing for
00323             // vertically oriented handles.
00324             QPixmap pix;
00325             if (horizontal)
00326                 pix.resize( h-2, w-2 );
00327             else
00328                 pix.resize( w-2, h-2 );
00329 
00330             QString title = wid->parentWidget()->caption();
00331             QPainter p2;
00332             p2.begin(&pix);
00333             p2.fillRect(pix.rect(), cg.brush(QColorGroup::Highlight));
00334             p2.setPen(cg.highlightedText());
00335             p2.setFont(fnt);
00336             p2.drawText(pix.rect(), AlignCenter, title);
00337             p2.end();
00338 
00339             // Draw a sunken bevel
00340             p->setPen(cg.dark());
00341             p->drawLine(x, y, x2, y);
00342             p->drawLine(x, y, x, y2);
00343             p->setPen(cg.light());
00344             p->drawLine(x+1, y2, x2, y2);
00345             p->drawLine(x2, y+1, x2, y2);
00346 
00347             if (horizontal) {
00348                 QWMatrix m;
00349                 m.rotate(-90.0);
00350                 QPixmap vpix = pix.xForm(m);
00351                 bitBlt(wid, r.x()+1, r.y()+1, &vpix);
00352             } else
00353                 bitBlt(wid, r.x()+1, r.y()+1, &pix);
00354 
00355             break;
00356         }
00357 
00358 
00359         /*
00360          * KPE_ListViewExpander and KPE_ListViewBranch are based on code from
00361          * QWindowStyle's CC_ListView, kindly donated by TrollTech.
00362          * CC_ListView code is Copyright (C) 1998-2000 TrollTech AS.
00363          */
00364 
00365         case KPE_ListViewExpander: {
00366             // Typical Windows style expand/collapse element.
00367             int radius = (r.width() - 4) / 2;
00368             int centerx = r.x() + r.width()/2;
00369             int centery = r.y() + r.height()/2;
00370 
00371             // Outer box
00372             p->setPen( cg.mid() );
00373             p->drawRect( r );
00374 
00375             // plus or minus
00376             p->setPen( cg.text() );
00377             p->drawLine( centerx - radius, centery, centerx + radius, centery );
00378             if ( flags & Style_On ) // Collapsed = On
00379                 p->drawLine( centerx, centery - radius, centerx, centery + radius );
00380             break;
00381         }
00382 
00383         case KPE_ListViewBranch: {
00384             // Typical Windows style listview branch element (dotted line).
00385 
00386             static QBitmap *verticalLine = 0, *horizontalLine = 0;
00387             static QCleanupHandler<QBitmap> qlv_cleanup_bitmap;
00388 
00389             // Create the dotline pixmaps if not already created
00390             if ( !verticalLine )
00391             {
00392                 // make 128*1 and 1*128 bitmaps that can be used for
00393                 // drawing the right sort of lines.
00394                 verticalLine   = new QBitmap( 1, 129, TRUE );
00395                 horizontalLine = new QBitmap( 128, 1, TRUE );
00396                 QPointArray a( 64 );
00397                 QPainter p2;
00398                 p2.begin( verticalLine );
00399 
00400                 int i;
00401                 for( i=0; i < 64; i++ )
00402                     a.setPoint( i, 0, i*2+1 );
00403                 p2.setPen( color1 );
00404                 p2.drawPoints( a );
00405                 p2.end();
00406                 QApplication::flushX();
00407                 verticalLine->setMask( *verticalLine );
00408 
00409                 p2.begin( horizontalLine );
00410                 for( i=0; i < 64; i++ )
00411                     a.setPoint( i, i*2+1, 0 );
00412                 p2.setPen( color1 );
00413                 p2.drawPoints( a );
00414                 p2.end();
00415                 QApplication::flushX();
00416                 horizontalLine->setMask( *horizontalLine );
00417 
00418                 qlv_cleanup_bitmap.add( &verticalLine );
00419                 qlv_cleanup_bitmap.add( &horizontalLine );
00420             }
00421 
00422             p->setPen( cg.text() );     // cg.dark() is bad for dark color schemes.
00423 
00424             if (flags & Style_Horizontal)
00425             {
00426                 int point = r.x();
00427                 int other = r.y();
00428                 int end = r.x()+r.width();
00429                 int thickness = r.height();
00430 
00431                 while( point < end )
00432                 {
00433                     int i = 128;
00434                     if ( i+point > end )
00435                         i = end-point;
00436                     p->drawPixmap( point, other, *horizontalLine, 0, 0, i, thickness );
00437                     point += i;
00438                 }
00439 
00440             } else {
00441                 int point = r.y();
00442                 int other = r.x();
00443                 int end = r.y()+r.height();
00444                 int thickness = r.width();
00445                 int pixmapoffset = (flags & Style_NoChange) ? 0 : 1;    // ### Hackish
00446 
00447                 while( point < end )
00448                 {
00449                     int i = 128;
00450                     if ( i+point > end )
00451                         i = end-point;
00452                     p->drawPixmap( other, point, *verticalLine, 0, pixmapoffset, thickness, i );
00453                     point += i;
00454                 }
00455             }
00456 
00457             break;
00458         }
00459 
00460         // Reimplement the other primitives in your styles.
00461         // The current implementation just paints something visibly different.
00462         case KPE_ToolBarHandle:
00463         case KPE_GeneralHandle:
00464         case KPE_SliderHandle:
00465             p->fillRect(r, cg.light());
00466             break;
00467 
00468         case KPE_SliderGroove:
00469             p->fillRect(r, cg.dark());
00470             break;
00471 
00472         default:
00473             p->fillRect(r, Qt::yellow); // Something really bad happened - highlight.
00474             break;
00475     }
00476 }
00477 
00478 
00479 int KStyle::kPixelMetric( KStylePixelMetric kpm, const QWidget* /* widget */) const
00480 {
00481     int value;
00482     switch(kpm)
00483     {
00484         case KPM_ListViewBranchThickness:
00485             value = 1;
00486             break;
00487 
00488         case KPM_MenuItemSeparatorHeight:
00489         case KPM_MenuItemHMargin:
00490         case KPM_MenuItemVMargin:
00491         case KPM_MenuItemHFrame:
00492         case KPM_MenuItemVFrame:
00493         case KPM_MenuItemCheckMarkHMargin:
00494         case KPM_MenuItemArrowHMargin:
00495         case KPM_MenuItemTabSpacing:
00496         default:
00497             value = 0;
00498     }
00499 
00500     return value;
00501 }
00502 
00503 
00504 // -----------------------------------------------------------------------------
00505 
00506 void KStyle::drawPrimitive( PrimitiveElement pe,
00507                             QPainter* p,
00508                             const QRect &r,
00509                             const QColorGroup &cg,
00510                             SFlags flags,
00511                             const QStyleOption& opt ) const
00512 {
00513     // TOOLBAR/DOCK WINDOW HANDLE
00514     // ------------------------------------------------------------------------
00515     if (pe == PE_DockWindowHandle)
00516     {
00517         // Wild workarounds are here. Beware.
00518         QWidget *widget, *parent;
00519 
00520         if (p && p->device()->devType() == QInternal::Widget) {
00521             widget = static_cast<QWidget*>(p->device());
00522             parent = widget->parentWidget();
00523         } else
00524             return;     // Don't paint on non-widgets
00525 
00526         // Check if we are a normal toolbar or a hidden dockwidget.
00527         if ( parent &&
00528             (parent->inherits("QToolBar") ||        // Normal toolbar
00529             (parent->inherits("QMainWindow")) ))    // Collapsed dock
00530 
00531             // Draw a toolbar handle
00532             drawKStylePrimitive( KPE_ToolBarHandle, p, widget, r, cg, flags, opt );
00533 
00534         else if ( widget->inherits("QDockWindowHandle") )
00535 
00536             // Draw a dock window handle
00537             drawKStylePrimitive( KPE_DockWindowHandle, p, widget, r, cg, flags, opt );
00538 
00539         else
00540             // General handle, probably a kicker applet handle.
00541             drawKStylePrimitive( KPE_GeneralHandle, p, widget, r, cg, flags, opt );
00542 
00543     } else
00544         QCommonStyle::drawPrimitive( pe, p, r, cg, flags, opt );
00545 }
00546 
00547 
00548 
00549 void KStyle::drawControl( ControlElement element,
00550                           QPainter* p,
00551                           const QWidget* widget,
00552                           const QRect &r,
00553                           const QColorGroup &cg,
00554                           SFlags flags,
00555                           const QStyleOption &opt ) const
00556 {
00557     switch (element)
00558     {
00559         // TABS
00560         // ------------------------------------------------------------------------
00561         case CE_TabBarTab: {
00562             const QTabBar* tb  = (const QTabBar*) widget;
00563             QTabBar::Shape tbs = tb->shape();
00564             bool selected      = flags & Style_Selected;
00565             int x = r.x(), y=r.y(), bottom=r.bottom(), right=r.right();
00566 
00567             switch (tbs) {
00568 
00569                 case QTabBar::RoundedAbove: {
00570                     if (!selected)
00571                         p->translate(0,1);
00572                     p->setPen(selected ? cg.light() : cg.shadow());
00573                     p->drawLine(x, y+4, x, bottom);
00574                     p->drawLine(x, y+4, x+4, y);
00575                     p->drawLine(x+4, y, right-1, y);
00576                     if (selected)
00577                         p->setPen(cg.shadow());
00578                     p->drawLine(right, y+1, right, bottom);
00579 
00580                     p->setPen(cg.midlight());
00581                     p->drawLine(x+1, y+4, x+1, bottom);
00582                     p->drawLine(x+1, y+4, x+4, y+1);
00583                     p->drawLine(x+5, y+1, right-2, y+1);
00584 
00585                     if (selected) {
00586                         p->setPen(cg.mid());
00587                         p->drawLine(right-1, y+1, right-1, bottom);
00588                     } else {
00589                         p->setPen(cg.mid());
00590                         p->drawPoint(right-1, y+1);
00591                         p->drawLine(x+4, y+2, right-1, y+2);
00592                         p->drawLine(x+3, y+3, right-1, y+3);
00593                         p->fillRect(x+2, y+4, r.width()-3, r.height()-6, cg.mid());
00594 
00595                         p->setPen(cg.light());
00596                         p->drawLine(x, bottom-1, right, bottom-1);
00597                         p->translate(0,-1);
00598                     }
00599                     break;
00600                 }
00601 
00602                 case QTabBar::RoundedBelow: {
00603                     if (!selected)
00604                         p->translate(0,-1);
00605                     p->setPen(selected ? cg.light() : cg.shadow());
00606                     p->drawLine(x, bottom-4, x, y);
00607                     if (selected)
00608                         p->setPen(cg.mid());
00609                     p->drawLine(x, bottom-4, x+4, bottom);
00610                     if (selected)
00611                         p->setPen(cg.shadow());
00612                     p->drawLine(x+4, bottom, right-1, bottom);
00613                     p->drawLine(right, bottom-1, right, y);
00614 
00615                     p->setPen(cg.midlight());
00616                     p->drawLine(x+1, bottom-4, x+1, y);
00617                     p->drawLine(x+1, bottom-4, x+4, bottom-1);
00618                     p->drawLine(x+5, bottom-1, right-2, bottom-1);
00619 
00620                     if (selected) {
00621                         p->setPen(cg.mid());
00622                         p->drawLine(right-1, y, right-1, bottom-1);
00623                     } else {
00624                         p->setPen(cg.mid());
00625                         p->drawPoint(right-1, bottom-1);
00626                         p->drawLine(x+4, bottom-2, right-1, bottom-2);
00627                         p->drawLine(x+3, bottom-3, right-1, bottom-3);
00628                         p->fillRect(x+2, y+2, r.width()-3, r.height()-6, cg.mid());
00629                         p->translate(0,1);
00630                         p->setPen(cg.dark());
00631                         p->drawLine(x, y, right, y);
00632                     }
00633                     break;
00634                 }
00635 
00636                 case QTabBar::TriangularAbove: {
00637                     if (!selected)
00638                         p->translate(0,1);
00639                     p->setPen(selected ? cg.light() : cg.shadow());
00640                     p->drawLine(x, bottom, x, y+6);
00641                     p->drawLine(x, y+6, x+6, y);
00642                     p->drawLine(x+6, y, right-6, y);
00643                     if (selected)
00644                         p->setPen(cg.mid());
00645                     p->drawLine(right-5, y+1, right-1, y+5);
00646                     p->setPen(cg.shadow());
00647                     p->drawLine(right, y+6, right, bottom);
00648 
00649                     p->setPen(cg.midlight());
00650                     p->drawLine(x+1, bottom, x+1, y+6);
00651                     p->drawLine(x+1, y+6, x+6, y+1);
00652                     p->drawLine(x+6, y+1, right-6, y+1);
00653                     p->drawLine(right-5, y+2, right-2, y+5);
00654                     p->setPen(cg.mid());
00655                     p->drawLine(right-1, y+6, right-1, bottom);
00656 
00657                     QPointArray a(6);
00658                     a.setPoint(0, x+2, bottom);
00659                     a.setPoint(1, x+2, y+7);
00660                     a.setPoint(2, x+7, y+2);
00661                     a.setPoint(3, right-7, y+2);
00662                     a.setPoint(4, right-2, y+7);
00663                     a.setPoint(5, right-2, bottom);
00664                     p->setPen  (selected ? cg.background() : cg.mid());
00665                     p->setBrush(selected ? cg.background() : cg.mid());
00666                     p->drawPolygon(a);
00667                     p->setBrush(NoBrush);
00668                     if (!selected) {
00669                         p->translate(0,-1);
00670                         p->setPen(cg.light());
00671                         p->drawLine(x, bottom, right, bottom);
00672                     }
00673                     break;
00674                 }
00675 
00676                 default: { // QTabBar::TriangularBelow
00677                     if (!selected)
00678                         p->translate(0,-1);
00679                     p->setPen(selected ? cg.light() : cg.shadow());
00680                     p->drawLine(x, y, x, bottom-6);
00681                     if (selected)
00682                         p->setPen(cg.mid());
00683                     p->drawLine(x, bottom-6, x+6, bottom);
00684                     if (selected)
00685                         p->setPen(cg.shadow());
00686                     p->drawLine(x+6, bottom, right-6, bottom);
00687                     p->drawLine(right-5, bottom-1, right-1, bottom-5);
00688                     if (!selected)
00689                         p->setPen(cg.shadow());
00690                     p->drawLine(right, bottom-6, right, y);
00691 
00692                     p->setPen(cg.midlight());
00693                     p->drawLine(x+1, y, x+1, bottom-6);
00694                     p->drawLine(x+1, bottom-6, x+6, bottom-1);
00695                     p->drawLine(x+6, bottom-1, right-6, bottom-1);
00696                     p->drawLine(right-5, bottom-2, right-2, bottom-5);
00697                     p->setPen(cg.mid());
00698                     p->drawLine(right-1, bottom-6, right-1, y);
00699 
00700                     QPointArray a(6);
00701                     a.setPoint(0, x+2, y);
00702                     a.setPoint(1, x+2, bottom-7);
00703                     a.setPoint(2, x+7, bottom-2);
00704                     a.setPoint(3, right-7, bottom-2);
00705                     a.setPoint(4, right-2, bottom-7);
00706                     a.setPoint(5, right-2, y);
00707                     p->setPen  (selected ? cg.background() : cg.mid());
00708                     p->setBrush(selected ? cg.background() : cg.mid());
00709                     p->drawPolygon(a);
00710                     p->setBrush(NoBrush);
00711                     if (!selected) {
00712                         p->translate(0,1);
00713                         p->setPen(cg.dark());
00714                         p->drawLine(x, y, right, y);
00715                     }
00716                     break;
00717                 }
00718             };
00719 
00720             break;
00721         }
00722 
00723 
00724         // PROGRESSBAR
00725         // ------------------------------------------------------------------------
00726         case CE_ProgressBarGroove: {
00727             QRect fr = subRect(SR_ProgressBarGroove, widget);
00728             drawPrimitive(PE_Panel, p, fr, cg, Style_Sunken, QStyleOption::Default);
00729             break;
00730         }
00731 
00732         case CE_ProgressBarContents: {
00733             // ### Take into account totalSteps() for busy indicator
00734             const QProgressBar* pb = (const QProgressBar*)widget;
00735             QRect cr = subRect(SR_ProgressBarContents, widget);
00736             double progress = pb->progress();
00737             bool reverse = QApplication::reverseLayout();
00738             int steps = pb->totalSteps();
00739 
00740             if (!cr.isValid())
00741                 return;
00742 
00743             // Draw progress bar
00744             if (progress > 0 || steps == 0) {
00745                 double pg = (steps == 0) ? 0.1 : progress / steps;
00746                 int width = QMIN(cr.width(), (int)(pg * cr.width()));
00747                 if (steps == 0) { //Busy indicator
00748 
00749                     if (width < 1) width = 1; //A busy indicator with width 0 is kind of useless
00750 
00751                     int remWidth = cr.width() - width; //Never disappear completely
00752                     if (remWidth <= 0) remWidth = 1; //Do something non-crashy when too small...
00753 
00754                     int pstep =  int(progress) % ( 2 *  remWidth );
00755 
00756                     if ( pstep > remWidth ) {
00757                         //Bounce about.. We're remWidth + some delta, we want to be remWidth - delta...
00758                         // - ( (remWidth + some delta) - 2* remWidth )  = - (some deleta - remWidth) = remWidth - some delta..
00759                         pstep = - (pstep - 2 * remWidth );
00760                     }
00761 
00762                     if (reverse)
00763                         p->fillRect(cr.x() + cr.width() - width - pstep, cr.y(), width, cr.height(),
00764                                     cg.brush(QColorGroup::Highlight));
00765                     else
00766                         p->fillRect(cr.x() + pstep, cr.y(), width, cr.height(),
00767                                     cg.brush(QColorGroup::Highlight));
00768 
00769                     return;
00770                 }
00771 
00772 
00773                 // Do fancy gradient for highcolor displays
00774                 if (d->highcolor) {
00775                     QColor c(cg.highlight());
00776                     KPixmap pix;
00777                     pix.resize(cr.width(), cr.height());
00778                     KPixmapEffect::gradient(pix, reverse ? c.light(150) : c.dark(150),
00779                                             reverse ? c.dark(150) : c.light(150),
00780                                             KPixmapEffect::HorizontalGradient);
00781                     if (reverse)
00782                         p->drawPixmap(cr.x()+(cr.width()-width), cr.y(), pix,
00783                                       cr.width()-width, 0, width, cr.height());
00784                     else
00785                         p->drawPixmap(cr.x(), cr.y(), pix, 0, 0, width, cr.height());
00786                 } else
00787                     if (reverse)
00788                         p->fillRect(cr.x()+(cr.width()-width), cr.y(), width, cr.height(),
00789                                     cg.brush(QColorGroup::Highlight));
00790                     else
00791                         p->fillRect(cr.x(), cr.y(), width, cr.height(),
00792                                     cg.brush(QColorGroup::Highlight));
00793             }
00794             break;
00795         }
00796 
00797         case CE_ProgressBarLabel: {
00798             const QProgressBar* pb = (const QProgressBar*)widget;
00799             QRect cr = subRect(SR_ProgressBarContents, widget);
00800             double progress = pb->progress();
00801             bool reverse = QApplication::reverseLayout();
00802             int steps = pb->totalSteps();
00803 
00804             if (!cr.isValid())
00805                 return;
00806 
00807             QFont font = p->font();
00808             font.setBold(true);
00809             p->setFont(font);
00810 
00811             // Draw label
00812             if (progress > 0 || steps == 0) {
00813                 double pg = (steps == 0) ? 1.0 : progress / steps;
00814                 int width = QMIN(cr.width(), (int)(pg * cr.width()));
00815                 QRect crect;
00816                 if (reverse)
00817                     crect.setRect(cr.x()+(cr.width()-width), cr.y(), cr.width(), cr.height());
00818                 else
00819                     crect.setRect(cr.x()+width, cr.y(), cr.width(), cr.height());
00820 
00821                 p->save();
00822                 p->setPen(pb->isEnabled() ? (reverse ? cg.text() : cg.highlightedText()) : cg.text());
00823                 p->drawText(r, AlignCenter, pb->progressString());
00824                 p->setClipRect(crect);
00825                 p->setPen(reverse ? cg.highlightedText() : cg.text());
00826                 p->drawText(r, AlignCenter, pb->progressString());
00827                 p->restore();
00828 
00829             } else {
00830                 p->setPen(cg.text());
00831                 p->drawText(r, AlignCenter, pb->progressString());
00832             }
00833 
00834             break;
00835         }
00836 
00837         default:
00838             QCommonStyle::drawControl(element, p, widget, r, cg, flags, opt);
00839     }
00840 }
00841 
00842 
00843 QRect KStyle::subRect(SubRect r, const QWidget* widget) const
00844 {
00845     switch(r)
00846     {
00847         // KDE2 look smooth progress bar
00848         // ------------------------------------------------------------------------
00849         case SR_ProgressBarGroove:
00850             return widget->rect();
00851 
00852         case SR_ProgressBarContents:
00853         case SR_ProgressBarLabel: {
00854             // ### take into account indicatorFollowsStyle()
00855             QRect rt = widget->rect();
00856             return QRect(rt.x()+2, rt.y()+2, rt.width()-4, rt.height()-4);
00857         }
00858 
00859         default:
00860             return QCommonStyle::subRect(r, widget);
00861     }
00862 }
00863 
00864 
00865 int KStyle::pixelMetric(PixelMetric m, const QWidget* widget) const
00866 {
00867     switch(m)
00868     {
00869         // BUTTONS
00870         // ------------------------------------------------------------------------
00871         case PM_ButtonShiftHorizontal:      // Offset by 1
00872         case PM_ButtonShiftVertical:        // ### Make configurable
00873             return 1;
00874 
00875         // TABS
00876         // ------------------------------------------------------------------------
00877         case PM_TabBarTabHSpace:
00878             return 24;
00879 
00880         case PM_TabBarTabVSpace: {
00881             const QTabBar * tb = (const QTabBar *) widget;
00882             if ( tb->shape() == QTabBar::RoundedAbove ||
00883                  tb->shape() == QTabBar::RoundedBelow )
00884                 return 10;
00885             else
00886                 return 4;
00887         }
00888 
00889         case PM_TabBarTabOverlap: {
00890             const QTabBar* tb = (const QTabBar*)widget;
00891             QTabBar::Shape tbs = tb->shape();
00892 
00893             if ( (tbs == QTabBar::RoundedAbove) ||
00894                  (tbs == QTabBar::RoundedBelow) )
00895                 return 0;
00896             else
00897                 return 2;
00898         }
00899 
00900         // SLIDER
00901         // ------------------------------------------------------------------------
00902         case PM_SliderLength:
00903             return 18;
00904 
00905         case PM_SliderThickness:
00906             return 24;
00907 
00908         // Determines how much space to leave for the actual non-tickmark
00909         // portion of the slider.
00910         case PM_SliderControlThickness: {
00911             const QSlider* slider   = (const QSlider*)widget;
00912             QSlider::TickSetting ts = slider->tickmarks();
00913             int thickness = (slider->orientation() == Horizontal) ?
00914                              slider->height() : slider->width();
00915             switch (ts) {
00916                 case QSlider::NoMarks:              // Use total area.
00917                     break;
00918                 case QSlider::Both:
00919                     thickness = (thickness/2) + 3;  // Use approx. 1/2 of area.
00920                     break;
00921                 default:                            // Use approx. 2/3 of area
00922                     thickness = ((thickness*2)/3) + 3;
00923                     break;
00924             };
00925             return thickness;
00926         }
00927 
00928         // SPLITTER
00929         // ------------------------------------------------------------------------
00930         case PM_SplitterWidth:
00931             if (widget && widget->inherits("QDockWindowResizeHandle"))
00932                 return 8;   // ### why do we need 2pix extra?
00933             else
00934                 return 6;
00935 
00936         // FRAMES
00937         // ------------------------------------------------------------------------
00938         case PM_MenuBarFrameWidth:
00939             return 1;
00940 
00941         case PM_DockWindowFrameWidth:
00942             return 1;
00943 
00944         // GENERAL
00945         // ------------------------------------------------------------------------
00946         case PM_MaximumDragDistance:
00947             return -1;
00948 
00949         default:
00950             return QCommonStyle::pixelMetric( m, widget );
00951     }
00952 }
00953 
00954 
00955 void KStyle::drawComplexControl( ComplexControl control,
00956                                  QPainter* p,
00957                                  const QWidget* widget,
00958                                  const QRect &r,
00959                                  const QColorGroup &cg,
00960                                  SFlags flags,
00961                                  SCFlags controls,
00962                                  SCFlags active,
00963                                  const QStyleOption &opt ) const
00964 {
00965     switch(control)
00966     {
00967         // 3 BUTTON SCROLLBAR
00968         // ------------------------------------------------------------------------
00969         case CC_ScrollBar: {
00970             // Many thanks to Brad Hughes for contributing this code.
00971             bool useThreeButtonScrollBar = (d->scrollbarType & ThreeButtonScrollBar);
00972 
00973             const QScrollBar *sb = (const QScrollBar*)widget;
00974             bool   maxedOut   = (sb->minValue()    == sb->maxValue());
00975             bool   horizontal = (sb->orientation() == Qt::Horizontal);
00976             SFlags sflags     = ((horizontal ? Style_Horizontal : Style_Default) |
00977                                  (maxedOut   ? Style_Default : Style_Enabled));
00978 
00979             QRect  addline, subline, subline2, addpage, subpage, slider, first, last;
00980             subline = querySubControlMetrics(control, widget, SC_ScrollBarSubLine, opt);
00981             addline = querySubControlMetrics(control, widget, SC_ScrollBarAddLine, opt);
00982             subpage = querySubControlMetrics(control, widget, SC_ScrollBarSubPage, opt);
00983             addpage = querySubControlMetrics(control, widget, SC_ScrollBarAddPage, opt);
00984             slider  = querySubControlMetrics(control, widget, SC_ScrollBarSlider,  opt);
00985             first   = querySubControlMetrics(control, widget, SC_ScrollBarFirst,   opt);
00986             last    = querySubControlMetrics(control, widget, SC_ScrollBarLast,    opt);
00987             subline2 = addline;
00988 
00989             if ( useThreeButtonScrollBar )
00990                 if (horizontal)
00991                     subline2.moveBy(-addline.width(), 0);
00992                 else
00993                     subline2.moveBy(0, -addline.height());
00994 
00995             // Draw the up/left button set
00996             if ((controls & SC_ScrollBarSubLine) && subline.isValid()) {
00997                 drawPrimitive(PE_ScrollBarSubLine, p, subline, cg,
00998                             sflags | (active == SC_ScrollBarSubLine ?
00999                                 Style_Down : Style_Default));
01000 
01001                 if (useThreeButtonScrollBar && subline2.isValid())
01002                     drawPrimitive(PE_ScrollBarSubLine, p, subline2, cg,
01003                             sflags | (active == SC_ScrollBarSubLine ?
01004                                 Style_Down : Style_Default));
01005             }
01006 
01007             if ((controls & SC_ScrollBarAddLine) && addline.isValid())
01008                 drawPrimitive(PE_ScrollBarAddLine, p, addline, cg,
01009                             sflags | ((active == SC_ScrollBarAddLine) ?
01010                                         Style_Down : Style_Default));
01011 
01012             if ((controls & SC_ScrollBarSubPage) && subpage.isValid())
01013                 drawPrimitive(PE_ScrollBarSubPage, p, subpage, cg,
01014                             sflags | ((active == SC_ScrollBarSubPage) ?
01015                                         Style_Down : Style_Default));
01016 
01017             if ((controls & SC_ScrollBarAddPage) && addpage.isValid())
01018                 drawPrimitive(PE_ScrollBarAddPage, p, addpage, cg,
01019                             sflags | ((active == SC_ScrollBarAddPage) ?
01020                                         Style_Down : Style_Default));
01021 
01022             if ((controls & SC_ScrollBarFirst) && first.isValid())
01023                 drawPrimitive(PE_ScrollBarFirst, p, first, cg,
01024                             sflags | ((active == SC_ScrollBarFirst) ?
01025                                         Style_Down : Style_Default));
01026 
01027             if ((controls & SC_ScrollBarLast) && last.isValid())
01028                 drawPrimitive(PE_ScrollBarLast, p, last, cg,
01029                             sflags | ((active == SC_ScrollBarLast) ?
01030                                         Style_Down : Style_Default));
01031 
01032             if ((controls & SC_ScrollBarSlider) && slider.isValid()) {
01033                 drawPrimitive(PE_ScrollBarSlider, p, slider, cg,
01034                             sflags | ((active == SC_ScrollBarSlider) ?
01035                                         Style_Down : Style_Default));
01036                 // Draw focus rect
01037                 if (sb->hasFocus()) {
01038                     QRect fr(slider.x() + 2, slider.y() + 2,
01039                              slider.width() - 5, slider.height() - 5);
01040                     drawPrimitive(PE_FocusRect, p, fr, cg, Style_Default);
01041                 }
01042             }
01043             break;
01044         }
01045 
01046 
01047         // SLIDER
01048         // -------------------------------------------------------------------
01049         case CC_Slider: {
01050             const QSlider* slider = (const QSlider*)widget;
01051             QRect groove = querySubControlMetrics(CC_Slider, widget, SC_SliderGroove, opt);
01052             QRect handle = querySubControlMetrics(CC_Slider, widget, SC_SliderHandle, opt);
01053 
01054             // Double-buffer slider for no flicker
01055             QPixmap pix(widget->size());
01056             QPainter p2;
01057             p2.begin(&pix);
01058 
01059             if ( slider->parentWidget() &&
01060                  slider->parentWidget()->backgroundPixmap() &&
01061                  !slider->parentWidget()->backgroundPixmap()->isNull() ) {
01062                 QPixmap pixmap = *(slider->parentWidget()->backgroundPixmap());
01063                 p2.drawTiledPixmap(r, pixmap, slider->pos());
01064             } else
01065                 pix.fill(cg.background());
01066 
01067             // Draw slider groove
01068             if ((controls & SC_SliderGroove) && groove.isValid()) {
01069                 drawKStylePrimitive( KPE_SliderGroove, &p2, widget, groove, cg, flags, opt );
01070 
01071                 // Draw the focus rect around the groove
01072                 if (slider->hasFocus())
01073                     drawPrimitive(PE_FocusRect, &p2, groove, cg);
01074             }
01075 
01076             // Draw the tickmarks
01077             if (controls & SC_SliderTickmarks)
01078                 QCommonStyle::drawComplexControl(control, &p2, widget,
01079                         r, cg, flags, SC_SliderTickmarks, active, opt);
01080 
01081             // Draw the slider handle
01082             if ((controls & SC_SliderHandle) && handle.isValid()) {
01083                 if (active == SC_SliderHandle)
01084                     flags |= Style_Active;
01085                 drawKStylePrimitive( KPE_SliderHandle, &p2, widget, handle, cg, flags, opt );
01086             }
01087 
01088             p2.end();
01089             bitBlt((QWidget*)widget, r.x(), r.y(), &pix);
01090             break;
01091         }
01092 
01093         // LISTVIEW
01094         // -------------------------------------------------------------------
01095         case CC_ListView: {
01096 
01097             /*
01098              * Many thanks to TrollTech AS for donating CC_ListView from QWindowsStyle.
01099              * CC_ListView code is Copyright (C) 1998-2000 TrollTech AS.
01100              */
01101 
01102             // Paint the icon and text.
01103             if ( controls & SC_ListView )
01104                 QCommonStyle::drawComplexControl( control, p, widget, r, cg, flags, controls, active, opt );
01105 
01106             // If we're have a branch or are expanded...
01107             if ( controls & (SC_ListViewBranch | SC_ListViewExpand) )
01108             {
01109                 // If no list view item was supplied, break
01110                 if (opt.isDefault())
01111                     break;
01112 
01113                 QListViewItem *item  = opt.listViewItem();
01114                 QListViewItem *child = item->firstChild();
01115 
01116                 int y = r.y();
01117                 int c;  // dotline vertice count
01118                 int dotoffset = 0;
01119                 QPointArray dotlines;
01120 
01121                 if ( active == SC_All && controls == SC_ListViewExpand ) {
01122                     // We only need to draw a vertical line
01123                     c = 2;
01124                     dotlines.resize(2);
01125                     dotlines[0] = QPoint( r.right(), r.top() );
01126                     dotlines[1] = QPoint( r.right(), r.bottom() );
01127 
01128                 } else {
01129 
01130                     int linetop = 0, linebot = 0;
01131                     // each branch needs at most two lines, ie. four end points
01132                     dotoffset = (item->itemPos() + item->height() - y) % 2;
01133                     dotlines.resize( item->childCount() * 4 );
01134                     c = 0;
01135 
01136                     // skip the stuff above the exposed rectangle
01137                     while ( child && y + child->height() <= 0 )
01138                     {
01139                         y += child->totalHeight();
01140                         child = child->nextSibling();
01141                     }
01142 
01143                     int bx = r.width() / 2;
01144 
01145                     // paint stuff in the magical area
01146                     QListView* v = item->listView();
01147                     int lh = QMAX( p->fontMetrics().height() + 2 * v->itemMargin(),
01148                                    QApplication::globalStrut().height() );
01149                     if ( lh % 2 > 0 )
01150                         lh++;
01151 
01152                     // Draw all the expand/close boxes...
01153                     QRect boxrect;
01154                     QStyle::StyleFlags boxflags;
01155                     while ( child && y < r.height() )
01156                     {
01157                         linebot = y + lh/2;
01158                         if ( (child->isExpandable() || child->childCount()) &&
01159                              (child->height() > 0) )
01160                         {
01161                             // The primitive requires a rect.
01162                             boxrect = QRect( bx-4, linebot-4, 9, 9 );
01163                             boxflags = child->isOpen() ? QStyle::Style_Off : QStyle::Style_On;
01164 
01165                             // KStyle extension: Draw the box and expand/collapse indicator
01166                             drawKStylePrimitive( KPE_ListViewExpander, p, NULL, boxrect, cg, boxflags, opt );
01167 
01168                             // dotlinery
01169                             p->setPen( cg.mid() );
01170                             dotlines[c++] = QPoint( bx, linetop );
01171                             dotlines[c++] = QPoint( bx, linebot - 5 );
01172                             dotlines[c++] = QPoint( bx + 5, linebot );
01173                             dotlines[c++] = QPoint( r.width(), linebot );
01174                             linetop = linebot + 5;
01175                         } else {
01176                             // just dotlinery
01177                             dotlines[c++] = QPoint( bx+1, linebot );
01178                             dotlines[c++] = QPoint( r.width(), linebot );
01179                         }
01180 
01181                         y += child->totalHeight();
01182                         child = child->nextSibling();
01183                     }
01184 
01185                     if ( child ) // there's a child, so move linebot to edge of rectangle
01186                         linebot = r.height();
01187 
01188                     if ( linetop < linebot )
01189                     {
01190                         dotlines[c++] = QPoint( bx, linetop );
01191                         dotlines[c++] = QPoint( bx, linebot );
01192                     }
01193                 }
01194 
01195                 // Draw all the branches...
01196                 static int thickness = kPixelMetric( KPM_ListViewBranchThickness );
01197                 int line; // index into dotlines
01198                 QRect branchrect;
01199                 QStyle::StyleFlags branchflags;
01200                 for( line = 0; line < c; line += 2 )
01201                 {
01202                     // assumptions here: lines are horizontal or vertical.
01203                     // lines always start with the numerically lowest
01204                     // coordinate.
01205 
01206                     // point ... relevant coordinate of current point
01207                     // end ..... same coordinate of the end of the current line
01208                     // other ... the other coordinate of the current point/line
01209                     if ( dotlines[line].y() == dotlines[line+1].y() )
01210                     {
01211                         // Horizontal branch
01212                         int end = dotlines[line+1].x();
01213                         int point = dotlines[line].x();
01214                         int other = dotlines[line].y();
01215 
01216                         branchrect  = QRect( point, other-(thickness/2), end-point, thickness );
01217                         branchflags = QStyle::Style_Horizontal;
01218 
01219                         // KStyle extension: Draw the horizontal branch
01220                         drawKStylePrimitive( KPE_ListViewBranch, p, NULL, branchrect, cg, branchflags, opt );
01221 
01222                     } else {
01223                         // Vertical branch
01224                         int end = dotlines[line+1].y();
01225                         int point = dotlines[line].y();
01226                         int other = dotlines[line].x();
01227                         int pixmapoffset = ((point & 1) != dotoffset ) ? 1 : 0;
01228 
01229                         branchrect  = QRect( other-(thickness/2), point, thickness, end-point );
01230                         if (!pixmapoffset)  // ### Hackish - used to hint the offset
01231                             branchflags = QStyle::Style_NoChange;
01232                         else
01233                             branchflags = QStyle::Style_Default;
01234 
01235                         // KStyle extension: Draw the vertical branch
01236                         drawKStylePrimitive( KPE_ListViewBranch, p, NULL, branchrect, cg, branchflags, opt );
01237                     }
01238                 }
01239             }
01240             break;
01241         }
01242 
01243         default:
01244             QCommonStyle::drawComplexControl( control, p, widget, r, cg,
01245                                               flags, controls, active, opt );
01246             break;
01247     }
01248 }
01249 
01250 
01251 QStyle::SubControl KStyle::querySubControl( ComplexControl control,
01252                                             const QWidget* widget,
01253                                             const QPoint &pos,
01254                                             const QStyleOption &opt ) const
01255 {
01256     QStyle::SubControl ret = QCommonStyle::querySubControl(control, widget, pos, opt);
01257 
01258     if (d->scrollbarType == ThreeButtonScrollBar) {
01259         // Enable third button
01260         if (control == CC_ScrollBar && ret == SC_None)
01261             ret = SC_ScrollBarSubLine;
01262     }
01263     return ret;
01264 }
01265 
01266 
01267 QRect KStyle::querySubControlMetrics( ComplexControl control,
01268                                       const QWidget* widget,
01269                                       SubControl sc,
01270                                       const QStyleOption &opt ) const
01271 {
01272     QRect ret;
01273 
01274     if (control == CC_ScrollBar)
01275     {
01276         bool threeButtonScrollBar = d->scrollbarType & ThreeButtonScrollBar;
01277         bool platinumScrollBar    = d->scrollbarType & PlatinumStyleScrollBar;
01278         bool nextScrollBar        = d->scrollbarType & NextStyleScrollBar;
01279 
01280         const QScrollBar *sb = (const QScrollBar*)widget;
01281         bool horizontal = sb->orientation() == Qt::Horizontal;
01282         int sliderstart = sb->sliderStart();
01283         int sbextent    = pixelMetric(PM_ScrollBarExtent, widget);
01284         int maxlen      = (horizontal ? sb->width() : sb->height())
01285                           - (sbextent * (threeButtonScrollBar ? 3 : 2));
01286         int sliderlen;
01287 
01288         // calculate slider length
01289         if (sb->maxValue() != sb->minValue())
01290         {
01291             uint range = sb->maxValue() - sb->minValue();
01292             sliderlen = (sb->pageStep() * maxlen) / (range + sb->pageStep());
01293 
01294             int slidermin = pixelMetric( PM_ScrollBarSliderMin, widget );
01295             if ( sliderlen < slidermin || range > INT_MAX / 2 )
01296                 sliderlen = slidermin;
01297             if ( sliderlen > maxlen )
01298                 sliderlen = maxlen;
01299         } else
01300             sliderlen = maxlen;
01301 
01302         // Subcontrols
01303         switch (sc)
01304         {
01305             case SC_ScrollBarSubLine: {
01306                 // top/left button
01307                 if (platinumScrollBar) {
01308                     if (horizontal)
01309                         ret.setRect(sb->width() - 2 * sbextent, 0, sbextent, sbextent);
01310                     else
01311                         ret.setRect(0, sb->height() - 2 * sbextent, sbextent, sbextent);
01312                 } else
01313                     ret.setRect(0, 0, sbextent, sbextent);
01314                 break;
01315             }
01316 
01317             case SC_ScrollBarAddLine: {
01318                 // bottom/right button
01319                 if (nextScrollBar) {
01320                     if (horizontal)
01321                         ret.setRect(sbextent, 0, sbextent, sbextent);
01322                     else
01323                         ret.setRect(0, sbextent, sbextent, sbextent);
01324                 } else {
01325                     if (horizontal)
01326                         ret.setRect(sb->width() - sbextent, 0, sbextent, sbextent);
01327                     else
01328                         ret.setRect(0, sb->height() - sbextent, sbextent, sbextent);
01329                 }
01330                 break;
01331             }
01332 
01333             case SC_ScrollBarSubPage: {
01334                 // between top/left button and slider
01335                 if (platinumScrollBar) {
01336                     if (horizontal)
01337                         ret.setRect(0, 0, sliderstart, sbextent);
01338                     else
01339                         ret.setRect(0, 0, sbextent, sliderstart);
01340                 } else if (nextScrollBar) {
01341                     if (horizontal)
01342                         ret.setRect(sbextent*2, 0, sliderstart-2*sbextent, sbextent);
01343                     else
01344                         ret.setRect(0, sbextent*2, sbextent, sliderstart-2*sbextent);
01345                 } else {
01346                     if (horizontal)
01347                         ret.setRect(sbextent, 0, sliderstart - sbextent, sbextent);
01348                     else
01349                         ret.setRect(0, sbextent, sbextent, sliderstart - sbextent);
01350                 }
01351                 break;
01352             }
01353 
01354             case SC_ScrollBarAddPage: {
01355                 // between bottom/right button and slider
01356                 int fudge;
01357 
01358                 if (platinumScrollBar)
01359                     fudge = 0;
01360                 else if (nextScrollBar)
01361                     fudge = 2*sbextent;
01362                 else
01363                     fudge = sbextent;
01364 
01365                 if (horizontal)
01366                     ret.setRect(sliderstart + sliderlen, 0,
01367                             maxlen - sliderstart - sliderlen + fudge, sbextent);
01368                 else
01369                     ret.setRect(0, sliderstart + sliderlen, sbextent,
01370                             maxlen - sliderstart - sliderlen + fudge);
01371                 break;
01372             }
01373 
01374             case SC_ScrollBarGroove: {
01375                 int multi = threeButtonScrollBar ? 3 : 2;
01376                 int fudge;
01377 
01378                 if (platinumScrollBar)
01379                     fudge = 0;
01380                 else if (nextScrollBar)
01381                     fudge = 2*sbextent;
01382                 else
01383                     fudge = sbextent;
01384 
01385                 if (horizontal)
01386                     ret.setRect(fudge, 0, sb->width() - sbextent * multi, sb->height());
01387                 else
01388                     ret.setRect(0, fudge, sb->width(), sb->height() - sbextent * multi);
01389                 break;
01390             }
01391 
01392             case SC_ScrollBarSlider: {
01393                 if (horizontal)
01394                     ret.setRect(sliderstart, 0, sliderlen, sbextent);
01395                 else
01396                     ret.setRect(0, sliderstart, sbextent, sliderlen);
01397                 break;
01398             }
01399 
01400             default:
01401                 ret = QCommonStyle::querySubControlMetrics(control, widget, sc, opt);
01402                 break;
01403         }
01404     } else
01405         ret = QCommonStyle::querySubControlMetrics(control, widget, sc, opt);
01406 
01407     return ret;
01408 }
01409 
01410 static const char * const kstyle_close_xpm[] = {
01411 "12 12 2 1",
01412 "# c #000000",
01413 ". c None",
01414 "............",
01415 "............",
01416 "..##....##..",
01417 "...##..##...",
01418 "....####....",
01419 ".....##.....",
01420 "....####....",
01421 "...##..##...",
01422 "..##....##..",
01423 "............",
01424 "............",
01425 "............"};
01426 
01427 static const char * const kstyle_maximize_xpm[]={
01428 "12 12 2 1",
01429 "# c #000000",
01430 ". c None",
01431 "............",
01432 "............",
01433 ".##########.",
01434 ".##########.",
01435 ".#........#.",
01436 ".#........#.",
01437 ".#........#.",
01438 ".#........#.",
01439 ".#........#.",
01440 ".#........#.",
01441 ".##########.",
01442 "............"};
01443 
01444 
01445 static const char * const kstyle_minimize_xpm[] = {
01446 "12 12 2 1",
01447 "# c #000000",
01448 ". c None",
01449 "............",
01450 "............",
01451 "............",
01452 "............",
01453 "............",
01454 "............",
01455 "............",
01456 "...######...",
01457 "...######...",
01458 "............",
01459 "............",
01460 "............"};
01461 
01462 static const char * const kstyle_normalizeup_xpm[] = {
01463 "12 12 2 1",
01464 "# c #000000",
01465 ". c None",
01466 "............",
01467 "...#######..",
01468 "...#######..",
01469 "...#.....#..",
01470 ".#######.#..",
01471 ".#######.#..",
01472 ".#.....#.#..",
01473 ".#.....###..",
01474 ".#.....#....",
01475 ".#.....#....",
01476 ".#######....",
01477 "............"};
01478 
01479 
01480 static const char * const kstyle_shade_xpm[] = {
01481 "12 12 2 1",
01482 "# c #000000",
01483 ". c None",
01484 "............",
01485 "............",
01486 "............",
01487 "............",
01488 "............",
01489 ".....#......",
01490 "....###.....",
01491 "...#####....",
01492 "..#######...",
01493 "............",
01494 "............",
01495 "............"};
01496 
01497 static const char * const kstyle_unshade_xpm[] = {
01498 "12 12 2 1",
01499 "# c #000000",
01500 ". c None",
01501 "............",
01502 "............",
01503 "............",
01504 "............",
01505 "..#######...",
01506 "...#####....",
01507 "....###.....",
01508 ".....#......",
01509 "............",
01510 "............",
01511 "............",
01512 "............"};
01513 
01514 static const char * dock_window_close_xpm[] = {
01515 "8 8 2 1",
01516 "# c #000000",
01517 ". c None",
01518 "##....##",
01519 ".##..##.",
01520 "..####..",
01521 "...##...",
01522 "..####..",
01523 ".##..##.",
01524 "##....##",
01525 "........"};
01526 
01527 // Message box icons, from page 210 of the Windows style guide.
01528 
01529 // Hand-drawn to resemble Microsoft's icons, but in the Mac/Netscape
01530 // palette.  The "question mark" icon, which Microsoft recommends not
01531 // using but a lot of people still use, is left out.
01532 
01533 /* XPM */
01534 static const char * const information_xpm[]={
01535 "32 32 5 1",
01536 ". c None",
01537 "c c #000000",
01538 "* c #999999",
01539 "a c #ffffff",
01540 "b c #0000ff",
01541 "...........********.............",
01542 "........***aaaaaaaa***..........",
01543 "......**aaaaaaaaaaaaaa**........",
01544 ".....*aaaaaaaaaaaaaaaaaa*.......",
01545 "....*aaaaaaaabbbbaaaaaaaac......",
01546 "...*aaaaaaaabbbbbbaaaaaaaac.....",
01547 "..*aaaaaaaaabbbbbbaaaaaaaaac....",
01548 ".*aaaaaaaaaaabbbbaaaaaaaaaaac...",
01549 ".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..",
01550 "*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.",
01551 "*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.",
01552 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
01553 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
01554 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
01555 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
01556 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
01557 ".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
01558 ".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
01559 "..*aaaaaaaaaabbbbbaaaaaaaaac***.",
01560 "...caaaaaaabbbbbbbbbaaaaaac****.",
01561 "....caaaaaaaaaaaaaaaaaaaac****..",
01562 ".....caaaaaaaaaaaaaaaaaac****...",
01563 "......ccaaaaaaaaaaaaaacc****....",
01564 ".......*cccaaaaaaaaccc*****.....",
01565 "........***cccaaaac*******......",
01566 "..........****caaac*****........",
01567 ".............*caaac**...........",
01568 "...............caac**...........",
01569 "................cac**...........",
01570 ".................cc**...........",
01571 "..................***...........",
01572 "...................**..........."};
01573 /* XPM */
01574 static const char* const warning_xpm[]={
01575 "32 32 4 1",
01576 ". c None",
01577 "a c #ffff00",
01578 "* c #000000",
01579 "b c #999999",
01580 ".............***................",
01581 "............*aaa*...............",
01582 "...........*aaaaa*b.............",
01583 "...........*aaaaa*bb............",
01584 "..........*aaaaaaa*bb...........",
01585 "..........*aaaaaaa*bb...........",
01586 ".........*aaaaaaaaa*bb..........",
01587 ".........*aaaaaaaaa*bb..........",
01588 "........*aaaaaaaaaaa*bb.........",
01589 "........*aaaa***aaaa*bb.........",
01590 ".......*aaaa*****aaaa*bb........",
01591 ".......*aaaa*****aaaa*bb........",
01592 "......*aaaaa*****aaaaa*bb.......",
01593 "......*aaaaa*****aaaaa*bb.......",
01594 ".....*aaaaaa*****aaaaaa*bb......",
01595 ".....*aaaaaa*****aaaaaa*bb......",
01596 "....*aaaaaaaa***aaaaaaaa*bb.....",
01597 "....*aaaaaaaa***aaaaaaaa*bb.....",
01598 "...*aaaaaaaaa***aaaaaaaaa*bb....",
01599 "...*aaaaaaaaaa*aaaaaaaaaa*bb....",
01600 "..*aaaaaaaaaaa*aaaaaaaaaaa*bb...",
01601 "..*aaaaaaaaaaaaaaaaaaaaaaa*bb...",
01602 ".*aaaaaaaaaaaa**aaaaaaaaaaa*bb..",
01603 ".*aaaaaaaaaaa****aaaaaaaaaa*bb..",
01604 "*aaaaaaaaaaaa****aaaaaaaaaaa*bb.",
01605 "*aaaaaaaaaaaaa**aaaaaaaaaaaa*bb.",
01606 "*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb",
01607 "*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb",
01608 ".*aaaaaaaaaaaaaaaaaaaaaaaaa*bbbb",
01609 "..*************************bbbbb",
01610 "....bbbbbbbbbbbbbbbbbbbbbbbbbbb.",
01611 ".....bbbbbbbbbbbbbbbbbbbbbbbbb.."};
01612 /* XPM */
01613 static const char* const critical_xpm[]={
01614 "32 32 4 1",
01615 ". c None",
01616 "a c #999999",
01617 "* c #ff0000",
01618 "b c #ffffff",
01619 "...........********.............",
01620 ".........************...........",
01621 ".......****************.........",
01622 "......******************........",
01623 ".....********************a......",
01624 "....**********************a.....",
01625 "...************************a....",
01626 "..*******b**********b*******a...",
01627 "..******bbb********bbb******a...",
01628 ".******bbbbb******bbbbb******a..",
01629 ".*******bbbbb****bbbbb*******a..",
01630 "*********bbbbb**bbbbb*********a.",
01631 "**********bbbbbbbbbb**********a.",
01632 "***********bbbbbbbb***********aa",
01633 "************bbbbbb************aa",
01634 "************bbbbbb************aa",
01635 "***********bbbbbbbb***********aa",
01636 "**********bbbbbbbbbb**********aa",
01637 "*********bbbbb**bbbbb*********aa",
01638 ".*******bbbbb****bbbbb*******aa.",
01639 ".******bbbbb******bbbbb******aa.",
01640 "..******bbb********bbb******aaa.",
01641 "..*******b**********b*******aa..",
01642 "...************************aaa..",
01643 "....**********************aaa...",
01644 "....a********************aaa....",
01645 ".....a******************aaa.....",
01646 "......a****************aaa......",
01647 ".......aa************aaaa.......",
01648 ".........aa********aaaaa........",
01649 "...........aaaaaaaaaaa..........",
01650 ".............aaaaaaa............"};
01651 
01652 QPixmap KStyle::stylePixmap( StylePixmap stylepixmap,
01653                           const QWidget* widget,
01654                           const QStyleOption& opt) const
01655 {
01656     switch (stylepixmap) {
01657         case SP_TitleBarShadeButton:
01658             return QPixmap(const_cast<const char**>(kstyle_shade_xpm));
01659         case SP_TitleBarUnshadeButton:
01660             return QPixmap(const_cast<const char**>(kstyle_unshade_xpm));
01661         case SP_TitleBarNormalButton:
01662             return QPixmap(const_cast<const char**>(kstyle_normalizeup_xpm));
01663         case SP_TitleBarMinButton:
01664             return QPixmap(const_cast<const char**>(kstyle_minimize_xpm));
01665         case SP_TitleBarMaxButton:
01666             return QPixmap(const_cast<const char**>(kstyle_maximize_xpm));
01667         case SP_TitleBarCloseButton:
01668             return QPixmap(const_cast<const char**>(kstyle_close_xpm));
01669         case SP_DockWindowCloseButton:
01670             return QPixmap(const_cast<const char**>(dock_window_close_xpm ));
01671         case SP_MessageBoxInformation:
01672             return QPixmap(const_cast<const char**>(information_xpm));
01673         case SP_MessageBoxWarning:
01674             return QPixmap(const_cast<const char**>(warning_xpm));
01675         case SP_MessageBoxCritical:
01676             return QPixmap(const_cast<const char**>(critical_xpm));
01677         default:
01678             break;
01679     }
01680     return QCommonStyle::stylePixmap(stylepixmap, widget, opt);
01681 }
01682 
01683 
01684 int KStyle::styleHint( StyleHint sh, const QWidget* w,
01685                        const QStyleOption &opt, QStyleHintReturn* shr) const
01686 {
01687     switch (sh)
01688     {
01689         case SH_EtchDisabledText:
01690             return d->etchDisabledText ? 1 : 0;
01691 
01692         case SH_PopupMenu_Scrollable:
01693             return d->scrollablePopupmenus ? 1 : 0;
01694 
01695         case SH_MenuBar_AltKeyNavigation:
01696             return d->menuAltKeyNavigation ? 1 : 0;
01697 
01698         case SH_PopupMenu_SubMenuPopupDelay:
01699             return d->popupMenuDelay;
01700 
01701         case SH_ItemView_ChangeHighlightOnFocus:
01702         case SH_Slider_SloppyKeyEvents:
01703         case SH_MainWindow_SpaceBelowMenuBar:
01704             return 0;
01705 
01706         case SH_Slider_SnapToValue:
01707         case SH_PrintDialog_RightAlignButtons:
01708         case SH_FontDialog_SelectAssociatedText:
01709         case SH_PopupMenu_AllowActiveAndDisabled:
01710         case SH_MenuBar_MouseTracking:
01711         case SH_PopupMenu_MouseTracking:
01712         case SH_ComboBox_ListMouseTracking:
01713         case SH_ScrollBar_MiddleClickAbsolutePosition:
01714             return 1;
01715 
01716         default:
01717             return QCommonStyle::styleHint(sh, w, opt, shr);
01718     }
01719 }
01720 
01721 
01722 bool KStyle::eventFilter( QObject* object, QEvent* event )
01723 {
01724     if ( d->useFilledFrameWorkaround )
01725     {
01726         // Make the QMenuBar/QToolBar paintEvent() cover a larger area to
01727         // ensure that the filled frame contents are properly painted.
01728         // We essentially modify the paintEvent's rect to include the
01729         // panel border, which also paints the widget's interior.
01730         // This is nasty, but I see no other way to properly repaint
01731         // filled frames in all QMenuBars and QToolBars.
01732         // -- Karol.
01733         if (event->type() == QEvent::Paint)
01734         {
01735             QMenuBar* menubar = 0;
01736             QToolBar* toolbar = 0;
01737             if (object->inherits("QMenuBar"))
01738                 menubar = static_cast<QMenuBar*>(object);
01739             else if (object->inherits("QToolBar"))
01740                 toolbar = static_cast<QToolBar*>(object);
01741             if ( menubar || toolbar )
01742             {
01743                 bool horizontal = true;
01744                 QPaintEvent* pe = (QPaintEvent*)event;
01745                 QFrame* frame   = (QFrame*)object;
01746                 QRect r = pe->rect();
01747 
01748                 if (toolbar && toolbar->orientation() == Qt::Vertical)
01749                     horizontal = false;
01750 
01751                 if (horizontal) {
01752                     if ( r.height() == frame->height() )
01753                         return false;   // Let QFrame handle the painting now.
01754 
01755                     // Else, send a new paint event with an updated paint rect.
01756                     QPaintEvent dummyPE( QRect( r.x(), 0, r.width(), frame->height()) );
01757                     QApplication::sendEvent( frame, &dummyPE );
01758                 }
01759                 else {  // Vertical
01760                     if ( r.width() == frame->width() )
01761                         return false;
01762 
01763                     QPaintEvent dummyPE( QRect( 0, r.y(), frame->width(), r.height()) );
01764                     QApplication::sendEvent( frame, &dummyPE );
01765                 }
01766 
01767                 // Discard this event as we sent a new paintEvent.
01768                 return true;
01769             }
01770         }
01771     }
01772 
01773     return false;
01774 }
01775 
01776 
01777 // -----------------------------------------------------------------------------
01778 // I N T E R N A L -  KStyle menu transparency handler
01779 // -----------------------------------------------------------------------------
01780 
01781 TransparencyHandler::TransparencyHandler( KStyle* style,
01782     TransparencyEngine tEngine, float menuOpacity, bool useDropShadow )
01783     : QObject()
01784 {
01785     te = tEngine;
01786     kstyle = style;
01787     opacity = menuOpacity;
01788     dropShadow = useDropShadow;
01789     pix.setOptimization(QPixmap::BestOptim);
01790 };
01791 
01792 TransparencyHandler::~TransparencyHandler()
01793 {
01794 };
01795 
01796 // This is meant to be ugly but fast.
01797 void TransparencyHandler::rightShadow(QImage& dst)
01798 {
01799     if (dst.depth() != 32)
01800         dst = dst.convertDepth(32);
01801 
01802     // blend top-right corner.
01803     int pixels = dst.width() * dst.height();
01804 #ifdef WORDS_BIGENDIAN
01805     register unsigned char* data = dst.bits() + 1;  // Skip alpha
01806 #else
01807     register unsigned char* data = dst.bits();      // Skip alpha
01808 #endif
01809     for(register int i = 0; i < 16; i++) {
01810         *data++ = (unsigned char)((*data)*top_right_corner[i]);
01811         *data++ = (unsigned char)((*data)*top_right_corner[i]);
01812         *data++ = (unsigned char)((*data)*top_right_corner[i]);
01813         data++; // skip alpha
01814     }
01815 
01816     pixels -= 32;   // tint right strip without rounded edges.
01817     register int c = 0;
01818     for(register int i = 0; i < pixels; i++) {
01819         *data++ = (unsigned char)((*data)*shadow_strip[c]);
01820         *data++ = (unsigned char)((*data)*shadow_strip[c]);
01821         *data++ = (unsigned char)((*data)*shadow_strip[c]);
01822         data++; // skip alpha
01823         c = ++c % 4;
01824     }
01825 
01826     // tint bottom edge
01827     for(register int i = 0; i < 16; i++) {
01828         *data++ = (unsigned char)((*data)*bottom_right_corner[i]);
01829         *data++ = (unsigned char)((*data)*bottom_right_corner[i]);
01830         *data++ = (unsigned char)((*data)*bottom_right_corner[i]);
01831         data++; // skip alpha
01832     }
01833 }
01834 
01835 void TransparencyHandler::bottomShadow(QImage& dst)
01836 {
01837     if (dst.depth() != 32)
01838         dst = dst.convertDepth(32);
01839 
01840     int line = 0;
01841     int width = dst.width() - 4;
01842     double strip_data = shadow_strip[0];
01843     double* corner = const_cast<double*>(bottom_left_corner);
01844 
01845 #ifdef WORDS_BIGENDIAN
01846     register unsigned char* data = dst.bits() + 1;  // Skip alpha
01847 #else
01848     register unsigned char* data = dst.bits();  // Skip alpha
01849 #endif
01850 
01851     for(int y = 0; y < 4; y++)
01852     {
01853         // Bottom-left Corner
01854         for(register int x = 0; x < 4; x++) {
01855             *data++ = (unsigned char)((*data)*(*corner));
01856             *data++ = (unsigned char)((*data)*(*corner));
01857             *data++ = (unsigned char)((*data)*(*corner));
01858             data++; // skip alpha
01859             corner++;
01860         }
01861 
01862         // Scanline
01863         for(register int x = 0; x < width; x++) {
01864             *data++ = (unsigned char)((*data)*strip_data);
01865             *data++ = (unsigned char)((*data)*strip_data);
01866             *data++ = (unsigned char)((*data)*strip_data);
01867             data++;
01868         }
01869 
01870         strip_data = shadow_strip[++line];
01871     }
01872 }
01873 
01874 // Create a shadow of thickness 4.
01875 void TransparencyHandler::createShadowWindows(const QPopupMenu* p)
01876 {
01877     int x2 = p->x()+p->width();
01878     int y2 = p->y()+p->height();
01879     QRect shadow1(x2, p->y() + 4, 4, p->height());
01880     QRect shadow2(p->x() + 4, y2, p->width() - 4, 4);
01881 
01882     // Create a fake drop-down shadow effect via blended Xwindows
01883     ShadowElements se;
01884     se.w1 = new QWidget(0, 0, WStyle_Customize | WType_Popup | WX11BypassWM );
01885     se.w2 = new QWidget(0, 0, WStyle_Customize | WType_Popup | WX11BypassWM );
01886     se.w1->setGeometry(shadow1);
01887     se.w2->setGeometry(shadow2);
01888     XSelectInput(qt_xdisplay(), se.w1->winId(), StructureNotifyMask );
01889     XSelectInput(qt_xdisplay(), se.w2->winId(), StructureNotifyMask );
01890 
01891     // Insert a new ShadowMap entry
01892     shadowMap()[p] = se;
01893 
01894     // Some hocus-pocus here to create the drop-shadow.
01895     QPixmap pix_shadow1 = QPixmap::grabWindow(qt_xrootwin(),
01896             shadow1.x(), shadow1.y(), shadow1.width(), shadow1.height());
01897     QPixmap pix_shadow2 = QPixmap::grabWindow(qt_xrootwin(),
01898             shadow2.x(), shadow2.y(), shadow2.width(), shadow2.height());
01899 
01900     QImage img;
01901     img = pix_shadow1.convertToImage();
01902     rightShadow(img);
01903     pix_shadow1.convertFromImage(img);
01904     img = pix_shadow2.convertToImage();
01905     bottomShadow(img);
01906     pix_shadow2.convertFromImage(img);
01907 
01908     // Set the background pixmaps
01909     se.w1->setErasePixmap(pix_shadow1);
01910     se.w2->setErasePixmap(pix_shadow2);
01911 
01912     // Show the 'shadow' just before showing the popup menu window
01913     // Don't use QWidget::show() so we don't confuse QEffects, thus causing broken focus.
01914     XMapWindow(qt_xdisplay(), se.w1->winId());
01915     XMapWindow(qt_xdisplay(), se.w2->winId());
01916 }
01917 
01918 void TransparencyHandler::removeShadowWindows(const QPopupMenu* p)
01919 {
01920     ShadowMap::iterator it = shadowMap().find(p);
01921     if (it != shadowMap().end())
01922     {
01923         ShadowElements se = it.data();
01924         XUnmapWindow(qt_xdisplay(), se.w1->winId());    // hide
01925         XUnmapWindow(qt_xdisplay(), se.w2->winId());
01926         XFlush(qt_xdisplay());                          // try to hide faster
01927         delete se.w1;
01928         delete se.w2;
01929         shadowMap().erase(it);
01930     }
01931 }
01932 
01933 bool TransparencyHandler::eventFilter( QObject* object, QEvent* event )
01934 {
01935     // Transparency idea was borrowed from KDE2's "MegaGradient" Style,
01936     // Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org>
01937 
01938     // Added 'fake' menu shadows <04-Jul-2002> -- Karol
01939     QPopupMenu* p = (QPopupMenu*)object;
01940     QEvent::Type et = event->type();
01941 
01942     if (et == QEvent::Show)
01943     {
01944         // Handle translucency
01945         if (te != Disabled)
01946         {
01947             pix = QPixmap::grabWindow(qt_xrootwin(),
01948                     p->x(), p->y(), p->width(), p->height());
01949 
01950             switch (te) {
01951 #ifdef HAVE_XRENDER
01952                 case XRender:
01953                     if (qt_use_xrender) {
01954                         XRenderBlendToPixmap(p);
01955                         break;
01956                     }
01957                     // Fall through intended
01958 #else
01959                 case XRender:
01960 #endif
01961                 case SoftwareBlend:
01962                     blendToPixmap(p->colorGroup(), p);
01963                     break;
01964 
01965                 case SoftwareTint:
01966                 default:
01967                     blendToColor(p->colorGroup().button());
01968             };
01969 
01970             p->setErasePixmap(pix);
01971         }
01972 
01973         // Handle drop shadow
01974         // * FIXME : !shadowMap().contains(p) is a workaround for leftover
01975         // * shadows after duplicate show events.
01976         // * TODO : determine real cause for duplicate events
01977         // * till 20021005
01978         if (dropShadow && p->width() > 16 && p->height() > 16 && !shadowMap().contains( p ))
01979             createShadowWindows(p);
01980     }
01981     else if (et == QEvent::Hide)
01982     {
01983         // Handle drop shadow
01984         if (dropShadow)
01985             removeShadowWindows(p);
01986 
01987         // Handle translucency
01988         if (te != Disabled)
01989             p->setErasePixmap(QPixmap());
01990     }
01991 
01992     return false;
01993 }
01994 
01995 
01996 // Blends a QImage to a predefined color, with a given opacity.
01997 void TransparencyHandler::blendToColor(const QColor &col)
01998 {
01999     if (opacity < 0.0 || opacity > 1.0)
02000         return;
02001 
02002     QImage img = pix.convertToImage();
02003     KImageEffect::blend(col, img, opacity);
02004     pix.convertFromImage(img);
02005 }
02006 
02007 
02008 void TransparencyHandler::blendToPixmap(const QColorGroup &cg, const QPopupMenu* p)
02009 {
02010     if (opacity < 0.0 || opacity > 1.0)
02011         return;
02012 
02013     KPixmap blendPix;
02014     blendPix.resize( pix.width(), pix.height() );
02015 
02016     if (blendPix.width()  != pix.width() ||
02017         blendPix.height() != pix.height())
02018         return;
02019 
02020     // Allow styles to define the blend pixmap - allows for some interesting effects.
02021     kstyle->renderMenuBlendPixmap( blendPix, cg, p );
02022 
02023     QImage blendImg = blendPix.convertToImage();
02024     QImage backImg  = pix.convertToImage();
02025     KImageEffect::blend(blendImg, backImg, opacity);
02026     pix.convertFromImage(backImg);
02027 }
02028 
02029 
02030 #ifdef HAVE_XRENDER
02031 // Here we go, use XRender in all its glory.
02032 // NOTE: This is actually a bit slower than the above routines
02033 // on non-accelerated displays. -- Karol.
02034 void TransparencyHandler::XRenderBlendToPixmap(const QPopupMenu* p)
02035 {
02036     KPixmap renderPix;
02037     renderPix.resize( pix.width(), pix.height() );
02038 
02039     // Allow styles to define the blend pixmap - allows for some interesting effects.
02040     kstyle->renderMenuBlendPixmap( renderPix, p->colorGroup(), p );
02041 
02042     Display* dpy = qt_xdisplay();
02043     Pixmap   alphaPixmap;
02044     Picture  alphaPicture;
02045     XRenderPictFormat        Rpf;
02046     XRenderPictureAttributes Rpa;
02047     XRenderColor clr;
02048     clr.alpha = ((unsigned short)(255*opacity) << 8);
02049 
02050     Rpf.type  = PictTypeDirect;
02051     Rpf.depth = 8;
02052     Rpf.direct.alphaMask = 0xff;
02053     Rpa.repeat = True;  // Tile
02054 
02055     XRenderPictFormat* xformat = XRenderFindFormat(dpy,
02056         PictFormatType | PictFormatDepth | PictFormatAlphaMask, &Rpf, 0);
02057 
02058     alphaPixmap = XCreatePixmap(dpy, p->handle(), 1, 1, 8);
02059     alphaPicture = XRenderCreatePicture(dpy, alphaPixmap, xformat, CPRepeat, &Rpa);
02060 
02061     XRenderFillRectangle(dpy, PictOpSrc, alphaPicture, &clr, 0, 0, 1, 1);
02062 
02063     XRenderComposite(dpy, PictOpOver,
02064             renderPix.x11RenderHandle(), alphaPicture, pix.x11RenderHandle(), // src, mask, dst
02065             0, 0,   // srcx,  srcy
02066             0, 0,   // maskx, masky
02067             0, 0,   // dstx,  dsty
02068             pix.width(), pix.height());
02069 
02070     XRenderFreePicture(dpy, alphaPicture);
02071     XFreePixmap(dpy, alphaPixmap);
02072 }
02073 #endif
02074 
02075 void KStyle::virtual_hook( int, void* )
02076 { /*BASE::virtual_hook( id, data );*/ }
02077 
02078 // vim: set noet ts=4 sw=4:
02079 
02080 #include "kstyle.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:20:30 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001