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