summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorbacker@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-25 20:13:02 +0000
committerbacker@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-25 20:13:02 +0000
commit2339fcfff952e8c38b2b527652d2283dd59b77fd (patch)
treecf18114e4cf7a2dea0a8567516a5b2cdf6dd6ab4 /views
parent43a16c3e00423d1b655a64bbabd0db37db3c111b (diff)
downloadchromium_src-2339fcfff952e8c38b2b527652d2283dd59b77fd.zip
chromium_src-2339fcfff952e8c38b2b527652d2283dd59b77fd.tar.gz
chromium_src-2339fcfff952e8c38b2b527652d2283dd59b77fd.tar.bz2
Adding a Views scrollbar implementation.
BUG=none TEST=Verified basic functionality using views_examples. Review URL: http://codereview.chromium.org/7669028 Patch from Daniel Nicoara <dnicoara@chromium.org>. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98278 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/controls/scrollbar/base_scroll_bar.cc383
-rw-r--r--views/controls/scrollbar/base_scroll_bar.h156
-rw-r--r--views/controls/scrollbar/base_scroll_bar_button.cc47
-rw-r--r--views/controls/scrollbar/base_scroll_bar_button.h50
-rw-r--r--views/controls/scrollbar/base_scroll_bar_thumb.cc127
-rw-r--r--views/controls/scrollbar/base_scroll_bar_thumb.h82
-rw-r--r--views/controls/scrollbar/bitmap_scroll_bar.cc512
-rw-r--r--views/controls/scrollbar/bitmap_scroll_bar.h130
-rw-r--r--views/controls/scrollbar/native_scroll_bar_gtk.cc6
-rw-r--r--views/controls/scrollbar/native_scroll_bar_views.cc371
-rw-r--r--views/controls/scrollbar/native_scroll_bar_views.h76
-rw-r--r--views/controls/scrollbar/native_scroll_bar_wrapper.h4
-rw-r--r--views/controls/scrollbar/scrollbar_unittest.cc150
-rw-r--r--views/views.gyp9
14 files changed, 1513 insertions, 590 deletions
diff --git a/views/controls/scrollbar/base_scroll_bar.cc b/views/controls/scrollbar/base_scroll_bar.cc
new file mode 100644
index 0000000..d18d4fd
--- /dev/null
+++ b/views/controls/scrollbar/base_scroll_bar.cc
@@ -0,0 +1,383 @@
+// Copyright (c) 2011 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 "views/controls/scrollbar/base_scroll_bar.h"
+
+#if defined(OS_LINUX)
+#include "ui/gfx/screen.h"
+#endif
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "grit/ui_strings.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/canvas.h"
+#include "views/controls/menu/menu.h"
+#include "views/controls/scrollbar/base_scroll_bar_thumb.h"
+#include "views/controls/scroll_view.h"
+#include "views/widget/widget.h"
+
+#undef min
+#undef max
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// BaseScrollBar, public:
+
+BaseScrollBar::BaseScrollBar(bool horizontal, BaseScrollBarThumb* thumb)
+ : ScrollBar(horizontal),
+ thumb_(thumb),
+ contents_size_(0),
+ contents_scroll_offset_(0),
+ thumb_track_state_(CustomButton::BS_NORMAL),
+ last_scroll_amount_(SCROLL_NONE),
+ ALLOW_THIS_IN_INITIALIZER_LIST(repeater_(
+ NewCallback<BaseScrollBar>(this,
+ &BaseScrollBar::TrackClicked))),
+ context_menu_mouse_position_(0) {
+ AddChildView(thumb_);
+
+ set_context_menu_controller(this);
+ thumb_->set_context_menu_controller(this);
+}
+
+void BaseScrollBar::ScrollByAmount(ScrollAmount amount) {
+ int offset = contents_scroll_offset_;
+ switch (amount) {
+ case SCROLL_START:
+ offset = GetMinPosition();
+ break;
+ case SCROLL_END:
+ offset = GetMaxPosition();
+ break;
+ case SCROLL_PREV_LINE:
+ offset -= GetScrollIncrement(false, false);
+ offset = std::max(GetMinPosition(), offset);
+ break;
+ case SCROLL_NEXT_LINE:
+ offset += GetScrollIncrement(false, true);
+ offset = std::min(GetMaxPosition(), offset);
+ break;
+ case SCROLL_PREV_PAGE:
+ offset -= GetScrollIncrement(true, false);
+ offset = std::max(GetMinPosition(), offset);
+ break;
+ case SCROLL_NEXT_PAGE:
+ offset += GetScrollIncrement(true, true);
+ offset = std::min(GetMaxPosition(), offset);
+ break;
+ default:
+ break;
+ }
+ contents_scroll_offset_ = offset;
+ ScrollContentsToOffset();
+}
+
+void BaseScrollBar::ScrollToThumbPosition(int thumb_position,
+ bool scroll_to_middle) {
+ contents_scroll_offset_ =
+ CalculateContentsOffset(thumb_position, scroll_to_middle);
+ if (contents_scroll_offset_ < GetMinPosition()) {
+ contents_scroll_offset_ = GetMinPosition();
+ } else if (contents_scroll_offset_ > GetMaxPosition()) {
+ contents_scroll_offset_ = GetMaxPosition();
+ }
+ ScrollContentsToOffset();
+ SchedulePaint();
+}
+
+void BaseScrollBar::ScrollByContentsOffset(int contents_offset) {
+ contents_scroll_offset_ -= contents_offset;
+ if (contents_scroll_offset_ < GetMinPosition()) {
+ contents_scroll_offset_ = GetMinPosition();
+ } else if (contents_scroll_offset_ > GetMaxPosition()) {
+ contents_scroll_offset_ = GetMaxPosition();
+ }
+ ScrollContentsToOffset();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BaseScrollBar, View implementation:
+
+bool BaseScrollBar::OnMousePressed(const MouseEvent& event) {
+ if (event.IsOnlyLeftMouseButton()) {
+ SetThumbTrackState(CustomButton::BS_PUSHED);
+ gfx::Rect thumb_bounds = thumb_->bounds();
+ if (IsHorizontal()) {
+ if (event.x() < thumb_bounds.x()) {
+ last_scroll_amount_ = SCROLL_PREV_PAGE;
+ } else if (event.x() > thumb_bounds.right()) {
+ last_scroll_amount_ = SCROLL_NEXT_PAGE;
+ }
+ } else {
+ if (event.y() < thumb_bounds.y()) {
+ last_scroll_amount_ = SCROLL_PREV_PAGE;
+ } else if (event.y() > thumb_bounds.bottom()) {
+ last_scroll_amount_ = SCROLL_NEXT_PAGE;
+ }
+ }
+ TrackClicked();
+ repeater_.Start();
+ }
+ return true;
+}
+
+void BaseScrollBar::OnMouseReleased(const MouseEvent& event) {
+ OnMouseCaptureLost();
+}
+
+void BaseScrollBar::OnMouseCaptureLost() {
+ SetThumbTrackState(CustomButton::BS_NORMAL);
+ repeater_.Stop();
+}
+
+bool BaseScrollBar::OnKeyPressed(const KeyEvent& event) {
+ ScrollAmount amount = SCROLL_NONE;
+ switch (event.key_code()) {
+ case ui::VKEY_UP:
+ if (!IsHorizontal())
+ amount = SCROLL_PREV_LINE;
+ break;
+ case ui::VKEY_DOWN:
+ if (!IsHorizontal())
+ amount = SCROLL_NEXT_LINE;
+ break;
+ case ui::VKEY_LEFT:
+ if (IsHorizontal())
+ amount = SCROLL_PREV_LINE;
+ break;
+ case ui::VKEY_RIGHT:
+ if (IsHorizontal())
+ amount = SCROLL_NEXT_LINE;
+ break;
+ case ui::VKEY_PRIOR:
+ amount = SCROLL_PREV_PAGE;
+ break;
+ case ui::VKEY_NEXT:
+ amount = SCROLL_NEXT_PAGE;
+ break;
+ case ui::VKEY_HOME:
+ amount = SCROLL_START;
+ break;
+ case ui::VKEY_END:
+ amount = SCROLL_END;
+ break;
+ default:
+ break;
+ }
+ if (amount != SCROLL_NONE) {
+ ScrollByAmount(amount);
+ return true;
+ }
+ return false;
+}
+
+bool BaseScrollBar::OnMouseWheel(const MouseWheelEvent& event) {
+ ScrollByContentsOffset(event.offset());
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BaseScrollBar, ContextMenuController implementation:
+
+enum ScrollBarContextMenuCommands {
+ ScrollBarContextMenuCommand_ScrollHere = 1,
+ ScrollBarContextMenuCommand_ScrollStart,
+ ScrollBarContextMenuCommand_ScrollEnd,
+ ScrollBarContextMenuCommand_ScrollPageUp,
+ ScrollBarContextMenuCommand_ScrollPageDown,
+ ScrollBarContextMenuCommand_ScrollPrev,
+ ScrollBarContextMenuCommand_ScrollNext
+};
+
+void BaseScrollBar::ShowContextMenuForView(View* source,
+ const gfx::Point& p,
+ bool is_mouse_gesture) {
+ Widget* widget = GetWidget();
+ gfx::Rect widget_bounds = widget->GetWindowScreenBounds();
+ gfx::Point temp_pt(p.x() - widget_bounds.x(), p.y() - widget_bounds.y());
+ View::ConvertPointFromWidget(this, &temp_pt);
+ context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y();
+
+ scoped_ptr<Menu> menu(
+ Menu::Create(this, Menu::TOPLEFT, GetWidget()->GetNativeView()));
+ menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere);
+ menu->AppendSeparator();
+ menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart);
+ menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollEnd);
+ menu->AppendSeparator();
+ menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageUp);
+ menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageDown);
+ menu->AppendSeparator();
+ menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev);
+ menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext);
+ menu->RunMenuAt(p.x(), p.y());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BaseScrollBar, Menu::Delegate implementation:
+
+std::wstring BaseScrollBar::GetLabel(int id) const {
+ int ids_value = 0;
+ switch (id) {
+ case ScrollBarContextMenuCommand_ScrollHere:
+ ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE;
+ break;
+ case ScrollBarContextMenuCommand_ScrollStart:
+ ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE
+ : IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME;
+ break;
+ case ScrollBarContextMenuCommand_ScrollEnd:
+ ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE
+ : IDS_APP_SCROLLBAR_CXMENU_SCROLLEND;
+ break;
+ case ScrollBarContextMenuCommand_ScrollPageUp:
+ ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP;
+ break;
+ case ScrollBarContextMenuCommand_ScrollPageDown:
+ ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN;
+ break;
+ case ScrollBarContextMenuCommand_ScrollPrev:
+ ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT
+ : IDS_APP_SCROLLBAR_CXMENU_SCROLLUP;
+ break;
+ case ScrollBarContextMenuCommand_ScrollNext:
+ ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT
+ : IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN;
+ break;
+ default:
+ NOTREACHED() << "Invalid BaseScrollBar Context Menu command!";
+ }
+
+ return ids_value ? UTF16ToWide(l10n_util::GetStringUTF16(ids_value)) : L"";
+}
+
+bool BaseScrollBar::IsCommandEnabled(int id) const {
+ switch (id) {
+ case ScrollBarContextMenuCommand_ScrollPageUp:
+ case ScrollBarContextMenuCommand_ScrollPageDown:
+ return !IsHorizontal();
+ }
+ return true;
+}
+
+void BaseScrollBar::ExecuteCommand(int id) {
+ switch (id) {
+ case ScrollBarContextMenuCommand_ScrollHere:
+ ScrollToThumbPosition(context_menu_mouse_position_, true);
+ break;
+ case ScrollBarContextMenuCommand_ScrollStart:
+ ScrollByAmount(SCROLL_START);
+ break;
+ case ScrollBarContextMenuCommand_ScrollEnd:
+ ScrollByAmount(SCROLL_END);
+ break;
+ case ScrollBarContextMenuCommand_ScrollPageUp:
+ ScrollByAmount(SCROLL_PREV_PAGE);
+ break;
+ case ScrollBarContextMenuCommand_ScrollPageDown:
+ ScrollByAmount(SCROLL_NEXT_PAGE);
+ break;
+ case ScrollBarContextMenuCommand_ScrollPrev:
+ ScrollByAmount(SCROLL_PREV_LINE);
+ break;
+ case ScrollBarContextMenuCommand_ScrollNext:
+ ScrollByAmount(SCROLL_NEXT_LINE);
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BaseScrollBar, ScrollBar implementation:
+
+void BaseScrollBar::Update(int viewport_size, int content_size,
+ int contents_scroll_offset) {
+ ScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
+
+ // Make sure contents_size is always > 0 to avoid divide by zero errors in
+ // calculations throughout this code.
+ contents_size_ = std::max(1, content_size);
+
+ if (content_size < 0)
+ content_size = 0;
+ if (contents_scroll_offset < 0)
+ contents_scroll_offset = 0;
+ if (contents_scroll_offset > content_size)
+ contents_scroll_offset = content_size;
+
+ // Thumb Height and Thumb Pos.
+ // The height of the thumb is the ratio of the Viewport height to the
+ // content size multiplied by the height of the thumb track.
+ double ratio = static_cast<double>(viewport_size) / contents_size_;
+ int thumb_size = static_cast<int>(ratio * GetTrackSize());
+ thumb_->SetSize(thumb_size);
+
+ int thumb_position = CalculateThumbPosition(contents_scroll_offset);
+ thumb_->SetPosition(thumb_position);
+}
+
+int BaseScrollBar::GetPosition() const {
+ return thumb_->GetPosition();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BaseScrollBar, protected:
+
+BaseScrollBarThumb* BaseScrollBar::GetThumb() const {
+ return thumb_;
+}
+
+CustomButton::ButtonState BaseScrollBar::GetThumbTrackState() const {
+ return thumb_track_state_;
+}
+
+void BaseScrollBar::ScrollToPosition(int position) {
+ GetController()->ScrollToPosition(this, position);
+}
+
+int BaseScrollBar::GetScrollIncrement(bool is_page, bool is_positive) {
+ return GetController()->GetScrollIncrement(this, is_page, is_positive);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// BaseScrollBar, private:
+
+void BaseScrollBar::TrackClicked() {
+ if (last_scroll_amount_ != SCROLL_NONE)
+ ScrollByAmount(last_scroll_amount_);
+}
+
+void BaseScrollBar::ScrollContentsToOffset() {
+ ScrollToPosition(contents_scroll_offset_);
+ thumb_->SetPosition(CalculateThumbPosition(contents_scroll_offset_));
+}
+
+int BaseScrollBar::GetTrackSize() const {
+ gfx::Rect track_bounds = GetTrackBounds();
+ return IsHorizontal() ? track_bounds.width() : track_bounds.height();
+}
+
+int BaseScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
+ return (contents_scroll_offset * GetTrackSize()) / contents_size_;
+}
+
+int BaseScrollBar::CalculateContentsOffset(int thumb_position,
+ bool scroll_to_middle) const {
+ if (scroll_to_middle)
+ thumb_position = thumb_position - (thumb_->GetSize() / 2);
+ return (thumb_position * contents_size_) / GetTrackSize();
+}
+
+void BaseScrollBar::SetThumbTrackState(CustomButton::ButtonState state) {
+ thumb_track_state_ = state;
+ SchedulePaint();
+}
+
+} // namespace views
diff --git a/views/controls/scrollbar/base_scroll_bar.h b/views/controls/scrollbar/base_scroll_bar.h
new file mode 100644
index 0000000..7dc037b
--- /dev/null
+++ b/views/controls/scrollbar/base_scroll_bar.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2011 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.
+
+#ifndef VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_H_
+#define VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_H_
+#pragma once
+
+#include "views/context_menu_controller.h"
+#include "views/controls/button/image_button.h"
+#include "views/controls/menu/menu.h"
+#include "views/controls/scrollbar/scroll_bar.h"
+#include "views/repeat_controller.h"
+
+namespace views {
+
+class BaseScrollBarThumb;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// BaseScrollBar
+//
+///////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT BaseScrollBar : public ScrollBar,
+ public ContextMenuController,
+ public Menu::Delegate {
+ public:
+ BaseScrollBar(bool horizontal, BaseScrollBarThumb* thumb);
+ virtual ~BaseScrollBar() { }
+
+ // Get the bounds of the "track" area that the thumb is free to slide within.
+ virtual gfx::Rect GetTrackBounds() const = 0;
+
+ // An enumeration of different amounts of incremental scroll, representing
+ // events sent from different parts of the UI/keyboard.
+ enum ScrollAmount {
+ SCROLL_NONE = 0,
+ SCROLL_START,
+ SCROLL_END,
+ SCROLL_PREV_LINE,
+ SCROLL_NEXT_LINE,
+ SCROLL_PREV_PAGE,
+ SCROLL_NEXT_PAGE,
+ };
+
+ // Scroll the contents by the specified type (see ScrollAmount above).
+ void ScrollByAmount(ScrollAmount amount);
+
+ // Scroll the contents to the appropriate position given the supplied
+ // position of the thumb (thumb track coordinates). If |scroll_to_middle| is
+ // true, then the conversion assumes |thumb_position| is in the middle of the
+ // thumb rather than the top.
+ void ScrollToThumbPosition(int thumb_position, bool scroll_to_middle);
+
+ // Scroll the contents by the specified offset (contents coordinates).
+ void ScrollByContentsOffset(int contents_offset);
+
+ // View overrides:
+ virtual gfx::Size GetPreferredSize() OVERRIDE = 0;
+ virtual void Layout() OVERRIDE = 0;
+ virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseCaptureLost() OVERRIDE;
+ virtual bool OnKeyPressed(const KeyEvent& event) OVERRIDE;
+ virtual bool OnMouseWheel(const MouseWheelEvent& event) OVERRIDE;
+
+ // ScrollBar overrides:
+ virtual void Update(int viewport_size,
+ int content_size,
+ int contents_scroll_offset) OVERRIDE;
+ virtual int GetLayoutSize() const OVERRIDE = 0;
+ virtual int GetPosition() const OVERRIDE;
+
+ // ContextMenuController overrides.
+ virtual void ShowContextMenuForView(View* source,
+ const gfx::Point& p,
+ bool is_mouse_gesture) OVERRIDE;
+
+ // Menu::Delegate overrides:
+ virtual std::wstring GetLabel(int id) const OVERRIDE;
+ virtual bool IsCommandEnabled(int id) const OVERRIDE;
+ virtual void ExecuteCommand(int id) OVERRIDE;
+
+ protected:
+ // View overrides:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE = 0;
+
+ BaseScrollBarThumb* GetThumb() const;
+
+ CustomButton::ButtonState GetThumbTrackState() const;
+
+ // Wrapper functions that calls the controller. We need this since native
+ // scrollbars wrap around a different scrollbar. When calling the controller
+ // we need to pass in the appropriate scrollbar. For normal scrollbars it's
+ // the |this| scrollbar, for native scrollbars it's the native scrollbar used
+ // to create this.
+ virtual void ScrollToPosition(int position);
+ virtual int GetScrollIncrement(bool is_page, bool is_positive);
+
+ private:
+ // Called when the mouse is pressed down in the track area.
+ void TrackClicked();
+
+ // Responsible for scrolling the contents and also updating the UI to the
+ // current value of the Scroll Offset.
+ void ScrollContentsToOffset();
+
+ // Returns the size (width or height) of the track area of the ScrollBar.
+ int GetTrackSize() const;
+
+ // Calculate the position of the thumb within the track based on the
+ // specified scroll offset of the contents.
+ int CalculateThumbPosition(int contents_scroll_offset) const;
+
+ // Calculates the current value of the contents offset (contents coordinates)
+ // based on the current thumb position (thumb track coordinates). See
+ // |ScrollToThumbPosition| for an explanation of |scroll_to_middle|.
+ int CalculateContentsOffset(int thumb_position,
+ bool scroll_to_middle) const;
+
+ // Called when the state of the thumb track changes (e.g. by the user
+ // pressing the mouse button down in it).
+ void SetThumbTrackState(CustomButton::ButtonState state);
+
+ BaseScrollBarThumb* thumb_;
+
+ // The size of the scrolled contents, in pixels.
+ int contents_size_;
+
+ // The current amount the contents is offset by in the viewport.
+ int contents_scroll_offset_;
+
+ // The state of the scrollbar track. Typically, the track will highlight when
+ // the user presses the mouse on them (during page scrolling).
+ CustomButton::ButtonState thumb_track_state_;
+
+ // The last amount of incremental scroll that this scrollbar performed. This
+ // is accessed by the callbacks for the auto-repeat up/down buttons to know
+ // what direction to repeatedly scroll in.
+ ScrollAmount last_scroll_amount_;
+
+ // An instance of a RepeatController which scrolls the scrollbar continuously
+ // as the user presses the mouse button down on the up/down buttons or the
+ // track.
+ RepeatController repeater_;
+
+ // The position of the mouse within the scroll bar when the context menu
+ // was invoked.
+ int context_menu_mouse_position_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseScrollBar);
+};
+
+} // namespace views
+
+#endif // VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_H_
diff --git a/views/controls/scrollbar/base_scroll_bar_button.cc b/views/controls/scrollbar/base_scroll_bar_button.cc
new file mode 100644
index 0000000..95239e7
--- /dev/null
+++ b/views/controls/scrollbar/base_scroll_bar_button.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 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 "views/controls/scrollbar/base_scroll_bar_button.h"
+
+namespace views {
+
+BaseScrollBarButton::BaseScrollBarButton(ButtonListener* listener)
+ : CustomButton(listener),
+ ALLOW_THIS_IN_INITIALIZER_LIST(repeater_(
+ NewCallback<BaseScrollBarButton>(this,
+ &BaseScrollBarButton::NotifyClick))) {
+}
+
+BaseScrollBarButton::~BaseScrollBarButton() {
+}
+
+bool BaseScrollBarButton::OnMousePressed(const MouseEvent& event) {
+ Button::NotifyClick(event);
+ repeater_.Start();
+ return true;
+}
+
+void BaseScrollBarButton::OnMouseReleased(const MouseEvent& event) {
+ OnMouseCaptureLost();
+}
+
+void BaseScrollBarButton::OnMouseCaptureLost() {
+ repeater_.Stop();
+}
+
+void BaseScrollBarButton::NotifyClick() {
+#if defined(OS_WIN)
+ DWORD pos = GetMessagePos();
+ POINTS points = MAKEPOINTS(pos);
+ gfx::Point cursor_point(points.x, points.y);
+#elif defined(OS_LINUX)
+ gfx::Point cursor_point = gfx::Screen::GetCursorScreenPoint();
+#endif
+ views::MouseEvent event(ui::ET_MOUSE_RELEASED,
+ cursor_point.x(), cursor_point.y(),
+ ui::EF_LEFT_BUTTON_DOWN);
+ Button::NotifyClick(event);
+}
+
+} // namespace views
diff --git a/views/controls/scrollbar/base_scroll_bar_button.h b/views/controls/scrollbar/base_scroll_bar_button.h
new file mode 100644
index 0000000..422ebfa
--- /dev/null
+++ b/views/controls/scrollbar/base_scroll_bar_button.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 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.
+
+#ifndef VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_BUTTON_H_
+#define VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_BUTTON_H_
+#pragma once
+
+#include "views/controls/button/custom_button.h"
+
+#include "views/repeat_controller.h"
+
+#if defined(OS_LINUX)
+#include "ui/gfx/screen.h"
+#endif
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// ScrollBarButton
+//
+// A button that activates on mouse pressed rather than released, and that
+// continues to fire the clicked action as the mouse button remains pressed
+// down on the button.
+//
+///////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT BaseScrollBarButton : public CustomButton {
+ public:
+ explicit BaseScrollBarButton(ButtonListener* listener);
+ virtual ~BaseScrollBarButton();
+
+ protected:
+ virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseCaptureLost() OVERRIDE;
+
+ private:
+ void NotifyClick();
+
+ // The repeat controller that we use to repeatedly click the button when the
+ // mouse button is down.
+ RepeatController repeater_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseScrollBarButton);
+};
+
+} // namespace views
+
+#endif // VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_BUTTON_H_
diff --git a/views/controls/scrollbar/base_scroll_bar_thumb.cc b/views/controls/scrollbar/base_scroll_bar_thumb.cc
new file mode 100644
index 0000000..bbd42f9
--- /dev/null
+++ b/views/controls/scrollbar/base_scroll_bar_thumb.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2011 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 "views/controls/scrollbar/base_scroll_bar_thumb.h"
+
+#include "views/controls/scrollbar/base_scroll_bar.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/rect.h"
+
+namespace {
+// The distance the mouse can be dragged outside the bounds of the thumb during
+// dragging before the scrollbar will snap back to its regular position.
+static const int kScrollThumbDragOutSnap = 100;
+}
+
+namespace views {
+
+BaseScrollBarThumb::BaseScrollBarThumb(BaseScrollBar* scroll_bar)
+ : scroll_bar_(scroll_bar),
+ drag_start_position_(-1),
+ mouse_offset_(-1),
+ state_(CustomButton::BS_NORMAL) {
+}
+
+BaseScrollBarThumb::~BaseScrollBarThumb() {
+}
+
+void BaseScrollBarThumb::SetSize(int size) {
+ // Make sure the thumb is never sized smaller than its minimum possible
+ // display size.
+ gfx::Size prefsize = GetPreferredSize();
+ size = std::max(size, scroll_bar_->IsHorizontal() ? prefsize.width() :
+ prefsize.height());
+ gfx::Rect thumb_bounds = bounds();
+ if (scroll_bar_->IsHorizontal()) {
+ thumb_bounds.set_width(size);
+ } else {
+ thumb_bounds.set_height(size);
+ }
+ SetBoundsRect(thumb_bounds);
+}
+
+int BaseScrollBarThumb::GetSize() const {
+ if (scroll_bar_->IsHorizontal())
+ return width();
+ return height();
+}
+
+void BaseScrollBarThumb::SetPosition(int position) {
+ gfx::Rect thumb_bounds = bounds();
+ gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
+ if (scroll_bar_->IsHorizontal()) {
+ thumb_bounds.set_x(track_bounds.x() + position);
+ } else {
+ thumb_bounds.set_y(track_bounds.y() + position);
+ }
+ SetBoundsRect(thumb_bounds);
+}
+
+int BaseScrollBarThumb::GetPosition() const {
+ gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
+ if (scroll_bar_->IsHorizontal())
+ return x() - track_bounds.x();
+ return y() - track_bounds.y();
+}
+
+void BaseScrollBarThumb::OnMouseEntered(const MouseEvent& event) {
+ SetState(CustomButton::BS_HOT);
+}
+
+void BaseScrollBarThumb::OnMouseExited(const MouseEvent& event) {
+ SetState(CustomButton::BS_NORMAL);
+}
+
+bool BaseScrollBarThumb::OnMousePressed(const MouseEvent& event) {
+ mouse_offset_ = scroll_bar_->IsHorizontal() ? event.x() : event.y();
+ drag_start_position_ = GetPosition();
+ SetState(CustomButton::BS_PUSHED);
+ return true;
+}
+
+bool BaseScrollBarThumb::OnMouseDragged(const MouseEvent& event) {
+ // If the user moves the mouse more than |kScrollThumbDragOutSnap| outside
+ // the bounds of the thumb, the scrollbar will snap the scroll back to the
+ // point it was at before the drag began.
+ if (scroll_bar_->IsHorizontal()) {
+ if ((event.y() < y() - kScrollThumbDragOutSnap) ||
+ (event.y() > (y() + height() + kScrollThumbDragOutSnap))) {
+ scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
+ return true;
+ }
+ } else {
+ if ((event.x() < x() - kScrollThumbDragOutSnap) ||
+ (event.x() > (x() + width() + kScrollThumbDragOutSnap))) {
+ scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
+ return true;
+ }
+ }
+ if (scroll_bar_->IsHorizontal()) {
+ int thumb_x = event.x() - mouse_offset_;
+ scroll_bar_->ScrollToThumbPosition(GetPosition() + thumb_x, false);
+ } else {
+ int thumb_y = event.y() - mouse_offset_;
+ scroll_bar_->ScrollToThumbPosition(GetPosition() + thumb_y, false);
+ }
+ return true;
+}
+
+void BaseScrollBarThumb::OnMouseReleased(const MouseEvent& event) {
+ OnMouseCaptureLost();
+}
+
+void BaseScrollBarThumb::OnMouseCaptureLost() {
+ SetState(CustomButton::BS_HOT);
+}
+
+CustomButton::ButtonState BaseScrollBarThumb::GetState() const {
+ return state_;
+}
+
+void BaseScrollBarThumb::SetState(CustomButton::ButtonState state) {
+ state_ = state;
+ SchedulePaint();
+}
+
+} // namespace views
diff --git a/views/controls/scrollbar/base_scroll_bar_thumb.h b/views/controls/scrollbar/base_scroll_bar_thumb.h
new file mode 100644
index 0000000..407b830
--- /dev/null
+++ b/views/controls/scrollbar/base_scroll_bar_thumb.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 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.
+
+#ifndef VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_THUMB_H_
+#define VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_THUMB_H_
+#pragma once
+
+#include "ui/gfx/size.h"
+#include "views/controls/button/custom_button.h"
+#include "views/controls/scrollbar/scroll_bar.h"
+#include "views/view.h"
+
+namespace gfx {
+class Canvas;
+}
+
+namespace views {
+
+class BaseScrollBar;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// BaseScrollBarThumb
+//
+// A view that acts as the thumb in the scroll bar track that the user can
+// drag to scroll the associated contents view within the viewport.
+//
+///////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT BaseScrollBarThumb : public View {
+ public:
+ explicit BaseScrollBarThumb(BaseScrollBar* scroll_bar);
+ virtual ~BaseScrollBarThumb();
+
+ // Sets the size (width or height) of the thumb to the specified value.
+ void SetSize(int size);
+
+ // Retrieves the size (width or height) of the thumb.
+ int GetSize() const;
+
+ // Sets the position of the thumb on the x or y axis.
+ void SetPosition(int position);
+
+ // Gets the position of the thumb on the x or y axis.
+ int GetPosition() const;
+
+ // View overrides:
+ virtual gfx::Size GetPreferredSize() OVERRIDE = 0;
+
+ protected:
+ // View overrides:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE = 0;
+ virtual void OnMouseEntered(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseExited(const MouseEvent& event) OVERRIDE;
+ virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
+ virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE;
+ virtual void OnMouseCaptureLost() OVERRIDE;
+
+ CustomButton::ButtonState GetState() const;
+ // Update our state and schedule a repaint when the mouse moves over us.
+ void SetState(CustomButton::ButtonState state);
+
+ private:
+ // The BaseScrollBar that owns us.
+ BaseScrollBar* scroll_bar_;
+
+ int drag_start_position_;
+
+ // The position of the mouse on the scroll axis relative to the top of this
+ // View when the drag started.
+ int mouse_offset_;
+
+ // The current state of the thumb button.
+ CustomButton::ButtonState state_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseScrollBarThumb);
+};
+
+} // namespace views
+
+#endif // VIEWS_CONTROLS_SCROLLBAR_BASE_SCROLL_BAR_THUMB_H_
diff --git a/views/controls/scrollbar/bitmap_scroll_bar.cc b/views/controls/scrollbar/bitmap_scroll_bar.cc
index b52e8d9..6b7fbc0 100644
--- a/views/controls/scrollbar/bitmap_scroll_bar.cc
+++ b/views/controls/scrollbar/bitmap_scroll_bar.cc
@@ -19,6 +19,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "views/controls/menu/menu.h"
+#include "views/controls/scrollbar/base_scroll_bar_thumb.h"
#include "views/controls/scroll_view.h"
#include "views/widget/widget.h"
@@ -44,7 +45,7 @@ static const int kScrollThumbDragOutSnap = 100;
///////////////////////////////////////////////////////////////////////////////
class AutorepeatButton : public ImageButton {
public:
- AutorepeatButton(ButtonListener* listener)
+ explicit AutorepeatButton(ButtonListener* listener)
: ImageButton(listener),
ALLOW_THIS_IN_INITIALIZER_LIST(repeater_(
NewCallback<AutorepeatButton>(this,
@@ -97,59 +98,14 @@ class AutorepeatButton : public ImageButton {
// drag to scroll the associated contents view within the viewport.
//
///////////////////////////////////////////////////////////////////////////////
-class BitmapScrollBarThumb : public View {
+class BitmapScrollBarThumb : public BaseScrollBarThumb {
public:
explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar)
- : scroll_bar_(scroll_bar),
- drag_start_position_(-1),
- mouse_offset_(-1),
- state_(CustomButton::BS_NORMAL) {
+ : BaseScrollBarThumb(scroll_bar),
+ scroll_bar_(scroll_bar) {
}
virtual ~BitmapScrollBarThumb() { }
- // Sets the size (width or height) of the thumb to the specified value.
- void SetSize(int size) {
- // Make sure the thumb is never sized smaller than its minimum possible
- // display size.
- gfx::Size prefsize = GetPreferredSize();
- size = std::max(size, scroll_bar_->IsHorizontal() ? prefsize.width() :
- prefsize.height());
- gfx::Rect thumb_bounds = bounds();
- if (scroll_bar_->IsHorizontal()) {
- thumb_bounds.set_width(size);
- } else {
- thumb_bounds.set_height(size);
- }
- SetBoundsRect(thumb_bounds);
- }
-
- // Retrieves the size (width or height) of the thumb.
- int GetSize() const {
- if (scroll_bar_->IsHorizontal())
- return width();
- return height();
- }
-
- // Sets the position of the thumb on the x or y axis.
- void SetPosition(int position) {
- gfx::Rect thumb_bounds = bounds();
- gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
- if (scroll_bar_->IsHorizontal()) {
- thumb_bounds.set_x(track_bounds.x() + position);
- } else {
- thumb_bounds.set_y(track_bounds.y() + position);
- }
- SetBoundsRect(thumb_bounds);
- }
-
- // Gets the position of the thumb on the x or y axis.
- int GetPosition() const {
- gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
- if (scroll_bar_->IsHorizontal())
- return x() - track_bounds.x();
- return y() - track_bounds.y();
- }
-
// View overrides:
virtual gfx::Size GetPreferredSize() OVERRIDE {
return gfx::Size(background_bitmap()->width(),
@@ -160,7 +116,7 @@ class BitmapScrollBarThumb : public View {
protected:
// View overrides:
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE {
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
canvas->DrawBitmapInt(*start_cap_bitmap(), 0, 0);
int top_cap_height = start_cap_bitmap()->height();
int bottom_cap_height = end_cap_bitmap()->height();
@@ -176,71 +132,21 @@ class BitmapScrollBarThumb : public View {
canvas->DrawBitmapInt(*grippy_bitmap(), grippy_x, grippy_y);
}
- virtual void OnMouseEntered(const MouseEvent& event) OVERRIDE {
- SetState(CustomButton::BS_HOT);
- }
-
- virtual void OnMouseExited(const MouseEvent& event) OVERRIDE {
- SetState(CustomButton::BS_NORMAL);
- }
-
- virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE {
- mouse_offset_ = scroll_bar_->IsHorizontal() ? event.x() : event.y();
- drag_start_position_ = GetPosition();
- SetState(CustomButton::BS_PUSHED);
- return true;
- }
-
- virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE {
- // If the user moves the mouse more than |kScrollThumbDragOutSnap| outside
- // the bounds of the thumb, the scrollbar will snap the scroll back to the
- // point it was at before the drag began.
- if (scroll_bar_->IsHorizontal()) {
- if ((event.y() < y() - kScrollThumbDragOutSnap) ||
- (event.y() > (y() + height() + kScrollThumbDragOutSnap))) {
- scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
- return true;
- }
- } else {
- if ((event.x() < x() - kScrollThumbDragOutSnap) ||
- (event.x() > (x() + width() + kScrollThumbDragOutSnap))) {
- scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
- return true;
- }
- }
- if (scroll_bar_->IsHorizontal()) {
- int thumb_x = event.x() - mouse_offset_;
- scroll_bar_->ScrollToThumbPosition(x() + thumb_x, false);
- } else {
- int thumb_y = event.y() - mouse_offset_;
- scroll_bar_->ScrollToThumbPosition(y() + thumb_y, false);
- }
- return true;
- }
-
- virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE {
- OnMouseCaptureLost();
- }
-
- virtual void OnMouseCaptureLost() OVERRIDE {
- SetState(CustomButton::BS_HOT);
- }
-
private:
// Returns the bitmap rendered at the start of the thumb.
SkBitmap* start_cap_bitmap() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][state_];
+ return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][GetState()];
}
// Returns the bitmap rendered at the end of the thumb.
SkBitmap* end_cap_bitmap() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][state_];
+ return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][GetState()];
}
// Returns the bitmap that is tiled in the background of the thumb between
// the start and the end caps.
SkBitmap* background_bitmap() const {
- return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][state_];
+ return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][GetState()];
}
// Returns the bitmap that is rendered in the middle of the thumb
@@ -250,24 +156,9 @@ class BitmapScrollBarThumb : public View {
[CustomButton::BS_NORMAL];
}
- // Update our state and schedule a repaint when the mouse moves over us.
- void SetState(CustomButton::ButtonState state) {
- state_ = state;
- SchedulePaint();
- }
-
// The BitmapScrollBar that owns us.
BitmapScrollBar* scroll_bar_;
- int drag_start_position_;
-
- // The position of the mouse on the scroll axis relative to the top of this
- // View when the drag started.
- int mouse_offset_;
-
- // The current state of the thumb button.
- CustomButton::ButtonState state_;
-
DISALLOW_COPY_AND_ASSIGN(BitmapScrollBarThumb);
};
@@ -277,19 +168,10 @@ class BitmapScrollBarThumb : public View {
// BitmapScrollBar, public:
BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons)
- : contents_size_(0),
- contents_scroll_offset_(0),
+ : BaseScrollBar(horizontal, new BitmapScrollBarThumb(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(prev_button_(new AutorepeatButton(this))),
ALLOW_THIS_IN_INITIALIZER_LIST(next_button_(new AutorepeatButton(this))),
- ALLOW_THIS_IN_INITIALIZER_LIST(thumb_(new BitmapScrollBarThumb(this))),
- thumb_track_state_(CustomButton::BS_NORMAL),
- last_scroll_amount_(SCROLL_NONE),
- ALLOW_THIS_IN_INITIALIZER_LIST(repeater_(
- NewCallback<BitmapScrollBar>(this,
- &BitmapScrollBar::TrackClicked))),
- context_menu_mouse_position_(0),
- show_scroll_buttons_(show_scroll_buttons),
- ScrollBar(horizontal) {
+ show_scroll_buttons_(show_scroll_buttons) {
if (!show_scroll_buttons_) {
prev_button_->SetVisible(false);
next_button_->SetVisible(false);
@@ -297,29 +179,10 @@ BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons)
AddChildView(prev_button_);
AddChildView(next_button_);
- AddChildView(thumb_);
set_context_menu_controller(this);
prev_button_->set_context_menu_controller(this);
next_button_->set_context_menu_controller(this);
- thumb_->set_context_menu_controller(this);
-}
-
-gfx::Rect BitmapScrollBar::GetTrackBounds() const {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- if (IsHorizontal()) {
- if (!show_scroll_buttons_)
- prefsize.set_width(0);
- int new_width =
- std::max(0, width() - (prefsize.width() * 2));
- gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height());
- return track_bounds;
- }
- if (!show_scroll_buttons_)
- prefsize.set_height(0);
- gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(),
- std::max(0, height() - (prefsize.height() * 2)));
- return track_bounds;
}
void BitmapScrollBar::SetImage(ScrollBarPart part,
@@ -344,58 +207,26 @@ void BitmapScrollBar::SetImage(ScrollBarPart part,
}
}
-void BitmapScrollBar::ScrollByAmount(ScrollAmount amount) {
- ScrollBarController* controller = GetController();
- int offset = contents_scroll_offset_;
- switch (amount) {
- case SCROLL_START:
- offset = GetMinPosition();
- break;
- case SCROLL_END:
- offset = GetMaxPosition();
- break;
- case SCROLL_PREV_LINE:
- offset -= controller->GetScrollIncrement(this, false, false);
- offset = std::max(GetMinPosition(), offset);
- break;
- case SCROLL_NEXT_LINE:
- offset += controller->GetScrollIncrement(this, false, true);
- offset = std::min(GetMaxPosition(), offset);
- break;
- case SCROLL_PREV_PAGE:
- offset -= controller->GetScrollIncrement(this, true, false);
- offset = std::max(GetMinPosition(), offset);
- break;
- case SCROLL_NEXT_PAGE:
- offset += controller->GetScrollIncrement(this, true, true);
- offset = std::min(GetMaxPosition(), offset);
- break;
- }
- contents_scroll_offset_ = offset;
- ScrollContentsToOffset();
-}
-
-void BitmapScrollBar::ScrollToThumbPosition(int thumb_position,
- bool scroll_to_middle) {
- contents_scroll_offset_ =
- CalculateContentsOffset(thumb_position, scroll_to_middle);
- if (contents_scroll_offset_ < GetMinPosition()) {
- contents_scroll_offset_ = GetMinPosition();
- } else if (contents_scroll_offset_ > GetMaxPosition()) {
- contents_scroll_offset_ = GetMaxPosition();
- }
- ScrollContentsToOffset();
- SchedulePaint();
+int BitmapScrollBar::GetLayoutSize() const {
+ gfx::Size prefsize = prev_button_->GetPreferredSize();
+ return IsHorizontal() ? prefsize.height() : prefsize.width();
}
-void BitmapScrollBar::ScrollByContentsOffset(int contents_offset) {
- contents_scroll_offset_ -= contents_offset;
- if (contents_scroll_offset_ < GetMinPosition()) {
- contents_scroll_offset_ = GetMinPosition();
- } else if (contents_scroll_offset_ > GetMaxPosition()) {
- contents_scroll_offset_ = GetMaxPosition();
+gfx::Rect BitmapScrollBar::GetTrackBounds() const {
+ gfx::Size prefsize = prev_button_->GetPreferredSize();
+ if (IsHorizontal()) {
+ if (!show_scroll_buttons_)
+ prefsize.set_width(0);
+ int new_width =
+ std::max(0, width() - (prefsize.width() * 2));
+ gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height());
+ return track_bounds;
}
- ScrollContentsToOffset();
+ if (!show_scroll_buttons_)
+ prefsize.set_height(0);
+ gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(),
+ std::max(0, height() - (prefsize.height() * 2)));
+ return track_bounds;
}
///////////////////////////////////////////////////////////////////////////////
@@ -426,19 +257,20 @@ void BitmapScrollBar::Layout() {
next_button_->SetBounds(0, 0, 0, 0);
}
+ BaseScrollBarThumb* thumb = GetThumb();
// Size and place the thumb
- gfx::Size thumb_prefsize = thumb_->GetPreferredSize();
+ gfx::Size thumb_prefsize = thumb->GetPreferredSize();
gfx::Rect track_bounds = GetTrackBounds();
// Preserve the height/width of the thumb (depending on orientation) as set
// by the last call to |Update|, but coerce the width/height to be the
// appropriate value for the bitmaps provided.
if (IsHorizontal()) {
- thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_->width(),
+ thumb->SetBounds(thumb->x(), thumb->y(), thumb->width(),
thumb_prefsize.height());
} else {
- thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_prefsize.width(),
- thumb_->height());
+ thumb->SetBounds(thumb->x(), thumb->y(), thumb_prefsize.width(),
+ thumb->height());
}
// Hide the thumb if the track isn't tall enough to display even a tiny
@@ -446,196 +278,21 @@ void BitmapScrollBar::Layout() {
// in this scenario.
if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) ||
(!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) {
- thumb_->SetVisible(false);
- } else if (!thumb_->IsVisible()) {
- thumb_->SetVisible(true);
+ thumb->SetVisible(false);
+ } else if (!thumb->IsVisible()) {
+ thumb->SetVisible(true);
}
}
-bool BitmapScrollBar::OnMousePressed(const MouseEvent& event) {
- if (event.IsOnlyLeftMouseButton()) {
- SetThumbTrackState(CustomButton::BS_PUSHED);
- gfx::Rect thumb_bounds = thumb_->bounds();
- if (IsHorizontal()) {
- if (event.x() < thumb_bounds.x()) {
- last_scroll_amount_ = SCROLL_PREV_PAGE;
- } else if (event.x() > thumb_bounds.right()) {
- last_scroll_amount_ = SCROLL_NEXT_PAGE;
- }
- } else {
- if (event.y() < thumb_bounds.y()) {
- last_scroll_amount_ = SCROLL_PREV_PAGE;
- } else if (event.y() > thumb_bounds.bottom()) {
- last_scroll_amount_ = SCROLL_NEXT_PAGE;
- }
- }
- TrackClicked();
- repeater_.Start();
- }
- return true;
-}
-
-void BitmapScrollBar::OnMouseReleased(const MouseEvent& event) {
- OnMouseCaptureLost();
-}
-
-void BitmapScrollBar::OnMouseCaptureLost() {
- SetThumbTrackState(CustomButton::BS_NORMAL);
- repeater_.Stop();
-}
-
-bool BitmapScrollBar::OnKeyPressed(const KeyEvent& event) {
- ScrollAmount amount = SCROLL_NONE;
- switch (event.key_code()) {
- case ui::VKEY_UP:
- if (!IsHorizontal())
- amount = SCROLL_PREV_LINE;
- break;
- case ui::VKEY_DOWN:
- if (!IsHorizontal())
- amount = SCROLL_NEXT_LINE;
- break;
- case ui::VKEY_LEFT:
- if (IsHorizontal())
- amount = SCROLL_PREV_LINE;
- break;
- case ui::VKEY_RIGHT:
- if (IsHorizontal())
- amount = SCROLL_NEXT_LINE;
- break;
- case ui::VKEY_PRIOR:
- amount = SCROLL_PREV_PAGE;
- break;
- case ui::VKEY_NEXT:
- amount = SCROLL_NEXT_PAGE;
- break;
- case ui::VKEY_HOME:
- amount = SCROLL_START;
- break;
- case ui::VKEY_END:
- amount = SCROLL_END;
- break;
- }
- if (amount != SCROLL_NONE) {
- ScrollByAmount(amount);
- return true;
- }
- return false;
-}
-
-bool BitmapScrollBar::OnMouseWheel(const MouseWheelEvent& event) {
- ScrollByContentsOffset(event.offset());
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, ContextMenuController implementation:
-
-enum ScrollBarContextMenuCommands {
- ScrollBarContextMenuCommand_ScrollHere = 1,
- ScrollBarContextMenuCommand_ScrollStart,
- ScrollBarContextMenuCommand_ScrollEnd,
- ScrollBarContextMenuCommand_ScrollPageUp,
- ScrollBarContextMenuCommand_ScrollPageDown,
- ScrollBarContextMenuCommand_ScrollPrev,
- ScrollBarContextMenuCommand_ScrollNext
-};
-
-void BitmapScrollBar::ShowContextMenuForView(View* source,
- const gfx::Point& p,
- bool is_mouse_gesture) {
- Widget* widget = GetWidget();
- gfx::Rect widget_bounds = widget->GetWindowScreenBounds();
- gfx::Point temp_pt(p.x() - widget_bounds.x(), p.y() - widget_bounds.y());
- View::ConvertPointFromWidget(this, &temp_pt);
- context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y();
-
- scoped_ptr<Menu> menu(
- Menu::Create(this, Menu::TOPLEFT, GetWidget()->GetNativeView()));
- menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere);
- menu->AppendSeparator();
- menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart);
- menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollEnd);
- menu->AppendSeparator();
- menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageUp);
- menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageDown);
- menu->AppendSeparator();
- menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev);
- menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext);
- menu->RunMenuAt(p.x(), p.y());
-}
-
///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, Menu::Delegate implementation:
-
-std::wstring BitmapScrollBar::GetLabel(int id) const {
- int ids_value = 0;
- switch (id) {
- case ScrollBarContextMenuCommand_ScrollHere:
- ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE;
- break;
- case ScrollBarContextMenuCommand_ScrollStart:
- ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE
- : IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME;
- break;
- case ScrollBarContextMenuCommand_ScrollEnd:
- ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE
- : IDS_APP_SCROLLBAR_CXMENU_SCROLLEND;
- break;
- case ScrollBarContextMenuCommand_ScrollPageUp:
- ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP;
- break;
- case ScrollBarContextMenuCommand_ScrollPageDown:
- ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN;
- break;
- case ScrollBarContextMenuCommand_ScrollPrev:
- ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT
- : IDS_APP_SCROLLBAR_CXMENU_SCROLLUP;
- break;
- case ScrollBarContextMenuCommand_ScrollNext:
- ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT
- : IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN;
- break;
- default:
- NOTREACHED() << "Invalid BitmapScrollBar Context Menu command!";
- }
-
- return ids_value ? UTF16ToWide(l10n_util::GetStringUTF16(ids_value)) : L"";
-}
-
-bool BitmapScrollBar::IsCommandEnabled(int id) const {
- switch (id) {
- case ScrollBarContextMenuCommand_ScrollPageUp:
- case ScrollBarContextMenuCommand_ScrollPageDown:
- return !IsHorizontal();
- }
- return true;
-}
+// BitmapScrollBar, View implementation:
-void BitmapScrollBar::ExecuteCommand(int id) {
- switch (id) {
- case ScrollBarContextMenuCommand_ScrollHere:
- ScrollToThumbPosition(context_menu_mouse_position_, true);
- break;
- case ScrollBarContextMenuCommand_ScrollStart:
- ScrollByAmount(SCROLL_START);
- break;
- case ScrollBarContextMenuCommand_ScrollEnd:
- ScrollByAmount(SCROLL_END);
- break;
- case ScrollBarContextMenuCommand_ScrollPageUp:
- ScrollByAmount(SCROLL_PREV_PAGE);
- break;
- case ScrollBarContextMenuCommand_ScrollPageDown:
- ScrollByAmount(SCROLL_NEXT_PAGE);
- break;
- case ScrollBarContextMenuCommand_ScrollPrev:
- ScrollByAmount(SCROLL_PREV_LINE);
- break;
- case ScrollBarContextMenuCommand_ScrollNext:
- ScrollByAmount(SCROLL_NEXT_LINE);
- break;
- }
+void BitmapScrollBar::OnPaint(gfx::Canvas* canvas) {
+ // Paint the track.
+ gfx::Rect track_bounds = GetTrackBounds();
+ canvas->TileImageInt(*images_[THUMB_TRACK][GetThumbTrackState()],
+ track_bounds.x(), track_bounds.y(),
+ track_bounds.width(), track_bounds.height());
}
///////////////////////////////////////////////////////////////////////////////
@@ -649,87 +306,4 @@ void BitmapScrollBar::ButtonPressed(Button* sender, const views::Event& event) {
}
}
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, ScrollBar implementation:
-
-void BitmapScrollBar::Update(int viewport_size, int content_size,
- int contents_scroll_offset) {
- ScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
-
- // Make sure contents_size is always > 0 to avoid divide by zero errors in
- // calculations throughout this code.
- contents_size_ = std::max(1, content_size);
-
- if (content_size < 0)
- content_size = 0;
- if (contents_scroll_offset < 0)
- contents_scroll_offset = 0;
- if (contents_scroll_offset > content_size)
- contents_scroll_offset = content_size;
-
- // Thumb Height and Thumb Pos.
- // The height of the thumb is the ratio of the Viewport height to the
- // content size multiplied by the height of the thumb track.
- double ratio = static_cast<double>(viewport_size) / contents_size_;
- int thumb_size = static_cast<int>(ratio * GetTrackSize());
- thumb_->SetSize(thumb_size);
-
- int thumb_position = CalculateThumbPosition(contents_scroll_offset);
- thumb_->SetPosition(thumb_position);
-}
-
-int BitmapScrollBar::GetLayoutSize() const {
- gfx::Size prefsize = prev_button_->GetPreferredSize();
- return IsHorizontal() ? prefsize.height() : prefsize.width();
-}
-
-int BitmapScrollBar::GetPosition() const {
- return thumb_->GetPosition();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, View implementation:
-
-void BitmapScrollBar::OnPaint(gfx::Canvas* canvas) {
- // Paint the track.
- gfx::Rect track_bounds = GetTrackBounds();
- canvas->TileImageInt(*images_[THUMB_TRACK][thumb_track_state_],
- track_bounds.x(), track_bounds.y(),
- track_bounds.width(), track_bounds.height());
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BitmapScrollBar, private:
-
-void BitmapScrollBar::TrackClicked() {
- if (last_scroll_amount_ != SCROLL_NONE)
- ScrollByAmount(last_scroll_amount_);
-}
-
-void BitmapScrollBar::ScrollContentsToOffset() {
- GetController()->ScrollToPosition(this, contents_scroll_offset_);
- thumb_->SetPosition(CalculateThumbPosition(contents_scroll_offset_));
-}
-
-int BitmapScrollBar::GetTrackSize() const {
- gfx::Rect track_bounds = GetTrackBounds();
- return IsHorizontal() ? track_bounds.width() : track_bounds.height();
-}
-
-int BitmapScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
- return (contents_scroll_offset * GetTrackSize()) / contents_size_;
-}
-
-int BitmapScrollBar::CalculateContentsOffset(int thumb_position,
- bool scroll_to_middle) const {
- if (scroll_to_middle)
- thumb_position = thumb_position - (thumb_->GetSize() / 2);
- return (thumb_position * contents_size_) / GetTrackSize();
-}
-
-void BitmapScrollBar::SetThumbTrackState(CustomButton::ButtonState state) {
- thumb_track_state_ = state;
- SchedulePaint();
-}
-
} // namespace views
diff --git a/views/controls/scrollbar/bitmap_scroll_bar.h b/views/controls/scrollbar/bitmap_scroll_bar.h
index ce072bf..9b5cc91 100644
--- a/views/controls/scrollbar/bitmap_scroll_bar.h
+++ b/views/controls/scrollbar/bitmap_scroll_bar.h
@@ -6,11 +6,7 @@
#define VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
#pragma once
-#include "views/context_menu_controller.h"
-#include "views/controls/button/image_button.h"
-#include "views/controls/menu/menu.h"
-#include "views/controls/scrollbar/scroll_bar.h"
-#include "views/repeat_controller.h"
+#include "views/controls/scrollbar/base_scroll_bar.h"
namespace views {
@@ -27,24 +23,13 @@ class BitmapScrollBarThumb;
// well as for the thumb and track. This is intended for creating UIs that
// have customized, non-native appearances, like floating HUDs etc.
//
-// Maybe TODO(beng): (Cleanup) If we need to, we may want to factor rendering
-// out of this altogether and have the user supply
-// Background impls for each component, and just use those
-// to render, so that for example we get native theme
-// rendering.
-//
///////////////////////////////////////////////////////////////////////////////
-class BitmapScrollBar : public ScrollBar,
- public ButtonListener,
- public ContextMenuController,
- public Menu::Delegate {
+class VIEWS_EXPORT BitmapScrollBar : public BaseScrollBar,
+ public ButtonListener {
public:
BitmapScrollBar(bool horizontal, bool show_scroll_buttons);
virtual ~BitmapScrollBar() { }
- // Get the bounds of the "track" area that the thumb is free to slide within.
- gfx::Rect GetTrackBounds() const;
-
// A list of parts that the user may supply bitmaps for.
enum ScrollBarPart {
// The button used to represent scrolling up/left by 1 line.
@@ -71,122 +56,31 @@ class BitmapScrollBar : public ScrollBar,
CustomButton::ButtonState state,
SkBitmap* bitmap);
- // An enumeration of different amounts of incremental scroll, representing
- // events sent from different parts of the UI/keyboard.
- enum ScrollAmount {
- SCROLL_NONE = 0,
- SCROLL_START,
- SCROLL_END,
- SCROLL_PREV_LINE,
- SCROLL_NEXT_LINE,
- SCROLL_PREV_PAGE,
- SCROLL_NEXT_PAGE,
- };
-
- // Scroll the contents by the specified type (see ScrollAmount above).
- void ScrollByAmount(ScrollAmount amount);
- // Scroll the contents to the appropriate position given the supplied
- // position of the thumb (thumb track coordinates). If |scroll_to_middle| is
- // true, then the conversion assumes |thumb_position| is in the middle of the
- // thumb rather than the top.
- void ScrollToThumbPosition(int thumb_position, bool scroll_to_middle);
-
- // Scroll the contents by the specified offset (contents coordinates).
- void ScrollByContentsOffset(int contents_offset);
+ gfx::Rect GetTrackBounds() const;
+ protected:
// View overrides:
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual void Layout() OVERRIDE;
- virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
- virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE;
- virtual void OnMouseCaptureLost() OVERRIDE;
- virtual bool OnKeyPressed(const KeyEvent& event) OVERRIDE;
- virtual bool OnMouseWheel(const MouseWheelEvent& event) OVERRIDE;
-
- // BaseButton::ButtonListener overrides:
- virtual void ButtonPressed(Button* sender,
- const views::Event& event) OVERRIDE;
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
// ScrollBar overrides:
- virtual void Update(int viewport_size,
- int content_size,
- int contents_scroll_offset) OVERRIDE;
virtual int GetLayoutSize() const OVERRIDE;
- virtual int GetPosition() const OVERRIDE;
-
- // ContextMenuController overrides.
- virtual void ShowContextMenuForView(View* source,
- const gfx::Point& p,
- bool is_mouse_gesture) OVERRIDE;
-
- // Menu::Delegate overrides:
- virtual std::wstring GetLabel(int id) const OVERRIDE;
- virtual bool IsCommandEnabled(int id) const OVERRIDE;
- virtual void ExecuteCommand(int id) OVERRIDE;
- protected:
- // View overrides:
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ // BaseButton::ButtonListener overrides:
+ virtual void ButtonPressed(Button* sender,
+ const views::Event& event) OVERRIDE;
private:
- // Called when the mouse is pressed down in the track area.
- void TrackClicked();
-
- // Responsible for scrolling the contents and also updating the UI to the
- // current value of the Scroll Offset.
- void ScrollContentsToOffset();
-
- // Returns the size (width or height) of the track area of the ScrollBar.
- int GetTrackSize() const;
-
- // Calculate the position of the thumb within the track based on the
- // specified scroll offset of the contents.
- int CalculateThumbPosition(int contents_scroll_offset) const;
-
- // Calculates the current value of the contents offset (contents coordinates)
- // based on the current thumb position (thumb track coordinates). See
- // |ScrollToThumbPosition| for an explanation of |scroll_to_middle|.
- int CalculateContentsOffset(int thumb_position,
- bool scroll_to_middle) const;
-
- // Called when the state of the thumb track changes (e.g. by the user
- // pressing the mouse button down in it).
- void SetThumbTrackState(CustomButton::ButtonState state);
+ // Up/Down/Left/Right buttons.
+ ImageButton* prev_button_;
+ ImageButton* next_button_;
// The thumb needs to be able to access the part images.
friend BitmapScrollBarThumb;
SkBitmap* images_[PART_COUNT][CustomButton::BS_COUNT];
- // The size of the scrolled contents, in pixels.
- int contents_size_;
-
- // The current amount the contents is offset by in the viewport.
- int contents_scroll_offset_;
-
- // Up/Down/Left/Right buttons and the Thumb.
- ImageButton* prev_button_;
- ImageButton* next_button_;
- BitmapScrollBarThumb* thumb_;
-
- // The state of the scrollbar track. Typically, the track will highlight when
- // the user presses the mouse on them (during page scrolling).
- CustomButton::ButtonState thumb_track_state_;
-
- // The last amount of incremental scroll that this scrollbar performed. This
- // is accessed by the callbacks for the auto-repeat up/down buttons to know
- // what direction to repeatedly scroll in.
- ScrollAmount last_scroll_amount_;
-
- // An instance of a RepeatController which scrolls the scrollbar continuously
- // as the user presses the mouse button down on the up/down buttons or the
- // track.
- RepeatController repeater_;
-
- // The position of the mouse within the scroll bar when the context menu
- // was invoked.
- int context_menu_mouse_position_;
-
// True if the scroll buttons at each end of the scroll bar should be shown.
bool show_scroll_buttons_;
diff --git a/views/controls/scrollbar/native_scroll_bar_gtk.cc b/views/controls/scrollbar/native_scroll_bar_gtk.cc
index dc1a9b6..cd9bebd 100644
--- a/views/controls/scrollbar/native_scroll_bar_gtk.cc
+++ b/views/controls/scrollbar/native_scroll_bar_gtk.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -8,7 +8,9 @@
#include "ui/base/keycodes/keyboard_codes_posix.h"
#include "views/controls/scrollbar/native_scroll_bar.h"
+#include "views/controls/scrollbar/native_scroll_bar_views.h"
#include "views/controls/scrollbar/scroll_bar.h"
+#include "views/widget/widget.h"
namespace views {
@@ -199,6 +201,8 @@ void NativeScrollBarGtk::MoveToBottom() {
// static
NativeScrollBarWrapper* NativeScrollBarWrapper::CreateWrapper(
NativeScrollBar* scroll_bar) {
+ if (Widget::IsPureViews())
+ return new NativeScrollBarViews(scroll_bar);
return new NativeScrollBarGtk(scroll_bar);
}
diff --git a/views/controls/scrollbar/native_scroll_bar_views.cc b/views/controls/scrollbar/native_scroll_bar_views.cc
new file mode 100644
index 0000000..775c23c
--- /dev/null
+++ b/views/controls/scrollbar/native_scroll_bar_views.cc
@@ -0,0 +1,371 @@
+// Copyright (c) 2011 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 "views/controls/scrollbar/native_scroll_bar_views.h"
+
+#include "base/logging.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/path.h"
+#include "views/controls/button/custom_button.h"
+#include "views/controls/focusable_border.h"
+#include "views/controls/scrollbar/native_scroll_bar.h"
+#include "views/controls/scrollbar/scroll_bar.h"
+#include "views/controls/scrollbar/base_scroll_bar_button.h"
+#include "views/controls/scrollbar/base_scroll_bar_thumb.h"
+
+namespace views {
+
+namespace {
+
+// Wrapper for the scroll buttons.
+class ScrollBarButton : public BaseScrollBarButton {
+ public:
+ enum Type {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT,
+ };
+
+ ScrollBarButton(ButtonListener* listener, Type type);
+ virtual ~ScrollBarButton();
+
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ protected:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+ gfx::NativeTheme::ExtraParams GetNativeThemeParams() const;
+ gfx::NativeTheme::Part GetNativeThemePart() const;
+ gfx::NativeTheme::State GetNativeThemeState() const;
+
+ Type type_;
+};
+
+// Wrapper for the scroll thumb
+class ScrollBarThumb : public BaseScrollBarThumb {
+ public:
+ explicit ScrollBarThumb(BaseScrollBar* scroll_bar);
+ virtual ~ScrollBarThumb();
+
+ virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+ protected:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+ gfx::NativeTheme::ExtraParams GetNativeThemeParams() const;
+ gfx::NativeTheme::Part GetNativeThemePart() const;
+ gfx::NativeTheme::State GetNativeThemeState() const;
+
+ ScrollBar* scroll_bar_;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// ScrollBarButton
+
+ScrollBarButton::ScrollBarButton(
+ ButtonListener* listener,
+ Type type)
+ : BaseScrollBarButton(listener),
+ type_(type) {
+}
+
+ScrollBarButton::~ScrollBarButton() {
+}
+
+gfx::Size ScrollBarButton::GetPreferredSize() {
+ const gfx::NativeTheme* native_theme = gfx::NativeTheme::instance();
+ return native_theme->GetPartSize(GetNativeThemePart(),
+ GetNativeThemeState(),
+ GetNativeThemeParams());
+}
+
+void ScrollBarButton::OnPaint(gfx::Canvas* canvas) {
+ const gfx::NativeTheme* native_theme = gfx::NativeTheme::instance();
+ gfx::Rect bounds;
+ bounds.set_size(GetPreferredSize());
+
+ native_theme->Paint(canvas->AsCanvasSkia(),
+ GetNativeThemePart(),
+ GetNativeThemeState(),
+ bounds,
+ GetNativeThemeParams());
+}
+
+gfx::NativeTheme::ExtraParams
+ ScrollBarButton::GetNativeThemeParams() const {
+ gfx::NativeTheme::ExtraParams params;
+
+ switch (state_) {
+ case CustomButton::BS_HOT:
+ params.scrollbar_arrow.is_hovering = true;
+ break;
+ default:
+ params.scrollbar_arrow.is_hovering = false;
+ break;
+ }
+
+ return params;
+}
+
+gfx::NativeTheme::Part
+ ScrollBarButton::GetNativeThemePart() const {
+ switch (type_) {
+ case UP:
+ return gfx::NativeTheme::kScrollbarUpArrow;
+ case DOWN:
+ return gfx::NativeTheme::kScrollbarDownArrow;
+ case LEFT:
+ return gfx::NativeTheme::kScrollbarLeftArrow;
+ case RIGHT:
+ return gfx::NativeTheme::kScrollbarRightArrow;
+ default:
+ return gfx::NativeTheme::kScrollbarUpArrow;
+ }
+}
+
+gfx::NativeTheme::State
+ ScrollBarButton::GetNativeThemeState() const {
+ gfx::NativeTheme::State state;
+
+ switch (state_) {
+ case CustomButton::BS_HOT:
+ state = gfx::NativeTheme::kHovered;
+ break;
+ case CustomButton::BS_PUSHED:
+ state = gfx::NativeTheme::kPressed;
+ break;
+ case CustomButton::BS_DISABLED:
+ state = gfx::NativeTheme::kDisabled;
+ break;
+ case CustomButton::BS_NORMAL:
+ default:
+ state = gfx::NativeTheme::kNormal;
+ break;
+ }
+
+ return state;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// ScrollBarThumb
+
+ScrollBarThumb::ScrollBarThumb(BaseScrollBar* scroll_bar)
+ : BaseScrollBarThumb(scroll_bar),
+ scroll_bar_(scroll_bar) {
+}
+
+ScrollBarThumb::~ScrollBarThumb() {
+}
+
+gfx::Size ScrollBarThumb::GetPreferredSize() {
+ const gfx::NativeTheme* native_theme = gfx::NativeTheme::instance();
+ return native_theme->GetPartSize(GetNativeThemePart(),
+ GetNativeThemeState(),
+ GetNativeThemeParams());
+}
+
+void ScrollBarThumb::OnPaint(gfx::Canvas* canvas) {
+ const gfx::NativeTheme* native_theme = gfx::NativeTheme::instance();
+
+ native_theme->Paint(canvas->AsCanvasSkia(),
+ GetNativeThemePart(),
+ GetNativeThemeState(),
+ GetLocalBounds(),
+ GetNativeThemeParams());
+}
+
+gfx::NativeTheme::ExtraParams
+ ScrollBarThumb::GetNativeThemeParams() const {
+ gfx::NativeTheme::ExtraParams params;
+
+ switch (GetState()) {
+ case CustomButton::BS_HOT:
+ params.scrollbar_thumb.is_hovering = true;
+ break;
+ default:
+ params.scrollbar_thumb.is_hovering = false;
+ break;
+ }
+
+ return params;
+}
+
+gfx::NativeTheme::Part ScrollBarThumb::GetNativeThemePart() const {
+ if (scroll_bar_->IsHorizontal())
+ return gfx::NativeTheme::kScrollbarHorizontalThumb;
+ return gfx::NativeTheme::kScrollbarVerticalThumb;
+}
+
+gfx::NativeTheme::State ScrollBarThumb::GetNativeThemeState() const {
+ gfx::NativeTheme::State state;
+
+ switch (GetState()) {
+ case CustomButton::BS_HOT:
+ state = gfx::NativeTheme::kHovered;
+ break;
+ case CustomButton::BS_PUSHED:
+ state = gfx::NativeTheme::kPressed;
+ break;
+ case CustomButton::BS_DISABLED:
+ state = gfx::NativeTheme::kDisabled;
+ break;
+ case CustomButton::BS_NORMAL:
+ default:
+ state = gfx::NativeTheme::kNormal;
+ break;
+ }
+
+ return state;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeScrollBarViews, public:
+
+NativeScrollBarViews::NativeScrollBarViews(NativeScrollBar* scroll_bar)
+ : BaseScrollBar(scroll_bar->IsHorizontal(),
+ new ScrollBarThumb(this)),
+ native_scroll_bar_(scroll_bar) {
+ SetController(native_scroll_bar_->GetController());
+
+ if (native_scroll_bar_->IsHorizontal()) {
+ prev_button_ = new ScrollBarButton(this, ScrollBarButton::LEFT);
+ next_button_ = new ScrollBarButton(this, ScrollBarButton::RIGHT);
+
+ part_ = gfx::NativeTheme::kScrollbarHorizontalTrack;
+ } else {
+ prev_button_ = new ScrollBarButton(this, ScrollBarButton::UP);
+ next_button_ = new ScrollBarButton(this, ScrollBarButton::DOWN);
+
+ part_ = gfx::NativeTheme::kScrollbarVerticalTrack;
+ }
+
+ state_ = gfx::NativeTheme::kNormal;
+
+ AddChildView(prev_button_);
+ AddChildView(next_button_);
+
+ prev_button_->set_context_menu_controller(this);
+ next_button_->set_context_menu_controller(this);
+}
+
+NativeScrollBarViews::~NativeScrollBarViews() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeScrollBarViews, View overrides:
+
+void NativeScrollBarViews::Layout() {
+ SetBoundsRect(native_scroll_bar_->GetLocalBounds());
+
+ gfx::Size size = prev_button_->GetPreferredSize();
+ prev_button_->SetBounds(0, 0, size.width(), size.height());
+
+ if (native_scroll_bar_->IsHorizontal()) {
+ next_button_->SetBounds(width() - size.width(), 0,
+ size.width(), size.height());
+ } else {
+ next_button_->SetBounds(0, height() - size.height(),
+ size.width(), size.height());
+ }
+
+ GetThumb()->SetBoundsRect(GetTrackBounds());
+}
+
+void NativeScrollBarViews::OnPaint(gfx::Canvas* canvas) {
+ const gfx::NativeTheme* native_theme = gfx::NativeTheme::instance();
+ gfx::Rect bounds = GetTrackBounds();
+
+ params_.scrollbar_track.track_x = bounds.x();
+ params_.scrollbar_track.track_y = bounds.y();
+ params_.scrollbar_track.track_width = bounds.width();
+ params_.scrollbar_track.track_height = bounds.height();
+
+
+ native_theme->Paint(canvas->AsCanvasSkia(),
+ part_,
+ state_,
+ bounds,
+ params_);
+}
+
+gfx::Size NativeScrollBarViews::GetPreferredSize() {
+ if (native_scroll_bar_->IsHorizontal())
+ return gfx::Size(0, GetHorizontalScrollBarHeight());
+ return gfx::Size(GetVerticalScrollBarWidth(), 0);
+}
+
+int NativeScrollBarViews::GetLayoutSize() const {
+ gfx::Size size = prev_button_->GetPreferredSize();
+ return IsHorizontal() ? size.height() : size.width();
+}
+
+void NativeScrollBarViews::ScrollToPosition(int position) {
+ GetController()->ScrollToPosition(native_scroll_bar_, position);
+}
+
+int NativeScrollBarViews::GetScrollIncrement(bool is_page,
+ bool is_positive) {
+ return GetController()->GetScrollIncrement(native_scroll_bar_,
+ is_page,
+ is_positive);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BaseButton::ButtonListener overrides:
+
+void NativeScrollBarViews::ButtonPressed(Button* sender,
+ const views::Event& event) {
+ if (sender == prev_button_) {
+ ScrollByAmount(SCROLL_PREV_LINE);
+ } else if (sender == next_button_) {
+ ScrollByAmount(SCROLL_NEXT_LINE);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeScrollBarViews, NativeScrollBarWrapper overrides:
+
+int NativeScrollBarViews::GetPosition() const {
+ return BaseScrollBar::GetPosition();
+}
+
+View* NativeScrollBarViews::GetView() {
+ return this;
+}
+
+void NativeScrollBarViews::Update(int viewport_size,
+ int content_size,
+ int current_pos) {
+ BaseScrollBar::Update(viewport_size, content_size, current_pos);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeScrollBarViews, private:
+
+gfx::Rect NativeScrollBarViews::GetTrackBounds() const {
+ gfx::Rect bounds = GetLocalBounds();
+ gfx::Size size = prev_button_->GetPreferredSize();
+ BaseScrollBarThumb* thumb = GetThumb();
+
+ if (native_scroll_bar_->IsHorizontal()) {
+ bounds.set_x(bounds.x() + size.width());
+ bounds.set_width(bounds.width() - 2 * size.width());
+ bounds.set_height(thumb->GetPreferredSize().height());
+ } else {
+ bounds.set_y(bounds.y() + size.height());
+ bounds.set_height(bounds.height() - 2 * size.height());
+ bounds.set_width(thumb->GetPreferredSize().width());
+ }
+
+ return bounds;
+}
+
+} // namespace views
diff --git a/views/controls/scrollbar/native_scroll_bar_views.h b/views/controls/scrollbar/native_scroll_bar_views.h
new file mode 100644
index 0000000..e863a1f
--- /dev/null
+++ b/views/controls/scrollbar/native_scroll_bar_views.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 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.
+
+#ifndef VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLL_BAR_VIEWS_H_
+#define VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLL_BAR_VIEWS_H_
+#pragma once
+
+#include "ui/gfx/native_theme.h"
+#include "ui/gfx/point.h"
+#include "views/controls/button/button.h"
+#include "views/controls/scrollbar/base_scroll_bar.h"
+#include "views/controls/scrollbar/native_scroll_bar_wrapper.h"
+#include "views/view.h"
+
+namespace gfx {
+class Canvas;
+}
+
+namespace views {
+
+class NativeScrollBar;
+
+// Views implementation for the scrollbar.
+class VIEWS_EXPORT NativeScrollBarViews : public BaseScrollBar,
+ public ButtonListener,
+ public NativeScrollBarWrapper {
+ public:
+ // Creates new scrollbar, either horizontal or vertical.
+ explicit NativeScrollBarViews(NativeScrollBar* native_scroll_bar);
+ virtual ~NativeScrollBarViews();
+
+ private:
+ // View overrides:
+ virtual void Layout();
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+ virtual gfx::Size GetPreferredSize();
+
+ // ScrollBar overrides:
+ virtual int GetLayoutSize() const OVERRIDE;
+
+ // BaseScrollBar overrides:
+ virtual void ScrollToPosition(int position);
+ virtual int GetScrollIncrement(bool is_page, bool is_positive);
+
+ // BaseButton::ButtonListener overrides:
+ virtual void ButtonPressed(Button* sender,
+ const views::Event& event) OVERRIDE;
+
+ // NativeScrollBarWrapper overrides:
+ virtual int GetPosition() const;
+ virtual View* GetView();
+ virtual void Update(int viewport_size, int content_size, int current_pos);
+
+ // Returns the area for the track. This is the area of the scrollbar minus
+ // the size of the arrow buttons.
+ gfx::Rect GetTrackBounds() const;
+
+ // The NativeScrollBar we are bound to.
+ NativeScrollBar* native_scroll_bar_;
+
+ // The scroll bar buttons (Up/Down, Left/Right).
+ Button* prev_button_;
+ Button* next_button_;
+
+ gfx::NativeTheme::ExtraParams params_;
+ gfx::NativeTheme::Part part_;
+ gfx::NativeTheme::State state_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeScrollBarViews);
+};
+
+} // namespace views
+
+#endif // VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLL_BAR_VIEWS_H_
+
diff --git a/views/controls/scrollbar/native_scroll_bar_wrapper.h b/views/controls/scrollbar/native_scroll_bar_wrapper.h
index fb92c3d..210401a 100644
--- a/views/controls/scrollbar/native_scroll_bar_wrapper.h
+++ b/views/controls/scrollbar/native_scroll_bar_wrapper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -13,7 +13,7 @@ class View;
// A specialization of NativeControlWrapper that hosts a platform-native
// scroll bar.
-class NativeScrollBarWrapper {
+class VIEWS_EXPORT NativeScrollBarWrapper {
public:
virtual ~NativeScrollBarWrapper() {}
diff --git a/views/controls/scrollbar/scrollbar_unittest.cc b/views/controls/scrollbar/scrollbar_unittest.cc
new file mode 100644
index 0000000..a19bfe6
--- /dev/null
+++ b/views/controls/scrollbar/scrollbar_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2011 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 "views/controls/scrollbar/scroll_bar.h"
+#include "views/controls/scrollbar/native_scroll_bar.h"
+#include "views/controls/scrollbar/native_scroll_bar_views.h"
+#include "views/test/views_test_base.h"
+#include "views/widget/widget.h"
+
+namespace {
+
+// The Scrollbar controller. This is the widget that should do the real
+// scrolling of contents.
+class TestScrollBarController : public views::ScrollBarController {
+ public:
+ virtual void ScrollToPosition(views::ScrollBar* source,
+ int position) OVERRIDE {
+ last_source = source;
+ last_position = position;
+ }
+
+ virtual int GetScrollIncrement(views::ScrollBar* source,
+ bool is_page,
+ bool is_positive) OVERRIDE {
+ last_source = source;
+ last_is_page = is_page;
+ last_is_positive = is_positive;
+
+ if (is_page)
+ return 20;
+ return 10;
+ }
+
+ // We save the last values in order to assert the corectness of the scroll
+ // operation.
+ views::ScrollBar* last_source;
+ bool last_is_positive;
+ bool last_is_page;
+ int last_position;
+};
+
+} // namespace
+
+namespace views {
+
+class NativeScrollBarTest : public ViewsTestBase {
+ public:
+ NativeScrollBarTest()
+ : widget_(NULL),
+ scrollbar_(NULL),
+ controller_(NULL) {
+ }
+
+ virtual void SetUp() {
+ ViewsTestBase::SetUp();
+ Widget::SetPureViews(true);
+ }
+
+ virtual void TearDown() {
+ Widget::SetPureViews(false);
+ if (widget_)
+ widget_->Close();
+ ViewsTestBase::TearDown();
+ }
+
+ void InitScrollBar() {
+ controller_.reset(new TestScrollBarController());
+
+ ASSERT_FALSE(scrollbar_);
+ native_scrollbar_ = new NativeScrollBar(true);
+ native_scrollbar_->SetBounds(0, 0, 100, 100);
+ scrollbar_ = new NativeScrollBarViews(native_scrollbar_);
+ scrollbar_->SetController(controller_.get());
+
+ widget_ = new Widget;
+ Widget::InitParams params(Widget::InitParams::TYPE_POPUP);
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ widget_->Init(params);
+ View* container = new View();
+ widget_->SetContentsView(container);
+ container->AddChildView(scrollbar_);
+ scrollbar_->SetBounds(0, 0, 100, 100);
+ scrollbar_->Update(100, 200, 0);
+
+ track_size_ = scrollbar_->GetTrackBounds().width();
+ }
+
+ protected:
+ Widget* widget_;
+
+ // This is the native scrollbar the Views one wraps around.
+ NativeScrollBar* native_scrollbar_;
+
+ // This is the Views scrollbar.
+ BaseScrollBar* scrollbar_;
+
+ // Keep track of the size of the track. This is how we can tell when we
+ // scroll to the middle.
+ int track_size_;
+
+ scoped_ptr<TestScrollBarController> controller_;
+};
+
+// TODO(dnicoara) Can't run the test on Windows since the scrollbar |Part|
+// isn't handled in NativeTheme.
+#if defined(OS_WIN)
+TEST_F(NativeScrollBarTest, DISABLED_Scrolling) {
+#else
+TEST_F(NativeScrollBarTest, Scrolling) {
+#endif
+ InitScrollBar();
+ EXPECT_EQ(scrollbar_->GetPosition(), 0);
+ EXPECT_EQ(scrollbar_->GetMaxPosition(), 100);
+ EXPECT_EQ(scrollbar_->GetMinPosition(), 0);
+
+ // Scroll to middle.
+ scrollbar_->ScrollToThumbPosition(track_size_ / 4, false);
+ EXPECT_EQ(controller_->last_position, 50);
+ EXPECT_EQ(controller_->last_source, native_scrollbar_);
+
+ // Scroll to the end.
+ scrollbar_->ScrollToThumbPosition(track_size_ / 2, false);
+ EXPECT_EQ(controller_->last_position, 100);
+
+ // Overscroll. Last position should be the maximum position.
+ scrollbar_->ScrollToThumbPosition(track_size_, false);
+ EXPECT_EQ(controller_->last_position, 100);
+
+ // Underscroll. Last position should be the minimum position.
+ scrollbar_->ScrollToThumbPosition(-10, false);
+ EXPECT_EQ(controller_->last_position, 0);
+
+ // Test the different fixed scrolling amounts. Generally used by buttons,
+ // or click on track.
+ scrollbar_->ScrollToThumbPosition(0, false);
+ scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_LINE);
+ EXPECT_EQ(controller_->last_position, 10);
+
+ scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_PREV_LINE);
+ EXPECT_EQ(controller_->last_position, 0);
+
+ scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_NEXT_PAGE);
+ EXPECT_EQ(controller_->last_position, 20);
+
+ scrollbar_->ScrollByAmount(BaseScrollBar::SCROLL_PREV_PAGE);
+ EXPECT_EQ(controller_->last_position, 0);
+}
+
+} // namespace views
diff --git a/views/views.gyp b/views/views.gyp
index 8415705..f770895 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -171,10 +171,18 @@
'controls/resize_area.h',
'controls/scroll_view.cc',
'controls/scroll_view.h',
+ 'controls/scrollbar/base_scroll_bar.cc',
+ 'controls/scrollbar/base_scroll_bar.h',
+ 'controls/scrollbar/base_scroll_bar_button.cc',
+ 'controls/scrollbar/base_scroll_bar_button.h',
+ 'controls/scrollbar/base_scroll_bar_thumb.cc',
+ 'controls/scrollbar/base_scroll_bar_thumb.h',
'controls/scrollbar/bitmap_scroll_bar.cc',
'controls/scrollbar/bitmap_scroll_bar.h',
'controls/scrollbar/native_scroll_bar_gtk.cc',
'controls/scrollbar/native_scroll_bar_gtk.h',
+ 'controls/scrollbar/native_scroll_bar_views.cc',
+ 'controls/scrollbar/native_scroll_bar_views.h',
'controls/scrollbar/native_scroll_bar_win.cc',
'controls/scrollbar/native_scroll_bar_win.h',
'controls/scrollbar/native_scroll_bar_wrapper.h',
@@ -490,6 +498,7 @@
'controls/menu/menu_model_adapter_unittest.cc',
'controls/textfield/native_textfield_views_unittest.cc',
'controls/textfield/textfield_views_model_unittest.cc',
+ 'controls/scrollbar/scrollbar_unittest.cc',
'events/event_unittest.cc',
'focus/accelerator_handler_gtk_unittest.cc',
'focus/focus_manager_unittest.cc',