diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 00:34:05 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 00:34:05 +0000 |
commit | 2362e4fe2905ab75d3230ebc3e307ae53e2b8362 (patch) | |
tree | e6d88357a2021811e0e354f618247217be8bb3da /views/controls/scrollbar | |
parent | db23ac3e713dc17509b2b15d3ee634968da45715 (diff) | |
download | chromium_src-2362e4fe2905ab75d3230ebc3e307ae53e2b8362.zip chromium_src-2362e4fe2905ab75d3230ebc3e307ae53e2b8362.tar.gz chromium_src-2362e4fe2905ab75d3230ebc3e307ae53e2b8362.tar.bz2 |
Move src/chrome/views to src/views. RS=darin http://crbug.com/11387
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15604 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/controls/scrollbar')
-rw-r--r-- | views/controls/scrollbar/bitmap_scroll_bar.cc | 703 | ||||
-rw-r--r-- | views/controls/scrollbar/bitmap_scroll_bar.h | 192 | ||||
-rw-r--r-- | views/controls/scrollbar/native_scroll_bar.cc | 357 | ||||
-rw-r--r-- | views/controls/scrollbar/native_scroll_bar.h | 67 | ||||
-rw-r--r-- | views/controls/scrollbar/scroll_bar.cc | 47 | ||||
-rw-r--r-- | views/controls/scrollbar/scroll_bar.h | 102 |
6 files changed, 1468 insertions, 0 deletions
diff --git a/views/controls/scrollbar/bitmap_scroll_bar.cc b/views/controls/scrollbar/bitmap_scroll_bar.cc new file mode 100644 index 0000000..4a93782 --- /dev/null +++ b/views/controls/scrollbar/bitmap_scroll_bar.cc @@ -0,0 +1,703 @@ +// Copyright (c) 2006-2008 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/bitmap_scroll_bar.h" + +#include "app/gfx/chrome_canvas.h" +#include "app/l10n_util.h" +#include "base/message_loop.h" +#include "grit/generated_resources.h" +#include "skia/include/SkBitmap.h" +#include "views/controls/menu/menu.h" +#include "views/controls/scroll_view.h" +#include "views/widget/widget.h" + +#undef min +#undef max + +namespace views { + +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; + +/////////////////////////////////////////////////////////////////////////////// +// +// AutorepeatButton +// +// 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 AutorepeatButton : public ImageButton { + public: + AutorepeatButton(ButtonListener* listener) + : ImageButton(listener), + repeater_(NewCallback<AutorepeatButton>(this, + &AutorepeatButton::NotifyClick)) { + } + virtual ~AutorepeatButton() {} + + protected: + virtual bool OnMousePressed(const MouseEvent& event) { + Button::NotifyClick(event.GetFlags()); + repeater_.Start(); + return true; + } + + virtual void OnMouseReleased(const MouseEvent& event, bool canceled) { + repeater_.Stop(); + View::OnMouseReleased(event, canceled); + } + + private: + void NotifyClick() { + Button::NotifyClick(0); + } + + // The repeat controller that we use to repeatedly click the button when the + // mouse button is down. + RepeatController repeater_; + + DISALLOW_EVIL_CONSTRUCTORS(AutorepeatButton); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// BitmapScrollBarThumb +// +// 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 BitmapScrollBarThumb : public View { + public: + explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar) + : scroll_bar_(scroll_bar), + drag_start_position_(-1), + mouse_offset_(-1), + state_(CustomButton::BS_NORMAL) { + } + 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, + static_cast<int>(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); + } + SetBounds(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_x(track_bounds.y() + position); + } + SetBounds(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() { + return gfx::Size(background_bitmap()->width(), + start_cap_bitmap()->height() + + end_cap_bitmap()->height() + + grippy_bitmap()->height()); + } + + protected: + // View overrides: + virtual void Paint(ChromeCanvas* canvas) { + canvas->DrawBitmapInt(*start_cap_bitmap(), 0, 0); + int top_cap_height = start_cap_bitmap()->height(); + int bottom_cap_height = end_cap_bitmap()->height(); + int thumb_body_height = height() - top_cap_height - bottom_cap_height; + canvas->TileImageInt(*background_bitmap(), 0, top_cap_height, + background_bitmap()->width(), thumb_body_height); + canvas->DrawBitmapInt(*end_cap_bitmap(), 0, + height() - bottom_cap_height); + + // Paint the grippy over the track. + int grippy_x = (width() - grippy_bitmap()->width()) / 2; + int grippy_y = (thumb_body_height - grippy_bitmap()->height()) / 2; + canvas->DrawBitmapInt(*grippy_bitmap(), grippy_x, grippy_y); + } + + virtual void OnMouseEntered(const MouseEvent& event) { + SetState(CustomButton::BS_HOT); + } + + virtual void OnMouseExited(const MouseEvent& event) { + SetState(CustomButton::BS_NORMAL); + } + + virtual bool OnMousePressed(const MouseEvent& event) { + 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) { + // 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, + bool canceled) { + SetState(CustomButton::BS_HOT); + View::OnMouseReleased(event, canceled); + } + + 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_]; + } + + // Returns the bitmap rendered at the end of the thumb. + SkBitmap* end_cap_bitmap() const { + return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][state_]; + } + + // 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_]; + } + + // Returns the bitmap that is rendered in the middle of the thumb + // transparently over the background bitmap. + SkBitmap* grippy_bitmap() const { + return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY] + [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_EVIL_CONSTRUCTORS(BitmapScrollBarThumb); +}; + +} // anonymous namespace + +/////////////////////////////////////////////////////////////////////////////// +// BitmapScrollBar, public: + +BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons) + : contents_size_(0), + contents_scroll_offset_(0), + prev_button_(new AutorepeatButton(this)), + next_button_(new AutorepeatButton(this)), + thumb_(new BitmapScrollBarThumb(this)), + thumb_track_state_(CustomButton::BS_NORMAL), + last_scroll_amount_(SCROLL_NONE), + repeater_(NewCallback<BitmapScrollBar>(this, + &BitmapScrollBar::TrackClicked)), + context_menu_mouse_position_(0), + show_scroll_buttons_(show_scroll_buttons), + ScrollBar(horizontal) { + if (!show_scroll_buttons_) { + prev_button_->SetVisible(false); + next_button_->SetVisible(false); + } + + AddChildView(prev_button_); + AddChildView(next_button_); + AddChildView(thumb_); + + SetContextMenuController(this); + prev_button_->SetContextMenuController(this); + next_button_->SetContextMenuController(this); + thumb_->SetContextMenuController(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, static_cast<int>(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, + CustomButton::ButtonState state, + SkBitmap* bitmap) { + DCHECK(part < PART_COUNT); + DCHECK(state < CustomButton::BS_COUNT); + switch (part) { + case PREV_BUTTON: + prev_button_->SetImage(state, bitmap); + break; + case NEXT_BUTTON: + next_button_->SetImage(state, bitmap); + break; + case THUMB_START_CAP: + case THUMB_MIDDLE: + case THUMB_END_CAP: + case THUMB_GRIPPY: + case THUMB_TRACK: + images_[part][state] = bitmap; + break; + } +} + +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(); +} + +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(); + } + ScrollContentsToOffset(); +} + +void BitmapScrollBar::TrackClicked() { + if (last_scroll_amount_ != SCROLL_NONE) + ScrollByAmount(last_scroll_amount_); +} + +/////////////////////////////////////////////////////////////////////////////// +// BitmapScrollBar, View implementation: + +gfx::Size BitmapScrollBar::GetPreferredSize() { + // In this case, we're returning the desired width of the scrollbar and its + // minimum allowable height. + gfx::Size button_prefsize = prev_button_->GetPreferredSize(); + return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2); +} + +void BitmapScrollBar::Paint(ChromeCanvas* 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()); +} + +void BitmapScrollBar::Layout() { + // Size and place the two scroll buttons. + if (show_scroll_buttons_) { + gfx::Size prefsize = prev_button_->GetPreferredSize(); + prev_button_->SetBounds(0, 0, prefsize.width(), prefsize.height()); + prefsize = next_button_->GetPreferredSize(); + if (IsHorizontal()) { + next_button_->SetBounds(width() - prefsize.width(), 0, prefsize.width(), + prefsize.height()); + } else { + next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(), + prefsize.height()); + } + } else { + prev_button_->SetBounds(0, 0, 0, 0); + next_button_->SetBounds(0, 0, 0, 0); + } + + // Size and place the thumb + 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_prefsize.height()); + } else { + 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 + // thumb. The user can only use the mousewheel, scroll buttons or keyboard + // 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); + } +} + +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, bool canceled) { + SetThumbTrackState(CustomButton::BS_NORMAL); + repeater_.Stop(); + View::OnMouseReleased(event, canceled); +} + +bool BitmapScrollBar::OnMouseWheel(const MouseWheelEvent& event) { + ScrollByContentsOffset(event.GetOffset()); + return true; +} + +bool BitmapScrollBar::OnKeyPressed(const KeyEvent& event) { + ScrollAmount amount = SCROLL_NONE; + switch(event.GetCharacter()) { + case VK_UP: + if (!IsHorizontal()) + amount = SCROLL_PREV_LINE; + break; + case VK_DOWN: + if (!IsHorizontal()) + amount = SCROLL_NEXT_LINE; + break; + case VK_LEFT: + if (IsHorizontal()) + amount = SCROLL_PREV_LINE; + break; + case VK_RIGHT: + if (IsHorizontal()) + amount = SCROLL_NEXT_LINE; + break; + case VK_PRIOR: + amount = SCROLL_PREV_PAGE; + break; + case VK_NEXT: + amount = SCROLL_NEXT_PAGE; + break; + case VK_HOME: + amount = SCROLL_START; + break; + case VK_END: + amount = SCROLL_END; + break; + } + if (amount != SCROLL_NONE) { + ScrollByAmount(amount); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// BitmapScrollBar, ContextMenuController implementation: + +enum ScrollBarContextMenuCommands { + ScrollBarContextMenuCommand_ScrollHere = 1, + ScrollBarContextMenuCommand_ScrollStart, + ScrollBarContextMenuCommand_ScrollEnd, + ScrollBarContextMenuCommand_ScrollPageUp, + ScrollBarContextMenuCommand_ScrollPageDown, + ScrollBarContextMenuCommand_ScrollPrev, + ScrollBarContextMenuCommand_ScrollNext +}; + +void BitmapScrollBar::ShowContextMenu(View* source, + int x, + int y, + bool is_mouse_gesture) { + Widget* widget = GetWidget(); + gfx::Rect widget_bounds; + widget->GetBounds(&widget_bounds, true); + gfx::Point temp_pt(x - widget_bounds.x(), y - widget_bounds.y()); + View::ConvertPointFromWidget(this, &temp_pt); + context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y(); + + Menu menu(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(x, y); +} + +/////////////////////////////////////////////////////////////////////////////// +// BitmapScrollBar, Menu::Delegate implementation: + +std::wstring BitmapScrollBar::GetLabel(int id) const { + switch (id) { + case ScrollBarContextMenuCommand_ScrollHere: + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLHERE); + case ScrollBarContextMenuCommand_ScrollStart: + if (IsHorizontal()) + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLLEFTEDGE); + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLHOME); + case ScrollBarContextMenuCommand_ScrollEnd: + if (IsHorizontal()) + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE); + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLEND); + case ScrollBarContextMenuCommand_ScrollPageUp: + if (IsHorizontal()) + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEUP); + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEUP); + case ScrollBarContextMenuCommand_ScrollPageDown: + if (IsHorizontal()) + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEDOWN); + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEDOWN); + case ScrollBarContextMenuCommand_ScrollPrev: + if (IsHorizontal()) + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLLEFT); + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLUP); + case ScrollBarContextMenuCommand_ScrollNext: + if (IsHorizontal()) + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLRIGHT); + return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLDOWN); + } + NOTREACHED() << "Invalid BitmapScrollBar Context Menu command!"; + return L""; +} + +bool BitmapScrollBar::IsCommandEnabled(int id) const { + switch (id) { + case ScrollBarContextMenuCommand_ScrollPageUp: + case ScrollBarContextMenuCommand_ScrollPageDown: + return !IsHorizontal(); + } + return true; +} + +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; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// BitmapScrollBar, ButtonListener implementation: + +void BitmapScrollBar::ButtonPressed(Button* sender) { + if (sender == prev_button_) { + ScrollByAmount(SCROLL_PREV_LINE); + } else if (sender == next_button_) { + ScrollByAmount(SCROLL_NEXT_LINE); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// 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, private: + +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 new file mode 100644 index 0000000..45e3535 --- /dev/null +++ b/views/controls/scrollbar/bitmap_scroll_bar.h @@ -0,0 +1,192 @@ +// Copyright (c) 2006-2008 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_BITMAP_SCROLL_BAR_H_ +#define VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_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 { + +namespace { +class BitmapScrollBarThumb; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// BitmapScrollBar +// +// A ScrollBar subclass that implements a scroll bar rendered using bitmaps +// that the user provides. There are bitmaps for the up and down buttons, as +// 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 { + 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. + PREV_BUTTON = 0, + // The button used to represent scrolling down/right by 1 line. + // IMPORTANT: The code assumes the prev and next + // buttons have equal width and equal height. + NEXT_BUTTON, + // The top/left segment of the thumb on the scrollbar. + THUMB_START_CAP, + // The tiled background image of the thumb. + THUMB_MIDDLE, + // The bottom/right segment of the thumb on the scrollbar. + THUMB_END_CAP, + // The grippy that is rendered in the center of the thumb. + THUMB_GRIPPY, + // The tiled background image of the thumb track. + THUMB_TRACK, + PART_COUNT + }; + + // Sets the bitmap to be rendered for the specified part and state. + void SetImage(ScrollBarPart part, + 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); + + // View overrides: + virtual gfx::Size GetPreferredSize(); + virtual void Paint(ChromeCanvas* canvas); + virtual void Layout(); + virtual bool OnMousePressed(const MouseEvent& event); + virtual void OnMouseReleased(const MouseEvent& event, bool canceled); + virtual bool OnMouseWheel(const MouseWheelEvent& event); + virtual bool OnKeyPressed(const KeyEvent& event); + + // BaseButton::ButtonListener overrides: + virtual void ButtonPressed(Button* sender); + + // ScrollBar overrides: + virtual void Update(int viewport_size, + int content_size, + int contents_scroll_offset); + virtual int GetLayoutSize() const; + virtual int GetPosition() const; + + // ContextMenuController overrides. + virtual void ShowContextMenu(View* source, + int x, + int y, + bool is_mouse_gesture); + + // Menu::Delegate overrides: + virtual std::wstring GetLabel(int id) const; + virtual bool IsCommandEnabled(int id) const; + virtual void ExecuteCommand(int id); + + 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); + + // 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_; + + DISALLOW_EVIL_CONSTRUCTORS(BitmapScrollBar); +}; + +} // namespace views + +#endif // #ifndef VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_ diff --git a/views/controls/scrollbar/native_scroll_bar.cc b/views/controls/scrollbar/native_scroll_bar.cc new file mode 100644 index 0000000..52ddd91 --- /dev/null +++ b/views/controls/scrollbar/native_scroll_bar.cc @@ -0,0 +1,357 @@ +// Copyright (c) 2006-2008 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.h" + +#include <atlbase.h> +#include <atlapp.h> +#include <atlwin.h> +#include <atlcrack.h> +#include <atlframe.h> +#include <atlmisc.h> +#include <string> + +#include "base/message_loop.h" +#include "views/controls/hwnd_view.h" +#include "views/widget/widget.h" + +namespace views { + +///////////////////////////////////////////////////////////////////////////// +// +// ScrollBarContainer +// +// Since windows scrollbar only send notifications to their parent hwnd, we +// use instance of this class to wrap native scrollbars. +// +///////////////////////////////////////////////////////////////////////////// +class ScrollBarContainer : public CWindowImpl<ScrollBarContainer, + CWindow, + CWinTraits<WS_CHILD>> { + public: + ScrollBarContainer(ScrollBar* parent) : parent_(parent), + scrollbar_(NULL) { + Create(parent->GetWidget()->GetNativeView()); + ::ShowWindow(m_hWnd, SW_SHOW); + } + + virtual ~ScrollBarContainer() { + } + + DECLARE_FRAME_WND_CLASS(L"ChromeViewsScrollBarContainer", NULL); + BEGIN_MSG_MAP(ScrollBarContainer); + MSG_WM_CREATE(OnCreate); + MSG_WM_ERASEBKGND(OnEraseBkgnd); + MSG_WM_PAINT(OnPaint); + MSG_WM_SIZE(OnSize); + MSG_WM_HSCROLL(OnHorizScroll); + MSG_WM_VSCROLL(OnVertScroll); + END_MSG_MAP(); + + HWND GetScrollBarHWND() { + return scrollbar_; + } + + // Invoked when the scrollwheel is used + void ScrollWithOffset(int o) { + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + ::GetScrollInfo(scrollbar_, SB_CTL, &si); + int pos = si.nPos - o; + + if (pos < parent_->GetMinPosition()) + pos = parent_->GetMinPosition(); + else if (pos > parent_->GetMaxPosition()) + pos = parent_->GetMaxPosition(); + + ScrollBarController* sbc = parent_->GetController(); + sbc->ScrollToPosition(parent_, pos); + + si.nPos = pos; + si.fMask = SIF_POS; + ::SetScrollInfo(scrollbar_, SB_CTL, &si, TRUE); + } + + private: + + LRESULT OnCreate(LPCREATESTRUCT create_struct) { + scrollbar_ = CreateWindow(L"SCROLLBAR", + L"", + WS_CHILD | (parent_->IsHorizontal() ? + SBS_HORZ : SBS_VERT), + 0, + 0, + parent_->width(), + parent_->height(), + m_hWnd, + NULL, + NULL, + NULL); + ::ShowWindow(scrollbar_, SW_SHOW); + return 1; + } + + LRESULT OnEraseBkgnd(HDC dc) { + return 1; + } + + void OnPaint(HDC ignore) { + PAINTSTRUCT ps; + HDC dc = ::BeginPaint(*this, &ps); + ::EndPaint(*this, &ps); + } + + void OnSize(int type, const CSize& sz) { + ::SetWindowPos(scrollbar_, + 0, + 0, + 0, + sz.cx, + sz.cy, + SWP_DEFERERASE | + SWP_NOACTIVATE | + SWP_NOCOPYBITS | + SWP_NOOWNERZORDER | + SWP_NOSENDCHANGING | + SWP_NOZORDER); + } + + void OnScroll(int code, HWND source, bool is_horizontal) { + int pos; + + if (code == SB_ENDSCROLL) { + return; + } + + // If we receive an event from the scrollbar, make the view + // component focused so we actually get mousewheel events. + if (source != NULL) { + Widget* widget = parent_->GetWidget(); + if (widget && widget->GetNativeView() != GetFocus()) { + parent_->RequestFocus(); + } + } + + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_POS | SIF_TRACKPOS; + ::GetScrollInfo(scrollbar_, SB_CTL, &si); + pos = si.nPos; + + ScrollBarController* sbc = parent_->GetController(); + + switch (code) { + case SB_BOTTOM: // case SB_RIGHT: + pos = parent_->GetMaxPosition(); + break; + case SB_TOP: // case SB_LEFT: + pos = parent_->GetMinPosition(); + break; + case SB_LINEDOWN: // case SB_LINERIGHT: + pos += sbc->GetScrollIncrement(parent_, false, true); + pos = std::min(parent_->GetMaxPosition(), pos); + break; + case SB_LINEUP: // case SB_LINELEFT: + pos -= sbc->GetScrollIncrement(parent_, false, false); + pos = std::max(parent_->GetMinPosition(), pos); + break; + case SB_PAGEDOWN: // case SB_PAGERIGHT: + pos += sbc->GetScrollIncrement(parent_, true, true); + pos = std::min(parent_->GetMaxPosition(), pos); + break; + case SB_PAGEUP: // case SB_PAGELEFT: + pos -= sbc->GetScrollIncrement(parent_, true, false); + pos = std::max(parent_->GetMinPosition(), pos); + break; + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + pos = si.nTrackPos; + if (pos < parent_->GetMinPosition()) + pos = parent_->GetMinPosition(); + else if (pos > parent_->GetMaxPosition()) + pos = parent_->GetMaxPosition(); + break; + default: + break; + } + + sbc->ScrollToPosition(parent_, pos); + + si.nPos = pos; + si.fMask = SIF_POS; + ::SetScrollInfo(scrollbar_, SB_CTL, &si, TRUE); + + // Note: the system scrollbar modal loop doesn't give a chance + // to our message_loop so we need to call DidProcessMessage() + // manually. + // + // Sadly, we don't know what message has been processed. We may + // want to remove the message from DidProcessMessage() + MSG dummy; + dummy.hwnd = NULL; + dummy.message = 0; + MessageLoopForUI::current()->DidProcessMessage(dummy); + } + + // note: always ignore 2nd param as it is 16 bits + void OnHorizScroll(int n_sb_code, int ignore, HWND source) { + OnScroll(n_sb_code, source, true); + } + + // note: always ignore 2nd param as it is 16 bits + void OnVertScroll(int n_sb_code, int ignore, HWND source) { + OnScroll(n_sb_code, source, false); + } + + + + ScrollBar* parent_; + HWND scrollbar_; +}; + +NativeScrollBar::NativeScrollBar(bool is_horiz) + : sb_view_(NULL), + sb_container_(NULL), + ScrollBar(is_horiz) { +} + +NativeScrollBar::~NativeScrollBar() { + if (sb_container_) { + // We always destroy the scrollbar container explicitly to cover all + // cases including when the container is no longer connected to a + // widget tree. + ::DestroyWindow(*sb_container_); + delete sb_container_; + } +} + +void NativeScrollBar::ViewHierarchyChanged(bool is_add, View *parent, + View *child) { + Widget* widget; + if (is_add && (widget = GetWidget()) && !sb_view_) { + sb_view_ = new HWNDView(); + AddChildView(sb_view_); + sb_container_ = new ScrollBarContainer(this); + sb_view_->Attach(*sb_container_); + Layout(); + } +} + +void NativeScrollBar::Layout() { + if (sb_view_) + sb_view_->SetBounds(GetLocalBounds(true)); +} + +gfx::Size NativeScrollBar::GetPreferredSize() { + if (IsHorizontal()) + return gfx::Size(0, GetLayoutSize()); + return gfx::Size(GetLayoutSize(), 0); +} + +void NativeScrollBar::Update(int viewport_size, + int content_size, + int current_pos) { + ScrollBar::Update(viewport_size, content_size, current_pos); + if (!sb_container_) + return; + + if (content_size < 0) + content_size = 0; + + if (current_pos < 0) + current_pos = 0; + + if (current_pos > content_size) + current_pos = content_size; + + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_DISABLENOSCROLL | SIF_POS | SIF_RANGE | SIF_PAGE; + si.nMin = 0; + si.nMax = content_size; + si.nPos = current_pos; + si.nPage = viewport_size; + ::SetScrollInfo(sb_container_->GetScrollBarHWND(), + SB_CTL, + &si, + TRUE); +} + +int NativeScrollBar::GetLayoutSize() const { + return ::GetSystemMetrics(IsHorizontal() ? SM_CYHSCROLL : SM_CYVSCROLL); +} + +int NativeScrollBar::GetPosition() const { + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + GetScrollInfo(sb_container_->GetScrollBarHWND(), SB_CTL, &si); + return si.nPos; +} + +bool NativeScrollBar::OnMouseWheel(const MouseWheelEvent& e) { + if (!sb_container_) { + return false; + } + + sb_container_->ScrollWithOffset(e.GetOffset()); + return true; +} + +bool NativeScrollBar::OnKeyPressed(const KeyEvent& event) { + if (!sb_container_) { + return false; + } + int code = -1; + switch(event.GetCharacter()) { + case VK_UP: + if (!IsHorizontal()) + code = SB_LINEUP; + break; + case VK_PRIOR: + code = SB_PAGEUP; + break; + case VK_NEXT: + code = SB_PAGEDOWN; + break; + case VK_DOWN: + if (!IsHorizontal()) + code = SB_LINEDOWN; + break; + case VK_HOME: + code = SB_TOP; + break; + case VK_END: + code = SB_BOTTOM; + break; + case VK_LEFT: + if (IsHorizontal()) + code = SB_LINELEFT; + break; + case VK_RIGHT: + if (IsHorizontal()) + code = SB_LINERIGHT; + break; + } + if (code != -1) { + ::SendMessage(*sb_container_, + IsHorizontal() ? WM_HSCROLL : WM_VSCROLL, + MAKELONG(static_cast<WORD>(code), 0), 0L); + return true; + } + return false; +} + +//static +int NativeScrollBar::GetHorizontalScrollBarHeight() { + return ::GetSystemMetrics(SM_CYHSCROLL); +} + +//static +int NativeScrollBar::GetVerticalScrollBarWidth() { + return ::GetSystemMetrics(SM_CXVSCROLL); +} + +} // namespace views diff --git a/views/controls/scrollbar/native_scroll_bar.h b/views/controls/scrollbar/native_scroll_bar.h new file mode 100644 index 0000000..2747bce --- /dev/null +++ b/views/controls/scrollbar/native_scroll_bar.h @@ -0,0 +1,67 @@ +// Copyright (c) 2006-2008 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_SCROLLBAR_H_ +#define VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLLBAR_H_ + +#include "build/build_config.h" + +#include "views/controls/scrollbar/scroll_bar.h" + +namespace views { + +class HWNDView; +class ScrollBarContainer; + +///////////////////////////////////////////////////////////////////////////// +// +// NativeScrollBar +// +// A View subclass that wraps a Native Windows scrollbar control. +// +// A scrollbar is either horizontal or vertical. +// +///////////////////////////////////////////////////////////////////////////// +class NativeScrollBar : public ScrollBar { + public: + + // Create new scrollbar, either horizontal or vertical + explicit NativeScrollBar(bool is_horiz); + virtual ~NativeScrollBar(); + + // Overridden for layout purpose + virtual void Layout(); + virtual gfx::Size GetPreferredSize(); + + // Overridden for keyboard UI purpose + virtual bool OnKeyPressed(const KeyEvent& event); + virtual bool OnMouseWheel(const MouseWheelEvent& e); + + virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); + + // Overridden from ScrollBar + virtual void Update(int viewport_size, int content_size, int current_pos); + virtual int GetLayoutSize() const; + virtual int GetPosition() const; + + // Return the system sizes + static int GetHorizontalScrollBarHeight(); + static int GetVerticalScrollBarWidth(); + + private: +#if defined(OS_WIN) + // The sb_view_ takes care of keeping sb_container in sync with the + // view hierarchy + HWNDView* sb_view_; +#endif // defined(OS_WIN) + + // sb_container_ is a custom hwnd that we use to wrap the real + // windows scrollbar. We need to do this to get the scroll events + // without having to do anything special in the high level hwnd. + ScrollBarContainer* sb_container_; +}; + +} // namespace views + +#endif // #ifndef VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLLBAR_H_ diff --git a/views/controls/scrollbar/scroll_bar.cc b/views/controls/scrollbar/scroll_bar.cc new file mode 100644 index 0000000..a475c44 --- /dev/null +++ b/views/controls/scrollbar/scroll_bar.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2006-2008 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" + +namespace views { + +///////////////////////////////////////////////////////////////////////////// +// +// ScrollBar implementation +// +///////////////////////////////////////////////////////////////////////////// + +ScrollBar::ScrollBar(bool is_horiz) : is_horiz_(is_horiz), + controller_(NULL), + max_pos_(0) { +} + +ScrollBar::~ScrollBar() { +} + +bool ScrollBar::IsHorizontal() const { + return is_horiz_; +} + +void ScrollBar::SetController(ScrollBarController* controller) { + controller_ = controller; +} + +ScrollBarController* ScrollBar::GetController() const { + return controller_; +} + +void ScrollBar::Update(int viewport_size, int content_size, int current_pos) { + max_pos_ = std::max(0, content_size - viewport_size); +} + +int ScrollBar::GetMaxPosition() const { + return max_pos_; +} + +int ScrollBar::GetMinPosition() const { + return 0; +} + +} // namespace views diff --git a/views/controls/scrollbar/scroll_bar.h b/views/controls/scrollbar/scroll_bar.h new file mode 100644 index 0000000..36a9d2e --- /dev/null +++ b/views/controls/scrollbar/scroll_bar.h @@ -0,0 +1,102 @@ +// Copyright (c) 2006-2008 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_SCROLLBAR_H_ +#define VIEWS_CONTROLS_SCROLLBAR_SCROLLBAR_H_ + +#include "views/view.h" +#include "views/event.h" + +namespace views { + +class ScrollBar; + +///////////////////////////////////////////////////////////////////////////// +// +// ScrollBarController +// +// ScrollBarController defines the method that should be implemented to +// receive notification from a scrollbar +// +///////////////////////////////////////////////////////////////////////////// +class ScrollBarController { + public: + + // Invoked by the scrollbar when the scrolling position changes + // This method typically implements the actual scrolling. + // + // The provided position is expressed in pixels. It is the new X or Y + // position which is in the GetMinPosition() / GetMaxPosition range. + virtual void ScrollToPosition(ScrollBar* source, int position) = 0; + + // Returns the amount to scroll. The amount to scroll may be requested in + // two different amounts. If is_page is true the 'page scroll' amount is + // requested. The page scroll amount typically corresponds to the + // visual size of the view. If is_page is false, the 'line scroll' amount + // is being requested. The line scroll amount typically corresponds to the + // size of one row/column. + // + // The return value should always be positive. A value <= 0 results in + // scrolling by a fixed amount. + virtual int GetScrollIncrement(ScrollBar* source, + bool is_page, + bool is_positive) = 0; +}; + +///////////////////////////////////////////////////////////////////////////// +// +// ScrollBar +// +// A View subclass to wrap to implement a ScrollBar. Our current windows +// version simply wraps a native windows scrollbar. +// +// A scrollbar is either horizontal or vertical +// +///////////////////////////////////////////////////////////////////////////// +class ScrollBar : public View { + public: + virtual ~ScrollBar(); + + // Return whether this scrollbar is horizontal + bool IsHorizontal() const; + + // Set / Get the controller + void SetController(ScrollBarController* controller); + ScrollBarController* GetController() const; + + // Update the scrollbar appearance given a viewport size, content size and + // current position + virtual void Update(int viewport_size, int content_size, int current_pos); + + // Return the max and min positions + int GetMaxPosition() const; + int GetMinPosition() const; + + // Returns the position of the scrollbar. + virtual int GetPosition() const = 0; + + // Get the width or height of this scrollbar, for use in layout calculations. + // For a vertical scrollbar, this is the width of the scrollbar, likewise it + // is the height for a horizontal scrollbar. + virtual int GetLayoutSize() const = 0; + + protected: + // Create new scrollbar, either horizontal or vertical. These are protected + // since you need to be creating either a NativeScrollBar or a + // BitmapScrollBar. + ScrollBar(bool is_horiz); + + private: + const bool is_horiz_; + + // Current controller + ScrollBarController* controller_; + + // properties + int max_pos_; +}; + +} // namespace views + +#endif // #ifndef VIEWS_CONTROLS_SCROLLBAR_SCROLLBAR_H_ |