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 ~ScrollBarButton() override
;
35 gfx::Size
GetPreferredSize() const override
;
36 const char* GetClassName() const override
{ return "ScrollBarButton"; }
39 void OnPaint(gfx::Canvas
* canvas
) override
;
42 ui::NativeTheme::ExtraParams
GetNativeThemeParams() const;
43 ui::NativeTheme::Part
GetNativeThemePart() const;
44 ui::NativeTheme::State
GetNativeThemeState() const;
49 // Wrapper for the scroll thumb
50 class ScrollBarThumb
: public BaseScrollBarThumb
{
52 explicit ScrollBarThumb(BaseScrollBar
* scroll_bar
);
53 ~ScrollBarThumb() override
;
55 gfx::Size
GetPreferredSize() const override
;
56 const char* GetClassName() const override
{ return "ScrollBarThumb"; }
59 void OnPaint(gfx::Canvas
* canvas
) override
;
62 ui::NativeTheme::ExtraParams
GetNativeThemeParams() const;
63 ui::NativeTheme::Part
GetNativeThemePart() const;
64 ui::NativeTheme::State
GetNativeThemeState() const;
66 ScrollBar
* scroll_bar_
;
69 /////////////////////////////////////////////////////////////////////////////
72 ScrollBarButton::ScrollBarButton(ButtonListener
* listener
, Type type
)
73 : BaseScrollBarButton(listener
),
76 SetAccessibilityFocusable(false);
79 ScrollBarButton::~ScrollBarButton() {
82 gfx::Size
ScrollBarButton::GetPreferredSize() const {
83 return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
84 GetNativeThemeState(),
85 GetNativeThemeParams());
88 void ScrollBarButton::OnPaint(gfx::Canvas
* canvas
) {
89 gfx::Rect
bounds(GetPreferredSize());
90 GetNativeTheme()->Paint(canvas
->sk_canvas(), GetNativeThemePart(),
91 GetNativeThemeState(), bounds
,
92 GetNativeThemeParams());
95 ui::NativeTheme::ExtraParams
96 ScrollBarButton::GetNativeThemeParams() const {
97 ui::NativeTheme::ExtraParams params
;
100 case CustomButton::STATE_HOVERED
:
101 params
.scrollbar_arrow
.is_hovering
= true;
104 params
.scrollbar_arrow
.is_hovering
= false;
111 ui::NativeTheme::Part
112 ScrollBarButton::GetNativeThemePart() const {
115 return ui::NativeTheme::kScrollbarUpArrow
;
117 return ui::NativeTheme::kScrollbarDownArrow
;
119 return ui::NativeTheme::kScrollbarLeftArrow
;
121 return ui::NativeTheme::kScrollbarRightArrow
;
123 return ui::NativeTheme::kScrollbarUpArrow
;
127 ui::NativeTheme::State
128 ScrollBarButton::GetNativeThemeState() const {
129 ui::NativeTheme::State state
;
132 case CustomButton::STATE_HOVERED
:
133 state
= ui::NativeTheme::kHovered
;
135 case CustomButton::STATE_PRESSED
:
136 state
= ui::NativeTheme::kPressed
;
138 case CustomButton::STATE_DISABLED
:
139 state
= ui::NativeTheme::kDisabled
;
141 case CustomButton::STATE_NORMAL
:
143 state
= ui::NativeTheme::kNormal
;
150 /////////////////////////////////////////////////////////////////////////////
153 ScrollBarThumb::ScrollBarThumb(BaseScrollBar
* scroll_bar
)
154 : BaseScrollBarThumb(scroll_bar
),
155 scroll_bar_(scroll_bar
) {
157 SetAccessibilityFocusable(false);
160 ScrollBarThumb::~ScrollBarThumb() {
163 gfx::Size
ScrollBarThumb::GetPreferredSize() const {
164 return GetNativeTheme()->GetPartSize(GetNativeThemePart(),
165 GetNativeThemeState(),
166 GetNativeThemeParams());
169 void ScrollBarThumb::OnPaint(gfx::Canvas
* canvas
) {
170 const gfx::Rect
local_bounds(GetLocalBounds());
171 const ui::NativeTheme::State theme_state
= GetNativeThemeState();
172 const ui::NativeTheme::ExtraParams
extra_params(GetNativeThemeParams());
173 GetNativeTheme()->Paint(canvas
->sk_canvas(),
174 GetNativeThemePart(),
178 const ui::NativeTheme::Part gripper_part
= scroll_bar_
->IsHorizontal() ?
179 ui::NativeTheme::kScrollbarHorizontalGripper
:
180 ui::NativeTheme::kScrollbarVerticalGripper
;
181 GetNativeTheme()->Paint(canvas
->sk_canvas(), gripper_part
, theme_state
,
182 local_bounds
, extra_params
);
185 ui::NativeTheme::ExtraParams
ScrollBarThumb::GetNativeThemeParams() const {
186 // This gives the behavior we want.
187 ui::NativeTheme::ExtraParams params
;
188 params
.scrollbar_thumb
.is_hovering
=
189 (GetState() != CustomButton::STATE_HOVERED
);
193 ui::NativeTheme::Part
ScrollBarThumb::GetNativeThemePart() const {
194 if (scroll_bar_
->IsHorizontal())
195 return ui::NativeTheme::kScrollbarHorizontalThumb
;
196 return ui::NativeTheme::kScrollbarVerticalThumb
;
199 ui::NativeTheme::State
ScrollBarThumb::GetNativeThemeState() const {
200 ui::NativeTheme::State state
;
202 switch (GetState()) {
203 case CustomButton::STATE_HOVERED
:
204 state
= ui::NativeTheme::kHovered
;
206 case CustomButton::STATE_PRESSED
:
207 state
= ui::NativeTheme::kPressed
;
209 case CustomButton::STATE_DISABLED
:
210 state
= ui::NativeTheme::kDisabled
;
212 case CustomButton::STATE_NORMAL
:
214 state
= ui::NativeTheme::kNormal
;
223 ////////////////////////////////////////////////////////////////////////////////
224 // NativeScrollBarViews, public:
226 const char NativeScrollBarViews::kViewClassName
[] = "NativeScrollBarViews";
228 NativeScrollBarViews::NativeScrollBarViews(NativeScrollBar
* scroll_bar
)
229 : BaseScrollBar(scroll_bar
->IsHorizontal(),
230 new ScrollBarThumb(this)),
231 native_scroll_bar_(scroll_bar
) {
232 set_controller(native_scroll_bar_
->controller());
234 if (native_scroll_bar_
->IsHorizontal()) {
235 prev_button_
= new ScrollBarButton(this, ScrollBarButton::LEFT
);
236 next_button_
= new ScrollBarButton(this, ScrollBarButton::RIGHT
);
238 part_
= ui::NativeTheme::kScrollbarHorizontalTrack
;
240 prev_button_
= new ScrollBarButton(this, ScrollBarButton::UP
);
241 next_button_
= new ScrollBarButton(this, ScrollBarButton::DOWN
);
243 part_
= ui::NativeTheme::kScrollbarVerticalTrack
;
246 state_
= ui::NativeTheme::kNormal
;
248 AddChildView(prev_button_
);
249 AddChildView(next_button_
);
251 prev_button_
->set_context_menu_controller(this);
252 next_button_
->set_context_menu_controller(this);
255 NativeScrollBarViews::~NativeScrollBarViews() {
258 ////////////////////////////////////////////////////////////////////////////////
259 // NativeScrollBarViews, View overrides:
261 void NativeScrollBarViews::Layout() {
262 gfx::Size size
= prev_button_
->GetPreferredSize();
263 prev_button_
->SetBounds(0, 0, size
.width(), size
.height());
265 if (native_scroll_bar_
->IsHorizontal()) {
266 next_button_
->SetBounds(width() - size
.width(), 0,
267 size
.width(), size
.height());
269 next_button_
->SetBounds(0, height() - size
.height(),
270 size
.width(), size
.height());
273 GetThumb()->SetBoundsRect(GetTrackBounds());
276 void NativeScrollBarViews::OnPaint(gfx::Canvas
* canvas
) {
277 gfx::Rect bounds
= GetTrackBounds();
279 if (bounds
.IsEmpty())
282 params_
.scrollbar_track
.track_x
= bounds
.x();
283 params_
.scrollbar_track
.track_y
= bounds
.y();
284 params_
.scrollbar_track
.track_width
= bounds
.width();
285 params_
.scrollbar_track
.track_height
= bounds
.height();
286 params_
.scrollbar_track
.classic_state
= 0;
288 GetNativeTheme()->Paint(canvas
->sk_canvas(), part_
, state_
, bounds
, params_
);
291 gfx::Size
NativeScrollBarViews::GetPreferredSize() const {
292 const ui::NativeTheme
* theme
= native_scroll_bar_
->GetNativeTheme();
293 if (native_scroll_bar_
->IsHorizontal())
294 return gfx::Size(0, GetHorizontalScrollBarHeight(theme
));
295 return gfx::Size(GetVerticalScrollBarWidth(theme
), 0);
298 const char* NativeScrollBarViews::GetClassName() const {
299 return kViewClassName
;
302 int NativeScrollBarViews::GetLayoutSize() const {
303 gfx::Size size
= prev_button_
->GetPreferredSize();
304 return IsHorizontal() ? size
.height() : size
.width();
307 void NativeScrollBarViews::ScrollToPosition(int position
) {
308 controller()->ScrollToPosition(native_scroll_bar_
, position
);
311 int NativeScrollBarViews::GetScrollIncrement(bool is_page
, bool is_positive
) {
312 return controller()->GetScrollIncrement(native_scroll_bar_
,
317 //////////////////////////////////////////////////////////////////////////////
318 // BaseButton::ButtonListener overrides:
320 void NativeScrollBarViews::ButtonPressed(Button
* sender
,
321 const ui::Event
& event
) {
322 if (sender
== prev_button_
) {
323 ScrollByAmount(SCROLL_PREV_LINE
);
324 } else if (sender
== next_button_
) {
325 ScrollByAmount(SCROLL_NEXT_LINE
);
329 ////////////////////////////////////////////////////////////////////////////////
330 // NativeScrollBarViews, NativeScrollBarWrapper overrides:
332 int NativeScrollBarViews::GetPosition() const {
333 return BaseScrollBar::GetPosition();
336 View
* NativeScrollBarViews::GetView() {
340 void NativeScrollBarViews::Update(int viewport_size
,
343 BaseScrollBar::Update(viewport_size
, content_size
, current_pos
);
346 ////////////////////////////////////////////////////////////////////////////////
347 // NativeScrollBarViews, private:
349 gfx::Rect
NativeScrollBarViews::GetTrackBounds() const {
350 gfx::Rect bounds
= GetLocalBounds();
351 gfx::Size size
= prev_button_
->GetPreferredSize();
352 BaseScrollBarThumb
* thumb
= GetThumb();
354 if (native_scroll_bar_
->IsHorizontal()) {
355 bounds
.set_x(bounds
.x() + size
.width());
356 bounds
.set_width(std::max(0, bounds
.width() - 2 * size
.width()));
357 bounds
.set_height(thumb
->GetPreferredSize().height());
359 bounds
.set_y(bounds
.y() + size
.height());
360 bounds
.set_height(std::max(0, bounds
.height() - 2 * size
.height()));
361 bounds
.set_width(thumb
->GetPreferredSize().width());
367 ////////////////////////////////////////////////////////////////////////////////
368 // NativewScrollBarWrapper, public:
371 NativeScrollBarWrapper
* NativeScrollBarWrapper::CreateWrapper(
372 NativeScrollBar
* scroll_bar
) {
373 return new NativeScrollBarViews(scroll_bar
);
377 int NativeScrollBarWrapper::GetHorizontalScrollBarHeight(
378 const ui::NativeTheme
* theme
) {
380 theme
= ui::NativeTheme::instance();
381 ui::NativeTheme::ExtraParams button_params
;
382 button_params
.scrollbar_arrow
.is_hovering
= false;
383 gfx::Size button_size
= theme
->GetPartSize(
384 ui::NativeTheme::kScrollbarLeftArrow
,
385 ui::NativeTheme::kNormal
,
388 ui::NativeTheme::ExtraParams thumb_params
;
389 thumb_params
.scrollbar_thumb
.is_hovering
= false;
390 gfx::Size track_size
= theme
->GetPartSize(
391 ui::NativeTheme::kScrollbarHorizontalThumb
,
392 ui::NativeTheme::kNormal
,
395 return std::max(track_size
.height(), button_size
.height());
399 int NativeScrollBarWrapper::GetVerticalScrollBarWidth(
400 const ui::NativeTheme
* theme
) {
402 theme
= ui::NativeTheme::instance();
403 ui::NativeTheme::ExtraParams button_params
;
404 button_params
.scrollbar_arrow
.is_hovering
= false;
405 gfx::Size button_size
= theme
->GetPartSize(
406 ui::NativeTheme::kScrollbarUpArrow
,
407 ui::NativeTheme::kNormal
,
410 ui::NativeTheme::ExtraParams thumb_params
;
411 thumb_params
.scrollbar_thumb
.is_hovering
= false;
412 gfx::Size track_size
= theme
->GetPartSize(
413 ui::NativeTheme::kScrollbarVerticalThumb
,
414 ui::NativeTheme::kNormal
,
417 return std::max(track_size
.width(), button_size
.width());