kstyle.cpp

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