kdefx Library API Documentation

kstyle.cpp

00001 /* 00002 * 00003 * KStyle 00004 * Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org> 00005 * 00006 * QWindowsStyle CC_ListView and style images were kindly donated by TrollTech, 00007 * Copyright (C) 1998-2000 TrollTech AS. 00008 * 00009 * Many thanks to Bradley T. Hughes for the 3 button scrollbar code. 00010 * 00011 * This library is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU Library General Public 00013 * License version 2 as published by the Free Software Foundation. 00014 * 00015 * This library is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Library General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Library General Public License 00021 * along with this library; see the file COPYING.LIB. If not, write to 00022 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00023 * Boston, MA 02111-1307, USA. 00024 */ 00025 00026 #ifdef HAVE_CONFIG_H 00027 #include "config.h" 00028 #endif 00029 00030 #include "kstyle.h" 00031 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", true); 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("krisp"); 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 #if QT_VERSION >= 0x030300 00987 case PM_MenuBarItemSpacing: 00988 return 5; 00989 00990 case PM_ToolBarItemSpacing: 00991 return 0; 00992 #endif 00993 case PM_PopupMenuScrollerHeight: 00994 return pixelMetric( PM_ScrollBarExtent, 0); 00995 00996 default: 00997 return QCommonStyle::pixelMetric( m, widget ); 00998 } 00999 } 01000 01001 //Helper to find the next sibling that's not hidden 01002 static QListViewItem* nextVisibleSibling(QListViewItem* item) 01003 { 01004 QListViewItem* sibling = item; 01005 do 01006 { 01007 sibling = sibling->nextSibling(); 01008 } 01009 while (sibling && !sibling->isVisible()); 01010 01011 return sibling; 01012 } 01013 01014 void KStyle::drawComplexControl( ComplexControl control, 01015 QPainter* p, 01016 const QWidget* widget, 01017 const QRect &r, 01018 const QColorGroup &cg, 01019 SFlags flags, 01020 SCFlags controls, 01021 SCFlags active, 01022 const QStyleOption &opt ) const 01023 { 01024 switch(control) 01025 { 01026 // 3 BUTTON SCROLLBAR 01027 // ------------------------------------------------------------------------ 01028 case CC_ScrollBar: { 01029 // Many thanks to Brad Hughes for contributing this code. 01030 bool useThreeButtonScrollBar = (d->scrollbarType & ThreeButtonScrollBar); 01031 01032 const QScrollBar *sb = (const QScrollBar*)widget; 01033 bool maxedOut = (sb->minValue() == sb->maxValue()); 01034 bool horizontal = (sb->orientation() == Qt::Horizontal); 01035 SFlags sflags = ((horizontal ? Style_Horizontal : Style_Default) | 01036 (maxedOut ? Style_Default : Style_Enabled)); 01037 01038 QRect addline, subline, subline2, addpage, subpage, slider, first, last; 01039 subline = querySubControlMetrics(control, widget, SC_ScrollBarSubLine, opt); 01040 addline = querySubControlMetrics(control, widget, SC_ScrollBarAddLine, opt); 01041 subpage = querySubControlMetrics(control, widget, SC_ScrollBarSubPage, opt); 01042 addpage = querySubControlMetrics(control, widget, SC_ScrollBarAddPage, opt); 01043 slider = querySubControlMetrics(control, widget, SC_ScrollBarSlider, opt); 01044 first = querySubControlMetrics(control, widget, SC_ScrollBarFirst, opt); 01045 last = querySubControlMetrics(control, widget, SC_ScrollBarLast, opt); 01046 subline2 = addline; 01047 01048 if ( useThreeButtonScrollBar ) 01049 if (horizontal) 01050 subline2.moveBy(-addline.width(), 0); 01051 else 01052 subline2.moveBy(0, -addline.height()); 01053 01054 // Draw the up/left button set 01055 if ((controls & SC_ScrollBarSubLine) && subline.isValid()) { 01056 drawPrimitive(PE_ScrollBarSubLine, p, subline, cg, 01057 sflags | (active == SC_ScrollBarSubLine ? 01058 Style_Down : Style_Default)); 01059 01060 if (useThreeButtonScrollBar && subline2.isValid()) 01061 drawPrimitive(PE_ScrollBarSubLine, p, subline2, cg, 01062 sflags | (active == SC_ScrollBarSubLine ? 01063 Style_Down : Style_Default)); 01064 } 01065 01066 if ((controls & SC_ScrollBarAddLine) && addline.isValid()) 01067 drawPrimitive(PE_ScrollBarAddLine, p, addline, cg, 01068 sflags | ((active == SC_ScrollBarAddLine) ? 01069 Style_Down : Style_Default)); 01070 01071 if ((controls & SC_ScrollBarSubPage) && subpage.isValid()) 01072 drawPrimitive(PE_ScrollBarSubPage, p, subpage, cg, 01073 sflags | ((active == SC_ScrollBarSubPage) ? 01074 Style_Down : Style_Default)); 01075 01076 if ((controls & SC_ScrollBarAddPage) && addpage.isValid()) 01077 drawPrimitive(PE_ScrollBarAddPage, p, addpage, cg, 01078 sflags | ((active == SC_ScrollBarAddPage) ? 01079 Style_Down : Style_Default)); 01080 01081 if ((controls & SC_ScrollBarFirst) && first.isValid()) 01082 drawPrimitive(PE_ScrollBarFirst, p, first, cg, 01083 sflags | ((active == SC_ScrollBarFirst) ? 01084 Style_Down : Style_Default)); 01085 01086 if ((controls & SC_ScrollBarLast) && last.isValid()) 01087 drawPrimitive(PE_ScrollBarLast, p, last, cg, 01088 sflags | ((active == SC_ScrollBarLast) ? 01089 Style_Down : Style_Default)); 01090 01091 if ((controls & SC_ScrollBarSlider) && slider.isValid()) { 01092 drawPrimitive(PE_ScrollBarSlider, p, slider, cg, 01093 sflags | ((active == SC_ScrollBarSlider) ? 01094 Style_Down : Style_Default)); 01095 // Draw focus rect 01096 if (sb->hasFocus()) { 01097 QRect fr(slider.x() + 2, slider.y() + 2, 01098 slider.width() - 5, slider.height() - 5); 01099 drawPrimitive(PE_FocusRect, p, fr, cg, Style_Default); 01100 } 01101 } 01102 break; 01103 } 01104 01105 01106 // SLIDER 01107 // ------------------------------------------------------------------- 01108 case CC_Slider: { 01109 const QSlider* slider = (const QSlider*)widget; 01110 QRect groove = querySubControlMetrics(CC_Slider, widget, SC_SliderGroove, opt); 01111 QRect handle = querySubControlMetrics(CC_Slider, widget, SC_SliderHandle, opt); 01112 01113 // Double-buffer slider for no flicker 01114 QPixmap pix(widget->size()); 01115 QPainter p2; 01116 p2.begin(&pix); 01117 01118 if ( slider->parentWidget() && 01119 slider->parentWidget()->backgroundPixmap() && 01120 !slider->parentWidget()->backgroundPixmap()->isNull() ) { 01121 QPixmap pixmap = *(slider->parentWidget()->backgroundPixmap()); 01122 p2.drawTiledPixmap(r, pixmap, slider->pos()); 01123 } else 01124 pix.fill(cg.background()); 01125 01126 // Draw slider groove 01127 if ((controls & SC_SliderGroove) && groove.isValid()) { 01128 drawKStylePrimitive( KPE_SliderGroove, &p2, widget, groove, cg, flags, opt ); 01129 01130 // Draw the focus rect around the groove 01131 if (slider->hasFocus()) 01132 drawPrimitive(PE_FocusRect, &p2, groove, cg); 01133 } 01134 01135 // Draw the tickmarks 01136 if (controls & SC_SliderTickmarks) 01137 QCommonStyle::drawComplexControl(control, &p2, widget, 01138 r, cg, flags, SC_SliderTickmarks, active, opt); 01139 01140 // Draw the slider handle 01141 if ((controls & SC_SliderHandle) && handle.isValid()) { 01142 if (active == SC_SliderHandle) 01143 flags |= Style_Active; 01144 drawKStylePrimitive( KPE_SliderHandle, &p2, widget, handle, cg, flags, opt ); 01145 } 01146 01147 p2.end(); 01148 bitBlt((QWidget*)widget, r.x(), r.y(), &pix); 01149 break; 01150 } 01151 01152 // LISTVIEW 01153 // ------------------------------------------------------------------- 01154 case CC_ListView: { 01155 01156 /* 01157 * Many thanks to TrollTech AS for donating CC_ListView from QWindowsStyle. 01158 * CC_ListView code is Copyright (C) 1998-2000 TrollTech AS. 01159 */ 01160 01161 // Paint the icon and text. 01162 if ( controls & SC_ListView ) 01163 QCommonStyle::drawComplexControl( control, p, widget, r, cg, flags, controls, active, opt ); 01164 01165 // If we're have a branch or are expanded... 01166 if ( controls & (SC_ListViewBranch | SC_ListViewExpand) ) 01167 { 01168 // If no list view item was supplied, break 01169 if (opt.isDefault()) 01170 break; 01171 01172 QListViewItem *item = opt.listViewItem(); 01173 QListViewItem *child = item->firstChild(); 01174 01175 int y = r.y(); 01176 int c; // dotline vertice count 01177 int dotoffset = 0; 01178 QPointArray dotlines; 01179 01180 if ( active == SC_All && controls == SC_ListViewExpand ) { 01181 // We only need to draw a vertical line 01182 c = 2; 01183 dotlines.resize(2); 01184 dotlines[0] = QPoint( r.right(), r.top() ); 01185 dotlines[1] = QPoint( r.right(), r.bottom() ); 01186 01187 } else { 01188 01189 int linetop = 0, linebot = 0; 01190 // each branch needs at most two lines, ie. four end points 01191 dotoffset = (item->itemPos() + item->height() - y) % 2; 01192 dotlines.resize( item->childCount() * 4 ); 01193 c = 0; 01194 01195 // skip the stuff above the exposed rectangle 01196 while ( child && y + child->height() <= 0 ) 01197 { 01198 y += child->totalHeight(); 01199 child = nextVisibleSibling(child); 01200 } 01201 01202 int bx = r.width() / 2; 01203 01204 // paint stuff in the magical area 01205 QListView* v = item->listView(); 01206 int lh = QMAX( p->fontMetrics().height() + 2 * v->itemMargin(), 01207 QApplication::globalStrut().height() ); 01208 if ( lh % 2 > 0 ) 01209 lh++; 01210 01211 // Draw all the expand/close boxes... 01212 QRect boxrect; 01213 QStyle::StyleFlags boxflags; 01214 while ( child && y < r.height() ) 01215 { 01216 linebot = y + lh/2; 01217 if ( (child->isExpandable() || child->childCount()) && 01218 (child->height() > 0) ) 01219 { 01220 // The primitive requires a rect. 01221 boxrect = QRect( bx-4, linebot-4, 9, 9 ); 01222 boxflags = child->isOpen() ? QStyle::Style_Off : QStyle::Style_On; 01223 01224 // KStyle extension: Draw the box and expand/collapse indicator 01225 drawKStylePrimitive( KPE_ListViewExpander, p, NULL, boxrect, cg, boxflags, opt ); 01226 01227 // dotlinery 01228 p->setPen( cg.mid() ); 01229 dotlines[c++] = QPoint( bx, linetop ); 01230 dotlines[c++] = QPoint( bx, linebot - 5 ); 01231 dotlines[c++] = QPoint( bx + 5, linebot ); 01232 dotlines[c++] = QPoint( r.width(), linebot ); 01233 linetop = linebot + 5; 01234 } else { 01235 // just dotlinery 01236 dotlines[c++] = QPoint( bx+1, linebot ); 01237 dotlines[c++] = QPoint( r.width(), linebot ); 01238 } 01239 01240 y += child->totalHeight(); 01241 child = nextVisibleSibling(child); 01242 } 01243 01244 if ( child ) // there's a child to draw, so move linebot to edge of rectangle 01245 linebot = r.height(); 01246 01247 if ( linetop < linebot ) 01248 { 01249 dotlines[c++] = QPoint( bx, linetop ); 01250 dotlines[c++] = QPoint( bx, linebot ); 01251 } 01252 } 01253 01254 // Draw all the branches... 01255 static int thickness = kPixelMetric( KPM_ListViewBranchThickness ); 01256 int line; // index into dotlines 01257 QRect branchrect; 01258 QStyle::StyleFlags branchflags; 01259 for( line = 0; line < c; line += 2 ) 01260 { 01261 // assumptions here: lines are horizontal or vertical. 01262 // lines always start with the numerically lowest 01263 // coordinate. 01264 01265 // point ... relevant coordinate of current point 01266 // end ..... same coordinate of the end of the current line 01267 // other ... the other coordinate of the current point/line 01268 if ( dotlines[line].y() == dotlines[line+1].y() ) 01269 { 01270 // Horizontal branch 01271 int end = dotlines[line+1].x(); 01272 int point = dotlines[line].x(); 01273 int other = dotlines[line].y(); 01274 01275 branchrect = QRect( point, other-(thickness/2), end-point, thickness ); 01276 branchflags = QStyle::Style_Horizontal; 01277 01278 // KStyle extension: Draw the horizontal branch 01279 drawKStylePrimitive( KPE_ListViewBranch, p, NULL, branchrect, cg, branchflags, opt ); 01280 01281 } else { 01282 // Vertical branch 01283 int end = dotlines[line+1].y(); 01284 int point = dotlines[line].y(); 01285 int other = dotlines[line].x(); 01286 int pixmapoffset = ((point & 1) != dotoffset ) ? 1 : 0; 01287 01288 branchrect = QRect( other-(thickness/2), point, thickness, end-point ); 01289 if (!pixmapoffset) // ### Hackish - used to hint the offset 01290 branchflags = QStyle::Style_NoChange; 01291 else 01292 branchflags = QStyle::Style_Default; 01293 01294 // KStyle extension: Draw the vertical branch 01295 drawKStylePrimitive( KPE_ListViewBranch, p, NULL, branchrect, cg, branchflags, opt ); 01296 } 01297 } 01298 } 01299 break; 01300 } 01301 01302 default: 01303 QCommonStyle::drawComplexControl( control, p, widget, r, cg, 01304 flags, controls, active, opt ); 01305 break; 01306 } 01307 } 01308 01309 01310 QStyle::SubControl KStyle::querySubControl( ComplexControl control, 01311 const QWidget* widget, 01312 const QPoint &pos, 01313 const QStyleOption &opt ) const 01314 { 01315 QStyle::SubControl ret = QCommonStyle::querySubControl(control, widget, pos, opt); 01316 01317 if (d->scrollbarType == ThreeButtonScrollBar) { 01318 // Enable third button 01319 if (control == CC_ScrollBar && ret == SC_None) 01320 ret = SC_ScrollBarSubLine; 01321 } 01322 return ret; 01323 } 01324 01325 01326 QRect KStyle::querySubControlMetrics( ComplexControl control, 01327 const QWidget* widget, 01328 SubControl sc, 01329 const QStyleOption &opt ) const 01330 { 01331 QRect ret; 01332 01333 if (control == CC_ScrollBar) 01334 { 01335 bool threeButtonScrollBar = d->scrollbarType & ThreeButtonScrollBar; 01336 bool platinumScrollBar = d->scrollbarType & PlatinumStyleScrollBar; 01337 bool nextScrollBar = d->scrollbarType & NextStyleScrollBar; 01338 01339 const QScrollBar *sb = (const QScrollBar*)widget; 01340 bool horizontal = sb->orientation() == Qt::Horizontal; 01341 int sliderstart = sb->sliderStart(); 01342 int sbextent = pixelMetric(PM_ScrollBarExtent, widget); 01343 int maxlen = (horizontal ? sb->width() : sb->height()) 01344 - (sbextent * (threeButtonScrollBar ? 3 : 2)); 01345 int sliderlen; 01346 01347 // calculate slider length 01348 if (sb->maxValue() != sb->minValue()) 01349 { 01350 uint range = sb->maxValue() - sb->minValue(); 01351 sliderlen = (sb->pageStep() * maxlen) / (range + sb->pageStep()); 01352 01353 int slidermin = pixelMetric( PM_ScrollBarSliderMin, widget ); 01354 if ( sliderlen < slidermin || range > INT_MAX / 2 ) 01355 sliderlen = slidermin; 01356 if ( sliderlen > maxlen ) 01357 sliderlen = maxlen; 01358 } else 01359 sliderlen = maxlen; 01360 01361 // Subcontrols 01362 switch (sc) 01363 { 01364 case SC_ScrollBarSubLine: { 01365 // top/left button 01366 if (platinumScrollBar) { 01367 if (horizontal) 01368 ret.setRect(sb->width() - 2 * sbextent, 0, sbextent, sbextent); 01369 else 01370 ret.setRect(0, sb->height() - 2 * sbextent, sbextent, sbextent); 01371 } else 01372 ret.setRect(0, 0, sbextent, sbextent); 01373 break; 01374 } 01375 01376 case SC_ScrollBarAddLine: { 01377 // bottom/right button 01378 if (nextScrollBar) { 01379 if (horizontal) 01380 ret.setRect(sbextent, 0, sbextent, sbextent); 01381 else 01382 ret.setRect(0, sbextent, sbextent, sbextent); 01383 } else { 01384 if (horizontal) 01385 ret.setRect(sb->width() - sbextent, 0, sbextent, sbextent); 01386 else 01387 ret.setRect(0, sb->height() - sbextent, sbextent, sbextent); 01388 } 01389 break; 01390 } 01391 01392 case SC_ScrollBarSubPage: { 01393 // between top/left button and slider 01394 if (platinumScrollBar) { 01395 if (horizontal) 01396 ret.setRect(0, 0, sliderstart, sbextent); 01397 else 01398 ret.setRect(0, 0, sbextent, sliderstart); 01399 } else if (nextScrollBar) { 01400 if (horizontal) 01401 ret.setRect(sbextent*2, 0, sliderstart-2*sbextent, sbextent); 01402 else 01403 ret.setRect(0, sbextent*2, sbextent, sliderstart-2*sbextent); 01404 } else { 01405 if (horizontal) 01406 ret.setRect(sbextent, 0, sliderstart - sbextent, sbextent); 01407 else 01408 ret.setRect(0, sbextent, sbextent, sliderstart - sbextent); 01409 } 01410 break; 01411 } 01412 01413 case SC_ScrollBarAddPage: { 01414 // between bottom/right button and slider 01415 int fudge; 01416 01417 if (platinumScrollBar) 01418 fudge = 0; 01419 else if (nextScrollBar) 01420 fudge = 2*sbextent; 01421 else 01422 fudge = sbextent; 01423 01424 if (horizontal) 01425 ret.setRect(sliderstart + sliderlen, 0, 01426 maxlen - sliderstart - sliderlen + fudge, sbextent); 01427 else 01428 ret.setRect(0, sliderstart + sliderlen, sbextent, 01429 maxlen - sliderstart - sliderlen + fudge); 01430 break; 01431 } 01432 01433 case SC_ScrollBarGroove: { 01434 int multi = threeButtonScrollBar ? 3 : 2; 01435 int fudge; 01436 01437 if (platinumScrollBar) 01438 fudge = 0; 01439 else if (nextScrollBar) 01440 fudge = 2*sbextent; 01441 else 01442 fudge = sbextent; 01443 01444 if (horizontal) 01445 ret.setRect(fudge, 0, sb->width() - sbextent * multi, sb->height()); 01446 else 01447 ret.setRect(0, fudge, sb->width(), sb->height() - sbextent * multi); 01448 break; 01449 } 01450 01451 case SC_ScrollBarSlider: { 01452 if (horizontal) 01453 ret.setRect(sliderstart, 0, sliderlen, sbextent); 01454 else 01455 ret.setRect(0, sliderstart, sbextent, sliderlen); 01456 break; 01457 } 01458 01459 default: 01460 ret = QCommonStyle::querySubControlMetrics(control, widget, sc, opt); 01461 break; 01462 } 01463 } else 01464 ret = QCommonStyle::querySubControlMetrics(control, widget, sc, opt); 01465 01466 return ret; 01467 } 01468 01469 static const char * const kstyle_close_xpm[] = { 01470 "12 12 2 1", 01471 "# c #000000", 01472 ". c None", 01473 "............", 01474 "............", 01475 "..##....##..", 01476 "...##..##...", 01477 "....####....", 01478 ".....##.....", 01479 "....####....", 01480 "...##..##...", 01481 "..##....##..", 01482 "............", 01483 "............", 01484 "............"}; 01485 01486 static const char * const kstyle_maximize_xpm[]={ 01487 "12 12 2 1", 01488 "# c #000000", 01489 ". c None", 01490 "............", 01491 "............", 01492 ".##########.", 01493 ".##########.", 01494 ".#........#.", 01495 ".#........#.", 01496 ".#........#.", 01497 ".#........#.", 01498 ".#........#.", 01499 ".#........#.", 01500 ".##########.", 01501 "............"}; 01502 01503 01504 static const char * const kstyle_minimize_xpm[] = { 01505 "12 12 2 1", 01506 "# c #000000", 01507 ". c None", 01508 "............", 01509 "............", 01510 "............", 01511 "............", 01512 "............", 01513 "............", 01514 "............", 01515 "...######...", 01516 "...######...", 01517 "............", 01518 "............", 01519 "............"}; 01520 01521 static const char * const kstyle_normalizeup_xpm[] = { 01522 "12 12 2 1", 01523 "# c #000000", 01524 ". c None", 01525 "............", 01526 "...#######..", 01527 "...#######..", 01528 "...#.....#..", 01529 ".#######.#..", 01530 ".#######.#..", 01531 ".#.....#.#..", 01532 ".#.....###..", 01533 ".#.....#....", 01534 ".#.....#....", 01535 ".#######....", 01536 "............"}; 01537 01538 01539 static const char * const kstyle_shade_xpm[] = { 01540 "12 12 2 1", 01541 "# c #000000", 01542 ". c None", 01543 "............", 01544 "............", 01545 "............", 01546 "............", 01547 "............", 01548 ".....#......", 01549 "....###.....", 01550 "...#####....", 01551 "..#######...", 01552 "............", 01553 "............", 01554 "............"}; 01555 01556 static const char * const kstyle_unshade_xpm[] = { 01557 "12 12 2 1", 01558 "# c #000000", 01559 ". c None", 01560 "............", 01561 "............", 01562 "............", 01563 "............", 01564 "..#######...", 01565 "...#####....", 01566 "....###.....", 01567 ".....#......", 01568 "............", 01569 "............", 01570 "............", 01571 "............"}; 01572 01573 static const char * const dock_window_close_xpm[] = { 01574 "8 8 2 1", 01575 "# c #000000", 01576 ". c None", 01577 "##....##", 01578 ".##..##.", 01579 "..####..", 01580 "...##...", 01581 "..####..", 01582 ".##..##.", 01583 "##....##", 01584 "........"}; 01585 01586 // Message box icons, from page 210 of the Windows style guide. 01587 01588 // Hand-drawn to resemble Microsoft's icons, but in the Mac/Netscape 01589 // palette. The "question mark" icon, which Microsoft recommends not 01590 // using but a lot of people still use, is left out. 01591 01592 /* XPM */ 01593 static const char * const information_xpm[]={ 01594 "32 32 5 1", 01595 ". c None", 01596 "c c #000000", 01597 "* c #999999", 01598 "a c #ffffff", 01599 "b c #0000ff", 01600 "...........********.............", 01601 "........***aaaaaaaa***..........", 01602 "......**aaaaaaaaaaaaaa**........", 01603 ".....*aaaaaaaaaaaaaaaaaa*.......", 01604 "....*aaaaaaaabbbbaaaaaaaac......", 01605 "...*aaaaaaaabbbbbbaaaaaaaac.....", 01606 "..*aaaaaaaaabbbbbbaaaaaaaaac....", 01607 ".*aaaaaaaaaaabbbbaaaaaaaaaaac...", 01608 ".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..", 01609 "*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.", 01610 "*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.", 01611 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", 01612 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", 01613 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", 01614 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", 01615 "*aaaaaaaaaaaabbbbbaaaaaaaaaaac**", 01616 ".*aaaaaaaaaaabbbbbaaaaaaaaaac***", 01617 ".*aaaaaaaaaaabbbbbaaaaaaaaaac***", 01618 "..*aaaaaaaaaabbbbbaaaaaaaaac***.", 01619 "...caaaaaaabbbbbbbbbaaaaaac****.", 01620 "....caaaaaaaaaaaaaaaaaaaac****..", 01621 ".....caaaaaaaaaaaaaaaaaac****...", 01622 "......ccaaaaaaaaaaaaaacc****....", 01623 ".......*cccaaaaaaaaccc*****.....", 01624 "........***cccaaaac*******......", 01625 "..........****caaac*****........", 01626 ".............*caaac**...........", 01627 "...............caac**...........", 01628 "................cac**...........", 01629 ".................cc**...........", 01630 "..................***...........", 01631 "...................**..........."}; 01632 /* XPM */ 01633 static const char* const warning_xpm[]={ 01634 "32 32 4 1", 01635 ". c None", 01636 "a c #ffff00", 01637 "* c #000000", 01638 "b c #999999", 01639 ".............***................", 01640 "............*aaa*...............", 01641 "...........*aaaaa*b.............", 01642 "...........*aaaaa*bb............", 01643 "..........*aaaaaaa*bb...........", 01644 "..........*aaaaaaa*bb...........", 01645 ".........*aaaaaaaaa*bb..........", 01646 ".........*aaaaaaaaa*bb..........", 01647 "........*aaaaaaaaaaa*bb.........", 01648 "........*aaaa***aaaa*bb.........", 01649 ".......*aaaa*****aaaa*bb........", 01650 ".......*aaaa*****aaaa*bb........", 01651 "......*aaaaa*****aaaaa*bb.......", 01652 "......*aaaaa*****aaaaa*bb.......", 01653 ".....*aaaaaa*****aaaaaa*bb......", 01654 ".....*aaaaaa*****aaaaaa*bb......", 01655 "....*aaaaaaaa***aaaaaaaa*bb.....", 01656 "....*aaaaaaaa***aaaaaaaa*bb.....", 01657 "...*aaaaaaaaa***aaaaaaaaa*bb....", 01658 "...*aaaaaaaaaa*aaaaaaaaaa*bb....", 01659 "..*aaaaaaaaaaa*aaaaaaaaaaa*bb...", 01660 "..*aaaaaaaaaaaaaaaaaaaaaaa*bb...", 01661 ".*aaaaaaaaaaaa**aaaaaaaaaaa*bb..", 01662 ".*aaaaaaaaaaa****aaaaaaaaaa*bb..", 01663 "*aaaaaaaaaaaa****aaaaaaaaaaa*bb.", 01664 "*aaaaaaaaaaaaa**aaaaaaaaaaaa*bb.", 01665 "*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb", 01666 "*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb", 01667 ".*aaaaaaaaaaaaaaaaaaaaaaaaa*bbbb", 01668 "..*************************bbbbb", 01669 "....bbbbbbbbbbbbbbbbbbbbbbbbbbb.", 01670 ".....bbbbbbbbbbbbbbbbbbbbbbbbb.."}; 01671 /* XPM */ 01672 static const char* const critical_xpm[]={ 01673 "32 32 4 1", 01674 ". c None", 01675 "a c #999999", 01676 "* c #ff0000", 01677 "b c #ffffff", 01678 "...........********.............", 01679 ".........************...........", 01680 ".......****************.........", 01681 "......******************........", 01682 ".....********************a......", 01683 "....**********************a.....", 01684 "...************************a....", 01685 "..*******b**********b*******a...", 01686 "..******bbb********bbb******a...", 01687 ".******bbbbb******bbbbb******a..", 01688 ".*******bbbbb****bbbbb*******a..", 01689 "*********bbbbb**bbbbb*********a.", 01690 "**********bbbbbbbbbb**********a.", 01691 "***********bbbbbbbb***********aa", 01692 "************bbbbbb************aa", 01693 "************bbbbbb************aa", 01694 "***********bbbbbbbb***********aa", 01695 "**********bbbbbbbbbb**********aa", 01696 "*********bbbbb**bbbbb*********aa", 01697 ".*******bbbbb****bbbbb*******aa.", 01698 ".******bbbbb******bbbbb******aa.", 01699 "..******bbb********bbb******aaa.", 01700 "..*******b**********b*******aa..", 01701 "...************************aaa..", 01702 "....**********************aaa...", 01703 "....a********************aaa....", 01704 ".....a******************aaa.....", 01705 "......a****************aaa......", 01706 ".......aa************aaaa.......", 01707 ".........aa********aaaaa........", 01708 "...........aaaaaaaaaaa..........", 01709 ".............aaaaaaa............"}; 01710 01711 QPixmap KStyle::stylePixmap( StylePixmap stylepixmap, 01712 const QWidget* widget, 01713 const QStyleOption& opt) const 01714 { 01715 switch (stylepixmap) { 01716 case SP_TitleBarShadeButton: 01717 return QPixmap(const_cast<const char**>(kstyle_shade_xpm)); 01718 case SP_TitleBarUnshadeButton: 01719 return QPixmap(const_cast<const char**>(kstyle_unshade_xpm)); 01720 case SP_TitleBarNormalButton: 01721 return QPixmap(const_cast<const char**>(kstyle_normalizeup_xpm)); 01722 case SP_TitleBarMinButton: 01723 return QPixmap(const_cast<const char**>(kstyle_minimize_xpm)); 01724 case SP_TitleBarMaxButton: 01725 return QPixmap(const_cast<const char**>(kstyle_maximize_xpm)); 01726 case SP_TitleBarCloseButton: 01727 return QPixmap(const_cast<const char**>(kstyle_close_xpm)); 01728 case SP_DockWindowCloseButton: 01729 return QPixmap(const_cast<const char**>(dock_window_close_xpm )); 01730 case SP_MessageBoxInformation: 01731 return QPixmap(const_cast<const char**>(information_xpm)); 01732 case SP_MessageBoxWarning: 01733 return QPixmap(const_cast<const char**>(warning_xpm)); 01734 case SP_MessageBoxCritical: 01735 return QPixmap(const_cast<const char**>(critical_xpm)); 01736 default: 01737 break; 01738 } 01739 return QCommonStyle::stylePixmap(stylepixmap, widget, opt); 01740 } 01741 01742 01743 int KStyle::styleHint( StyleHint sh, const QWidget* w, 01744 const QStyleOption &opt, QStyleHintReturn* shr) const 01745 { 01746 switch (sh) 01747 { 01748 case SH_EtchDisabledText: 01749 return d->etchDisabledText ? 1 : 0; 01750 01751 case SH_PopupMenu_Scrollable: 01752 return d->scrollablePopupmenus ? 1 : 0; 01753 01754 case SH_MenuBar_AltKeyNavigation: 01755 return d->menuAltKeyNavigation ? 1 : 0; 01756 01757 case SH_PopupMenu_SubMenuPopupDelay: 01758 if ( styleHint( SH_PopupMenu_SloppySubMenus, w ) ) 01759 return QMIN( 100, d->popupMenuDelay ); 01760 else 01761 return d->popupMenuDelay; 01762 01763 case SH_PopupMenu_SloppySubMenus: 01764 return d->sloppySubMenus; 01765 01766 case SH_ItemView_ChangeHighlightOnFocus: 01767 case SH_Slider_SloppyKeyEvents: 01768 case SH_MainWindow_SpaceBelowMenuBar: 01769 case SH_PopupMenu_AllowActiveAndDisabled: 01770 return 0; 01771 01772 case SH_Slider_SnapToValue: 01773 case SH_PrintDialog_RightAlignButtons: 01774 case SH_FontDialog_SelectAssociatedText: 01775 case SH_MenuBar_MouseTracking: 01776 case SH_PopupMenu_MouseTracking: 01777 case SH_ComboBox_ListMouseTracking: 01778 case SH_ScrollBar_MiddleClickAbsolutePosition: 01779 return 1; 01780 01781 default: 01782 return QCommonStyle::styleHint(sh, w, opt, shr); 01783 } 01784 } 01785 01786 01787 bool KStyle::eventFilter( QObject* object, QEvent* event ) 01788 { 01789 if ( d->useFilledFrameWorkaround ) 01790 { 01791 // Make the QMenuBar/QToolBar paintEvent() cover a larger area to 01792 // ensure that the filled frame contents are properly painted. 01793 // We essentially modify the paintEvent's rect to include the 01794 // panel border, which also paints the widget's interior. 01795 // This is nasty, but I see no other way to properly repaint 01796 // filled frames in all QMenuBars and QToolBars. 01797 // -- Karol. 01798 QFrame *frame = 0; 01799 if ( event->type() == QEvent::Paint 01800 && (frame = ::qt_cast<QFrame*>(object)) ) 01801 { 01802 if (frame->frameShape() != QFrame::ToolBarPanel && frame->frameShape() != QFrame::MenuBarPanel) 01803 return false; 01804 01805 bool horizontal = true; 01806 QPaintEvent* pe = (QPaintEvent*)event; 01807 QToolBar *toolbar = ::qt_cast< QToolBar *>( frame ); 01808 QRect r = pe->rect(); 01809 01810 if (toolbar && toolbar->orientation() == Qt::Vertical) 01811 horizontal = false; 01812 01813 if (horizontal) { 01814 if ( r.height() == frame->height() ) 01815 return false; // Let QFrame handle the painting now. 01816 01817 // Else, send a new paint event with an updated paint rect. 01818 QPaintEvent dummyPE( QRect( r.x(), 0, r.width(), frame->height()) ); 01819 QApplication::sendEvent( frame, &dummyPE ); 01820 } 01821 else { // Vertical 01822 if ( r.width() == frame->width() ) 01823 return false; 01824 01825 QPaintEvent dummyPE( QRect( 0, r.y(), frame->width(), r.height()) ); 01826 QApplication::sendEvent( frame, &dummyPE ); 01827 } 01828 01829 // Discard this event as we sent a new paintEvent. 01830 return true; 01831 } 01832 } 01833 01834 return false; 01835 } 01836 01837 01838 // ----------------------------------------------------------------------------- 01839 // I N T E R N A L - KStyle menu transparency handler 01840 // ----------------------------------------------------------------------------- 01841 01842 TransparencyHandler::TransparencyHandler( KStyle* style, 01843 TransparencyEngine tEngine, float menuOpacity, bool useDropShadow ) 01844 : QObject() 01845 { 01846 te = tEngine; 01847 kstyle = style; 01848 opacity = menuOpacity; 01849 dropShadow = useDropShadow; 01850 pix.setOptimization(QPixmap::BestOptim); 01851 } 01852 01853 TransparencyHandler::~TransparencyHandler() 01854 { 01855 } 01856 01857 // This is meant to be ugly but fast. 01858 void TransparencyHandler::rightShadow(QImage& dst) 01859 { 01860 if (dst.depth() != 32) 01861 dst = dst.convertDepth(32); 01862 01863 // blend top-right corner. 01864 int pixels = dst.width() * dst.height(); 01865 #ifdef WORDS_BIGENDIAN 01866 register unsigned char* data = dst.bits() + 1; // Skip alpha 01867 #else 01868 register unsigned char* data = dst.bits(); // Skip alpha 01869 #endif 01870 for(register int i = 0; i < 16; i++) { 01871 *data = (unsigned char)((*data)*top_right_corner[i]); data++; 01872 *data = (unsigned char)((*data)*top_right_corner[i]); data++; 01873 *data = (unsigned char)((*data)*top_right_corner[i]); data++; 01874 data++; // skip alpha 01875 } 01876 01877 pixels -= 32; // tint right strip without rounded edges. 01878 register int c = 0; 01879 for(register int i = 0; i < pixels; i++) { 01880 *data = (unsigned char)((*data)*shadow_strip[c]); data++; 01881 *data = (unsigned char)((*data)*shadow_strip[c]); data++; 01882 *data = (unsigned char)((*data)*shadow_strip[c]); data++; 01883 data++; // skip alpha 01884 ++c; 01885 c %= 4; 01886 } 01887 01888 // tint bottom edge 01889 for(register int i = 0; i < 16; i++) { 01890 *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; 01891 *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; 01892 *data = (unsigned char)((*data)*bottom_right_corner[i]); data++; 01893 data++; // skip alpha 01894 } 01895 } 01896 01897 void TransparencyHandler::bottomShadow(QImage& dst) 01898 { 01899 if (dst.depth() != 32) 01900 dst = dst.convertDepth(32); 01901 01902 int line = 0; 01903 int width = dst.width() - 4; 01904 double strip_data = shadow_strip[0]; 01905 double* corner = const_cast<double*>(bottom_left_corner); 01906 01907 #ifdef WORDS_BIGENDIAN 01908 register unsigned char* data = dst.bits() + 1; // Skip alpha 01909 #else 01910 register unsigned char* data = dst.bits(); // Skip alpha 01911 #endif 01912 01913 for(int y = 0; y < 4; y++) 01914 { 01915 // Bottom-left Corner 01916 for(register int x = 0; x < 4; x++) { 01917 *data = (unsigned char)((*data)*(*corner)); data++; 01918 *data = (unsigned char)((*data)*(*corner)); data++; 01919 *data = (unsigned char)((*data)*(*corner)); data++; 01920 data++; // skip alpha 01921 corner++; 01922 } 01923 01924 // Scanline 01925 for(register int x = 0; x < width; x++) { 01926 *data = (unsigned char)((*data)*strip_data); data++; 01927 *data = (unsigned char)((*data)*strip_data); data++; 01928 *data = (unsigned char)((*data)*strip_data); data++; 01929 data++; 01930 } 01931 01932 strip_data = shadow_strip[++line]; 01933 } 01934 } 01935 01936 // Create a shadow of thickness 4. 01937 void TransparencyHandler::createShadowWindows(const QPopupMenu* p) 01938 { 01939 #ifdef Q_WS_X11 01940 int x2 = p->x()+p->width(); 01941 int y2 = p->y()+p->height(); 01942 QRect shadow1(x2, p->y() + 4, 4, p->height()); 01943 QRect shadow2(p->x() + 4, y2, p->width() - 4, 4); 01944 01945 // Create a fake drop-down shadow effect via blended Xwindows 01946 ShadowElements se; 01947 se.w1 = new QWidget(0, 0, WStyle_Customize | WType_Popup | WX11BypassWM ); 01948 se.w2 = new QWidget(0, 0, WStyle_Customize | WType_Popup | WX11BypassWM ); 01949 se.w1->setGeometry(shadow1); 01950 se.w2->setGeometry(shadow2); 01951 XSelectInput(qt_xdisplay(), se.w1->winId(), StructureNotifyMask ); 01952 XSelectInput(qt_xdisplay(), se.w2->winId(), StructureNotifyMask ); 01953 01954 // Insert a new ShadowMap entry 01955 shadowMap()[p] = se; 01956 01957 // Some hocus-pocus here to create the drop-shadow. 01958 QPixmap pix_shadow1 = QPixmap::grabWindow(qt_xrootwin(), 01959 shadow1.x(), shadow1.y(), shadow1.width(), shadow1.height()); 01960 QPixmap pix_shadow2 = QPixmap::grabWindow(qt_xrootwin(), 01961 shadow2.x(), shadow2.y(), shadow2.width(), shadow2.height()); 01962 01963 QImage img; 01964 img = pix_shadow1.convertToImage(); 01965 rightShadow(img); 01966 pix_shadow1.convertFromImage(img); 01967 img = pix_shadow2.convertToImage(); 01968 bottomShadow(img); 01969 pix_shadow2.convertFromImage(img); 01970 01971 // Set the background pixmaps 01972 se.w1->setErasePixmap(pix_shadow1); 01973 se.w2->setErasePixmap(pix_shadow2); 01974 01975 // Show the 'shadow' just before showing the popup menu window 01976 // Don't use QWidget::show() so we don't confuse QEffects, thus causing broken focus. 01977 XMapWindow(qt_xdisplay(), se.w1->winId()); 01978 XMapWindow(qt_xdisplay(), se.w2->winId()); 01979 #else 01980 Q_UNUSED( p ) 01981 #endif 01982 } 01983 01984 void TransparencyHandler::removeShadowWindows(const QPopupMenu* p) 01985 { 01986 #ifdef Q_WS_X11 01987 ShadowMap::iterator it = shadowMap().find(p); 01988 if (it != shadowMap().end()) 01989 { 01990 ShadowElements se = it.data(); 01991 XUnmapWindow(qt_xdisplay(), se.w1->winId()); // hide 01992 XUnmapWindow(qt_xdisplay(), se.w2->winId()); 01993 XFlush(qt_xdisplay()); // try to hide faster 01994 delete se.w1; 01995 delete se.w2; 01996 shadowMap().erase(it); 01997 } 01998 #else 01999 Q_UNUSED( p ) 02000 #endif 02001 } 02002 02003 bool TransparencyHandler::eventFilter( QObject* object, QEvent* event ) 02004 { 02005 #if !defined Q_WS_MAC && !defined Q_WS_WIN 02006 // Transparency idea was borrowed from KDE2's "MegaGradient" Style, 02007 // Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org> 02008 02009 // Added 'fake' menu shadows <04-Jul-2002> -- Karol 02010 QPopupMenu* p = (QPopupMenu*)object; 02011 QEvent::Type et = event->type(); 02012 02013 if (et == QEvent::Show) 02014 { 02015 // Handle translucency 02016 if (te != Disabled) 02017 { 02018 pix = QPixmap::grabWindow(qt_xrootwin(), 02019 p->x(), p->y(), p->width(), p->height()); 02020 02021 switch (te) { 02022 #ifdef HAVE_XRENDER 02023 case XRender: 02024 if (qt_use_xrender) { 02025 XRenderBlendToPixmap(p); 02026 break; 02027 } 02028 // Fall through intended 02029 #else 02030 case XRender: 02031 #endif 02032 case SoftwareBlend: 02033 blendToPixmap(p->colorGroup(), p); 02034 break; 02035 02036 case SoftwareTint: 02037 default: 02038 blendToColor(p->colorGroup().button()); 02039 }; 02040 02041 p->setErasePixmap(pix); 02042 } 02043 02044 // Handle drop shadow 02045 // * FIXME : !shadowMap().contains(p) is a workaround for leftover 02046 // * shadows after duplicate show events. 02047 // * TODO : determine real cause for duplicate events 02048 // * till 20021005 02049 if (dropShadow && p->width() > 16 && p->height() > 16 && !shadowMap().contains( p )) 02050 createShadowWindows(p); 02051 } 02052 else if (et == QEvent::Hide) 02053 { 02054 // Handle drop shadow 02055 if (dropShadow) 02056 removeShadowWindows(p); 02057 02058 // Handle translucency 02059 if (te != Disabled) 02060 p->setErasePixmap(QPixmap()); 02061 } 02062 02063 #endif 02064 return false; 02065 } 02066 02067 02068 // Blends a QImage to a predefined color, with a given opacity. 02069 void TransparencyHandler::blendToColor(const QColor &col) 02070 { 02071 if (opacity < 0.0 || opacity > 1.0) 02072 return; 02073 02074 QImage img = pix.convertToImage(); 02075 KImageEffect::blend(col, img, opacity); 02076 pix.convertFromImage(img); 02077 } 02078 02079 02080 void TransparencyHandler::blendToPixmap(const QColorGroup &cg, const QPopupMenu* p) 02081 { 02082 if (opacity < 0.0 || opacity > 1.0) 02083 return; 02084 02085 KPixmap blendPix; 02086 blendPix.resize( pix.width(), pix.height() ); 02087 02088 if (blendPix.width() != pix.width() || 02089 blendPix.height() != pix.height()) 02090 return; 02091 02092 // Allow styles to define the blend pixmap - allows for some interesting effects. 02093 kstyle->renderMenuBlendPixmap( blendPix, cg, p ); 02094 02095 QImage blendImg = blendPix.convertToImage(); 02096 QImage backImg = pix.convertToImage(); 02097 KImageEffect::blend(blendImg, backImg, opacity); 02098 pix.convertFromImage(backImg); 02099 } 02100 02101 02102 #ifdef HAVE_XRENDER 02103 // Here we go, use XRender in all its glory. 02104 // NOTE: This is actually a bit slower than the above routines 02105 // on non-accelerated displays. -- Karol. 02106 void TransparencyHandler::XRenderBlendToPixmap(const QPopupMenu* p) 02107 { 02108 KPixmap renderPix; 02109 renderPix.resize( pix.width(), pix.height() ); 02110 02111 // Allow styles to define the blend pixmap - allows for some interesting effects. 02112 kstyle->renderMenuBlendPixmap( renderPix, p->colorGroup(), p ); 02113 02114 Display* dpy = qt_xdisplay(); 02115 Pixmap alphaPixmap; 02116 Picture alphaPicture; 02117 XRenderPictFormat Rpf; 02118 XRenderPictureAttributes Rpa; 02119 XRenderColor clr; 02120 clr.alpha = ((unsigned short)(255*opacity) << 8); 02121 02122 Rpf.type = PictTypeDirect; 02123 Rpf.depth = 8; 02124 Rpf.direct.alphaMask = 0xff; 02125 Rpa.repeat = True; // Tile 02126 02127 XRenderPictFormat* xformat = XRenderFindFormat(dpy, 02128 PictFormatType | PictFormatDepth | PictFormatAlphaMask, &Rpf, 0); 02129 02130 alphaPixmap = XCreatePixmap(dpy, p->handle(), 1, 1, 8); 02131 alphaPicture = XRenderCreatePicture(dpy, alphaPixmap, xformat, CPRepeat, &Rpa); 02132 02133 XRenderFillRectangle(dpy, PictOpSrc, alphaPicture, &clr, 0, 0, 1, 1); 02134 02135 XRenderComposite(dpy, PictOpOver, 02136 renderPix.x11RenderHandle(), alphaPicture, pix.x11RenderHandle(), // src, mask, dst 02137 0, 0, // srcx, srcy 02138 0, 0, // maskx, masky 02139 0, 0, // dstx, dsty 02140 pix.width(), pix.height()); 02141 02142 XRenderFreePicture(dpy, alphaPicture); 02143 XFreePixmap(dpy, alphaPixmap); 02144 } 02145 #endif 02146 02147 void KStyle::virtual_hook( int, void* ) 02148 { /*BASE::virtual_hook( id, data );*/ } 02149 02150 // vim: set noet ts=4 sw=4: 02151 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off; 02152 02153 #include "kstyle.moc"
KDE Logo
This file is part of the documentation for kdefx Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:02:57 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003