Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Side by Side Diff: views/controls/scroll_view.cc

Issue 8687031: views: Move the remaining files to ui/views/controls/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « views/controls/scroll_view.h ('k') | views/controls/separator.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "views/controls/scroll_view.h"
6
7 #include "base/logging.h"
8 #include "ui/views/controls/scrollbar/native_scroll_bar.h"
9 #include "ui/views/widget/root_view.h"
10
11 namespace views {
12
13 const char* const ScrollView::kViewClassName = "views/ScrollView";
14
15 // Viewport contains the contents View of the ScrollView.
16 class Viewport : public View {
17 public:
18 Viewport() {}
19 virtual ~Viewport() {}
20
21 virtual std::string GetClassName() const {
22 return "views/Viewport";
23 }
24
25 virtual void ScrollRectToVisible(const gfx::Rect& rect) {
26 if (!has_children() || !parent())
27 return;
28
29 View* contents = child_at(0);
30 gfx::Rect scroll_rect(rect);
31 scroll_rect.Offset(-contents->x(), -contents->y());
32 static_cast<ScrollView*>(parent())->ScrollContentsRegionToBeVisible(
33 scroll_rect);
34 }
35
36 private:
37 DISALLOW_COPY_AND_ASSIGN(Viewport);
38 };
39
40
41 ScrollView::ScrollView() {
42 Init(new NativeScrollBar(true), new NativeScrollBar(false), NULL);
43 }
44
45 ScrollView::ScrollView(ScrollBar* horizontal_scrollbar,
46 ScrollBar* vertical_scrollbar,
47 View* resize_corner) {
48 Init(horizontal_scrollbar, vertical_scrollbar, resize_corner);
49 }
50
51 ScrollView::~ScrollView() {
52 // If scrollbars are currently not used, delete them
53 if (!horiz_sb_->parent())
54 delete horiz_sb_;
55
56 if (!vert_sb_->parent())
57 delete vert_sb_;
58
59 if (resize_corner_ && !resize_corner_->parent())
60 delete resize_corner_;
61 }
62
63 void ScrollView::SetContents(View* a_view) {
64 if (contents_ && contents_ != a_view) {
65 viewport_->RemoveChildView(contents_);
66 delete contents_;
67 contents_ = NULL;
68 }
69
70 if (a_view) {
71 contents_ = a_view;
72 viewport_->AddChildView(contents_);
73 }
74
75 Layout();
76 }
77
78 View* ScrollView::GetContents() const {
79 return contents_;
80 }
81
82 void ScrollView::Init(ScrollBar* horizontal_scrollbar,
83 ScrollBar* vertical_scrollbar,
84 View* resize_corner) {
85 DCHECK(horizontal_scrollbar && vertical_scrollbar);
86
87 contents_ = NULL;
88 horiz_sb_ = horizontal_scrollbar;
89 vert_sb_ = vertical_scrollbar;
90 resize_corner_ = resize_corner;
91
92 viewport_ = new Viewport();
93 AddChildView(viewport_);
94
95 // Don't add the scrollbars as children until we discover we need them
96 // (ShowOrHideScrollBar).
97 horiz_sb_->SetVisible(false);
98 horiz_sb_->set_controller(this);
99 vert_sb_->SetVisible(false);
100 vert_sb_->set_controller(this);
101 if (resize_corner_)
102 resize_corner_->SetVisible(false);
103 }
104
105 // Make sure that a single scrollbar is created and visible as needed
106 void ScrollView::SetControlVisibility(View* control, bool should_show) {
107 if (!control)
108 return;
109 if (should_show) {
110 if (!control->IsVisible()) {
111 AddChildView(control);
112 control->SetVisible(true);
113 }
114 } else {
115 RemoveChildView(control);
116 control->SetVisible(false);
117 }
118 }
119
120 void ScrollView::ComputeScrollBarsVisibility(const gfx::Size& vp_size,
121 const gfx::Size& content_size,
122 bool* horiz_is_shown,
123 bool* vert_is_shown) const {
124 // Try to fit both ways first, then try vertical bar only, then horizontal
125 // bar only, then defaults to both shown.
126 if (content_size.width() <= vp_size.width() &&
127 content_size.height() <= vp_size.height()) {
128 *horiz_is_shown = false;
129 *vert_is_shown = false;
130 } else if (content_size.width() <= vp_size.width() - GetScrollBarWidth()) {
131 *horiz_is_shown = false;
132 *vert_is_shown = true;
133 } else if (content_size.height() <= vp_size.height() - GetScrollBarHeight()) {
134 *horiz_is_shown = true;
135 *vert_is_shown = false;
136 } else {
137 *horiz_is_shown = true;
138 *vert_is_shown = true;
139 }
140 }
141
142 void ScrollView::Layout() {
143 // Most views will want to auto-fit the available space. Most of them want to
144 // use the all available width (without overflowing) and only overflow in
145 // height. Examples are HistoryView, MostVisitedView, DownloadTabView, etc.
146 // Other views want to fit in both ways. An example is PrintView. To make both
147 // happy, assume a vertical scrollbar but no horizontal scrollbar. To
148 // override this default behavior, the inner view has to calculate the
149 // available space, used ComputeScrollBarsVisibility() to use the same
150 // calculation that is done here and sets its bound to fit within.
151 gfx::Rect viewport_bounds = GetLocalBounds();
152 // Realign it to 0 so it can be used as-is for SetBounds().
153 viewport_bounds.set_origin(gfx::Point(0, 0));
154 // viewport_size is the total client space available.
155 gfx::Size viewport_size = viewport_bounds.size();
156 if (viewport_bounds.IsEmpty()) {
157 // There's nothing to layout.
158 return;
159 }
160
161 // Assumes a vertical scrollbar since most the current views are designed for
162 // this.
163 int horiz_sb_height = GetScrollBarHeight();
164 int vert_sb_width = GetScrollBarWidth();
165 viewport_bounds.set_width(viewport_bounds.width() - vert_sb_width);
166 // Update the bounds right now so the inner views can fit in it.
167 viewport_->SetBoundsRect(viewport_bounds);
168
169 // Give contents_ a chance to update its bounds if it depends on the
170 // viewport.
171 if (contents_)
172 contents_->Layout();
173
174 bool should_layout_contents = false;
175 bool horiz_sb_required = false;
176 bool vert_sb_required = false;
177 if (contents_) {
178 gfx::Size content_size = contents_->size();
179 ComputeScrollBarsVisibility(viewport_size,
180 content_size,
181 &horiz_sb_required,
182 &vert_sb_required);
183 }
184 bool resize_corner_required = resize_corner_ && horiz_sb_required &&
185 vert_sb_required;
186 // Take action.
187 SetControlVisibility(horiz_sb_, horiz_sb_required);
188 SetControlVisibility(vert_sb_, vert_sb_required);
189 SetControlVisibility(resize_corner_, resize_corner_required);
190
191 // Non-default.
192 if (horiz_sb_required) {
193 viewport_bounds.set_height(
194 std::max(0, viewport_bounds.height() - horiz_sb_height));
195 should_layout_contents = true;
196 }
197 // Default.
198 if (!vert_sb_required) {
199 viewport_bounds.set_width(viewport_bounds.width() + vert_sb_width);
200 should_layout_contents = true;
201 }
202
203 if (horiz_sb_required) {
204 horiz_sb_->SetBounds(0,
205 viewport_bounds.bottom(),
206 viewport_bounds.right(),
207 horiz_sb_height);
208 }
209 if (vert_sb_required) {
210 vert_sb_->SetBounds(viewport_bounds.right(),
211 0,
212 vert_sb_width,
213 viewport_bounds.bottom());
214 }
215 if (resize_corner_required) {
216 // Show the resize corner.
217 resize_corner_->SetBounds(viewport_bounds.right(),
218 viewport_bounds.bottom(),
219 vert_sb_width,
220 horiz_sb_height);
221 }
222
223 // Update to the real client size with the visible scrollbars.
224 viewport_->SetBoundsRect(viewport_bounds);
225 if (should_layout_contents && contents_)
226 contents_->Layout();
227
228 CheckScrollBounds();
229 SchedulePaint();
230 UpdateScrollBarPositions();
231 }
232
233 int ScrollView::CheckScrollBounds(int viewport_size,
234 int content_size,
235 int current_pos) {
236 int max = std::max(content_size - viewport_size, 0);
237 if (current_pos < 0)
238 current_pos = 0;
239 else if (current_pos > max)
240 current_pos = max;
241 return current_pos;
242 }
243
244 void ScrollView::CheckScrollBounds() {
245 if (contents_) {
246 int x, y;
247
248 x = CheckScrollBounds(viewport_->width(),
249 contents_->width(),
250 -contents_->x());
251 y = CheckScrollBounds(viewport_->height(),
252 contents_->height(),
253 -contents_->y());
254
255 // This is no op if bounds are the same
256 contents_->SetBounds(-x, -y, contents_->width(), contents_->height());
257 }
258 }
259
260 gfx::Rect ScrollView::GetVisibleRect() const {
261 if (!contents_)
262 return gfx::Rect();
263
264 const int x =
265 (horiz_sb_ && horiz_sb_->IsVisible()) ? horiz_sb_->GetPosition() : 0;
266 const int y =
267 (vert_sb_ && vert_sb_->IsVisible()) ? vert_sb_->GetPosition() : 0;
268 return gfx::Rect(x, y, viewport_->width(), viewport_->height());
269 }
270
271 void ScrollView::ScrollContentsRegionToBeVisible(const gfx::Rect& rect) {
272 if (!contents_ || ((!horiz_sb_ || !horiz_sb_->IsVisible()) &&
273 (!vert_sb_ || !vert_sb_->IsVisible()))) {
274 return;
275 }
276
277 // Figure out the maximums for this scroll view.
278 const int contents_max_x =
279 std::max(viewport_->width(), contents_->width());
280 const int contents_max_y =
281 std::max(viewport_->height(), contents_->height());
282
283 // Make sure x and y are within the bounds of [0,contents_max_*].
284 int x = std::max(0, std::min(contents_max_x, rect.x()));
285 int y = std::max(0, std::min(contents_max_y, rect.y()));
286
287 // Figure out how far and down the rectangle will go taking width
288 // and height into account. This will be "clipped" by the viewport.
289 const int max_x = std::min(contents_max_x,
290 x + std::min(rect.width(), viewport_->width()));
291 const int max_y = std::min(contents_max_y,
292 y + std::min(rect.height(), viewport_->height()));
293
294 // See if the rect is already visible. Note the width is (max_x - x)
295 // and the height is (max_y - y) to take into account the clipping of
296 // either viewport or the content size.
297 const gfx::Rect vis_rect = GetVisibleRect();
298 if (vis_rect.Contains(gfx::Rect(x, y, max_x - x, max_y - y)))
299 return;
300
301 // Shift contents_'s X and Y so that the region is visible. If we
302 // need to shift up or left from where we currently are then we need
303 // to get it so that the content appears in the upper/left
304 // corner. This is done by setting the offset to -X or -Y. For down
305 // or right shifts we need to make sure it appears in the
306 // lower/right corner. This is calculated by taking max_x or max_y
307 // and scaling it back by the size of the viewport.
308 const int new_x =
309 (vis_rect.x() > x) ? x : std::max(0, max_x - viewport_->width());
310 const int new_y =
311 (vis_rect.y() > y) ? y : std::max(0, max_y - viewport_->height());
312
313 contents_->SetX(-new_x);
314 contents_->SetY(-new_y);
315 UpdateScrollBarPositions();
316 }
317
318 void ScrollView::UpdateScrollBarPositions() {
319 if (!contents_) {
320 return;
321 }
322
323 if (horiz_sb_->IsVisible()) {
324 int vw = viewport_->width();
325 int cw = contents_->width();
326 int origin = contents_->x();
327 horiz_sb_->Update(vw, cw, -origin);
328 }
329 if (vert_sb_->IsVisible()) {
330 int vh = viewport_->height();
331 int ch = contents_->height();
332 int origin = contents_->y();
333 vert_sb_->Update(vh, ch, -origin);
334 }
335 }
336
337 // TODO(ACW): We should really use ScrollWindowEx as needed
338 void ScrollView::ScrollToPosition(ScrollBar* source, int position) {
339 if (!contents_)
340 return;
341
342 if (source == horiz_sb_ && horiz_sb_->IsVisible()) {
343 int vw = viewport_->width();
344 int cw = contents_->width();
345 int origin = contents_->x();
346 if (-origin != position) {
347 int max_pos = std::max(0, cw - vw);
348 if (position < 0)
349 position = 0;
350 else if (position > max_pos)
351 position = max_pos;
352 contents_->SetX(-position);
353 contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
354 }
355 } else if (source == vert_sb_ && vert_sb_->IsVisible()) {
356 int vh = viewport_->height();
357 int ch = contents_->height();
358 int origin = contents_->y();
359 if (-origin != position) {
360 int max_pos = std::max(0, ch - vh);
361 if (position < 0)
362 position = 0;
363 else if (position > max_pos)
364 position = max_pos;
365 contents_->SetY(-position);
366 contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
367 }
368 }
369 }
370
371 int ScrollView::GetScrollIncrement(ScrollBar* source, bool is_page,
372 bool is_positive) {
373 bool is_horizontal = source->IsHorizontal();
374 int amount = 0;
375 View* view = GetContents();
376 if (view) {
377 if (is_page)
378 amount = view->GetPageScrollIncrement(this, is_horizontal, is_positive);
379 else
380 amount = view->GetLineScrollIncrement(this, is_horizontal, is_positive);
381 if (amount > 0)
382 return amount;
383 }
384 // No view, or the view didn't return a valid amount.
385 if (is_page)
386 return is_horizontal ? viewport_->width() : viewport_->height();
387 return is_horizontal ? viewport_->width() / 5 : viewport_->height() / 5;
388 }
389
390 bool ScrollView::OnKeyPressed(const KeyEvent& event) {
391 bool processed = false;
392
393 // Give vertical scrollbar priority
394 if (vert_sb_->IsVisible()) {
395 processed = vert_sb_->OnKeyPressed(event);
396 }
397
398 if (!processed && horiz_sb_->IsVisible()) {
399 processed = horiz_sb_->OnKeyPressed(event);
400 }
401 return processed;
402 }
403
404 bool ScrollView::OnMouseWheel(const MouseWheelEvent& e) {
405 bool processed = false;
406 // Give vertical scrollbar priority
407 if (vert_sb_->IsVisible()) {
408 processed = vert_sb_->OnMouseWheel(e);
409 }
410 if (!processed && horiz_sb_->IsVisible()) {
411 processed = horiz_sb_->OnMouseWheel(e);
412 }
413 return processed;
414 }
415
416 std::string ScrollView::GetClassName() const {
417 return kViewClassName;
418 }
419
420 int ScrollView::GetScrollBarWidth() const {
421 return vert_sb_->GetLayoutSize();
422 }
423
424 int ScrollView::GetScrollBarHeight() const {
425 return horiz_sb_->GetLayoutSize();
426 }
427
428 // VariableRowHeightScrollHelper ----------------------------------------------
429
430 VariableRowHeightScrollHelper::VariableRowHeightScrollHelper(
431 Controller* controller) : controller_(controller) {
432 }
433
434 VariableRowHeightScrollHelper::~VariableRowHeightScrollHelper() {
435 }
436
437 int VariableRowHeightScrollHelper::GetPageScrollIncrement(
438 ScrollView* scroll_view, bool is_horizontal, bool is_positive) {
439 if (is_horizontal)
440 return 0;
441 // y coordinate is most likely negative.
442 int y = abs(scroll_view->GetContents()->y());
443 int vis_height = scroll_view->GetContents()->parent()->height();
444 if (is_positive) {
445 // Align the bottom most row to the top of the view.
446 int bottom = std::min(scroll_view->GetContents()->height() - 1,
447 y + vis_height);
448 RowInfo bottom_row_info = GetRowInfo(bottom);
449 // If 0, ScrollView will provide a default value.
450 return std::max(0, bottom_row_info.origin - y);
451 } else {
452 // Align the row on the previous page to to the top of the view.
453 int last_page_y = y - vis_height;
454 RowInfo last_page_info = GetRowInfo(std::max(0, last_page_y));
455 if (last_page_y != last_page_info.origin)
456 return std::max(0, y - last_page_info.origin - last_page_info.height);
457 return std::max(0, y - last_page_info.origin);
458 }
459 }
460
461 int VariableRowHeightScrollHelper::GetLineScrollIncrement(
462 ScrollView* scroll_view, bool is_horizontal, bool is_positive) {
463 if (is_horizontal)
464 return 0;
465 // y coordinate is most likely negative.
466 int y = abs(scroll_view->GetContents()->y());
467 RowInfo row = GetRowInfo(y);
468 if (is_positive) {
469 return row.height - (y - row.origin);
470 } else if (y == row.origin) {
471 row = GetRowInfo(std::max(0, row.origin - 1));
472 return y - row.origin;
473 } else {
474 return y - row.origin;
475 }
476 }
477
478 VariableRowHeightScrollHelper::RowInfo
479 VariableRowHeightScrollHelper::GetRowInfo(int y) {
480 return controller_->GetRowInfo(y);
481 }
482
483 // FixedRowHeightScrollHelper -----------------------------------------------
484
485 FixedRowHeightScrollHelper::FixedRowHeightScrollHelper(int top_margin,
486 int row_height)
487 : VariableRowHeightScrollHelper(NULL),
488 top_margin_(top_margin),
489 row_height_(row_height) {
490 DCHECK_GT(row_height, 0);
491 }
492
493 VariableRowHeightScrollHelper::RowInfo
494 FixedRowHeightScrollHelper::GetRowInfo(int y) {
495 if (y < top_margin_)
496 return RowInfo(0, top_margin_);
497 return RowInfo((y - top_margin_) / row_height_ * row_height_ + top_margin_,
498 row_height_);
499 }
500
501 } // namespace views
OLDNEW
« no previous file with comments | « views/controls/scroll_view.h ('k') | views/controls/separator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698