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