1/* 2 * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. 3 * Copyright (C) 2007 Staikos Computing Services Inc. <info@staikos.net> 4 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29#include "ScrollbarThemeQt.h" 30 31#include "GraphicsContext.h" 32#include "PlatformMouseEvent.h" 33#include "RenderThemeQt.h" 34#include "Scrollbar.h" 35#include "ScrollView.h" 36 37#include <QApplication> 38#include <QDebug> 39#include <QPainter> 40#include <QStyle> 41#include <QStyleOptionSlider> 42#include <QMenu> 43 44namespace WebCore { 45 46ScrollbarTheme* ScrollbarTheme::nativeTheme() 47{ 48 static ScrollbarThemeQt theme; 49 return &theme; 50} 51 52ScrollbarThemeQt::~ScrollbarThemeQt() 53{ 54} 55 56static QStyle::SubControl scPart(const ScrollbarPart& part) 57{ 58 switch (part) { 59 case NoPart: 60 return QStyle::SC_None; 61 case BackButtonStartPart: 62 case BackButtonEndPart: 63 return QStyle::SC_ScrollBarSubLine; 64 case BackTrackPart: 65 return QStyle::SC_ScrollBarSubPage; 66 case ThumbPart: 67 return QStyle::SC_ScrollBarSlider; 68 case ForwardTrackPart: 69 return QStyle::SC_ScrollBarAddPage; 70 case ForwardButtonStartPart: 71 case ForwardButtonEndPart: 72 return QStyle::SC_ScrollBarAddLine; 73 } 74 75 return QStyle::SC_None; 76} 77 78static ScrollbarPart scrollbarPart(const QStyle::SubControl& sc) 79{ 80 switch (sc) { 81 case QStyle::SC_None: 82 return NoPart; 83 case QStyle::SC_ScrollBarSubLine: 84 return BackButtonStartPart; 85 case QStyle::SC_ScrollBarSubPage: 86 return BackTrackPart; 87 case QStyle::SC_ScrollBarSlider: 88 return ThumbPart; 89 case QStyle::SC_ScrollBarAddPage: 90 return ForwardTrackPart; 91 case QStyle::SC_ScrollBarAddLine: 92 return ForwardButtonStartPart; 93 } 94 return NoPart; 95} 96 97static QStyleOptionSlider* styleOptionSlider(Scrollbar* scrollbar, QWidget* widget = 0) 98{ 99 static QStyleOptionSlider opt; 100 if (widget) 101 opt.initFrom(widget); 102 else 103 opt.state |= QStyle::State_Active; 104 105 opt.state &= ~QStyle::State_HasFocus; 106 107 opt.rect = scrollbar->frameRect(); 108 if (scrollbar->enabled()) 109 opt.state |= QStyle::State_Enabled; 110 if (scrollbar->controlSize() != RegularScrollbar) 111 opt.state |= QStyle::State_Mini; 112 opt.orientation = (scrollbar->orientation() == VerticalScrollbar) ? Qt::Vertical : Qt::Horizontal; 113 if (scrollbar->orientation() == HorizontalScrollbar) 114 opt.state |= QStyle::State_Horizontal; 115 opt.sliderValue = scrollbar->value(); 116 opt.sliderPosition = opt.sliderValue; 117 opt.pageStep = scrollbar->visibleSize(); 118 opt.singleStep = scrollbar->lineStep(); 119 opt.minimum = 0; 120 opt.maximum = qMax(0, scrollbar->maximum()); 121 ScrollbarPart pressedPart = scrollbar->pressedPart(); 122 ScrollbarPart hoveredPart = scrollbar->hoveredPart(); 123 if (pressedPart != NoPart) { 124 opt.activeSubControls = scPart(scrollbar->pressedPart()); 125 if (pressedPart == BackButtonStartPart || pressedPart == ForwardButtonStartPart || 126 pressedPart == BackButtonEndPart || pressedPart == ForwardButtonEndPart || 127 pressedPart == ThumbPart) 128 opt.state |= QStyle::State_Sunken; 129 } else 130 opt.activeSubControls = scPart(hoveredPart); 131 if (hoveredPart != NoPart) 132 opt.state |= QStyle::State_MouseOver; 133 return &opt; 134} 135 136bool ScrollbarThemeQt::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect) 137{ 138 if (graphicsContext->updatingControlTints()) { 139 scrollbar->invalidateRect(damageRect); 140 return false; 141 } 142 143 StylePainter p(this, graphicsContext); 144 if (!p.isValid()) 145 return true; 146 147 p.painter->save(); 148 QStyleOptionSlider* opt = styleOptionSlider(scrollbar, p.widget); 149 150 p.painter->setClipRect(opt->rect.intersected(damageRect), Qt::IntersectClip); 151 152#ifdef Q_WS_MAC 153 p.drawComplexControl(QStyle::CC_ScrollBar, *opt); 154#else 155 const QPoint topLeft = opt->rect.topLeft(); 156 p.painter->translate(topLeft); 157 opt->rect.moveTo(QPoint(0, 0)); 158 159 // The QStyle expects the background to be already filled 160 p.painter->fillRect(opt->rect, opt->palette.background()); 161 162 p.drawComplexControl(QStyle::CC_ScrollBar, *opt); 163 opt->rect.moveTo(topLeft); 164#endif 165 p.painter->restore(); 166 167 return true; 168} 169 170ScrollbarPart ScrollbarThemeQt::hitTest(Scrollbar* scrollbar, const PlatformMouseEvent& evt) 171{ 172 QStyleOptionSlider* opt = styleOptionSlider(scrollbar); 173 const QPoint pos = scrollbar->convertFromContainingWindow(evt.pos()); 174 opt->rect.moveTo(QPoint(0, 0)); 175 QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ScrollBar, opt, pos, 0); 176 return scrollbarPart(sc); 177} 178 179bool ScrollbarThemeQt::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) 180{ 181 // Middle click centers slider thumb (if supported) 182 return style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition) && evt.button() == MiddleButton; 183} 184 185void ScrollbarThemeQt::invalidatePart(Scrollbar* scrollbar, ScrollbarPart) 186{ 187 // FIXME: Do more precise invalidation. 188 scrollbar->invalidate(); 189} 190 191int ScrollbarThemeQt::scrollbarThickness(ScrollbarControlSize controlSize) 192{ 193 QStyleOptionSlider o; 194 o.orientation = Qt::Vertical; 195 o.state &= ~QStyle::State_Horizontal; 196 if (controlSize != RegularScrollbar) 197 o.state |= QStyle::State_Mini; 198 return style()->pixelMetric(QStyle::PM_ScrollBarExtent, &o, 0); 199} 200 201int ScrollbarThemeQt::thumbPosition(Scrollbar* scrollbar) 202{ 203 if (scrollbar->enabled()) 204 return (int)((float)scrollbar->currentPos() * (trackLength(scrollbar) - thumbLength(scrollbar)) / scrollbar->maximum()); 205 return 0; 206} 207 208int ScrollbarThemeQt::thumbLength(Scrollbar* scrollbar) 209{ 210 QStyleOptionSlider* opt = styleOptionSlider(scrollbar); 211 IntRect thumb = style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarSlider, 0); 212 return scrollbar->orientation() == HorizontalScrollbar ? thumb.width() : thumb.height(); 213} 214 215int ScrollbarThemeQt::trackPosition(Scrollbar* scrollbar) 216{ 217 QStyleOptionSlider* opt = styleOptionSlider(scrollbar); 218 IntRect track = style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarGroove, 0); 219 return scrollbar->orientation() == HorizontalScrollbar ? track.x() - scrollbar->x() : track.y() - scrollbar->y(); 220} 221 222int ScrollbarThemeQt::trackLength(Scrollbar* scrollbar) 223{ 224 QStyleOptionSlider* opt = styleOptionSlider(scrollbar); 225 IntRect track = style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarGroove, 0); 226 return scrollbar->orientation() == HorizontalScrollbar ? track.width() : track.height(); 227} 228 229void ScrollbarThemeQt::paintScrollCorner(ScrollView* scrollView, GraphicsContext* context, const IntRect& rect) 230{ 231 if (context->updatingControlTints()) { 232 scrollView->invalidateRect(rect); 233 return; 234 } 235 236#if QT_VERSION < 0x040500 237 context->fillRect(rect, QApplication::palette().color(QPalette::Normal, QPalette::Window), DeviceColorSpace); 238#else 239 StylePainter p(this, context); 240 if (!p.isValid()) 241 return; 242 243 QStyleOption option; 244 option.rect = rect; 245 p.drawPrimitive(QStyle::PE_PanelScrollAreaCorner, option); 246#endif 247} 248 249QStyle* ScrollbarThemeQt::style() const 250{ 251 return QApplication::style(); 252} 253 254} 255 256