| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "views/controls/scrollbar/bitmap_scroll_bar.h" | 5 #include "views/controls/scrollbar/bitmap_scroll_bar.h" |
| 6 | 6 |
| 7 #if defined(OS_LINUX) | 7 #if defined(OS_LINUX) |
| 8 #include "views/screen.h" | 8 #include "views/screen.h" |
| 9 #endif | 9 #endif |
| 10 | 10 |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
| 14 #include "base/string16.h" | 14 #include "base/string16.h" |
| 15 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 16 #include "grit/ui_strings.h" | 16 #include "grit/ui_strings.h" |
| 17 #include "third_party/skia/include/core/SkBitmap.h" | 17 #include "third_party/skia/include/core/SkBitmap.h" |
| 18 #include "ui/base/keycodes/keyboard_codes.h" | 18 #include "ui/base/keycodes/keyboard_codes.h" |
| 19 #include "ui/base/l10n/l10n_util.h" | 19 #include "ui/base/l10n/l10n_util.h" |
| 20 #include "ui/gfx/canvas.h" | 20 #include "ui/gfx/canvas.h" |
| 21 #include "views/controls/menu/menu.h" | 21 #include "views/controls/menu/menu.h" |
| 22 #include "views/controls/scrollbar/base_scroll_bar_thumb.h" |
| 22 #include "views/controls/scroll_view.h" | 23 #include "views/controls/scroll_view.h" |
| 23 #include "views/widget/widget.h" | 24 #include "views/widget/widget.h" |
| 24 | 25 |
| 25 #undef min | 26 #undef min |
| 26 #undef max | 27 #undef max |
| 27 | 28 |
| 28 namespace views { | 29 namespace views { |
| 29 | 30 |
| 30 namespace { | 31 namespace { |
| 31 | 32 |
| 32 // The distance the mouse can be dragged outside the bounds of the thumb during | 33 // The distance the mouse can be dragged outside the bounds of the thumb during |
| 33 // dragging before the scrollbar will snap back to its regular position. | 34 // dragging before the scrollbar will snap back to its regular position. |
| 34 static const int kScrollThumbDragOutSnap = 100; | 35 static const int kScrollThumbDragOutSnap = 100; |
| 35 | 36 |
| 36 /////////////////////////////////////////////////////////////////////////////// | 37 /////////////////////////////////////////////////////////////////////////////// |
| 37 // | 38 // |
| 38 // AutorepeatButton | 39 // AutorepeatButton |
| 39 // | 40 // |
| 40 // A button that activates on mouse pressed rather than released, and that | 41 // A button that activates on mouse pressed rather than released, and that |
| 41 // continues to fire the clicked action as the mouse button remains pressed | 42 // continues to fire the clicked action as the mouse button remains pressed |
| 42 // down on the button. | 43 // down on the button. |
| 43 // | 44 // |
| 44 /////////////////////////////////////////////////////////////////////////////// | 45 /////////////////////////////////////////////////////////////////////////////// |
| 45 class AutorepeatButton : public ImageButton { | 46 class AutorepeatButton : public ImageButton { |
| 46 public: | 47 public: |
| 47 AutorepeatButton(ButtonListener* listener) | 48 explicit AutorepeatButton(ButtonListener* listener) |
| 48 : ImageButton(listener), | 49 : ImageButton(listener), |
| 49 ALLOW_THIS_IN_INITIALIZER_LIST(repeater_( | 50 ALLOW_THIS_IN_INITIALIZER_LIST(repeater_( |
| 50 NewCallback<AutorepeatButton>(this, | 51 NewCallback<AutorepeatButton>(this, |
| 51 &AutorepeatButton::NotifyClick))) { | 52 &AutorepeatButton::NotifyClick))) { |
| 52 } | 53 } |
| 53 virtual ~AutorepeatButton() {} | 54 virtual ~AutorepeatButton() {} |
| 54 | 55 |
| 55 protected: | 56 protected: |
| 56 virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE { | 57 virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE { |
| 57 Button::NotifyClick(event); | 58 Button::NotifyClick(event); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 }; | 91 }; |
| 91 | 92 |
| 92 /////////////////////////////////////////////////////////////////////////////// | 93 /////////////////////////////////////////////////////////////////////////////// |
| 93 // | 94 // |
| 94 // BitmapScrollBarThumb | 95 // BitmapScrollBarThumb |
| 95 // | 96 // |
| 96 // A view that acts as the thumb in the scroll bar track that the user can | 97 // A view that acts as the thumb in the scroll bar track that the user can |
| 97 // drag to scroll the associated contents view within the viewport. | 98 // drag to scroll the associated contents view within the viewport. |
| 98 // | 99 // |
| 99 /////////////////////////////////////////////////////////////////////////////// | 100 /////////////////////////////////////////////////////////////////////////////// |
| 100 class BitmapScrollBarThumb : public View { | 101 class BitmapScrollBarThumb : public BaseScrollBarThumb { |
| 101 public: | 102 public: |
| 102 explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar) | 103 explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar) |
| 103 : scroll_bar_(scroll_bar), | 104 : BaseScrollBarThumb(scroll_bar), |
| 104 drag_start_position_(-1), | 105 scroll_bar_(scroll_bar) { |
| 105 mouse_offset_(-1), | |
| 106 state_(CustomButton::BS_NORMAL) { | |
| 107 } | 106 } |
| 108 virtual ~BitmapScrollBarThumb() { } | 107 virtual ~BitmapScrollBarThumb() { } |
| 109 | 108 |
| 110 // Sets the size (width or height) of the thumb to the specified value. | |
| 111 void SetSize(int size) { | |
| 112 // Make sure the thumb is never sized smaller than its minimum possible | |
| 113 // display size. | |
| 114 gfx::Size prefsize = GetPreferredSize(); | |
| 115 size = std::max(size, scroll_bar_->IsHorizontal() ? prefsize.width() : | |
| 116 prefsize.height()); | |
| 117 gfx::Rect thumb_bounds = bounds(); | |
| 118 if (scroll_bar_->IsHorizontal()) { | |
| 119 thumb_bounds.set_width(size); | |
| 120 } else { | |
| 121 thumb_bounds.set_height(size); | |
| 122 } | |
| 123 SetBoundsRect(thumb_bounds); | |
| 124 } | |
| 125 | |
| 126 // Retrieves the size (width or height) of the thumb. | |
| 127 int GetSize() const { | |
| 128 if (scroll_bar_->IsHorizontal()) | |
| 129 return width(); | |
| 130 return height(); | |
| 131 } | |
| 132 | |
| 133 // Sets the position of the thumb on the x or y axis. | |
| 134 void SetPosition(int position) { | |
| 135 gfx::Rect thumb_bounds = bounds(); | |
| 136 gfx::Rect track_bounds = scroll_bar_->GetTrackBounds(); | |
| 137 if (scroll_bar_->IsHorizontal()) { | |
| 138 thumb_bounds.set_x(track_bounds.x() + position); | |
| 139 } else { | |
| 140 thumb_bounds.set_y(track_bounds.y() + position); | |
| 141 } | |
| 142 SetBoundsRect(thumb_bounds); | |
| 143 } | |
| 144 | |
| 145 // Gets the position of the thumb on the x or y axis. | |
| 146 int GetPosition() const { | |
| 147 gfx::Rect track_bounds = scroll_bar_->GetTrackBounds(); | |
| 148 if (scroll_bar_->IsHorizontal()) | |
| 149 return x() - track_bounds.x(); | |
| 150 return y() - track_bounds.y(); | |
| 151 } | |
| 152 | |
| 153 // View overrides: | 109 // View overrides: |
| 154 virtual gfx::Size GetPreferredSize() OVERRIDE { | 110 virtual gfx::Size GetPreferredSize() OVERRIDE { |
| 155 return gfx::Size(background_bitmap()->width(), | 111 return gfx::Size(background_bitmap()->width(), |
| 156 start_cap_bitmap()->height() + | 112 start_cap_bitmap()->height() + |
| 157 end_cap_bitmap()->height() + | 113 end_cap_bitmap()->height() + |
| 158 grippy_bitmap()->height()); | 114 grippy_bitmap()->height()); |
| 159 } | 115 } |
| 160 | 116 |
| 161 protected: | 117 protected: |
| 162 // View overrides: | 118 // View overrides: |
| 163 virtual void Paint(gfx::Canvas* canvas) OVERRIDE { | 119 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { |
| 164 canvas->DrawBitmapInt(*start_cap_bitmap(), 0, 0); | 120 canvas->DrawBitmapInt(*start_cap_bitmap(), 0, 0); |
| 165 int top_cap_height = start_cap_bitmap()->height(); | 121 int top_cap_height = start_cap_bitmap()->height(); |
| 166 int bottom_cap_height = end_cap_bitmap()->height(); | 122 int bottom_cap_height = end_cap_bitmap()->height(); |
| 167 int thumb_body_height = height() - top_cap_height - bottom_cap_height; | 123 int thumb_body_height = height() - top_cap_height - bottom_cap_height; |
| 168 canvas->TileImageInt(*background_bitmap(), 0, top_cap_height, | 124 canvas->TileImageInt(*background_bitmap(), 0, top_cap_height, |
| 169 background_bitmap()->width(), thumb_body_height); | 125 background_bitmap()->width(), thumb_body_height); |
| 170 canvas->DrawBitmapInt(*end_cap_bitmap(), 0, | 126 canvas->DrawBitmapInt(*end_cap_bitmap(), 0, |
| 171 height() - bottom_cap_height); | 127 height() - bottom_cap_height); |
| 172 | 128 |
| 173 // Paint the grippy over the track. | 129 // Paint the grippy over the track. |
| 174 int grippy_x = (width() - grippy_bitmap()->width()) / 2; | 130 int grippy_x = (width() - grippy_bitmap()->width()) / 2; |
| 175 int grippy_y = (thumb_body_height - grippy_bitmap()->height()) / 2; | 131 int grippy_y = (thumb_body_height - grippy_bitmap()->height()) / 2; |
| 176 canvas->DrawBitmapInt(*grippy_bitmap(), grippy_x, grippy_y); | 132 canvas->DrawBitmapInt(*grippy_bitmap(), grippy_x, grippy_y); |
| 177 } | 133 } |
| 178 | 134 |
| 179 virtual void OnMouseEntered(const MouseEvent& event) OVERRIDE { | |
| 180 SetState(CustomButton::BS_HOT); | |
| 181 } | |
| 182 | |
| 183 virtual void OnMouseExited(const MouseEvent& event) OVERRIDE { | |
| 184 SetState(CustomButton::BS_NORMAL); | |
| 185 } | |
| 186 | |
| 187 virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE { | |
| 188 mouse_offset_ = scroll_bar_->IsHorizontal() ? event.x() : event.y(); | |
| 189 drag_start_position_ = GetPosition(); | |
| 190 SetState(CustomButton::BS_PUSHED); | |
| 191 return true; | |
| 192 } | |
| 193 | |
| 194 virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE { | |
| 195 // If the user moves the mouse more than |kScrollThumbDragOutSnap| outside | |
| 196 // the bounds of the thumb, the scrollbar will snap the scroll back to the | |
| 197 // point it was at before the drag began. | |
| 198 if (scroll_bar_->IsHorizontal()) { | |
| 199 if ((event.y() < y() - kScrollThumbDragOutSnap) || | |
| 200 (event.y() > (y() + height() + kScrollThumbDragOutSnap))) { | |
| 201 scroll_bar_->ScrollToThumbPosition(drag_start_position_, false); | |
| 202 return true; | |
| 203 } | |
| 204 } else { | |
| 205 if ((event.x() < x() - kScrollThumbDragOutSnap) || | |
| 206 (event.x() > (x() + width() + kScrollThumbDragOutSnap))) { | |
| 207 scroll_bar_->ScrollToThumbPosition(drag_start_position_, false); | |
| 208 return true; | |
| 209 } | |
| 210 } | |
| 211 if (scroll_bar_->IsHorizontal()) { | |
| 212 int thumb_x = event.x() - mouse_offset_; | |
| 213 scroll_bar_->ScrollToThumbPosition(x() + thumb_x, false); | |
| 214 } else { | |
| 215 int thumb_y = event.y() - mouse_offset_; | |
| 216 scroll_bar_->ScrollToThumbPosition(y() + thumb_y, false); | |
| 217 } | |
| 218 return true; | |
| 219 } | |
| 220 | |
| 221 virtual void OnMouseReleased(const MouseEvent& event) OVERRIDE { | |
| 222 OnMouseCaptureLost(); | |
| 223 } | |
| 224 | |
| 225 virtual void OnMouseCaptureLost() OVERRIDE { | |
| 226 SetState(CustomButton::BS_HOT); | |
| 227 } | |
| 228 | |
| 229 private: | 135 private: |
| 230 // Returns the bitmap rendered at the start of the thumb. | 136 // Returns the bitmap rendered at the start of the thumb. |
| 231 SkBitmap* start_cap_bitmap() const { | 137 SkBitmap* start_cap_bitmap() const { |
| 232 return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][state_]; | 138 return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][GetState()]; |
| 233 } | 139 } |
| 234 | 140 |
| 235 // Returns the bitmap rendered at the end of the thumb. | 141 // Returns the bitmap rendered at the end of the thumb. |
| 236 SkBitmap* end_cap_bitmap() const { | 142 SkBitmap* end_cap_bitmap() const { |
| 237 return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][state_]; | 143 return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][GetState()]; |
| 238 } | 144 } |
| 239 | 145 |
| 240 // Returns the bitmap that is tiled in the background of the thumb between | 146 // Returns the bitmap that is tiled in the background of the thumb between |
| 241 // the start and the end caps. | 147 // the start and the end caps. |
| 242 SkBitmap* background_bitmap() const { | 148 SkBitmap* background_bitmap() const { |
| 243 return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][state_]; | 149 return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][GetState()]; |
| 244 } | 150 } |
| 245 | 151 |
| 246 // Returns the bitmap that is rendered in the middle of the thumb | 152 // Returns the bitmap that is rendered in the middle of the thumb |
| 247 // transparently over the background bitmap. | 153 // transparently over the background bitmap. |
| 248 SkBitmap* grippy_bitmap() const { | 154 SkBitmap* grippy_bitmap() const { |
| 249 return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY] | 155 return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY] |
| 250 [CustomButton::BS_NORMAL]; | 156 [CustomButton::BS_NORMAL]; |
| 251 } | 157 } |
| 252 | 158 |
| 253 // Update our state and schedule a repaint when the mouse moves over us. | |
| 254 void SetState(CustomButton::ButtonState state) { | |
| 255 state_ = state; | |
| 256 SchedulePaint(); | |
| 257 } | |
| 258 | |
| 259 // The BitmapScrollBar that owns us. | 159 // The BitmapScrollBar that owns us. |
| 260 BitmapScrollBar* scroll_bar_; | 160 BitmapScrollBar* scroll_bar_; |
| 261 | 161 |
| 262 int drag_start_position_; | |
| 263 | |
| 264 // The position of the mouse on the scroll axis relative to the top of this | |
| 265 // View when the drag started. | |
| 266 int mouse_offset_; | |
| 267 | |
| 268 // The current state of the thumb button. | |
| 269 CustomButton::ButtonState state_; | |
| 270 | |
| 271 DISALLOW_COPY_AND_ASSIGN(BitmapScrollBarThumb); | 162 DISALLOW_COPY_AND_ASSIGN(BitmapScrollBarThumb); |
| 272 }; | 163 }; |
| 273 | 164 |
| 274 } // anonymous namespace | 165 } // anonymous namespace |
| 275 | 166 |
| 276 /////////////////////////////////////////////////////////////////////////////// | 167 /////////////////////////////////////////////////////////////////////////////// |
| 277 // BitmapScrollBar, public: | 168 // BitmapScrollBar, public: |
| 278 | 169 |
| 279 BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons) | 170 BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons) |
| 280 : contents_size_(0), | 171 : BaseScrollBar(horizontal, new BitmapScrollBarThumb(this)), |
| 281 contents_scroll_offset_(0), | |
| 282 ALLOW_THIS_IN_INITIALIZER_LIST(prev_button_(new AutorepeatButton(this))), | 172 ALLOW_THIS_IN_INITIALIZER_LIST(prev_button_(new AutorepeatButton(this))), |
| 283 ALLOW_THIS_IN_INITIALIZER_LIST(next_button_(new AutorepeatButton(this))), | 173 ALLOW_THIS_IN_INITIALIZER_LIST(next_button_(new AutorepeatButton(this))), |
| 284 ALLOW_THIS_IN_INITIALIZER_LIST(thumb_(new BitmapScrollBarThumb(this))), | 174 show_scroll_buttons_(show_scroll_buttons) { |
| 285 thumb_track_state_(CustomButton::BS_NORMAL), | |
| 286 last_scroll_amount_(SCROLL_NONE), | |
| 287 ALLOW_THIS_IN_INITIALIZER_LIST(repeater_( | |
| 288 NewCallback<BitmapScrollBar>(this, | |
| 289 &BitmapScrollBar::TrackClicked))), | |
| 290 context_menu_mouse_position_(0), | |
| 291 show_scroll_buttons_(show_scroll_buttons), | |
| 292 ScrollBar(horizontal) { | |
| 293 if (!show_scroll_buttons_) { | 175 if (!show_scroll_buttons_) { |
| 294 prev_button_->SetVisible(false); | 176 prev_button_->SetVisible(false); |
| 295 next_button_->SetVisible(false); | 177 next_button_->SetVisible(false); |
| 296 } | 178 } |
| 297 | 179 |
| 298 AddChildView(prev_button_); | 180 AddChildView(prev_button_); |
| 299 AddChildView(next_button_); | 181 AddChildView(next_button_); |
| 300 AddChildView(thumb_); | |
| 301 | 182 |
| 302 set_context_menu_controller(this); | 183 set_context_menu_controller(this); |
| 303 prev_button_->set_context_menu_controller(this); | 184 prev_button_->set_context_menu_controller(this); |
| 304 next_button_->set_context_menu_controller(this); | 185 next_button_->set_context_menu_controller(this); |
| 305 thumb_->set_context_menu_controller(this); | |
| 306 } | |
| 307 | |
| 308 gfx::Rect BitmapScrollBar::GetTrackBounds() const { | |
| 309 gfx::Size prefsize = prev_button_->GetPreferredSize(); | |
| 310 if (IsHorizontal()) { | |
| 311 if (!show_scroll_buttons_) | |
| 312 prefsize.set_width(0); | |
| 313 int new_width = | |
| 314 std::max(0, width() - (prefsize.width() * 2)); | |
| 315 gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height()); | |
| 316 return track_bounds; | |
| 317 } | |
| 318 if (!show_scroll_buttons_) | |
| 319 prefsize.set_height(0); | |
| 320 gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(), | |
| 321 std::max(0, height() - (prefsize.height() * 2))); | |
| 322 return track_bounds; | |
| 323 } | 186 } |
| 324 | 187 |
| 325 void BitmapScrollBar::SetImage(ScrollBarPart part, | 188 void BitmapScrollBar::SetImage(ScrollBarPart part, |
| 326 CustomButton::ButtonState state, | 189 CustomButton::ButtonState state, |
| 327 SkBitmap* bitmap) { | 190 SkBitmap* bitmap) { |
| 328 DCHECK(part < PART_COUNT); | 191 DCHECK(part < PART_COUNT); |
| 329 DCHECK(state < CustomButton::BS_COUNT); | 192 DCHECK(state < CustomButton::BS_COUNT); |
| 330 switch (part) { | 193 switch (part) { |
| 331 case PREV_BUTTON: | 194 case PREV_BUTTON: |
| 332 prev_button_->SetImage(state, bitmap); | 195 prev_button_->SetImage(state, bitmap); |
| 333 break; | 196 break; |
| 334 case NEXT_BUTTON: | 197 case NEXT_BUTTON: |
| 335 next_button_->SetImage(state, bitmap); | 198 next_button_->SetImage(state, bitmap); |
| 336 break; | 199 break; |
| 337 case THUMB_START_CAP: | 200 case THUMB_START_CAP: |
| 338 case THUMB_MIDDLE: | 201 case THUMB_MIDDLE: |
| 339 case THUMB_END_CAP: | 202 case THUMB_END_CAP: |
| 340 case THUMB_GRIPPY: | 203 case THUMB_GRIPPY: |
| 341 case THUMB_TRACK: | 204 case THUMB_TRACK: |
| 342 images_[part][state] = bitmap; | 205 images_[part][state] = bitmap; |
| 343 break; | 206 break; |
| 344 } | 207 } |
| 345 } | 208 } |
| 346 | 209 |
| 347 void BitmapScrollBar::ScrollByAmount(ScrollAmount amount) { | 210 int BitmapScrollBar::GetLayoutSize() const { |
| 348 ScrollBarController* controller = GetController(); | 211 gfx::Size prefsize = prev_button_->GetPreferredSize(); |
| 349 int offset = contents_scroll_offset_; | 212 return IsHorizontal() ? prefsize.height() : prefsize.width(); |
| 350 switch (amount) { | |
| 351 case SCROLL_START: | |
| 352 offset = GetMinPosition(); | |
| 353 break; | |
| 354 case SCROLL_END: | |
| 355 offset = GetMaxPosition(); | |
| 356 break; | |
| 357 case SCROLL_PREV_LINE: | |
| 358 offset -= controller->GetScrollIncrement(this, false, false); | |
| 359 offset = std::max(GetMinPosition(), offset); | |
| 360 break; | |
| 361 case SCROLL_NEXT_LINE: | |
| 362 offset += controller->GetScrollIncrement(this, false, true); | |
| 363 offset = std::min(GetMaxPosition(), offset); | |
| 364 break; | |
| 365 case SCROLL_PREV_PAGE: | |
| 366 offset -= controller->GetScrollIncrement(this, true, false); | |
| 367 offset = std::max(GetMinPosition(), offset); | |
| 368 break; | |
| 369 case SCROLL_NEXT_PAGE: | |
| 370 offset += controller->GetScrollIncrement(this, true, true); | |
| 371 offset = std::min(GetMaxPosition(), offset); | |
| 372 break; | |
| 373 } | |
| 374 contents_scroll_offset_ = offset; | |
| 375 ScrollContentsToOffset(); | |
| 376 } | 213 } |
| 377 | 214 |
| 378 void BitmapScrollBar::ScrollToThumbPosition(int thumb_position, | 215 gfx::Rect BitmapScrollBar::GetTrackBounds() const { |
| 379 bool scroll_to_middle) { | 216 gfx::Size prefsize = prev_button_->GetPreferredSize(); |
| 380 contents_scroll_offset_ = | 217 if (IsHorizontal()) { |
| 381 CalculateContentsOffset(thumb_position, scroll_to_middle); | 218 if (!show_scroll_buttons_) |
| 382 if (contents_scroll_offset_ < GetMinPosition()) { | 219 prefsize.set_width(0); |
| 383 contents_scroll_offset_ = GetMinPosition(); | 220 int new_width = |
| 384 } else if (contents_scroll_offset_ > GetMaxPosition()) { | 221 std::max(0, width() - (prefsize.width() * 2)); |
| 385 contents_scroll_offset_ = GetMaxPosition(); | 222 gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height()); |
| 223 return track_bounds; |
| 386 } | 224 } |
| 387 ScrollContentsToOffset(); | 225 if (!show_scroll_buttons_) |
| 388 SchedulePaint(); | 226 prefsize.set_height(0); |
| 389 } | 227 gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(), |
| 390 | 228 std::max(0, height() - (prefsize.height() * 2))); |
| 391 void BitmapScrollBar::ScrollByContentsOffset(int contents_offset) { | 229 return track_bounds; |
| 392 contents_scroll_offset_ -= contents_offset; | |
| 393 if (contents_scroll_offset_ < GetMinPosition()) { | |
| 394 contents_scroll_offset_ = GetMinPosition(); | |
| 395 } else if (contents_scroll_offset_ > GetMaxPosition()) { | |
| 396 contents_scroll_offset_ = GetMaxPosition(); | |
| 397 } | |
| 398 ScrollContentsToOffset(); | |
| 399 } | 230 } |
| 400 | 231 |
| 401 /////////////////////////////////////////////////////////////////////////////// | 232 /////////////////////////////////////////////////////////////////////////////// |
| 402 // BitmapScrollBar, View implementation: | 233 // BitmapScrollBar, View implementation: |
| 403 | 234 |
| 404 gfx::Size BitmapScrollBar::GetPreferredSize() { | 235 gfx::Size BitmapScrollBar::GetPreferredSize() { |
| 405 // In this case, we're returning the desired width of the scrollbar and its | 236 // In this case, we're returning the desired width of the scrollbar and its |
| 406 // minimum allowable height. | 237 // minimum allowable height. |
| 407 gfx::Size button_prefsize = prev_button_->GetPreferredSize(); | 238 gfx::Size button_prefsize = prev_button_->GetPreferredSize(); |
| 408 return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2); | 239 return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 419 prefsize.height()); | 250 prefsize.height()); |
| 420 } else { | 251 } else { |
| 421 next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(), | 252 next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(), |
| 422 prefsize.height()); | 253 prefsize.height()); |
| 423 } | 254 } |
| 424 } else { | 255 } else { |
| 425 prev_button_->SetBounds(0, 0, 0, 0); | 256 prev_button_->SetBounds(0, 0, 0, 0); |
| 426 next_button_->SetBounds(0, 0, 0, 0); | 257 next_button_->SetBounds(0, 0, 0, 0); |
| 427 } | 258 } |
| 428 | 259 |
| 260 BaseScrollBarThumb* thumb = GetThumb(); |
| 429 // Size and place the thumb | 261 // Size and place the thumb |
| 430 gfx::Size thumb_prefsize = thumb_->GetPreferredSize(); | 262 gfx::Size thumb_prefsize = thumb->GetPreferredSize(); |
| 431 gfx::Rect track_bounds = GetTrackBounds(); | 263 gfx::Rect track_bounds = GetTrackBounds(); |
| 432 | 264 |
| 433 // Preserve the height/width of the thumb (depending on orientation) as set | 265 // Preserve the height/width of the thumb (depending on orientation) as set |
| 434 // by the last call to |Update|, but coerce the width/height to be the | 266 // by the last call to |Update|, but coerce the width/height to be the |
| 435 // appropriate value for the bitmaps provided. | 267 // appropriate value for the bitmaps provided. |
| 436 if (IsHorizontal()) { | 268 if (IsHorizontal()) { |
| 437 thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_->width(), | 269 thumb->SetBounds(thumb->x(), thumb->y(), thumb->width(), |
| 438 thumb_prefsize.height()); | 270 thumb_prefsize.height()); |
| 439 } else { | 271 } else { |
| 440 thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_prefsize.width(), | 272 thumb->SetBounds(thumb->x(), thumb->y(), thumb_prefsize.width(), |
| 441 thumb_->height()); | 273 thumb->height()); |
| 442 } | 274 } |
| 443 | 275 |
| 444 // Hide the thumb if the track isn't tall enough to display even a tiny | 276 // Hide the thumb if the track isn't tall enough to display even a tiny |
| 445 // thumb. The user can only use the mousewheel, scroll buttons or keyboard | 277 // thumb. The user can only use the mousewheel, scroll buttons or keyboard |
| 446 // in this scenario. | 278 // in this scenario. |
| 447 if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) || | 279 if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) || |
| 448 (!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) { | 280 (!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) { |
| 449 thumb_->SetVisible(false); | 281 thumb->SetVisible(false); |
| 450 } else if (!thumb_->IsVisible()) { | 282 } else if (!thumb->IsVisible()) { |
| 451 thumb_->SetVisible(true); | 283 thumb->SetVisible(true); |
| 452 } | |
| 453 } | |
| 454 | |
| 455 bool BitmapScrollBar::OnMousePressed(const MouseEvent& event) { | |
| 456 if (event.IsOnlyLeftMouseButton()) { | |
| 457 SetThumbTrackState(CustomButton::BS_PUSHED); | |
| 458 gfx::Rect thumb_bounds = thumb_->bounds(); | |
| 459 if (IsHorizontal()) { | |
| 460 if (event.x() < thumb_bounds.x()) { | |
| 461 last_scroll_amount_ = SCROLL_PREV_PAGE; | |
| 462 } else if (event.x() > thumb_bounds.right()) { | |
| 463 last_scroll_amount_ = SCROLL_NEXT_PAGE; | |
| 464 } | |
| 465 } else { | |
| 466 if (event.y() < thumb_bounds.y()) { | |
| 467 last_scroll_amount_ = SCROLL_PREV_PAGE; | |
| 468 } else if (event.y() > thumb_bounds.bottom()) { | |
| 469 last_scroll_amount_ = SCROLL_NEXT_PAGE; | |
| 470 } | |
| 471 } | |
| 472 TrackClicked(); | |
| 473 repeater_.Start(); | |
| 474 } | |
| 475 return true; | |
| 476 } | |
| 477 | |
| 478 void BitmapScrollBar::OnMouseReleased(const MouseEvent& event) { | |
| 479 OnMouseCaptureLost(); | |
| 480 } | |
| 481 | |
| 482 void BitmapScrollBar::OnMouseCaptureLost() { | |
| 483 SetThumbTrackState(CustomButton::BS_NORMAL); | |
| 484 repeater_.Stop(); | |
| 485 } | |
| 486 | |
| 487 bool BitmapScrollBar::OnKeyPressed(const KeyEvent& event) { | |
| 488 ScrollAmount amount = SCROLL_NONE; | |
| 489 switch (event.key_code()) { | |
| 490 case ui::VKEY_UP: | |
| 491 if (!IsHorizontal()) | |
| 492 amount = SCROLL_PREV_LINE; | |
| 493 break; | |
| 494 case ui::VKEY_DOWN: | |
| 495 if (!IsHorizontal()) | |
| 496 amount = SCROLL_NEXT_LINE; | |
| 497 break; | |
| 498 case ui::VKEY_LEFT: | |
| 499 if (IsHorizontal()) | |
| 500 amount = SCROLL_PREV_LINE; | |
| 501 break; | |
| 502 case ui::VKEY_RIGHT: | |
| 503 if (IsHorizontal()) | |
| 504 amount = SCROLL_NEXT_LINE; | |
| 505 break; | |
| 506 case ui::VKEY_PRIOR: | |
| 507 amount = SCROLL_PREV_PAGE; | |
| 508 break; | |
| 509 case ui::VKEY_NEXT: | |
| 510 amount = SCROLL_NEXT_PAGE; | |
| 511 break; | |
| 512 case ui::VKEY_HOME: | |
| 513 amount = SCROLL_START; | |
| 514 break; | |
| 515 case ui::VKEY_END: | |
| 516 amount = SCROLL_END; | |
| 517 break; | |
| 518 } | |
| 519 if (amount != SCROLL_NONE) { | |
| 520 ScrollByAmount(amount); | |
| 521 return true; | |
| 522 } | |
| 523 return false; | |
| 524 } | |
| 525 | |
| 526 bool BitmapScrollBar::OnMouseWheel(const MouseWheelEvent& event) { | |
| 527 ScrollByContentsOffset(event.offset()); | |
| 528 return true; | |
| 529 } | |
| 530 | |
| 531 /////////////////////////////////////////////////////////////////////////////// | |
| 532 // BitmapScrollBar, ContextMenuController implementation: | |
| 533 | |
| 534 enum ScrollBarContextMenuCommands { | |
| 535 ScrollBarContextMenuCommand_ScrollHere = 1, | |
| 536 ScrollBarContextMenuCommand_ScrollStart, | |
| 537 ScrollBarContextMenuCommand_ScrollEnd, | |
| 538 ScrollBarContextMenuCommand_ScrollPageUp, | |
| 539 ScrollBarContextMenuCommand_ScrollPageDown, | |
| 540 ScrollBarContextMenuCommand_ScrollPrev, | |
| 541 ScrollBarContextMenuCommand_ScrollNext | |
| 542 }; | |
| 543 | |
| 544 void BitmapScrollBar::ShowContextMenuForView(View* source, | |
| 545 const gfx::Point& p, | |
| 546 bool is_mouse_gesture) { | |
| 547 Widget* widget = GetWidget(); | |
| 548 gfx::Rect widget_bounds = widget->GetWindowScreenBounds(); | |
| 549 gfx::Point temp_pt(p.x() - widget_bounds.x(), p.y() - widget_bounds.y()); | |
| 550 View::ConvertPointFromWidget(this, &temp_pt); | |
| 551 context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y(); | |
| 552 | |
| 553 scoped_ptr<Menu> menu( | |
| 554 Menu::Create(this, Menu::TOPLEFT, GetWidget()->GetNativeView())); | |
| 555 menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere); | |
| 556 menu->AppendSeparator(); | |
| 557 menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart); | |
| 558 menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollEnd); | |
| 559 menu->AppendSeparator(); | |
| 560 menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageUp); | |
| 561 menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageDown); | |
| 562 menu->AppendSeparator(); | |
| 563 menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev); | |
| 564 menu->AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext); | |
| 565 menu->RunMenuAt(p.x(), p.y()); | |
| 566 } | |
| 567 | |
| 568 /////////////////////////////////////////////////////////////////////////////// | |
| 569 // BitmapScrollBar, Menu::Delegate implementation: | |
| 570 | |
| 571 std::wstring BitmapScrollBar::GetLabel(int id) const { | |
| 572 int ids_value = 0; | |
| 573 switch (id) { | |
| 574 case ScrollBarContextMenuCommand_ScrollHere: | |
| 575 ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE; | |
| 576 break; | |
| 577 case ScrollBarContextMenuCommand_ScrollStart: | |
| 578 ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFTEDGE | |
| 579 : IDS_APP_SCROLLBAR_CXMENU_SCROLLHOME; | |
| 580 break; | |
| 581 case ScrollBarContextMenuCommand_ScrollEnd: | |
| 582 ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE | |
| 583 : IDS_APP_SCROLLBAR_CXMENU_SCROLLEND; | |
| 584 break; | |
| 585 case ScrollBarContextMenuCommand_ScrollPageUp: | |
| 586 ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEUP; | |
| 587 break; | |
| 588 case ScrollBarContextMenuCommand_ScrollPageDown: | |
| 589 ids_value = IDS_APP_SCROLLBAR_CXMENU_SCROLLPAGEDOWN; | |
| 590 break; | |
| 591 case ScrollBarContextMenuCommand_ScrollPrev: | |
| 592 ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLLEFT | |
| 593 : IDS_APP_SCROLLBAR_CXMENU_SCROLLUP; | |
| 594 break; | |
| 595 case ScrollBarContextMenuCommand_ScrollNext: | |
| 596 ids_value = IsHorizontal() ? IDS_APP_SCROLLBAR_CXMENU_SCROLLRIGHT | |
| 597 : IDS_APP_SCROLLBAR_CXMENU_SCROLLDOWN; | |
| 598 break; | |
| 599 default: | |
| 600 NOTREACHED() << "Invalid BitmapScrollBar Context Menu command!"; | |
| 601 } | |
| 602 | |
| 603 return ids_value ? UTF16ToWide(l10n_util::GetStringUTF16(ids_value)) : L""; | |
| 604 } | |
| 605 | |
| 606 bool BitmapScrollBar::IsCommandEnabled(int id) const { | |
| 607 switch (id) { | |
| 608 case ScrollBarContextMenuCommand_ScrollPageUp: | |
| 609 case ScrollBarContextMenuCommand_ScrollPageDown: | |
| 610 return !IsHorizontal(); | |
| 611 } | |
| 612 return true; | |
| 613 } | |
| 614 | |
| 615 void BitmapScrollBar::ExecuteCommand(int id) { | |
| 616 switch (id) { | |
| 617 case ScrollBarContextMenuCommand_ScrollHere: | |
| 618 ScrollToThumbPosition(context_menu_mouse_position_, true); | |
| 619 break; | |
| 620 case ScrollBarContextMenuCommand_ScrollStart: | |
| 621 ScrollByAmount(SCROLL_START); | |
| 622 break; | |
| 623 case ScrollBarContextMenuCommand_ScrollEnd: | |
| 624 ScrollByAmount(SCROLL_END); | |
| 625 break; | |
| 626 case ScrollBarContextMenuCommand_ScrollPageUp: | |
| 627 ScrollByAmount(SCROLL_PREV_PAGE); | |
| 628 break; | |
| 629 case ScrollBarContextMenuCommand_ScrollPageDown: | |
| 630 ScrollByAmount(SCROLL_NEXT_PAGE); | |
| 631 break; | |
| 632 case ScrollBarContextMenuCommand_ScrollPrev: | |
| 633 ScrollByAmount(SCROLL_PREV_LINE); | |
| 634 break; | |
| 635 case ScrollBarContextMenuCommand_ScrollNext: | |
| 636 ScrollByAmount(SCROLL_NEXT_LINE); | |
| 637 break; | |
| 638 } | 284 } |
| 639 } | 285 } |
| 640 | 286 |
| 641 /////////////////////////////////////////////////////////////////////////////// | 287 /////////////////////////////////////////////////////////////////////////////// |
| 288 // BitmapScrollBar, View implementation: |
| 289 |
| 290 void BitmapScrollBar::OnPaint(gfx::Canvas* canvas) { |
| 291 // Paint the track. |
| 292 gfx::Rect track_bounds = GetTrackBounds(); |
| 293 canvas->TileImageInt(*images_[THUMB_TRACK][GetThumbTrackState()], |
| 294 track_bounds.x(), track_bounds.y(), |
| 295 track_bounds.width(), track_bounds.height()); |
| 296 } |
| 297 |
| 298 /////////////////////////////////////////////////////////////////////////////// |
| 642 // BitmapScrollBar, ButtonListener implementation: | 299 // BitmapScrollBar, ButtonListener implementation: |
| 643 | 300 |
| 644 void BitmapScrollBar::ButtonPressed(Button* sender, const views::Event& event) { | 301 void BitmapScrollBar::ButtonPressed(Button* sender, const views::Event& event) { |
| 645 if (sender == prev_button_) { | 302 if (sender == prev_button_) { |
| 646 ScrollByAmount(SCROLL_PREV_LINE); | 303 ScrollByAmount(SCROLL_PREV_LINE); |
| 647 } else if (sender == next_button_) { | 304 } else if (sender == next_button_) { |
| 648 ScrollByAmount(SCROLL_NEXT_LINE); | 305 ScrollByAmount(SCROLL_NEXT_LINE); |
| 649 } | 306 } |
| 650 } | 307 } |
| 651 | 308 |
| 652 /////////////////////////////////////////////////////////////////////////////// | |
| 653 // BitmapScrollBar, ScrollBar implementation: | |
| 654 | |
| 655 void BitmapScrollBar::Update(int viewport_size, int content_size, | |
| 656 int contents_scroll_offset) { | |
| 657 ScrollBar::Update(viewport_size, content_size, contents_scroll_offset); | |
| 658 | |
| 659 // Make sure contents_size is always > 0 to avoid divide by zero errors in | |
| 660 // calculations throughout this code. | |
| 661 contents_size_ = std::max(1, content_size); | |
| 662 | |
| 663 if (content_size < 0) | |
| 664 content_size = 0; | |
| 665 if (contents_scroll_offset < 0) | |
| 666 contents_scroll_offset = 0; | |
| 667 if (contents_scroll_offset > content_size) | |
| 668 contents_scroll_offset = content_size; | |
| 669 | |
| 670 // Thumb Height and Thumb Pos. | |
| 671 // The height of the thumb is the ratio of the Viewport height to the | |
| 672 // content size multiplied by the height of the thumb track. | |
| 673 double ratio = static_cast<double>(viewport_size) / contents_size_; | |
| 674 int thumb_size = static_cast<int>(ratio * GetTrackSize()); | |
| 675 thumb_->SetSize(thumb_size); | |
| 676 | |
| 677 int thumb_position = CalculateThumbPosition(contents_scroll_offset); | |
| 678 thumb_->SetPosition(thumb_position); | |
| 679 } | |
| 680 | |
| 681 int BitmapScrollBar::GetLayoutSize() const { | |
| 682 gfx::Size prefsize = prev_button_->GetPreferredSize(); | |
| 683 return IsHorizontal() ? prefsize.height() : prefsize.width(); | |
| 684 } | |
| 685 | |
| 686 int BitmapScrollBar::GetPosition() const { | |
| 687 return thumb_->GetPosition(); | |
| 688 } | |
| 689 | |
| 690 /////////////////////////////////////////////////////////////////////////////// | |
| 691 // BitmapScrollBar, View implementation: | |
| 692 | |
| 693 void BitmapScrollBar::OnPaint(gfx::Canvas* canvas) { | |
| 694 // Paint the track. | |
| 695 gfx::Rect track_bounds = GetTrackBounds(); | |
| 696 canvas->TileImageInt(*images_[THUMB_TRACK][thumb_track_state_], | |
| 697 track_bounds.x(), track_bounds.y(), | |
| 698 track_bounds.width(), track_bounds.height()); | |
| 699 } | |
| 700 | |
| 701 /////////////////////////////////////////////////////////////////////////////// | |
| 702 // BitmapScrollBar, private: | |
| 703 | |
| 704 void BitmapScrollBar::TrackClicked() { | |
| 705 if (last_scroll_amount_ != SCROLL_NONE) | |
| 706 ScrollByAmount(last_scroll_amount_); | |
| 707 } | |
| 708 | |
| 709 void BitmapScrollBar::ScrollContentsToOffset() { | |
| 710 GetController()->ScrollToPosition(this, contents_scroll_offset_); | |
| 711 thumb_->SetPosition(CalculateThumbPosition(contents_scroll_offset_)); | |
| 712 } | |
| 713 | |
| 714 int BitmapScrollBar::GetTrackSize() const { | |
| 715 gfx::Rect track_bounds = GetTrackBounds(); | |
| 716 return IsHorizontal() ? track_bounds.width() : track_bounds.height(); | |
| 717 } | |
| 718 | |
| 719 int BitmapScrollBar::CalculateThumbPosition(int contents_scroll_offset) const { | |
| 720 return (contents_scroll_offset * GetTrackSize()) / contents_size_; | |
| 721 } | |
| 722 | |
| 723 int BitmapScrollBar::CalculateContentsOffset(int thumb_position, | |
| 724 bool scroll_to_middle) const { | |
| 725 if (scroll_to_middle) | |
| 726 thumb_position = thumb_position - (thumb_->GetSize() / 2); | |
| 727 return (thumb_position * contents_size_) / GetTrackSize(); | |
| 728 } | |
| 729 | |
| 730 void BitmapScrollBar::SetThumbTrackState(CustomButton::ButtonState state) { | |
| 731 thumb_track_state_ = state; | |
| 732 SchedulePaint(); | |
| 733 } | |
| 734 | |
| 735 } // namespace views | 309 } // namespace views |
| OLD | NEW |