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