1 /* 2 * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. 3 * Copyright (C) 2007 Staikos Computing Services Inc. <info (at) 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 "ScrollView.h" 35 #include "Scrollbar.h" 36 37 #include <QApplication> 38 #include <QDebug> 39 #include <QMenu> 40 #include <QPainter> 41 #include <QStyle> 42 #include <QStyleOptionSlider> 43 44 namespace WebCore { 45 46 ScrollbarTheme* ScrollbarTheme::nativeTheme() 47 { 48 static ScrollbarThemeQt theme; 49 return &theme; 50 } 51 52 ScrollbarThemeQt::~ScrollbarThemeQt() 53 { 54 } 55 56 static 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 78 static 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 97 static 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 114 if (scrollbar->orientation() == HorizontalScrollbar) 115 opt.state |= QStyle::State_Horizontal; 116 else 117 opt.state &= ~QStyle::State_Horizontal; 118 119 opt.sliderValue = scrollbar->value(); 120 opt.sliderPosition = opt.sliderValue; 121 opt.pageStep = scrollbar->pageStep(); 122 opt.singleStep = scrollbar->lineStep(); 123 opt.minimum = 0; 124 opt.maximum = qMax(0, scrollbar->maximum()); 125 ScrollbarPart pressedPart = scrollbar->pressedPart(); 126 ScrollbarPart hoveredPart = scrollbar->hoveredPart(); 127 if (pressedPart != NoPart) { 128 opt.activeSubControls = scPart(scrollbar->pressedPart()); 129 if (pressedPart == BackButtonStartPart || pressedPart == ForwardButtonStartPart 130 || pressedPart == BackButtonEndPart || pressedPart == ForwardButtonEndPart 131 || pressedPart == ThumbPart) 132 opt.state |= QStyle::State_Sunken; 133 } else 134 opt.activeSubControls = scPart(hoveredPart); 135 if (hoveredPart != NoPart) 136 opt.state |= QStyle::State_MouseOver; 137 return &opt; 138 } 139 140 bool ScrollbarThemeQt::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect) 141 { 142 if (graphicsContext->updatingControlTints()) { 143 scrollbar->invalidateRect(damageRect); 144 return false; 145 } 146 147 StylePainter p(this, graphicsContext); 148 if (!p.isValid()) 149 return true; 150 151 p.painter->save(); 152 QStyleOptionSlider* opt = styleOptionSlider(scrollbar, p.widget); 153 154 p.painter->setClipRect(opt->rect.intersected(damageRect), Qt::IntersectClip); 155 156 #ifdef Q_WS_MAC 157 p.drawComplexControl(QStyle::CC_ScrollBar, *opt); 158 #else 159 const QPoint topLeft = opt->rect.topLeft(); 160 p.painter->translate(topLeft); 161 opt->rect.moveTo(QPoint(0, 0)); 162 163 // The QStyle expects the background to be already filled 164 p.painter->fillRect(opt->rect, opt->palette.background()); 165 166 p.drawComplexControl(QStyle::CC_ScrollBar, *opt); 167 opt->rect.moveTo(topLeft); 168 #endif 169 p.painter->restore(); 170 171 return true; 172 } 173 174 ScrollbarPart ScrollbarThemeQt::hitTest(Scrollbar* scrollbar, const PlatformMouseEvent& evt) 175 { 176 QStyleOptionSlider* opt = styleOptionSlider(scrollbar); 177 const QPoint pos = scrollbar->convertFromContainingWindow(evt.pos()); 178 opt->rect.moveTo(QPoint(0, 0)); 179 QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ScrollBar, opt, pos, 0); 180 return scrollbarPart(sc); 181 } 182 183 bool ScrollbarThemeQt::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) 184 { 185 // Middle click centers slider thumb (if supported) 186 return style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition) && evt.button() == MiddleButton; 187 } 188 189 void ScrollbarThemeQt::invalidatePart(Scrollbar* scrollbar, ScrollbarPart) 190 { 191 // FIXME: Do more precise invalidation. 192 scrollbar->invalidate(); 193 } 194 195 int ScrollbarThemeQt::scrollbarThickness(ScrollbarControlSize controlSize) 196 { 197 #if USE(QT_MOBILE_THEME) 198 return 0; 199 #endif 200 QStyleOptionSlider o; 201 o.orientation = Qt::Vertical; 202 o.state &= ~QStyle::State_Horizontal; 203 if (controlSize != RegularScrollbar) 204 o.state |= QStyle::State_Mini; 205 return style()->pixelMetric(QStyle::PM_ScrollBarExtent, &o, 0); 206 } 207 208 int ScrollbarThemeQt::thumbPosition(Scrollbar* scrollbar) 209 { 210 if (scrollbar->enabled()) 211 return (int)((float)scrollbar->currentPos() * (trackLength(scrollbar) - thumbLength(scrollbar)) / scrollbar->maximum()); 212 return 0; 213 } 214 215 int ScrollbarThemeQt::thumbLength(Scrollbar* scrollbar) 216 { 217 QStyleOptionSlider* opt = styleOptionSlider(scrollbar); 218 IntRect thumb = style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarSlider, 0); 219 return scrollbar->orientation() == HorizontalScrollbar ? thumb.width() : thumb.height(); 220 } 221 222 int ScrollbarThemeQt::trackPosition(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.x() - scrollbar->x() : track.y() - scrollbar->y(); 227 } 228 229 int ScrollbarThemeQt::trackLength(Scrollbar* scrollbar) 230 { 231 QStyleOptionSlider* opt = styleOptionSlider(scrollbar); 232 IntRect track = style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarGroove, 0); 233 return scrollbar->orientation() == HorizontalScrollbar ? track.width() : track.height(); 234 } 235 236 void ScrollbarThemeQt::paintScrollCorner(ScrollView* scrollView, GraphicsContext* context, const IntRect& rect) 237 { 238 if (context->updatingControlTints()) { 239 scrollView->invalidateRect(rect); 240 return; 241 } 242 243 StylePainter p(this, context); 244 if (!p.isValid()) 245 return; 246 247 QStyleOption option; 248 option.rect = rect; 249 p.drawPrimitive(QStyle::PE_PanelScrollAreaCorner, option); 250 } 251 252 QStyle* ScrollbarThemeQt::style() const 253 { 254 return QApplication::style(); 255 } 256 257 } 258 259