kdefx Library API Documentation

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