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
44 namespace WebCore {
45
nativeTheme()46 ScrollbarTheme* ScrollbarTheme::nativeTheme()
47 {
48 static ScrollbarThemeQt theme;
49 return &theme;
50 }
51
~ScrollbarThemeQt()52 ScrollbarThemeQt::~ScrollbarThemeQt()
53 {
54 }
55
scPart(const ScrollbarPart & part)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
scrollbarPart(const QStyle::SubControl & sc)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
styleOptionSlider(Scrollbar * scrollbar,QWidget * widget=0)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 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
paint(Scrollbar * scrollbar,GraphicsContext * graphicsContext,const IntRect & damageRect)136 bool 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(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));
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
hitTest(Scrollbar * scrollbar,const PlatformMouseEvent & evt)170 ScrollbarPart 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 = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, opt, pos, 0);
176 return scrollbarPart(sc);
177 }
178
shouldCenterOnThumb(Scrollbar *,const PlatformMouseEvent & evt)179 bool ScrollbarThemeQt::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
180 {
181 // Middle click centers slider thumb (if supported)
182 return QApplication::style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition) && evt.button() == MiddleButton;
183 }
184
invalidatePart(Scrollbar * scrollbar,ScrollbarPart)185 void ScrollbarThemeQt::invalidatePart(Scrollbar* scrollbar, ScrollbarPart)
186 {
187 // FIXME: Do more precise invalidation.
188 scrollbar->invalidate();
189 }
190
scrollbarThickness(ScrollbarControlSize controlSize)191 int ScrollbarThemeQt::scrollbarThickness(ScrollbarControlSize controlSize)
192 {
193 QStyle* s = QApplication::style();
194 QStyleOptionSlider o;
195 o.orientation = Qt::Vertical;
196 o.state &= ~QStyle::State_Horizontal;
197 if (controlSize != RegularScrollbar)
198 o.state |= QStyle::State_Mini;
199 return s->pixelMetric(QStyle::PM_ScrollBarExtent, &o, 0);
200 }
201
thumbPosition(Scrollbar * scrollbar)202 int ScrollbarThemeQt::thumbPosition(Scrollbar* scrollbar)
203 {
204 if (scrollbar->enabled())
205 return (int)((float)scrollbar->currentPos() * (trackLength(scrollbar) - thumbLength(scrollbar)) / scrollbar->maximum());
206 return 0;
207 }
208
thumbLength(Scrollbar * scrollbar)209 int ScrollbarThemeQt::thumbLength(Scrollbar* scrollbar)
210 {
211 QStyleOptionSlider* opt = styleOptionSlider(scrollbar);
212 IntRect thumb = QApplication::style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarSlider, 0);
213 return scrollbar->orientation() == HorizontalScrollbar ? thumb.width() : thumb.height();
214 }
215
trackPosition(Scrollbar * scrollbar)216 int ScrollbarThemeQt::trackPosition(Scrollbar* scrollbar)
217 {
218 QStyleOptionSlider* opt = styleOptionSlider(scrollbar);
219 IntRect track = QApplication::style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarGroove, 0);
220 return scrollbar->orientation() == HorizontalScrollbar ? track.x() - scrollbar->x() : track.y() - scrollbar->y();
221 }
222
trackLength(Scrollbar * scrollbar)223 int ScrollbarThemeQt::trackLength(Scrollbar* scrollbar)
224 {
225 QStyleOptionSlider* opt = styleOptionSlider(scrollbar);
226 IntRect track = QApplication::style()->subControlRect(QStyle::CC_ScrollBar, opt, QStyle::SC_ScrollBarGroove, 0);
227 return scrollbar->orientation() == HorizontalScrollbar ? track.width() : track.height();
228 }
229
paintScrollCorner(ScrollView * scrollView,GraphicsContext * context,const IntRect & rect)230 void ScrollbarThemeQt::paintScrollCorner(ScrollView* scrollView, GraphicsContext* context, const IntRect& rect)
231 {
232 if (context->updatingControlTints()) {
233 scrollView->invalidateRect(rect);
234 return;
235 }
236
237 #if QT_VERSION < 0x040500
238 context->fillRect(rect, QApplication::palette().color(QPalette::Normal, QPalette::Window));
239 #else
240 StylePainter p(context);
241 if (!p.isValid())
242 return;
243
244 QStyleOption option;
245 option.rect = rect;
246 p.drawPrimitive(QStyle::PE_PanelScrollAreaCorner, option);
247 #endif
248 }
249
250 }
251
252