Chromium Code Reviews| Index: ui/views/controls/scrollbar/cocoa_scroll_bar.mm |
| diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d6a003cc08495aff8138cae9ef6e050f6b987af8 |
| --- /dev/null |
| +++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm |
| @@ -0,0 +1,288 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ui/views/controls/scrollbar/cocoa_scroll_bar.h" |
| + |
| +#import "base/mac/sdk_forward_declarations.h" |
| +#include "third_party/skia/include/core/SkColor.h" |
| +#include "ui/compositor/layer.h" |
| +#include "ui/compositor/layer_animator.h" |
| +#include "ui/gfx/canvas.h" |
| +#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h" |
| + |
| +namespace views { |
| + |
| +namespace { |
| + |
| +// How long we should wait before hiding the scrollbar. |
| +const int kScrollbarHideTimeoutMs = 500; |
| + |
| +// The width of the scrollbar. |
| +const int kScrollbarWidth = 15; |
| + |
| +// The width of the scrollbar thumb. |
| +const int kScrollbarThumbWidth = 10; |
| + |
| +// The width of the scroller track border. |
| +const int kScrollerTrackBorderWidth = 1; |
| + |
| +// The amount the thumb is inset from both the ends and the sides of the track. |
| +const int kScrollbarThumbInset = 3; |
| + |
| +// Scrollbar thumb color. |
| +const SkColor kScrollerThumbColor = SkColorSetARGB(0x38, 0, 0, 0); |
| + |
| +// Scroller track colors. |
| +const SkColor kScrollerTrackColor = SkColorSetRGB(0xF9, 0xF9, 0xF9); |
| +const SkColor kScrollerTrackInnerBorderColor = SkColorSetRGB(0xE4, 0xE4, 0xE4); |
| +const SkColor kScrollerTrackOuterBorderColor = SkColorSetRGB(0xEF, 0xEF, 0xEF); |
| + |
| +// The length of the fade animation. |
| +static const int kFadeDurationMs = 240; |
|
tapted
2016/02/16 06:47:58
nit: not static
Also perhaps move this up next to
spqchan
2016/02/16 23:18:19
Done.
|
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBarThumb |
| + |
| +class CocoaScrollBarThumb : public BaseScrollBarThumb { |
| + public: |
| + explicit CocoaScrollBarThumb(CocoaScrollBar* scroll_bar); |
| + ~CocoaScrollBarThumb() override; |
| + |
| + protected: |
| + // View overrides: |
| + gfx::Size GetPreferredSize() const override; |
| + void OnPaint(gfx::Canvas* canvas) override; |
| + void OnMouseEntered(const ui::MouseEvent& event) override; |
| + void OnMouseExited(const ui::MouseEvent& event) override; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(CocoaScrollBarThumb); |
| +}; |
| + |
| +CocoaScrollBarThumb::CocoaScrollBarThumb(CocoaScrollBar* scroll_bar) |
| + : BaseScrollBarThumb(scroll_bar) { |
| + // This is necessary, otherwise the thumb will be rendered below the views if |
| + // those views paint to their own layers. |
| + SetPaintToLayer(true); |
| + SetFillsBoundsOpaquely(false); |
| +} |
| + |
| +CocoaScrollBarThumb::~CocoaScrollBarThumb() {} |
| + |
| +gfx::Size CocoaScrollBarThumb::GetPreferredSize() const { |
| + return gfx::Size(kScrollbarThumbWidth, kScrollbarThumbWidth); |
| +} |
| + |
| +void CocoaScrollBarThumb::OnPaint(gfx::Canvas* canvas) { |
| + gfx::Rect local_bounds(GetLocalBounds()); |
| + SkPaint paint; |
| + paint.setStyle(SkPaint::kFill_Style); |
| + paint.setColor(kScrollerThumbColor); |
| + const SkScalar radius = std::min(local_bounds.width(), local_bounds.height()); |
| + canvas->DrawRoundRect(local_bounds, radius, paint); |
| +} |
| + |
| +void CocoaScrollBarThumb::OnMouseEntered(const ui::MouseEvent& event) { |
| + BaseScrollBarThumb::OnMouseEntered(event); |
| + CocoaScrollBar* scrollbar = static_cast<CocoaScrollBar*>(scroll_bar()); |
| + scrollbar->OnMouseEnteredScrollbarThumb(event); |
| +} |
| + |
| +void CocoaScrollBarThumb::OnMouseExited(const ui::MouseEvent& event) { |
| + BaseScrollBarThumb::OnMouseExited(event); |
| + CocoaScrollBar* scrollbar = static_cast<CocoaScrollBar*>(scroll_bar()); |
| + scrollbar->OnMouseExitedScrollbarThumb(event); |
| +} |
| + |
| +} // namespace |
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBar class |
| + |
| +CocoaScrollBar::CocoaScrollBar(bool horizontal) |
| + : BaseScrollBar(horizontal, new CocoaScrollBarThumb(this)), |
| + is_hovering_(false) { |
| + bridge_.reset([[ViewsScrollbarBridge alloc] init]); |
| + [bridge_ setDelegate:this]; |
| + |
| + scroller_style_ = [ViewsScrollbarBridge getPreferredScrollerStyle]; |
| + |
| + SetPaintToLayer(true); |
| + has_scrolltrack_ = scroller_style_ == NSScrollerStyleLegacy; |
| + layer()->SetOpacity(scroller_style_ == NSScrollerStyleOverlay ? 0.0 : 1.0); |
| +} |
| + |
| +CocoaScrollBar::~CocoaScrollBar() { |
| + [bridge_ setDelegate:nullptr]; |
| +} |
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBar, BaseScrollBar: |
| + |
| +gfx::Rect CocoaScrollBar::GetTrackBounds() const { |
| + gfx::Rect local_bounds(GetLocalBounds()); |
| + local_bounds.Inset(kScrollbarThumbInset, kScrollbarThumbInset); |
| + |
| + gfx::Size track_size = local_bounds.size(); |
| + track_size.SetToMax(GetThumb()->size()); |
| + local_bounds.set_size(track_size); |
| + return local_bounds; |
| +} |
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBar, ScrollBar: |
| + |
| +int CocoaScrollBar::GetLayoutSize() const { |
| + return 0; |
| +} |
| + |
| +int CocoaScrollBar::GetContentOverlapSize() const { |
| + // TODO: (spqchan) Figure out what to do when we have a corner. |
| + return kScrollbarWidth; |
| +} |
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBar::Views: |
| + |
| +gfx::Size CocoaScrollBar::GetPreferredSize() const { |
| + return gfx::Size(); |
|
tapted
2016/02/16 06:47:58
Does this need to change based on scroller_style_?
spqchan
2016/02/16 23:18:18
This most likely will have to change later, especi
spqchan
2016/02/16 23:22:49
Oh shoot, I see what you mean. I'll look into this
|
| +} |
| + |
| +void CocoaScrollBar::Layout() { |
|
tapted
2016/02/16 06:47:58
I wonder if this could go in BaseScrollBar.... Of
spqchan
2016/02/16 23:18:18
Yeah, that would work.
|
| + gfx::Rect thumb_bounds = GetTrackBounds(); |
| + BaseScrollBarThumb* thumb = GetThumb(); |
| + if (IsHorizontal()) { |
| + thumb_bounds.set_x(thumb->x()); |
| + thumb_bounds.set_width(thumb->width()); |
| + } else { |
| + thumb_bounds.set_y(thumb->y()); |
| + thumb_bounds.set_height(thumb->height()); |
| + } |
| + thumb->SetBoundsRect(thumb_bounds); |
| +} |
| + |
| +void CocoaScrollBar::OnPaint(gfx::Canvas* canvas) { |
| + if (!has_scrolltrack_) |
| + return; |
| + |
| + // Paint the scrollbar track background. |
| + gfx::Rect track_rect = GetLocalBounds(); |
| + SkPaint paint; |
| + paint.setColor(kScrollerTrackColor); |
| + canvas->DrawRect(track_rect, paint); |
| + |
| + // Paint the inner and outer borders. |
| + // Note: Unless there's a possibility of wanting borders |
| + // to be more than 1px wide, we might want to use drawLine |
| + if (IsHorizontal()) { |
| + // Draw the top border. |
| + SkPaint paint; |
| + paint.setColor(kScrollerTrackInnerBorderColor); |
| + gfx::Rect top_border(track_rect); |
| + top_border.set_height(kScrollerTrackBorderWidth); |
| + canvas->DrawRect(top_border, paint); |
| + |
| + // Draw the bottom border. |
| + paint.setColor(kScrollerTrackOuterBorderColor); |
| + gfx::Rect bottom_border(top_border); |
| + bottom_border.set_y(track_rect.bottom()); |
| + canvas->DrawRect(bottom_border, paint); |
| + } else { |
| + // Draw the left border. |
| + SkPaint paint; |
| + paint.setColor(kScrollerTrackInnerBorderColor); |
| + gfx::Rect left_border(track_rect); |
| + left_border.set_width(kScrollerTrackBorderWidth); |
|
tapted
2016/02/16 06:47:58
do these look any better merged? I think only the
spqchan
2016/02/16 23:18:18
I kept it separate because I thought it would be e
|
| + canvas->DrawRect(left_border, paint); |
| + |
| + // Draw the right border. |
| + paint.setColor(kScrollerTrackOuterBorderColor); |
| + gfx::Rect right_border(left_border); |
| + right_border.set_x(track_rect.right()); |
| + canvas->DrawRect(right_border, paint); |
| + } |
| +} |
| + |
| +void CocoaScrollBar::OnMouseEnteredScrollbarThumb(const ui::MouseEvent& event) { |
| + if (scroller_style_ != NSScrollerStyleOverlay) |
| + return; |
| + |
| + hide_scrollbar_timer_.Stop(); |
| + is_hovering_ = true; |
| + if (layer()->opacity()) { |
| + ShowScrollbar(); |
| + } |
| +} |
| + |
| +void CocoaScrollBar::OnMouseExitedScrollbarThumb(const ui::MouseEvent& event) { |
| + if (scroller_style_ != NSScrollerStyleOverlay) |
| + return; |
|
tapted
2016/02/16 06:47:58
nit: blank line after return
spqchan
2016/02/16 23:18:18
We can't have blank lines after return?
TIL, I'll
tapted
2016/02/16 23:32:57
Ah, no the opposite :). There *should* be a line b
|
| + is_hovering_ = false; |
| + ResetTimer(); |
| +} |
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBar::ScrollDelegate: |
| + |
| +bool CocoaScrollBar::OnScroll(float dx, float dy) { |
| + bool did_scroll = BaseScrollBar::OnScroll(dx, dy); |
| + if (did_scroll && scroller_style_ == NSScrollerStyleOverlay) { |
| + if (layer()->opacity() < 1.0) |
| + ShowScrollbar(); |
| + ResetTimer(); |
| + } |
| + return did_scroll; |
| +} |
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBar::ViewsScrollbarBridge: |
| + |
| +void CocoaScrollBar::OnScrollerStyleChanged() { |
| + NSScrollerStyle scroller_style = |
| + [ViewsScrollbarBridge getPreferredScrollerStyle]; |
| + if (scroller_style_ == scroller_style) |
| + return; |
| + |
| + scroller_style_ = scroller_style; |
| + if (scroller_style_ == NSScrollerStyleOverlay) { |
| + HideScrollbar(); |
| + } else { |
| + ShowScrollbar(); |
| + } |
| +} |
| + |
| +////////////////////////////////////////////////////////////////// |
| +// CocoaScrollBar, private: |
| + |
| +void CocoaScrollBar::HideScrollbar() { |
| + layer()->GetAnimator()->SetTransitionDuration( |
| + base::TimeDelta::FromMilliseconds(kFadeDurationMs)); |
| + layer()->SetOpacity(0.0); |
| +} |
| + |
| +void CocoaScrollBar::ShowScrollbar() { |
| + // Updates the scrolltrack and repaint it, if necessary. |
| + bool has_scrolltrack = |
| + scroller_style_ == NSScrollerStyleLegacy || is_hovering_; |
| + if (has_scrolltrack_ != has_scrolltrack) { |
| + has_scrolltrack_ = has_scrolltrack; |
| + SchedulePaint(); |
| + } |
| + |
| + layer()->GetAnimator()->SetTransitionDuration( |
| + base::TimeDelta::FromMilliseconds(0)); |
|
tapted
2016/02/16 06:47:58
this line probably won't be needed with the Scoped
spqchan
2016/02/16 23:18:18
Done.
|
| + layer()->SetOpacity(1.0); |
| +} |
| + |
| +void CocoaScrollBar::ResetTimer() { |
| + if (hide_scrollbar_timer_.IsRunning()) { |
| + hide_scrollbar_timer_.Reset(); |
| + } else { |
| + hide_scrollbar_timer_.Start( |
| + FROM_HERE, base::TimeDelta::FromMilliseconds(kScrollbarHideTimeoutMs), |
| + this, &CocoaScrollBar::HideScrollbar); |
| + } |
| +} |
| + |
| +} // namespace views |