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 "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
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
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
paint(Scrollbar * scrollbar,GraphicsContext * graphicsContext,const IntRect & damageRect)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
hitTest(Scrollbar * scrollbar,const PlatformMouseEvent & evt)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
shouldCenterOnThumb(Scrollbar *,const PlatformMouseEvent & evt)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
invalidatePart(Scrollbar * scrollbar,ScrollbarPart)189 void ScrollbarThemeQt::invalidatePart(Scrollbar* scrollbar, ScrollbarPart)
190 {
191 // FIXME: Do more precise invalidation.
192 scrollbar->invalidate();
193 }
194
scrollbarThickness(ScrollbarControlSize controlSize)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
thumbPosition(Scrollbar * scrollbar)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
thumbLength(Scrollbar * scrollbar)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
trackPosition(Scrollbar * scrollbar)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
trackLength(Scrollbar * scrollbar)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
paintScrollCorner(ScrollView * scrollView,GraphicsContext * context,const IntRect & rect)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
style() const252 QStyle* ScrollbarThemeQt::style() const
253 {
254 return QApplication::style();
255 }
256
257 }
258
259