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" | |
23 #include "views/controls/scroll_view.h" | 22 #include "views/controls/scroll_view.h" |
24 #include "views/widget/widget.h" | 23 #include "views/widget/widget.h" |
25 | 24 |
26 #undef min | 25 #undef min |
27 #undef max | 26 #undef max |
28 | 27 |
29 namespace views { | 28 namespace views { |
30 | 29 |
31 namespace { | 30 namespace { |
32 | 31 |
33 // The distance the mouse can be dragged outside the bounds of the thumb during | 32 // The distance the mouse can be dragged outside the bounds of the thumb during |
34 // dragging before the scrollbar will snap back to its regular position. | 33 // dragging before the scrollbar will snap back to its regular position. |
35 static const int kScrollThumbDragOutSnap = 100; | 34 static const int kScrollThumbDragOutSnap = 100; |
36 | 35 |
37 /////////////////////////////////////////////////////////////////////////////// | 36 /////////////////////////////////////////////////////////////////////////////// |
38 // | 37 // |
39 // AutorepeatButton | 38 // AutorepeatButton |
40 // | 39 // |
41 // A button that activates on mouse pressed rather than released, and that | 40 // A button that activates on mouse pressed rather than released, and that |
42 // continues to fire the clicked action as the mouse button remains pressed | 41 // continues to fire the clicked action as the mouse button remains pressed |
43 // down on the button. | 42 // down on the button. |
44 // | 43 // |
45 /////////////////////////////////////////////////////////////////////////////// | 44 /////////////////////////////////////////////////////////////////////////////// |
46 class AutorepeatButton : public ImageButton { | 45 class AutorepeatButton : public ImageButton { |
47 public: | 46 public: |
48 explicit AutorepeatButton(ButtonListener* listener) | 47 AutorepeatButton(ButtonListener* listener) |
49 : ImageButton(listener), | 48 : ImageButton(listener), |
50 ALLOW_THIS_IN_INITIALIZER_LIST(repeater_( | 49 ALLOW_THIS_IN_INITIALIZER_LIST(repeater_( |
51 NewCallback<AutorepeatButton>(this, | 50 NewCallback<AutorepeatButton>(this, |
52 &AutorepeatButton::NotifyClick))) { | 51 &AutorepeatButton::NotifyClick))) { |
53 } | 52 } |
54 virtual ~AutorepeatButton() {} | 53 virtual ~AutorepeatButton() {} |
55 | 54 |
56 protected: | 55 protected: |
57 virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE { | 56 virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE { |
58 Button::NotifyClick(event); | 57 Button::NotifyClick(event); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 }; | 90 }; |
92 | 91 |
93 /////////////////////////////////////////////////////////////////////////////// | 92 /////////////////////////////////////////////////////////////////////////////// |
94 // | 93 // |
95 // BitmapScrollBarThumb | 94 // BitmapScrollBarThumb |
96 // | 95 // |
97 // A view that acts as the thumb in the scroll bar track that the user can | 96 // A view that acts as the thumb in the scroll bar track that the user can |
98 // drag to scroll the associated contents view within the viewport. | 97 // drag to scroll the associated contents view within the viewport. |
99 // | 98 // |
100 /////////////////////////////////////////////////////////////////////////////// | 99 /////////////////////////////////////////////////////////////////////////////// |
101 class BitmapScrollBarThumb : public BaseScrollBarThumb { | 100 class BitmapScrollBarThumb : public View { |
102 public: | 101 public: |
103 explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar) | 102 explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar) |
104 : BaseScrollBarThumb(scroll_bar), | 103 : scroll_bar_(scroll_bar), |
105 scroll_bar_(scroll_bar) { | 104 drag_start_position_(-1), |
| 105 mouse_offset_(-1), |
| 106 state_(CustomButton::BS_NORMAL) { |
106 } | 107 } |
107 virtual ~BitmapScrollBarThumb() { } | 108 virtual ~BitmapScrollBarThumb() { } |
108 | 109 |
| 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 |
109 // View overrides: | 153 // View overrides: |
110 virtual gfx::Size GetPreferredSize() OVERRIDE { | 154 virtual gfx::Size GetPreferredSize() OVERRIDE { |
111 return gfx::Size(background_bitmap()->width(), | 155 return gfx::Size(background_bitmap()->width(), |
112 start_cap_bitmap()->height() + | 156 start_cap_bitmap()->height() + |
113 end_cap_bitmap()->height() + | 157 end_cap_bitmap()->height() + |
114 grippy_bitmap()->height()); | 158 grippy_bitmap()->height()); |
115 } | 159 } |
116 | 160 |
117 protected: | 161 protected: |
118 // View overrides: | 162 // View overrides: |
119 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | 163 virtual void Paint(gfx::Canvas* canvas) OVERRIDE { |
120 canvas->DrawBitmapInt(*start_cap_bitmap(), 0, 0); | 164 canvas->DrawBitmapInt(*start_cap_bitmap(), 0, 0); |
121 int top_cap_height = start_cap_bitmap()->height(); | 165 int top_cap_height = start_cap_bitmap()->height(); |
122 int bottom_cap_height = end_cap_bitmap()->height(); | 166 int bottom_cap_height = end_cap_bitmap()->height(); |
123 int thumb_body_height = height() - top_cap_height - bottom_cap_height; | 167 int thumb_body_height = height() - top_cap_height - bottom_cap_height; |
124 canvas->TileImageInt(*background_bitmap(), 0, top_cap_height, | 168 canvas->TileImageInt(*background_bitmap(), 0, top_cap_height, |
125 background_bitmap()->width(), thumb_body_height); | 169 background_bitmap()->width(), thumb_body_height); |
126 canvas->DrawBitmapInt(*end_cap_bitmap(), 0, | 170 canvas->DrawBitmapInt(*end_cap_bitmap(), 0, |
127 height() - bottom_cap_height); | 171 height() - bottom_cap_height); |
128 | 172 |
129 // Paint the grippy over the track. | 173 // Paint the grippy over the track. |
130 int grippy_x = (width() - grippy_bitmap()->width()) / 2; | 174 int grippy_x = (width() - grippy_bitmap()->width()) / 2; |
131 int grippy_y = (thumb_body_height - grippy_bitmap()->height()) / 2; | 175 int grippy_y = (thumb_body_height - grippy_bitmap()->height()) / 2; |
132 canvas->DrawBitmapInt(*grippy_bitmap(), grippy_x, grippy_y); | 176 canvas->DrawBitmapInt(*grippy_bitmap(), grippy_x, grippy_y); |
133 } | 177 } |
134 | 178 |
| 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 |
135 private: | 229 private: |
136 // Returns the bitmap rendered at the start of the thumb. | 230 // Returns the bitmap rendered at the start of the thumb. |
137 SkBitmap* start_cap_bitmap() const { | 231 SkBitmap* start_cap_bitmap() const { |
138 return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][GetState()]; | 232 return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][state_]; |
139 } | 233 } |
140 | 234 |
141 // Returns the bitmap rendered at the end of the thumb. | 235 // Returns the bitmap rendered at the end of the thumb. |
142 SkBitmap* end_cap_bitmap() const { | 236 SkBitmap* end_cap_bitmap() const { |
143 return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][GetState()]; | 237 return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][state_]; |
144 } | 238 } |
145 | 239 |
146 // Returns the bitmap that is tiled in the background of the thumb between | 240 // Returns the bitmap that is tiled in the background of the thumb between |
147 // the start and the end caps. | 241 // the start and the end caps. |
148 SkBitmap* background_bitmap() const { | 242 SkBitmap* background_bitmap() const { |
149 return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][GetState()]; | 243 return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][state_]; |
150 } | 244 } |
151 | 245 |
152 // Returns the bitmap that is rendered in the middle of the thumb | 246 // Returns the bitmap that is rendered in the middle of the thumb |
153 // transparently over the background bitmap. | 247 // transparently over the background bitmap. |
154 SkBitmap* grippy_bitmap() const { | 248 SkBitmap* grippy_bitmap() const { |
155 return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY] | 249 return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY] |
156 [CustomButton::BS_NORMAL]; | 250 [CustomButton::BS_NORMAL]; |
157 } | 251 } |
158 | 252 |
| 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 |
159 // The BitmapScrollBar that owns us. | 259 // The BitmapScrollBar that owns us. |
160 BitmapScrollBar* scroll_bar_; | 260 BitmapScrollBar* scroll_bar_; |
161 | 261 |
| 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 |
162 DISALLOW_COPY_AND_ASSIGN(BitmapScrollBarThumb); | 271 DISALLOW_COPY_AND_ASSIGN(BitmapScrollBarThumb); |
163 }; | 272 }; |
164 | 273 |
165 } // anonymous namespace | 274 } // anonymous namespace |
166 | 275 |
167 /////////////////////////////////////////////////////////////////////////////// | 276 /////////////////////////////////////////////////////////////////////////////// |
168 // BitmapScrollBar, public: | 277 // BitmapScrollBar, public: |
169 | 278 |
170 BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons) | 279 BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons) |
171 : BaseScrollBar(horizontal, new BitmapScrollBarThumb(this)), | 280 : contents_size_(0), |
| 281 contents_scroll_offset_(0), |
172 ALLOW_THIS_IN_INITIALIZER_LIST(prev_button_(new AutorepeatButton(this))), | 282 ALLOW_THIS_IN_INITIALIZER_LIST(prev_button_(new AutorepeatButton(this))), |
173 ALLOW_THIS_IN_INITIALIZER_LIST(next_button_(new AutorepeatButton(this))), | 283 ALLOW_THIS_IN_INITIALIZER_LIST(next_button_(new AutorepeatButton(this))), |
174 show_scroll_buttons_(show_scroll_buttons) { | 284 ALLOW_THIS_IN_INITIALIZER_LIST(thumb_(new BitmapScrollBarThumb(this))), |
| 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) { |
175 if (!show_scroll_buttons_) { | 293 if (!show_scroll_buttons_) { |
176 prev_button_->SetVisible(false); | 294 prev_button_->SetVisible(false); |
177 next_button_->SetVisible(false); | 295 next_button_->SetVisible(false); |
178 } | 296 } |
179 | 297 |
180 AddChildView(prev_button_); | 298 AddChildView(prev_button_); |
181 AddChildView(next_button_); | 299 AddChildView(next_button_); |
| 300 AddChildView(thumb_); |
182 | 301 |
183 set_context_menu_controller(this); | 302 set_context_menu_controller(this); |
184 prev_button_->set_context_menu_controller(this); | 303 prev_button_->set_context_menu_controller(this); |
185 next_button_->set_context_menu_controller(this); | 304 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; |
186 } | 323 } |
187 | 324 |
188 void BitmapScrollBar::SetImage(ScrollBarPart part, | 325 void BitmapScrollBar::SetImage(ScrollBarPart part, |
189 CustomButton::ButtonState state, | 326 CustomButton::ButtonState state, |
190 SkBitmap* bitmap) { | 327 SkBitmap* bitmap) { |
191 DCHECK(part < PART_COUNT); | 328 DCHECK(part < PART_COUNT); |
192 DCHECK(state < CustomButton::BS_COUNT); | 329 DCHECK(state < CustomButton::BS_COUNT); |
193 switch (part) { | 330 switch (part) { |
194 case PREV_BUTTON: | 331 case PREV_BUTTON: |
195 prev_button_->SetImage(state, bitmap); | 332 prev_button_->SetImage(state, bitmap); |
196 break; | 333 break; |
197 case NEXT_BUTTON: | 334 case NEXT_BUTTON: |
198 next_button_->SetImage(state, bitmap); | 335 next_button_->SetImage(state, bitmap); |
199 break; | 336 break; |
200 case THUMB_START_CAP: | 337 case THUMB_START_CAP: |
201 case THUMB_MIDDLE: | 338 case THUMB_MIDDLE: |
202 case THUMB_END_CAP: | 339 case THUMB_END_CAP: |
203 case THUMB_GRIPPY: | 340 case THUMB_GRIPPY: |
204 case THUMB_TRACK: | 341 case THUMB_TRACK: |
205 images_[part][state] = bitmap; | 342 images_[part][state] = bitmap; |
206 break; | 343 break; |
207 } | 344 } |
208 } | 345 } |
209 | 346 |
210 int BitmapScrollBar::GetLayoutSize() const { | 347 void BitmapScrollBar::ScrollByAmount(ScrollAmount amount) { |
211 gfx::Size prefsize = prev_button_->GetPreferredSize(); | 348 ScrollBarController* controller = GetController(); |
212 return IsHorizontal() ? prefsize.height() : prefsize.width(); | 349 int offset = contents_scroll_offset_; |
| 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(); |
213 } | 376 } |
214 | 377 |
215 gfx::Rect BitmapScrollBar::GetTrackBounds() const { | 378 void BitmapScrollBar::ScrollToThumbPosition(int thumb_position, |
216 gfx::Size prefsize = prev_button_->GetPreferredSize(); | 379 bool scroll_to_middle) { |
217 if (IsHorizontal()) { | 380 contents_scroll_offset_ = |
218 if (!show_scroll_buttons_) | 381 CalculateContentsOffset(thumb_position, scroll_to_middle); |
219 prefsize.set_width(0); | 382 if (contents_scroll_offset_ < GetMinPosition()) { |
220 int new_width = | 383 contents_scroll_offset_ = GetMinPosition(); |
221 std::max(0, width() - (prefsize.width() * 2)); | 384 } else if (contents_scroll_offset_ > GetMaxPosition()) { |
222 gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height()); | 385 contents_scroll_offset_ = GetMaxPosition(); |
223 return track_bounds; | |
224 } | 386 } |
225 if (!show_scroll_buttons_) | 387 ScrollContentsToOffset(); |
226 prefsize.set_height(0); | 388 SchedulePaint(); |
227 gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(), | 389 } |
228 std::max(0, height() - (prefsize.height() * 2))); | 390 |
229 return track_bounds; | 391 void BitmapScrollBar::ScrollByContentsOffset(int contents_offset) { |
| 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(); |
230 } | 399 } |
231 | 400 |
232 /////////////////////////////////////////////////////////////////////////////// | 401 /////////////////////////////////////////////////////////////////////////////// |
233 // BitmapScrollBar, View implementation: | 402 // BitmapScrollBar, View implementation: |
234 | 403 |
235 gfx::Size BitmapScrollBar::GetPreferredSize() { | 404 gfx::Size BitmapScrollBar::GetPreferredSize() { |
236 // In this case, we're returning the desired width of the scrollbar and its | 405 // In this case, we're returning the desired width of the scrollbar and its |
237 // minimum allowable height. | 406 // minimum allowable height. |
238 gfx::Size button_prefsize = prev_button_->GetPreferredSize(); | 407 gfx::Size button_prefsize = prev_button_->GetPreferredSize(); |
239 return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2); | 408 return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2); |
(...skipping 10 matching lines...) Expand all Loading... |
250 prefsize.height()); | 419 prefsize.height()); |
251 } else { | 420 } else { |
252 next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(), | 421 next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(), |
253 prefsize.height()); | 422 prefsize.height()); |
254 } | 423 } |
255 } else { | 424 } else { |
256 prev_button_->SetBounds(0, 0, 0, 0); | 425 prev_button_->SetBounds(0, 0, 0, 0); |
257 next_button_->SetBounds(0, 0, 0, 0); | 426 next_button_->SetBounds(0, 0, 0, 0); |
258 } | 427 } |
259 | 428 |
260 BaseScrollBarThumb* thumb = GetThumb(); | |
261 // Size and place the thumb | 429 // Size and place the thumb |
262 gfx::Size thumb_prefsize = thumb->GetPreferredSize(); | 430 gfx::Size thumb_prefsize = thumb_->GetPreferredSize(); |
263 gfx::Rect track_bounds = GetTrackBounds(); | 431 gfx::Rect track_bounds = GetTrackBounds(); |
264 | 432 |
265 // Preserve the height/width of the thumb (depending on orientation) as set | 433 // Preserve the height/width of the thumb (depending on orientation) as set |
266 // by the last call to |Update|, but coerce the width/height to be the | 434 // by the last call to |Update|, but coerce the width/height to be the |
267 // appropriate value for the bitmaps provided. | 435 // appropriate value for the bitmaps provided. |
268 if (IsHorizontal()) { | 436 if (IsHorizontal()) { |
269 thumb->SetBounds(thumb->x(), thumb->y(), thumb->width(), | 437 thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_->width(), |
270 thumb_prefsize.height()); | 438 thumb_prefsize.height()); |
271 } else { | 439 } else { |
272 thumb->SetBounds(thumb->x(), thumb->y(), thumb_prefsize.width(), | 440 thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_prefsize.width(), |
273 thumb->height()); | 441 thumb_->height()); |
274 } | 442 } |
275 | 443 |
276 // Hide the thumb if the track isn't tall enough to display even a tiny | 444 // Hide the thumb if the track isn't tall enough to display even a tiny |
277 // thumb. The user can only use the mousewheel, scroll buttons or keyboard | 445 // thumb. The user can only use the mousewheel, scroll buttons or keyboard |
278 // in this scenario. | 446 // in this scenario. |
279 if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) || | 447 if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) || |
280 (!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) { | 448 (!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) { |
281 thumb->SetVisible(false); | 449 thumb_->SetVisible(false); |
282 } else if (!thumb->IsVisible()) { | 450 } else if (!thumb_->IsVisible()) { |
283 thumb->SetVisible(true); | 451 thumb_->SetVisible(true); |
284 } | 452 } |
285 } | 453 } |
286 | 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 |
287 /////////////////////////////////////////////////////////////////////////////// | 531 /////////////////////////////////////////////////////////////////////////////// |
288 // BitmapScrollBar, View implementation: | 532 // BitmapScrollBar, ContextMenuController implementation: |
289 | 533 |
290 void BitmapScrollBar::OnPaint(gfx::Canvas* canvas) { | 534 enum ScrollBarContextMenuCommands { |
291 // Paint the track. | 535 ScrollBarContextMenuCommand_ScrollHere = 1, |
292 gfx::Rect track_bounds = GetTrackBounds(); | 536 ScrollBarContextMenuCommand_ScrollStart, |
293 canvas->TileImageInt(*images_[THUMB_TRACK][GetThumbTrackState()], | 537 ScrollBarContextMenuCommand_ScrollEnd, |
294 track_bounds.x(), track_bounds.y(), | 538 ScrollBarContextMenuCommand_ScrollPageUp, |
295 track_bounds.width(), track_bounds.height()); | 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 } |
296 } | 639 } |
297 | 640 |
298 /////////////////////////////////////////////////////////////////////////////// | 641 /////////////////////////////////////////////////////////////////////////////// |
299 // BitmapScrollBar, ButtonListener implementation: | 642 // BitmapScrollBar, ButtonListener implementation: |
300 | 643 |
301 void BitmapScrollBar::ButtonPressed(Button* sender, const views::Event& event) { | 644 void BitmapScrollBar::ButtonPressed(Button* sender, const views::Event& event) { |
302 if (sender == prev_button_) { | 645 if (sender == prev_button_) { |
303 ScrollByAmount(SCROLL_PREV_LINE); | 646 ScrollByAmount(SCROLL_PREV_LINE); |
304 } else if (sender == next_button_) { | 647 } else if (sender == next_button_) { |
305 ScrollByAmount(SCROLL_NEXT_LINE); | 648 ScrollByAmount(SCROLL_NEXT_LINE); |
306 } | 649 } |
307 } | 650 } |
308 | 651 |
| 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 |
309 } // namespace views | 735 } // namespace views |
OLD | NEW |