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

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: nits 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
« no previous file with comments | « ui/views/controls/scrollbar/cocoa_scroll_bar.h ('k') | ui/views/style/platform_style.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..7f8bae8126bb887be82c0e94352be3b3eadad48b
--- /dev/null
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
@@ -0,0 +1,301 @@
+// Copyright 2016 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.
+
+#import "ui/views/controls/scrollbar/cocoa_scroll_bar.h"
+
+#import "base/mac/sdk_forward_declarations.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
+
+namespace views {
+
+namespace {
+
+// The length of the fade animation.
+const int kFadeDurationMs = 240;
+
+// 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 colors.
+const SkColor kScrollerDefaultThumbColor = SkColorSetARGB(0x38, 0, 0, 0);
+const SkColor kScrollerHoverThumbColor = SkColorSetARGB(0x80, 0, 0, 0);
+
+// Scroller track colors.
+// TODO(spqchan): Add an alpha channel for the overlay-style scroll track.
+const SkColor kScrollerTrackGradientColors[] = {
+ SkColorSetRGB(0xEF, 0xEF, 0xEF), SkColorSetRGB(0xF9, 0xF9, 0xF9),
+ SkColorSetRGB(0xFD, 0xFD, 0xFD), SkColorSetRGB(0xF6, 0xF6, 0xF6)};
+const SkColor kScrollerTrackInnerBorderColor = SkColorSetRGB(0xE4, 0xE4, 0xE4);
+const SkColor kScrollerTrackOuterBorderColor = SkColorSetRGB(0xEF, 0xEF, 0xEF);
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBarThumb
+
+class CocoaScrollBarThumb : public BaseScrollBarThumb {
+ public:
+ explicit CocoaScrollBarThumb(CocoaScrollBar* scroll_bar);
+ ~CocoaScrollBarThumb() override;
+
+ // Returns true if the thumb is in hover or pressed state.
+ bool IsStateHoverOrPressed();
+
+ protected:
+ // View:
+ gfx::Size GetPreferredSize() const override;
+ void OnPaint(gfx::Canvas* canvas) override;
+ void OnMouseEntered(const ui::MouseEvent& event) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CocoaScrollBarThumb);
+};
+
+CocoaScrollBarThumb::CocoaScrollBarThumb(CocoaScrollBar* scroll_bar)
+ : BaseScrollBarThumb(scroll_bar) {
+ DCHECK(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() {}
+
+bool CocoaScrollBarThumb::IsStateHoverOrPressed() {
+ CustomButton::ButtonState state = GetState();
+ return state == CustomButton::STATE_HOVERED ||
+ state == CustomButton::STATE_PRESSED;
+}
+
+gfx::Size CocoaScrollBarThumb::GetPreferredSize() const {
+ return gfx::Size(kScrollbarThumbWidth, kScrollbarThumbWidth);
+}
+
+void CocoaScrollBarThumb::OnPaint(gfx::Canvas* canvas) {
+ CocoaScrollBar* scrollbar = static_cast<CocoaScrollBar*>(scroll_bar());
+ DCHECK(scrollbar);
+
+ SkColor thumb_color = kScrollerDefaultThumbColor;
+ if (scrollbar->GetScrollerStyle() == NSScrollerStyleOverlay ||
+ IsStateHoverOrPressed()) {
+ thumb_color = kScrollerHoverThumbColor;
+ }
+
+ gfx::Rect local_bounds(GetLocalBounds());
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(thumb_color);
+ 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);
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar class
+
+CocoaScrollBar::CocoaScrollBar(bool horizontal)
+ : BaseScrollBar(horizontal, new CocoaScrollBarThumb(this)),
+ hide_scrollbar_timer_(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kScrollbarHideTimeoutMs),
+ base::Bind(&CocoaScrollBar::HideScrollbar, base::Unretained(this)),
+ false) {
+ bridge_.reset([[ViewsScrollbarBridge alloc] initWithDelegate:this]);
+
+ scroller_style_ = [ViewsScrollbarBridge getPreferredScrollerStyle];
+
+ SetPaintToLayer(true);
+ has_scrolltrack_ = scroller_style_ == NSScrollerStyleLegacy;
+ layer()->SetOpacity(scroller_style_ == NSScrollerStyleOverlay ? 0.0 : 1.0);
+}
+
+CocoaScrollBar::~CocoaScrollBar() {
+ [bridge_ clearDelegate];
+}
+
+//////////////////////////////////////////////////////////////////
+// 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 scroller_style_ == NSScrollerStyleOverlay ? 0 : kScrollbarWidth;
+}
+
+int CocoaScrollBar::GetContentOverlapSize() const {
+ return scroller_style_ == NSScrollerStyleLegacy ? 0 : kScrollbarWidth;
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar::Views:
+
+void CocoaScrollBar::Layout() {
+ GetThumb()->SetBoundsRect(GetTrackBounds());
+}
+
+gfx::Size CocoaScrollBar::GetPreferredSize() const {
+ return gfx::Size();
+}
+
+void CocoaScrollBar::OnPaint(gfx::Canvas* canvas) {
+ if (!has_scrolltrack_)
+ return;
+
+ // Paint the scrollbar track background.
+ gfx::Rect track_rect = GetLocalBounds();
+
+ SkPoint gradient_bounds[2];
+ if (IsHorizontal()) {
+ gradient_bounds[0].set(track_rect.x(), track_rect.y());
+ gradient_bounds[1].set(track_rect.x(), track_rect.bottom());
+ } else {
+ gradient_bounds[0].set(track_rect.x(), track_rect.y());
+ gradient_bounds[1].set(track_rect.right(), track_rect.y());
+ }
+ skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::CreateLinear(
+ gradient_bounds, kScrollerTrackGradientColors, nullptr,
+ arraysize(kScrollerTrackGradientColors), SkShader::kClamp_TileMode));
+ SkPaint gradient;
+ gradient.setShader(shader.get());
+ canvas->DrawRect(track_rect, gradient);
+
+ // Draw the inner border: top if horizontal, left if vertical.
+ SkPaint paint;
+ paint.setColor(kScrollerTrackInnerBorderColor);
+ gfx::Rect inner_border(track_rect);
+ if (IsHorizontal())
+ inner_border.set_height(kScrollerTrackBorderWidth);
+ else
+ inner_border.set_width(kScrollerTrackBorderWidth);
+ canvas->DrawRect(inner_border, paint);
+
+ // Draw the outer border: bottom if horizontal, right if veritcal.
+ paint.setColor(kScrollerTrackOuterBorderColor);
+ gfx::Rect outer_border(inner_border);
+ if (IsHorizontal())
+ outer_border.set_y(track_rect.bottom());
+ else
+ outer_border.set_x(track_rect.right());
+ canvas->DrawRect(outer_border, paint);
+}
+
+void CocoaScrollBar::OnMouseEnteredScrollbarThumb(const ui::MouseEvent& event) {
+ if (scroller_style_ != NSScrollerStyleOverlay)
+ return;
+
+ // If the scrollbar thumb has not compeletely faded away, then reshow it when
+ // the mouse enters the scrollbar thumb.
+ if (layer()->opacity())
+ ShowScrollbar();
+
+ hide_scrollbar_timer_.Reset();
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar::ScrollDelegate:
+
+bool CocoaScrollBar::OnScroll(float dx, float dy) {
+ bool did_scroll = BaseScrollBar::OnScroll(dx, dy);
+ if (did_scroll && scroller_style_ == NSScrollerStyleOverlay) {
+ ShowScrollbar();
+ hide_scrollbar_timer_.Reset();
+ }
+ return did_scroll;
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar::ViewsScrollbarBridge:
+
+void CocoaScrollBar::OnScrollerStyleChanged() {
+ NSScrollerStyle scroller_style =
+ [ViewsScrollbarBridge getPreferredScrollerStyle];
+ if (scroller_style_ == scroller_style)
+ return;
+
+ scroller_style_ = scroller_style;
+
+ // Ensure that the ScrollView updates the scrollbar's layout.
+ if (parent())
+ parent()->Layout();
+
+ if (scroller_style_ == NSScrollerStyleOverlay) {
+ // Hide the scrollbar, but don't fade out.
+ layer()->SetOpacity(0.0);
+ } else {
+ ShowScrollbar();
+ }
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar, private:
+
+void CocoaScrollBar::HideScrollbar() {
+ DCHECK_EQ(scroller_style_, NSScrollerStyleOverlay);
+
+ // If the thumb is in a hover or pressed state, we don't want the scrollbar
+ // to disappear. As such, we should reset the timer.
+ CocoaScrollBarThumb* thumb = static_cast<CocoaScrollBarThumb*>(GetThumb());
+ if (thumb->IsStateHoverOrPressed()) {
+ hide_scrollbar_timer_.Reset();
+ return;
+ }
+
+ ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
+ animation.SetTransitionDuration(
+ base::TimeDelta::FromMilliseconds(kFadeDurationMs));
+ layer()->SetOpacity(0.0);
+}
+
+void CocoaScrollBar::ShowScrollbar() {
+ // Updates the scrolltrack and repaint it, if necessary.
+ CocoaScrollBarThumb* thumb = static_cast<CocoaScrollBarThumb*>(GetThumb());
+ bool has_scrolltrack = scroller_style_ == NSScrollerStyleLegacy ||
+ thumb->IsStateHoverOrPressed();
+ if (has_scrolltrack_ != has_scrolltrack) {
+ has_scrolltrack_ = has_scrolltrack;
+ SchedulePaint();
+ }
+
+ layer()->SetOpacity(1.0);
+ hide_scrollbar_timer_.Stop();
+}
+
+} // namespace views
« no previous file with comments | « ui/views/controls/scrollbar/cocoa_scroll_bar.h ('k') | ui/views/style/platform_style.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698