File: overlay_scroll_bar.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (209 lines) | stat: -rw-r--r-- 7,227 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Copyright 2013 The Chromium Authors
// 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/overlay_scroll_bar.h"

#include <memory>

#include "base/functional/bind.h"
#include "base/i18n/rtl.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/canvas.h"
#include "ui/native_theme/overlay_scrollbar_constants_aura.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/layout/fill_layout.h"

namespace views {
namespace {

// Total thickness of the thumb (matches visuals when hovered).
constexpr int kThumbThickness =
    ui::kOverlayScrollbarThumbWidthPressed + ui::kOverlayScrollbarStrokeWidth;
// When hovered, the thumb takes up the full width. Otherwise, it's a bit
// slimmer.
constexpr int kThumbHoverOffset = 4;
// The layout size of the thumb stroke, in DIP.
constexpr int kThumbStroke = ui::kOverlayScrollbarStrokeWidth;
// The visual size of the thumb stroke, in px.
constexpr int kThumbStrokeVisualSize = ui::kOverlayScrollbarStrokeWidth;

}  // namespace

OverlayScrollBar::Thumb::Thumb(OverlayScrollBar* scroll_bar)
    : BaseScrollBarThumb(scroll_bar), scroll_bar_(scroll_bar) {
  // |scroll_bar| isn't done being constructed; it's not safe to do anything
  // that might reference it yet.
}

OverlayScrollBar::Thumb::~Thumb() = default;

void OverlayScrollBar::Thumb::Init() {
  SetFlipCanvasOnPaintForRTLUI(true);
  SetPaintToLayer();
  layer()->SetFillsBoundsOpaquely(false);
  // Animate all changes to the layer except the first one.
  OnStateChanged();
  layer()->SetAnimator(ui::LayerAnimator::CreateImplicitAnimator());
}

gfx::Size OverlayScrollBar::Thumb::CalculatePreferredSize(
    const SizeBounds& /*available_size*/) const {
  // The visual size of the thumb is kThumbThickness, but it slides back and
  // forth by kThumbHoverOffset. To make event targetting work well, expand the
  // width of the thumb such that it's always taking up the full width of the
  // track regardless of the offset.
  return gfx::Size(kThumbThickness + kThumbHoverOffset,
                   kThumbThickness + kThumbHoverOffset);
}

void OverlayScrollBar::Thumb::OnPaint(gfx::Canvas* canvas) {
  const bool hovered = GetState() != Button::STATE_NORMAL;
  cc::PaintFlags fill_flags;
  fill_flags.setStyle(cc::PaintFlags::kFill_Style);
  fill_flags.setColor(GetColorProvider()->GetColor(
      hovered ? ui::kColorOverlayScrollbarFillHovered
              : ui::kColorOverlayScrollbarFill));
  gfx::RectF fill_bounds(GetLocalBounds());
  fill_bounds.Inset(gfx::InsetsF::TLBR(IsHorizontal() ? kThumbHoverOffset : 0,
                                       IsHorizontal() ? 0 : kThumbHoverOffset,
                                       0, 0));
  fill_bounds.Inset(gfx::InsetsF::TLBR(kThumbStroke, kThumbStroke,
                                       IsHorizontal() ? 0 : kThumbStroke,
                                       IsHorizontal() ? kThumbStroke : 0));
  canvas->DrawRect(fill_bounds, fill_flags);

  cc::PaintFlags stroke_flags;
  stroke_flags.setStyle(cc::PaintFlags::kStroke_Style);
  stroke_flags.setColor(GetColorProvider()->GetColor(
      hovered ? ui::kColorOverlayScrollbarStrokeHovered
              : ui::kColorOverlayScrollbarStroke));
  stroke_flags.setStrokeWidth(kThumbStrokeVisualSize);
  stroke_flags.setStrokeCap(cc::PaintFlags::kSquare_Cap);

  // The stroke is a single pixel, so we must deal with the unscaled canvas.
  const float dsf = canvas->UndoDeviceScaleFactor();
  gfx::RectF stroke_bounds(fill_bounds);
  stroke_bounds.Scale(dsf);
  // The stroke should be aligned to the pixel center that is nearest the fill,
  // so outset by a half pixel.
  stroke_bounds.Inset(gfx::InsetsF(-kThumbStrokeVisualSize / 2.0f));
  // The stroke doesn't apply to the far edge of the thumb.
  SkPath path;
  path.moveTo(gfx::PointFToSkPoint(stroke_bounds.top_right()));
  path.lineTo(gfx::PointFToSkPoint(stroke_bounds.origin()));
  path.lineTo(gfx::PointFToSkPoint(stroke_bounds.bottom_left()));
  if (IsHorizontal()) {
    path.moveTo(gfx::PointFToSkPoint(stroke_bounds.bottom_right()));
    path.close();
  } else {
    path.lineTo(gfx::PointFToSkPoint(stroke_bounds.bottom_right()));
  }
  canvas->DrawPath(path, stroke_flags);
}

void OverlayScrollBar::Thumb::OnBoundsChanged(
    const gfx::Rect& previous_bounds) {
  scroll_bar_->Show();
  // Don't start the hide countdown if the thumb is still hovered or pressed.
  if (GetState() == Button::STATE_NORMAL) {
    scroll_bar_->StartHideCountdown();
  }
}

void OverlayScrollBar::Thumb::OnStateChanged() {
  if (GetState() == Button::STATE_NORMAL) {
    gfx::Transform translation;
    const int direction = base::i18n::IsRTL() ? -1 : 1;
    translation.Translate(
        gfx::Vector2d(IsHorizontal() ? 0 : direction * kThumbHoverOffset,
                      IsHorizontal() ? kThumbHoverOffset : 0));
    layer()->SetTransform(translation);

    if (GetWidget()) {
      scroll_bar_->StartHideCountdown();
    }
  } else {
    layer()->SetTransform(gfx::Transform());
  }
  SchedulePaint();
}

BEGIN_METADATA(OverlayScrollBar, Thumb)
END_METADATA

OverlayScrollBar::OverlayScrollBar(Orientation orientation)
    : ScrollBar(orientation) {
  SetNotifyEnterExitOnChild(true);
  SetPaintToLayer();
  layer()->SetMasksToBounds(true);
  layer()->SetFillsBoundsOpaquely(false);

  // Allow the thumb to take up the whole size of the scrollbar.  Layout need
  // only set the thumb cross-axis coordinate; ScrollBar::Update() will set the
  // thumb size/offset.
  SetLayoutManager(std::make_unique<views::FillLayout>());
  auto* thumb = new Thumb(this);
  SetThumb(thumb);
  thumb->Init();
}

OverlayScrollBar::~OverlayScrollBar() = default;

gfx::Insets OverlayScrollBar::GetInsets() const {
  return GetOrientation() == Orientation::kHorizontal
             ? gfx::Insets::TLBR(-kThumbHoverOffset, 0, 0, 0)
             : gfx::Insets::TLBR(0, -kThumbHoverOffset, 0, 0);
}

void OverlayScrollBar::OnMouseEntered(const ui::MouseEvent& event) {
  Show();
}

void OverlayScrollBar::OnMouseExited(const ui::MouseEvent& event) {
  StartHideCountdown();
}

bool OverlayScrollBar::OverlapsContent() const {
  return true;
}

gfx::Rect OverlayScrollBar::GetTrackBounds() const {
  return GetContentsBounds();
}

int OverlayScrollBar::GetThickness() const {
  return kThumbThickness;
}

void OverlayScrollBar::Show() {
  layer()->SetOpacity(1.0f);
  hide_timer_.Stop();
}

void OverlayScrollBar::Hide() {
  ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
  settings.SetTransitionDuration(ui::kOverlayScrollbarFadeDuration);
  layer()->SetOpacity(0.0f);
}

void OverlayScrollBar::StartHideCountdown() {
  if (IsMouseHovered()) {
    return;
  }
  hide_timer_.Start(
      FROM_HERE, ui::kOverlayScrollbarFadeDelay,
      base::BindOnce(&OverlayScrollBar::Hide, base::Unretained(this)));
}

BEGIN_METADATA(OverlayScrollBar)
END_METADATA

}  // namespace views