Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(172)

Unified Diff: ui/views/controls/scrollbar/cocoa_scroll_bar.mm

Issue 1671313002: MacViews: Overlay Scrollbars with Show/Hide Animations (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698