1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/controls/scrollbar/native_scroll_bar_views.h"
7 #include "base/logging.h"
8 #include "ui/events/keycodes/keyboard_codes.h"
9 #include "ui/gfx/canvas.h"
10 #include "ui/gfx/path.h"
11 #include "ui/views/controls/button/custom_button.h"
12 #include "ui/views/controls/focusable_border.h"
13 #include "ui/views/controls/scrollbar/base_scroll_bar_button.h"
14 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
15 #include "ui/views/controls/scrollbar/native_scroll_bar.h"
16 #include "ui/views/controls/scrollbar/scroll_bar.h"
22 // Wrapper for the scroll buttons.
23 class ScrollBarButton
: public BaseScrollBarButton
{
32 ScrollBarButton(ButtonListener
* listener
, Type type
);
33 virtual ~ScrollBarButton();
35 virtual gfx::Size
GetPreferredSize() const OVERRIDE
;
36 virtual const char* GetClassName() const OVERRIDE
{
37 return "ScrollBarButton";
41 virtual void OnPaint(gfx::Canvas
* canvas
) OVERRIDE
;
44 ui::NativeTheme::ExtraParams
GetNativeThemeParams() const;
45 ui::NativeTheme::Part
GetNativeThemePart() const;
46 ui::NativeTheme::State
GetNativeThemeState() const;
51 // Wrapper for the scroll thumb
52 class ScrollBarThumb
: public BaseScrollBarThumb
{
54 explicit ScrollBarThumb(BaseScrollBar
* scroll_bar
);
55 virtual ~ScrollBarThumb();
57 virtual gfx::Size
GetPreferredSize() const OVERRIDE
;
58 virtual const char* GetClassName() const OVERRIDE
{
59 return "ScrollBarThumb";
63 virtual void OnPaint(gfx::Canvas
* canvas
) OVERRIDE
;
66 ui::NativeTheme::ExtraParams
GetNativeThemeParams() const;
67 ui::NativeTheme::Part
GetNativeThemePart() const;
68 ui::NativeTheme::State
GetNativeThemeState() const;
70 ScrollBar
* scroll_bar_
;
73 /////////////////////////////////////////////////////////////////////////////
76 ScrollBarButton::ScrollBarButton(ButtonListener
* listener
, Type type
)
77 : BaseScrollBarButton(listener
),
80 SetAccessibilityFocusable(false);
83 ScrollBarButton::~ScrollBarButton() {
86 gfx::Size
ScrollBarButton::GetPreferredSize() const {
87 return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
88 GetNativeThemeState(),
89 GetNativeThemeParams());
92 void ScrollBarButton::OnPaint(gfx::Canvas
* canvas
) {
93 gfx::Rect
bounds(GetPreferredSize());
94 GetNativeTheme()->Paint(canvas
->sk_canvas(), GetNativeThemePart(),
95 GetNativeThemeState(), bounds
,
96 GetNativeThemeParams());
99 ui::NativeTheme::ExtraParams
100 ScrollBarButton::GetNativeThemeParams() const {
101 ui::NativeTheme::ExtraParams params
;
104 case CustomButton::STATE_HOVERED
:
105 params
.scrollbar_arrow
.is_hovering
= true;
108 params
.scrollbar_arrow
.is_hovering
= false;
115 ui::NativeTheme::Part
116 ScrollBarButton::GetNativeThemePart() const {
119 return ui::NativeTheme::kScrollbarUpArrow
;
121 return ui::NativeTheme::kScrollbarDownArrow
;
123 return ui::NativeTheme::kScrollbarLeftArrow
;
125 return ui::NativeTheme::kScrollbarRightArrow
;
127 return ui::NativeTheme::kScrollbarUpArrow
;
131 ui::NativeTheme::State
132 ScrollBarButton::GetNativeThemeState() const {
133 ui::NativeTheme::State state
;
136 case CustomButton::STATE_HOVERED
:
137 state
= ui::NativeTheme::kHovered
;
139 case CustomButton::STATE_PRESSED
:
140 state
= ui::NativeTheme::kPressed
;
142 case CustomButton::STATE_DISABLED
:
143 state
= ui::NativeTheme::kDisabled
;
145 case CustomButton::STATE_NORMAL
:
147 state
= ui::NativeTheme::kNormal
;
154 /////////////////////////////////////////////////////////////////////////////
157 ScrollBarThumb::ScrollBarThumb(BaseScrollBar
* scroll_bar
)
158 : BaseScrollBarThumb(scroll_bar
),
159 scroll_bar_(scroll_bar
) {
161 SetAccessibilityFocusable(false);
164 ScrollBarThumb::~ScrollBarThumb() {
167 gfx::Size
ScrollBarThumb::GetPreferredSize() const {
168 return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
169 GetNativeThemeState(),
170 GetNativeThemeParams());
173 void ScrollBarThumb::OnPaint(gfx::Canvas
* canvas
) {
174 const gfx::Rect
local_bounds(GetLocalBounds());
175 const ui::NativeTheme::State theme_state
= GetNativeThemeState();
176 const ui::NativeTheme::ExtraParams
extra_params(GetNativeThemeParams());
177 GetNativeTheme()->Paint(canvas
->sk_canvas(),
178 GetNativeThemePart(),
182 const ui::NativeTheme::Part gripper_part
= scroll_bar_
->IsHorizontal() ?
183 ui::NativeTheme::kScrollbarHorizontalGripper
:
184 ui::NativeTheme::kScrollbarVerticalGripper
;
185 GetNativeTheme()->Paint(canvas
->sk_canvas(), gripper_part
, theme_state
,
186 local_bounds
, extra_params
);
189 ui::NativeTheme::ExtraParams
ScrollBarThumb::GetNativeThemeParams() const {
190 // This gives the behavior we want.
191 ui::NativeTheme::ExtraParams params
;
192 params
.scrollbar_thumb
.is_hovering
=
193 (GetState() != CustomButton::STATE_HOVERED
);
197 ui::NativeTheme::Part
ScrollBarThumb::GetNativeThemePart() const {
198 if (scroll_bar_
->IsHorizontal())
199 return ui::NativeTheme::kScrollbarHorizontalThumb
;
200 return ui::NativeTheme::kScrollbarVerticalThumb
;
203 ui::NativeTheme::State
ScrollBarThumb::GetNativeThemeState() const {
204 ui::NativeTheme::State state
;
206 switch (GetState()) {
207 case CustomButton::STATE_HOVERED
:
208 state
= ui::NativeTheme::kHovered
;
210 case CustomButton::STATE_PRESSED
:
211 state
= ui::NativeTheme::kPressed
;
213 case CustomButton::STATE_DISABLED
:
214 state
= ui::NativeTheme::kDisabled
;
216 case CustomButton::STATE_NORMAL
:
218 state
= ui::NativeTheme::kNormal
;
227 ////////////////////////////////////////////////////////////////////////////////
228 // NativeScrollBarViews, public:
230 const char NativeScrollBarViews::kViewClassName
[] = "NativeScrollBarViews";
232 NativeScrollBarViews::NativeScrollBarViews(NativeScrollBar
* scroll_bar
)
233 : BaseScrollBar(scroll_bar
->IsHorizontal(),
234 new ScrollBarThumb(this)),
235 native_scroll_bar_(scroll_bar
) {
236 set_controller(native_scroll_bar_
->controller());
238 if (native_scroll_bar_
->IsHorizontal()) {
239 prev_button_
= new ScrollBarButton(this, ScrollBarButton::LEFT
);
240 next_button_
= new ScrollBarButton(this, ScrollBarButton::RIGHT
);
242 part_
= ui::NativeTheme::kScrollbarHorizontalTrack
;
244 prev_button_
= new ScrollBarButton(this, ScrollBarButton::UP
);
245 next_button_
= new ScrollBarButton(this, ScrollBarButton::DOWN
);
247 part_
= ui::NativeTheme::kScrollbarVerticalTrack
;
250 state_
= ui::NativeTheme::kNormal
;
252 AddChildView(prev_button_
);
253 AddChildView(next_button_
);
255 prev_button_
->set_context_menu_controller(this);
256 next_button_
->set_context_menu_controller(this);
259 NativeScrollBarViews::~NativeScrollBarViews() {
262 ////////////////////////////////////////////////////////////////////////////////
263 // NativeScrollBarViews, View overrides:
265 void NativeScrollBarViews::Layout() {
266 gfx::Size size
= prev_button_
->GetPreferredSize();
267 prev_button_
->SetBounds(0, 0, size
.width(), size
.height());
269 if (native_scroll_bar_
->IsHorizontal()) {
270 next_button_
->SetBounds(width() - size
.width(), 0,
271 size
.width(), size
.height());
273 next_button_
->SetBounds(0, height() - size
.height(),
274 size
.width(), size
.height());
277 GetThumb()->SetBoundsRect(GetTrackBounds());
280 void NativeScrollBarViews::OnPaint(gfx::Canvas
* canvas
) {
281 gfx::Rect bounds
= GetTrackBounds();
283 if (bounds
.IsEmpty())
286 params_
.scrollbar_track
.track_x
= bounds
.x();
287 params_
.scrollbar_track
.track_y
= bounds
.y();
288 params_
.scrollbar_track
.track_width
= bounds
.width();
289 params_
.scrollbar_track
.track_height
= bounds
.height();
290 params_
.scrollbar_track
.classic_state
= 0;
292 GetNativeTheme()->Paint(canvas
->sk_canvas(), part_
, state_
, bounds
, params_
);
295 gfx::Size
NativeScrollBarViews::GetPreferredSize() const {
296 const ui::NativeTheme
* theme
= native_scroll_bar_
->GetNativeTheme();
297 if (native_scroll_bar_
->IsHorizontal())
298 return gfx::Size(0, GetHorizontalScrollBarHeight(theme
));
299 return gfx::Size(GetVerticalScrollBarWidth(theme
), 0);
302 const char* NativeScrollBarViews::GetClassName() const {
303 return kViewClassName
;
306 int NativeScrollBarViews::GetLayoutSize() const {
307 gfx::Size size
= prev_button_
->GetPreferredSize();
308 return IsHorizontal() ? size
.height() : size
.width();
311 void NativeScrollBarViews::ScrollToPosition(int position
) {
312 controller()->ScrollToPosition(native_scroll_bar_
, position
);
315 int NativeScrollBarViews::GetScrollIncrement(bool is_page
, bool is_positive
) {
316 return controller()->GetScrollIncrement(native_scroll_bar_
,
321 //////////////////////////////////////////////////////////////////////////////
322 // BaseButton::ButtonListener overrides:
324 void NativeScrollBarViews::ButtonPressed(Button
* sender
,
325 const ui::Event
& event
) {
326 if (sender
== prev_button_
) {
327 ScrollByAmount(SCROLL_PREV_LINE
);
328 } else if (sender
== next_button_
) {
329 ScrollByAmount(SCROLL_NEXT_LINE
);
333 ////////////////////////////////////////////////////////////////////////////////
334 // NativeScrollBarViews, NativeScrollBarWrapper overrides:
336 int NativeScrollBarViews::GetPosition() const {
337 return BaseScrollBar::GetPosition();
340 View
* NativeScrollBarViews::GetView() {
344 void NativeScrollBarViews::Update(int viewport_size
,
347 BaseScrollBar::Update(viewport_size
, content_size
, current_pos
);
350 ////////////////////////////////////////////////////////////////////////////////
351 // NativeScrollBarViews, private:
353 gfx::Rect
NativeScrollBarViews::GetTrackBounds() const {
354 gfx::Rect bounds
= GetLocalBounds();
355 gfx::Size size
= prev_button_
->GetPreferredSize();
356 BaseScrollBarThumb
* thumb
= GetThumb();
358 if (native_scroll_bar_
->IsHorizontal()) {
359 bounds
.set_x(bounds
.x() + size
.width());
360 bounds
.set_width(std::max(0, bounds
.width() - 2 * size
.width()));
361 bounds
.set_height(thumb
->GetPreferredSize().height());
363 bounds
.set_y(bounds
.y() + size
.height());
364 bounds
.set_height(std::max(0, bounds
.height() - 2 * size
.height()));
365 bounds
.set_width(thumb
->GetPreferredSize().width());
371 ////////////////////////////////////////////////////////////////////////////////
372 // NativewScrollBarWrapper, public:
375 NativeScrollBarWrapper
* NativeScrollBarWrapper::CreateWrapper(
376 NativeScrollBar
* scroll_bar
) {
377 return new NativeScrollBarViews(scroll_bar
);
381 int NativeScrollBarWrapper::GetHorizontalScrollBarHeight(
382 const ui::NativeTheme
* theme
) {
384 theme
= ui::NativeTheme::instance();
385 ui::NativeTheme::ExtraParams button_params
;
386 button_params
.scrollbar_arrow
.is_hovering
= false;
387 gfx::Size button_size
= theme
->GetPartSize(
388 ui::NativeTheme::kScrollbarLeftArrow
,
389 ui::NativeTheme::kNormal
,
392 ui::NativeTheme::ExtraParams thumb_params
;
393 thumb_params
.scrollbar_thumb
.is_hovering
= false;
394 gfx::Size track_size
= theme
->GetPartSize(
395 ui::NativeTheme::kScrollbarHorizontalThumb
,
396 ui::NativeTheme::kNormal
,
399 return std::max(track_size
.height(), button_size
.height());
403 int NativeScrollBarWrapper::GetVerticalScrollBarWidth(
404 const ui::NativeTheme
* theme
) {
406 theme
= ui::NativeTheme::instance();
407 ui::NativeTheme::ExtraParams button_params
;
408 button_params
.scrollbar_arrow
.is_hovering
= false;
409 gfx::Size button_size
= theme
->GetPartSize(
410 ui::NativeTheme::kScrollbarUpArrow
,
411 ui::NativeTheme::kNormal
,
414 ui::NativeTheme::ExtraParams thumb_params
;
415 thumb_params
.scrollbar_thumb
.is_hovering
= false;
416 gfx::Size track_size
= theme
->GetPartSize(
417 ui::NativeTheme::kScrollbarVerticalThumb
,
418 ui::NativeTheme::kNormal
,
421 return std::max(track_size
.width(), button_size
.width());