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

Side by Side Diff: ui/views/view.cc

Issue 6286013: V2 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months 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 | « ui/views/view.h ('k') | ui/views/view_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
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 "ui/views/view.h"
6
7 #include <algorithm>
8 #include <functional>
9
10 #include "gfx/canvas.h"
11 #include "gfx/point.h"
12 #include "gfx/size.h"
13 #include "ui/base/dragdrop/drag_drop_types.h"
14 #include "ui/views/events/context_menu_controller.h"
15 #include "ui/views/events/drag_controller.h"
16 #include "ui/views/layout/layout_manager.h"
17 #include "ui/views/rendering/border.h"
18 #include "ui/views/widget/widget.h"
19
20 namespace ui {
21
22 namespace {
23
24 // Saves gfx::Canvas state upon construction and automatically restores it when
25 // it goes out of scope.
26 class ScopedCanvasState {
27 public:
28 explicit ScopedCanvasState(gfx::Canvas* canvas) : canvas_(canvas) {
29 canvas_->Save();
30 }
31 ~ScopedCanvasState() {
32 canvas_->Restore();
33 }
34
35 private:
36 gfx::Canvas* canvas_;
37 DISALLOW_COPY_AND_ASSIGN(ScopedCanvasState);
38 };
39
40 bool ExceededDragThreshold(const gfx::Point& press_point,
41 const gfx::Point& event_point) {
42 // TODO(beng): implement
43 return true;
44 }
45
46 } // namespace
47
48 ////////////////////////////////////////////////////////////////////////////////
49 // View, public:
50
51 View::View()
52 : parent_(NULL),
53 parent_owned_(true),
54 visible_(true),
55 enabled_(true),
56 id_(-1),
57 group_(-1),
58 focusable_(false),
59 context_menu_controller_(NULL),
60 drag_controller_(NULL) {
61 }
62
63 View::~View() {
64 if (parent_)
65 parent_->RemoveChildView(this);
66
67 ViewVector::const_iterator it = children_.begin();
68 for (; it != children_.end(); ++it) {
69 (*it)->parent_ = NULL;
70 if ((*it)->parent_owned())
71 delete *it;
72 }
73 }
74
75 // Size and disposition --------------------------------------------------------
76
77 void View::SetBounds(int x, int y, int width, int height) {
78 SetBoundsRect(gfx::Rect(x, y, std::max(0, width), std::max(0, height)));
79 }
80
81 void View::SetBoundsRect(const gfx::Rect& bounds) {
82 gfx::Rect old_bounds = bounds_;
83 bounds_ = bounds;
84 // TODO(beng): investigate usage of needs_layout_ in old View code.
85 if (old_bounds != bounds_) {
86 OnBoundsChanged();
87 Layout();
88 }
89 }
90
91 gfx::Rect View::GetVisibleBounds() const {
92 // TODO(beng):
93 return bounds();
94 }
95
96 void View::SetSize(const gfx::Size& size) {
97 SetBounds(x(), y(), size.width(), size.height());
98 }
99
100 void View::SetPosition(const gfx::Point& position) {
101 SetBounds(position.x(), position.y(), width(), height());
102 }
103
104 void View::SetBorder(Border* border) {
105 border_.reset(border);
106 }
107
108 gfx::Rect View::GetContentsBounds() const {
109 if (border_.get()) {
110 return gfx::Rect(
111 border_->insets().left(), border_->insets().top(),
112 width() - border_->insets().right() - border_->insets().left(),
113 height() - border_->insets().bottom() - border_->insets().top());
114 }
115 return gfx::Rect(0, 0, width(), height());
116 }
117
118 void View::OnBoundsChanged() {
119 }
120
121 gfx::Size View::GetPreferredSize() const {
122 return gfx::Size();
123 }
124
125 gfx::Size View::GetMinimumSize() const {
126 return GetPreferredSize();
127 }
128
129 void View::SetLayoutManager(LayoutManager* layout_manager) {
130 layout_manager_.reset(layout_manager);
131 }
132
133 void View::Layout() {
134 if (layout_manager_.get()) {
135 // Layout Manager handles laying out children.
136 layout_manager_->Layout(this);
137 } else {
138 // We handle laying out our own children.
139 ViewVector::iterator it = children_.begin();
140 for (; it != children_.end(); ++it)
141 (*it)->Layout();
142 }
143 // TODO(beng): needs_layout_? SchedulePaint()?
144 }
145
146 void View::SetVisible(bool visible) {
147 if (visible != visible_) {
148 visible_ = visible;
149
150 // InvaldateRect() checks for view visibility before proceeding, so we need
151 // to ask the parent to invalidate our bounds.
152 if (parent_)
153 parent_->InvalidateRect(bounds_);
154 }
155 }
156
157 void View::SetEnabled(bool enabled) {
158 if (enabled != enabled_) {
159 enabled_ = enabled;
160 Invalidate();
161 }
162 }
163
164 // Coordinate conversion -------------------------------------------------------
165
166 // static
167 void View::ConvertPointToView(View* source, View* target, gfx::Point* point) {
168 View* inner = NULL;
169 View* outer = NULL;
170 if (source->Contains(target)) {
171 inner = target;
172 outer = source;
173 } else if (target->Contains(source)) {
174 inner = source;
175 outer = target;
176 } // Note that we cannot do a plain "else" here since |source| and |target|
177 // may be in different hierarchies with no relation.
178
179 if (inner && outer) {
180 gfx::Point offset;
181 View* temp = inner;
182 while (temp != outer) {
183 offset.Offset(temp->x(), temp->y());
184 temp = temp->parent();
185 }
186 // When target is contained by source, we need to subtract the offset.
187 // When source is contained by target, we need to add the fofset.
188 int multiplier = inner == target ? -1 : 1;
189 point->Offset(multiplier * offset.x(), multiplier * offset.y());
190 }
191 }
192
193 // static
194 void View::ConvertPointToScreen(View* source, gfx::Point* point) {
195 Widget* widget = source->GetWidget();
196 if (widget) {
197 ConvertPointToWidget(source, point);
198 gfx::Rect r = widget->GetClientAreaScreenBounds();
199 point->Offset(r.x(), r.y());
200 }
201 }
202
203 // static
204 void View::ConvertPointToWidget(View* source, gfx::Point* point) {
205 for (View* v = source; v; v = v->parent())
206 point->Offset(v->x(), v->y());
207 }
208
209 // Tree operations -------------------------------------------------------------
210
211 Widget* View::GetWidget() const {
212 return parent_ ? parent_->GetWidget() : NULL;
213 }
214
215 void View::AddChildView(View* view) {
216 AddChildViewAt(view, children_.size());
217 }
218
219 void View::AddChildViewAt(View* view, size_t index) {
220 CHECK(view != this) << "A view cannot be its own child.";
221
222 // Remove the child from its current parent if any.
223 if (view->parent())
224 view->parent()->RemoveChildView(view);
225
226 children_.insert(children_.begin() + index, view);
227 view->parent_ = this;
228
229 // Notify the hierarchy.
230 NotifyHierarchyChanged(this, view, true);
231
232 // TODO(beng): Notify other objects like tooltip, layout manager, etc.
233 // Figure out RegisterChildrenForVisibleBoundsNotification.
234 }
235
236 View* View::RemoveChildView(View* view) {
237 ViewVector::iterator it = find(children_.begin(), children_.end(), view);
238 if (it != children_.end()) {
239 View* old_parent = view->parent_;
240 view->parent_ = NULL;
241 children_.erase(it);
242 NotifyHierarchyChanged(old_parent, view, false);
243 }
244
245 // TODO(beng): Notify other objects like tooltip, layout manager, etc.
246 return view;
247 }
248
249 void View::RemoveAllChildViews(bool delete_children) {
250 // TODO(beng): use for_each.
251 ViewVector::iterator it = children_.begin();
252 while (it != children_.end()) {
253 View* v = RemoveChildView(*it);
254 if (delete_children)
255 delete v;
256 // TODO(beng): view deletion is actually more complicated in the old view.cc
257 // figure out why. (it uses a ScopedVector to accumulate a list
258 // of views to delete).
259 }
260 }
261
262 View* View::GetChildViewAt(size_t index) {
263 CHECK(index < child_count());
264 return children_[index];
265 }
266
267 bool View::Contains(View* child) {
268 while (child) {
269 if (child == this)
270 return true;
271 child = child->parent();
272 }
273 return false;
274 }
275
276 View* View::GetViewForPoint(const gfx::Point& point) const {
277 ViewVector::const_reverse_iterator it = children_.rbegin();
278 for (; it != children_.rend(); ++it) {
279 View* child = *it;
280 if (!child->visible())
281 continue;
282
283 gfx::Point point_in_child_coords(point);
284 View::ConvertPointToView(const_cast<View*>(this), child,
285 &point_in_child_coords);
286 if (child->HitTest(point_in_child_coords))
287 return child->GetViewForPoint(point_in_child_coords);
288 }
289 return const_cast<View*>(this);
290 }
291
292 bool View::HitTest(const gfx::Point& point) const {
293 // TODO(beng): Hit test mask support.
294 return gfx::Rect(0, 0, width(), height()).Contains(point);
295 }
296
297 View* View::GetViewById(int id) const {
298 if (id_ == id)
299 return const_cast<View*>(this);
300 ViewVector::const_iterator it = children_.begin();
301 for (; it != children_.end(); ++it) {
302 View* view = (*it)->GetViewById(id);
303 if (view)
304 return view;
305 }
306 return NULL;
307 }
308
309 void View::GetViewsWithGroup(int group, ViewVector* vec) const {
310 if (group_ == group)
311 vec->push_back(const_cast<View*>(this));
312 ViewVector::const_iterator it = children_.begin();
313 for (; it != children_.end(); ++it)
314 (*it)->GetViewsWithGroup(group, vec);
315 }
316
317 void View::OnViewAdded(View* parent, View* child) {
318 }
319
320 void View::OnViewRemoved(View* parent, View* child) {
321 }
322
323 void View::OnViewAddedToWidget() {
324 }
325
326 void View::OnViewRemovedFromWidget() {
327 }
328
329 // Accelerators ----------------------------------------------------------------
330
331 void View::AddAccelerator(const Accelerator& accelerator) {
332 }
333
334 void View::RemoveAccelerator(const Accelerator& accelerator) {
335 }
336
337 void View::RemoveAllAccelerators() {
338 }
339
340 bool View::OnAcceleratorPressed(const Accelerator& accelerator) {
341 return false;
342 }
343
344 // Focus -----------------------------------------------------------------------
345
346 FocusManager* View::GetFocusManager() const {
347 return NULL;
348 }
349
350 FocusTraversable* View::GetFocusTraversable() const {
351 return NULL;
352 }
353
354 View* View::GetNextFocusableView() const {
355 return NULL;
356 }
357
358 View* View::GetPreviousFocusableView() const {
359 return NULL;
360 }
361
362 bool View::SkipDefaultKeyEventProcessing(const KeyEvent& event) const {
363 return false;
364 }
365
366 bool View::IsFocusable() const {
367 return false;
368 }
369
370 bool View::HasFocus() const {
371 return false;
372 }
373
374 void View::RequestFocus() {
375 }
376
377 void View::OnFocus(/* const FocusEvent& event */) {
378 }
379
380 void View::OnBlur() {
381 }
382
383 // Input -----------------------------------------------------------------------
384
385 bool View::OnKeyPressed(const KeyEvent& event) {
386 return true;
387 }
388
389 bool View::OnKeyReleased(const KeyEvent& event) {
390 return true;
391 }
392
393 bool View::OnMouseWheel(const MouseWheelEvent& event) {
394 return true;
395 }
396
397 bool View::OnMousePressed(const MouseEvent& event) {
398 return true;
399 }
400
401 bool View::OnMouseDragged(const MouseEvent& event) {
402 return true;
403 }
404
405 void View::OnMouseReleased(const MouseEvent& event) {
406
407 }
408
409 void View::OnMouseCaptureLost() {
410
411 }
412
413 void View::OnMouseMoved(const MouseEvent& event) {
414
415 }
416
417 void View::OnMouseEntered(const MouseEvent& event) {
418
419 }
420
421 void View::OnMouseExited(const MouseEvent& event) {
422
423 }
424
425 gfx::NativeCursor View::GetCursorForPoint(const gfx::Point& point) {
426 return NULL;
427 }
428
429 // Painting --------------------------------------------------------------------
430
431 void View::Invalidate() {
432 InvalidateRect(gfx::Rect(0, 0, width(), height()));
433 }
434
435 void View::InvalidateRect(const gfx::Rect& invalid_rect) {
436 if (!visible_)
437 return;
438
439 if (parent_) {
440 gfx::Rect r = invalid_rect;
441 r.Offset(bounds_.origin());
442 parent_->InvalidateRect(r);
443 }
444 }
445
446 void View::Paint(gfx::Canvas* canvas) {
447 // Invisible views are not painted.
448 if (!visible_)
449 return;
450
451 ScopedCanvasState canvas_state(canvas);
452 if (canvas->ClipRectInt(x(), y(), width(), height())) {
453 canvas->TranslateInt(x(), y());
454 // TODO(beng): RTL
455 ScopedCanvasState canvas_state(canvas);
456 OnPaint(canvas);
457 PaintChildren(canvas);
458 }
459 }
460
461 void View::PaintChildren(gfx::Canvas* canvas) {
462 // TODO(beng): use for_each.
463 // std::for_each(children_.begin(), children_.end(),
464 // std::bind2nd(std::mem_fun_ref(&View::Paint), canvas));
465 ViewVector::iterator it = children_.begin();
466 for (; it != children_.end(); ++it)
467 (*it)->Paint(canvas);
468 }
469
470 void View::OnPaint(gfx::Canvas* canvas) {
471 // TODO(beng): investigate moving these function calls to Paint().
472 OnPaintBackground(canvas);
473 OnPaintFocusBorder(canvas);
474 OnPaintBorder(canvas);
475 }
476
477 void View::OnPaintBackground(gfx::Canvas* canvas) {
478 }
479
480 void View::OnPaintBorder(gfx::Canvas* canvas) {
481 if (border_.get())
482 border_->Paint(const_cast<const View*>(this), canvas);
483 }
484
485 void View::OnPaintFocusBorder(gfx::Canvas* canvas) {
486 }
487
488 // Resources -------------------------------------------------------------------
489
490 ThemeProvider* View::GetThemeProvider() const {
491 Widget* widget = GetWidget();
492 return widget ? widget->GetThemeProvider() : NULL;
493 }
494
495 ////////////////////////////////////////////////////////////////////////////////
496 // View, private:
497
498 void View::DragInfo::Reset() {
499 possible_drag = false;
500 press_point = gfx::Point();
501 }
502
503 void View::DragInfo::PossibleDrag(const gfx::Point& point) {
504 possible_drag = true;
505 press_point = point;
506 }
507
508 // Drag & Drop -----------------------------------------------------------------
509
510 int View::GetDragOperations(const gfx::Point& point) {
511 return drag_controller_ ?
512 drag_controller_->GetDragOperations(const_cast<View*>(this), point) :
513 DragDropTypes::DRAG_NONE;
514 }
515
516 void View::WriteDragData(const gfx::Point& point, OSExchangeData* data) {
517 drag_controller_->WriteDragData(this, point, data);
518 }
519
520 void View::StartShellDrag(const MouseEvent& event,
521 const gfx::Point& press_point) {
522 // TODO(beng): system stuff.
523 }
524
525 // RootView API ----------------------------------------------------------------
526
527 bool View::MousePressed(const MouseEvent& event, DragInfo* drag_info) {
528 bool handled = OnMousePressed(event);
529 // TODO(beng): deal with view deletion, see ProcessMousePressed() in old code.
530 if (!enabled_)
531 return handled;
532
533 int drag_operations =
534 enabled_ && event.IsOnlyLeftMouseButton() && HitTest(event.location()) ?
535 GetDragOperations(event.location()) : DragDropTypes::DRAG_NONE;
536 if (drag_operations != DragDropTypes::DRAG_NONE) {
537 drag_info->PossibleDrag(event.location());
538 return true;
539 }
540 bool has_context_menu = event.IsRightMouseButton() ?
541 !!context_menu_controller_ : NULL;
542 return has_context_menu || handled;
543 }
544
545 bool View::MouseDragged(const MouseEvent& event, DragInfo* drag_info) {
546 if (drag_info->possible_drag &&
547 ExceededDragThreshold(drag_info->press_point, event.location())) {
548 if (!drag_controller_ ||
549 drag_controller_->CanStartDrag(this, drag_info->press_point,
550 event.location())) {
551 StartShellDrag(event, drag_info->press_point);
552 }
553 } else {
554 if (OnMouseDragged(event))
555 return true;
556 }
557 // TODO(beng): Handle view deletion from OnMouseDragged().
558 return !!context_menu_controller_ || drag_info->possible_drag;
559 }
560
561 void View::MouseReleased(const MouseEvent& event) {
562 OnMouseReleased(event);
563 // TODO(beng): Handle view deletion from OnMouseReleased().
564 if (context_menu_controller_ && event.IsOnlyRightMouseButton()) {
565 gfx::Point location(event.location());
566 if (HitTest(location)) {
567 ConvertPointToScreen(this, &location);
568 context_menu_controller_->ShowContextMenu(this, location, true);
569 }
570 }
571 }
572
573 // Tree operations -------------------------------------------------------------
574
575 void View::NotifyHierarchyChanged(View* parent, View* child, bool is_add) {
576 // Notify the child. Note that we call GetWidget() on the parent, not the
577 // child, since this method is called after the child is already removed from
578 // the hierarchy when |is_add| is false and so child->GetWidget() will always
579 // return NULL.
580 bool has_widget = parent->GetWidget() != NULL;
581 CallViewNotification(child, parent, child, is_add, has_widget);
582
583 // Notify the hierarchy up.
584 NotifyHierarchyChangedUp(parent, child, is_add);
585
586 // Notify the hierarchy down.
587 if (!is_add) {
588 // Because |child| has already been removed from |parent|'s child list, we
589 // need to notify its hierarchy manually.
590 child->NotifyHierarchyChangedDown(parent, child, is_add, has_widget);
591 }
592 NotifyHierarchyChangedDown(parent, child, is_add, has_widget);
593 }
594
595 void View::NotifyHierarchyChangedUp(View* parent, View* child, bool is_add) {
596 for (View* v = parent; v; v = v->parent()) {
597 if (is_add)
598 v->OnViewAdded(parent, child);
599 else
600 v->OnViewRemoved(parent, child);
601 }
602 }
603
604 void View::NotifyHierarchyChangedDown(View* parent, View* child, bool is_add,
605 bool has_widget) {
606 ViewVector::iterator it = children_.begin();
607 for (; it != children_.end(); ++it) {
608 CallViewNotification(*it, parent, child, is_add, has_widget);
609 (*it)->NotifyHierarchyChangedDown(parent, child, is_add, has_widget);
610 }
611 }
612
613 void View::CallViewNotification(View* target,
614 View* parent,
615 View* child,
616 bool is_add,
617 bool has_widget) {
618 if (is_add) {
619 target->OnViewAdded(parent, child);
620 if (has_widget)
621 target->OnViewAddedToWidget();
622 } else {
623 target->OnViewRemoved(parent, child);
624 if (has_widget)
625 target->OnViewRemovedFromWidget();
626 }
627 }
628
629 } // namespace ui
OLDNEW
« no previous file with comments | « ui/views/view.h ('k') | ui/views/view_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698